2016-08-18 3 views
-4

Ich habe einen OpenCL-Kernel für einige Berechnungen. Ich habe festgestellt, dass nur ein Thread mit CPU-Codes ein anderes Ergebnis liefert. Ich benutze vs2010 x64 Freigabemodus.OpenCL Kernel Float Division gibt unterschiedliche Ergebnisse

Durch die Überprüfung der OpenCL-Codes durch einige Beispiele, fand ich einige interessante Ergebnisse. Hier sind die Testbeispiele in Kernel-Codes.

float fval = (10296184.0)/(float)(x*y*z); // which gives result fval = 3351.6225585938 

float fval = (10296184.0f)/(float)(x*y*z); // which gives result fval = 3351.6225585938 

Variablen sind:: int x,y, z

von einigen Operationen Diese Werte werden berechnet

I 3 Fällen in OpenCL Kernel getestet wird die Präzision durch printf("%.10f", fval);

Fall 1 geprüft. Und ihre Werte sind x = 12, y = 16, z = 16;

Fall 2:

float fval = (10296184.0)/(float)(12*16*16); // which gives result fval = 3351.6223144531 

float fval = (10296184.0f)/(float)(12*16*16); // which gives result fval = 3351.6223144531 

Fall 3:

Wenn ich jedoch die Differenz der fval durch Verwendung beiden obigen Ausdrücke zu berechnen, ist das Ergebnis 0, wenn 10296184.0 verwenden.

float fval = (10296184.0)/(float)(x*y*z) - (10296184.0)/(float)(12*16*16); // which gives result fval = 0.0000000000

float fval = (10296184.0f)/(float)(x*y*z) - (10296184.0f)/(float)(12*16*16); // which gives result fval = 0.0001812663

Könnte jemand den Grund erklären oder einige Hinweise geben Sie mir?

+3

Siehe [Ist Fließkomma-Mathematik gebrochen] (http://stackoverflow.com/questions/588004/is-floating-point-math-broken)? Diese Ungenauigkeiten sind ein Grund, warum ich immer 'double' benutze (obwohl es dasselbe erleidet), es sei denn, ein Zwang zwingt mich, den minderwertigen' float' zu verwenden. –

+0

Wenn Sie mehr Präzision als das benötigen, ist Double-Precision-FP ein Ding auf GPUs. Es hat sehr wenig Anwendung beim Rendern. –

+0

Geben Sie an, wie die Werte von '3351.6226, 3351.6223 und 0' ermittelt wurden. 'printf ("% f ", ...)', Debugger, etc. – chux

Antwort

3

Einige Beobachtungen:

Die beiden float Werte um 1 ULP. Die Ergebnisse unterscheiden sich daher um einen Mindestbetrag.

// Float ULP in the 2's place here 
//  v 
0x1.a2f3ea0000000p+11 3351.622314... // OP's lower float value 
0x1.a2f3eaaaaaaabp+11 3351.622395... // higher precision quotient 
0x1.a2f3ec0000000p+11 3351.622558... // OP's higher float value 

(10296184.0)/(float)(12*16*16) bei berechnet Zeit kompilieren wie die näher Ergebnis auf die erwartete mathematische Antwort.

float fval = (10296184.0)/(float)(x*y*z) wird unter Lauf Zeit berechnet.

Betrachtet man float Variablen verwendet wird, überrascht, dass Code diese Division mit double math. Tut. Dies ist eine double konstante Teilung durch eine double (die die Förderung der float Produkt ist), was zu einem double Quotienten, konvertiert in eine float und dann gespeichert. Ich würde erwarten, 10296184.0f - beachten Sie die f - verwendet worden, dann könnte die Mathematik alles als float s getan worden sein.

C ermöglicht verschiedene Rundungsmodi, die mit FLT_ROUNDS gekennzeichnet sind. Diese können zur Kompilierzeit und Laufzeit abweichen und können den Unterschied erklären. Das Wissen über das Ergebnis fegetround() (Die Funktion erhält die aktuelle Rundungsrichtung.) Würde helfen.

OP Mai haben verschiedene Compiler-Optimierungen verwendet, die Genauigkeit für die Geschwindigkeit opfern.


C nicht nicht geben Sie die Präzision von mathematischen Operationen, aber gut zum letzten ULP sollte mit */+ - sqrt() modf() auf Qualität Plattformen zu erwarten. Ich vermute, dass Code unter einer schwachen mathematischen Implementierung leidet.

Verwandte Themen