Ich habe einige Code-Blöcke, die tun:Ist (float) (1.2345f * 6.7809) genauer als 1.2345f * 6.7809f?
float total = <some float>;
double some_dbl = <some double>;
total *= some_dbl;
Dies löst eine Compiler-Warnung, die ich zum Schweigen bringen will, aber ich weiß nicht, wie solche Warnungen ausschalten - stattdessen würde ich eher explizit Typen werfen als erforderlich. Was hat mich denken lassen ... ist ein (float)(total * some_dbl)
genauer als total * (float)some_dbl
? Ist es compiler- oder plattformspezifisch?
Besseres Codebeispiel (unten verlinkt):
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main() {
double d_total = 1.2345678;
float f_total = (float)d_total;
double some_dbl = 6.7809123;
double actual = (d_total * some_dbl);
float no_cast = (float)(f_total * some_dbl);
float with_cast = (float)(f_total * (float)some_dbl);
cout << "actual: " << setprecision(25) << actual << endl;
cout << "no_cast: " << setprecision(25) << no_cast << endl;
cout << "with_cast: " << setprecision(25) << with_cast << endl;
cout << "no_cast, nextafter: " << setprecision(25) << nextafter(no_cast, 500.0f) << endl;
cout << endl;
cout << "Diff no_cast: " << setprecision(25) << actual - no_cast << endl;
cout << "Diff with_cast: " << setprecision(25) << with_cast - actual << endl;
return 0;
}
Edit: Also gab ich dies einen Schuss. Mit den Beispielen, die ich versuchte, fand ich einen schnell, wo total * (float)(some_dbl)
scheint mehr genau zu sein. Ich nehme an, dass das nicht immer der Fall sein wird, aber stattdessen ist das Glück des Zeichnens, oder der Compiler schneidet Double, um zu floaten, anstatt zu runden, was möglicherweise schlechtere Ergebnisse verursacht. Siehe: http://ideone.com/sRXj1z
Edit 2: Ich bestätigte mit std::nextafter
dass (float)(total * some_dbl)
wird der abgeschnittene Wert zurückkehrt, und die verknüpfte Code aktualisiert. Es ist ziemlich überraschend: Wenn der Compiler in diesem Fall immer doppelt verdoppelt, dann können Sie (float)some_dbl <= some_dbl
sagen, was dann with_cast <= no_cast
bedeutet. Dies ist jedoch nicht der Fall! with_cast
ist nicht nur größer als no_cast
, sondern auch näher am tatsächlichen Wert, was irgendwie überraschend ist, da wir Informationen vor der Multiplikation verwerfen.
'(float) (insgesamt * some_dbl)' sollte genauer sein, denn, nun, Mathe ... und das gilt für jede Sprache. –
gcc hat eine Flagge '-ffast-math', in der es nicht mehr durch einige der Beschränkungen gebunden ist, die der Standard auf Gleitkomma setzt; Es wäre interessant zu sehen, ob das Auswirkungen auf Ihr Ergebnis hat. –
Eine andere "seltsame" Sache, die Sie finden können, ist, dass die Verwendung von '1.2345678f' in Ihrer Quelle ein anderes Ergebnis ergibt als (doppelt) 1.2345678' - die Rundung zur Laufzeit kann anders auftreten zur Rundung zur Kompilierzeit. –