Domanda

Sto scrivendo un'applicazione che legge grandi matrici di float ed esegue alcune semplici operazioni con esse. Sto usando i float, perché ho pensato che sarebbe stato più veloce dei doppi, ma dopo aver fatto qualche ricerca ho scoperto che c'è un po 'di confusione su questo argomento. Qualcuno può approfondire questo?

È stato utile?

Soluzione

La risposta breve è "utilizzare la precisione necessaria per ottenere risultati accettabili."

La tua unica garanzia è che le operazioni eseguite su dati in virgola mobile sono eseguite almeno nel membro di massima precisione dell'espressione. Quindi moltiplicare due float viene fatto con almeno la precisione di float e moltiplicare un float e un double sarebbe fatto con almeno doppia precisione. Lo standard afferma che le operazioni "a virgola mobile" possono essere eseguite con una precisione maggiore rispetto al tipo di risultato dell'operazione. "

Dato che JIT per .NET tenta di lasciare le operazioni in virgola mobile nella precisione richiesta, possiamo dare un'occhiata alla documentazione di Intel per accelerare le nostre operazioni. Sulla piattaforma Intel le operazioni in virgola mobile possono essere eseguite con una precisione intermedia di 80 bit e convertite fino alla precisione richiesta.

Dalla guida di Intel alle operazioni in virgola mobile C ++ 1 (mi dispiace avere solo un albero morto), citano:

  
      
  • Utilizzare un solo tipo di precisione (ad esempio float) a meno che non sia richiesta la precisione aggiuntiva ottenuta attraverso il doppio o il doppio lungo. I tipi di precisione maggiore aumentano i requisiti di dimensioni della memoria e larghezza di banda.   ...
  •   
  • Evita espressioni aritmetiche di tipi di dati misti
  •   

Quest'ultimo punto è importante in quanto puoi rallentare te stesso con inutili cast verso / da float e double , che si traducono in codice JIT che richiede all'x87 di abbandonare il suo formato intermedio a 80 bit tra le operazioni!

1. Sì, dice C ++, ma lo standard C # più la conoscenza del CLR ci consente di sapere che le informazioni per C ++ dovrebbero essere applicabili in questo caso.

Altri suggerimenti

Ho appena letto il " Microsoft .NET Framework-Application Development Foundation 2nd " per l'esame MCTS 70-536 e c'è una nota a pagina 4 (capitolo 1):

  

NOTA Ottimizzazione delle prestazioni con tipi integrati
  Il runtime ottimizza le prestazioni dei tipi interi a 32 bit (Int32 e UInt32), quindi utilizzare questi tipi per contatori e altre variabili integrali a cui si accede frequentemente. Per le operazioni a virgola mobile, Double è il tipo più efficiente perché tali operazioni sono ottimizzate dall'hardware.

È scritto da Tony Northrup. Non so se sia un'autorità o no, ma mi aspetto che il libro ufficiale per l'esame .NET abbia un peso. Ovviamente non è una garanzia. Ho solo pensato di aggiungerlo a questa discussione.

Ho profilato una domanda simile qualche settimana fa. La linea di fondo è che per l'hardware x86, non vi è alcuna differenza significativa nelle prestazioni dei float rispetto ai doppi a meno che non diventi associato alla memoria o inizi a correre nel problema della cache. In tal caso i float avranno generalmente il vantaggio perché sono più piccoli.

Le attuali CPU Intel eseguono tutte le operazioni in virgola mobile in registri con larghezza di 80 bit, pertanto la velocità effettiva del calcolo non dovrebbe variare tra float e double.

Se carica & amp; le operazioni del negozio sono il collo di bottiglia, quindi i float saranno più veloci, perché sono più piccoli. Se stai eseguendo un numero significativo di calcoli tra carichi e magazzini, dovrebbe essere circa uguale.

Qualcun altro ha citato di evitare conversioni tra float & amp; doppio e calcoli che utilizzano operandi di entrambi i tipi. Questo è un buon consiglio, e se usi qualsiasi funzione della libreria matematica che restituisce il doppio (per esempio), allora mantenere tutto come doppio sarà più veloce.

Sto scrivendo un ray tracer e la sostituzione dei float con i doppi per la mia classe Color mi dà uno speedup del 5%. Sostituire i vettori galleggianti con doppio è un altro 5% più veloce! Abbastanza bello :)

Questo è con un Core i7 920

Con l'aritmetica di 387 FPU, float è solo più veloce del doppio per alcune operazioni iterative lunghe come pow, log, ecc (e solo se il compilatore imposta la parola di controllo FPU in modo appropriato).

Con l'aritmetica SSE compresso, fa comunque una grande differenza.

Matthijs,

Ti sbagli. 32-bit è molto più efficiente di 16-bit - nei moderni processori ... Forse non per quanto riguarda la memoria, ma in effetti a 32 bit è la strada da percorrere.

Dovresti davvero aggiornare il tuo professore con qualcosa di più "aggiornato". ;)

Comunque, per rispondere alla domanda; float e double hanno esattamente le stesse prestazioni, almeno sul mio Intel i7 870 (come in teoria).

Ecco le mie misure:

(ho creato un "algoritmo" che ho ripetuto per 10.000.000 di volte, e poi ripetuto per 300 volte, e da ciò ho fatto una media.)

double
-----------------------------
1 core  = 990 ms
4 cores = 340 ms
6 cores = 282 ms
8 cores = 250 ms

float
-----------------------------
1 core  = 992 ms
4 cores = 340 ms
6 cores = 282 ms
8 cores = 250 ms

Ciò indica che i float sono leggermente più veloci dei doppi: http://www.herongyang.com /cs_b/performance.html

In generale, ogni volta che si esegue un confronto sulle prestazioni, è necessario tenere conto di casi particolari, ad esempio l'utilizzo di un tipo richiede conversioni aggiuntive o il massaggio dei dati? Questi si sommano e possono credere a parametri di riferimento generici come questo.

I float dovrebbero essere più veloci su un sistema a 32 bit, ma profilare il codice per assicurarsi di ottimizzare la cosa giusta.

Ho sempre pensato che i processori fossero ottimizzati o uguali indipendentemente da float o double. Cercando ottimizzazioni sui miei calcoli intensivi (molti tratte da una matrice, confronti di due valori) ho scoperto che i float corrono circa il 13% più velocemente.

Questo mi ha sorpreso, ma immagino sia dovuto alla natura del mio problema. Non eseguo cast tra float e double nel nucleo delle operazioni, e i miei calcoli stanno principalmente aggiungendo, moltiplicando e sottraendo.

Questo è sul mio i7 920, con un sistema operativo a 64 bit.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top