2013-10-27 16 views
13

La maggior parte dei problemi di calcolo scientifico che è necessario risolvere implementando un particolare algoritmo in C/C++ richiede un'accuratezza molto inferiore alla doppia precisione. Ad esempio, 1e-6, 1e-7 la precisione copre 99% dei casi per i risolutori ODE o l'integrazione numerica. Anche nei rari casi in cui abbiamo bisogno di maggiore accuratezza, di solito il metodo numerico fallisce prima di poter sognare di raggiungere un'accuratezza vicina alla doppia precisione. Esempio: non possiamo aspettarci un'accuratezza 1e-16 da un semplice metodo Runge-Kutta anche quando si risolve un'equazione differenziale ordinaria normale del nostiff a causa di errori di arrotondamento. In questo caso, il requisito della doppia precisione è analogo a quello di chiedere una migliore approssimazione della risposta sbagliata.Ottimizzazioni a virgola mobile - linea guida

Quindi, l'ottimizzazione aggressiva del punto di viraggio sembra essere una situazione vantaggiosa per tutti, in quanto rende il codice più veloce (molto più veloce!) E non influisce sulla precisione di destinazione del problema specifico. Detto questo, sembra notevole difficile assicurarsi che una particolare implementazione/codice sia stabile contro le ottimizzazioni fp. Esempio classico (e alquanto inquietante): GSL, la biblioteca scientifica GNU, non è solo la libreria numerica standard sul mercato, ma è anche una libreria molto ben scritta (non riesco a immaginare di fare un lavoro migliore). Tuttavia, GSL non è stabile contro le ottimizzazioni fp. Infatti, se si compila GSL con il compilatore intel, ad esempio, i test interni non avranno esito positivo a meno che non si attivi il flag -fp-model strict che disattiva le ottimizzazioni fp.

Quindi, la mia domanda è: ci sono linee guida generali per scrivere codice che sia stabile contro le ottimizzazioni in virgola mobile aggressive. Sono queste le linee guida linguistiche (compilatore) specifiche. In tal caso, quali sono le best practice C/C++ (gcc/icc)?

Nota 1: questa domanda non chiede quali sono i flag di ottimizzazione fp in gcc/icc.

Nota 2: questa domanda non si pone in merito alle linee guida generali per l'ottimizzazione di C/C++ (come non utilizzare le funzioni virtuali per le funzioni di piccole dimensioni chiamate molto).

Nota 3: questa domanda non richiede l'elenco delle ottimizzazioni fp più standard (come x/x -> 1).

Nota 4: Credo fermamente che questa NON sia una domanda soggettiva/fuori tema simile al classico "The Coolest Server Names". Se non sei d'accordo (perché non sto fornendo un esempio/codice/problema concreto), segnalalo come wiki della comunità. Sono molto più interessato alla risposta che ad ottenere alcuni punti di stato (non sono importanti - ottieni il punto!).

+2

Gli errori si accumulano - anche se tutti i calcoli eseguiti a doppia precisione, il risultato finale non sarà preciso fino all'ultimo bit, lontano da esso. Se si utilizza float ovunque, è necessario eseguire una corretta analisi degli errori per capire quanti bit della risposta sono affidabili (se ce ne sono). Dovresti fare la stessa cosa per il doppio, ovviamente. –

+2

La stabilità numerica generale è spesso ottenuta tramite passaggi intermedi scelti con cura e per lo più fragili, specificamente progettati per superare il carattere non associativo dell'aritmetica a virgola mobile a precisione finita. Ottimizzazioni aggressive tendono a rompersi, ad es. cambiando l'ordine di esecuzione. La regolazione iterativa potrebbe aiutare, ma poi ci vuole più tempo per ottenere la risposta. Suggerimento: potresti voler pubblicare la tua domanda sul sito [Computational Science] (http://scicomp.stackexchange.com/). –

risposta

12

I produttori di compilatori giustificano il tipo di ottimizzazioni -ffast-math con l'affermazione che l'influenza di queste ottimizzazioni su numerically stable algorithms è minima.

Pertanto, se si desidera scrivere codice che sia efficace contro queste ottimizzazioni, una condizione sufficiente è scrivere solo codice numericamente stabile.

Ora la tua domanda potrebbe essere: "Come si scrive codice numericamente stabile?". È qui che la tua domanda potrebbe essere un po 'ampia: ci sono interi libri dedicati all'argomento. La pagina di Wikipedia che ho già collegato ha un buon esempio e lo here è un altro buon esempio. Non potrei raccomandare un libro in particolare, questa non è la mia area di competenza.

Nota 1: La desiderabilità della stabilità numerica va oltre l'ottimizzazione del compilatore. Se si ha scelta, scrivere codice numericamente stabile anche se non si prevede di utilizzare le ottimizzazioni dello stile -ffast-math. Il codice numericamente instabile può fornire risultati errati anche se compilato con una semantica a virgola mobile IEEE 754 rigorosa.

Nota 2: non è possibile aspettarsi che le librerie esterne funzionino quando sono compilate con flag -ffast-math. Queste librerie, scritte da esperti in virgola mobile, potrebbero aver bisogno di giocare trucchi sottili con le proprietà dei calcoli IEEE 754. Questo tipo di trucco potrebbe essere rotto dalle ottimizzazioni -ffast-math, ma migliorano le prestazioni più di quanto ci si aspetti dal compilatore, anche se lo si lascia fare. Per i calcoli a virgola mobile, esperto con conoscenza del dominio batte ogni volta il compilatore. Ad esempio tra molti è l'implementazione tripla-doppia trovata in CRlibm. Questo codice si interrompe se non è compilato con una semantica IEEE 754 rigorosa. Un altro algoritmo più elementare che interrompe le ottimizzazioni del compilatore è Kahan summation: quando viene compilato con ottimizzazioni non sicure, c = (t - sum) - y è ottimizzato per c = 0. Questo, ovviamente, sconfigge completamente lo scopo dell'algoritmo.

+1

Non è impossibile per una libreria lavorare con "-ffast-math". Uno degli obiettivi cardine degli sviluppatori GSL è di rendere GSL stabile sotto -ffast-math (secondo un rapporto sulla mailing list di gsl). Dicono che sarebbe difficile (ma non impossibile). Inoltre, GSL implementa solo algoritmi molto affidabili e stabili. Quindi è un problema di codice che non è impossibile da risolvere => ci devono essere tecniche generali in C/C++ per raggiungere questo obiettivo. –

+2

@ViniciusMiranda Ho detto "non puoi aspettarti le librerie esterne". È una dichiarazione generale su tutte le librerie a virgola mobile. Se preferisci: Non Forall libreria F in virgola mobile, puoi aspettarti che F funzioni con '-ffast-math'. Se gli autori di GSL puntano alla compatibilità con queste opzioni, fanno bene a loro. Non tutti lo fanno e, in alcuni casi, non ha nemmeno senso, per il tipo di ragione a cui ho alluso. –