Float-Zahlen
-
Hallo,
kann mir einer folgendes Verhalten erklären:
#include <stdio.h> int main() { float even = 0; for( int i=0 ; i<2048 ; i+=2 ) { even += i * i; } float odd = 0; for( int i=1 ; i<2048 ; i+=2 ) { odd += i * i; } float gold = 0; for( int i=1 ; i<2048 ; i+=1 ) { gold += i * i; } printf("sum=%f, gold=%f\n", even+odd, gold); return 0; } // Ausgabe: sum=2861214720.000000, gold=2861216768.000000
Entgegen der Intuition ist sum!=gold.
Erhöht man jetzt jedoch die Genauigkeit für "gold" (float -> double), dann erhält man wie erwartet sum==gold:#include <stdio.h> int main() { float even = 0; for( int i=0 ; i<2048 ; i+=2 ) { even += i * i; } float odd = 0; for( int i=1 ; i<2048 ; i+=2 ) { odd += i * i; } double gold = 0; for( int i=1 ; i<2048 ; i+=1 ) { gold += i * i; } printf("sum=%f, gold=%f\n", even+odd, gold); return 0; } // Ausgabe: sum=2861214720.000000, gold=2861214720.000000
Das scheint mit der nicht-kommutativität von Float-Zahlen zusammenzuhängen. Was mich jedoch wundert: warum ist eine Berechnung genauer, wenn man sie in Teilsummen aufteilt und erst final zusammenfügt?
Gruß
-
Ein IEEE 754 float hat nur 32 Bit, ein Bit ist Vorzeichen, ein paar weitere sind für das Bias, und der größte Teil sind für die Matrize. 2.861.216.768 ist schon zu viel, als du mit einem 32-Bit int darstellen könntest (signed, weil floats halt auch ein Vorzeichen-Bit haben). Darauf dann noch eine Menge Additionsoperationen anzuwenden ist ... doof.
In der gold-Schleife hättest du auch:
if(i > 2042) printf("%f | %d | %f\n",gold,i * i,gold + i * i);
Einfügen können, um zu sehen, wo die Rundungsfehler kommen:
2840306688.000000 | 4173849 | 2844480512.000000 2844480512.000000 | 4177936 | 2848658432.000000 2848658432.000000 | 4182025 | 2852840448.000000 2852840448.000000 | 4186116 | 2857026560.000000 2857026560.000000 | 4190209 | 2861216768.000000
Jetzt nimm im Vergleich 1.429.557.760 und 1.431.656.960 - die passen bequem in ein 32-Bit int. Und die Addition ist hier noch nicht so kritisch. Ergibt daher schon Sinn.
EDIT: Vermaledeite Einrückungen ...
-
Mit Anzahl bits hat das überhaupt nix zu tun, hier passt alles sicherlich in 32 bits:
#include <stdio.h> int main() { float sum = 0; float summand = 0.1; int i; for(i = 0; i < 10; ++i) sum += summand; if(sum == 1) printf("1 und %f sind gleich", sum); else printf("1 und %f sind ungleich", sum); }
-
Belli schrieb:
Mit Anzahl bits hat das überhaupt nix zu tun,
Doch!
hier passt alles sicherlich in 32 bits:
Was hat dein Beispiel mit dem Problem des TE zu tun? Du demonstrierst eine völlig andere Eigenschaft von Fließkommazahlen.
-
dachschaden schrieb:
der größte Teil sind für die Matrize
Mantisse heißt das.
-
SeppJ schrieb:
Was hat dein Beispiel mit dem Problem des TE zu tun? Du demonstrierst eine völlig andere Eigenschaft von Fließkommazahlen.
Siehe:
Gast43321 schrieb:
...
Entgegen der Intuition ist sum!=gold.So ist es auch in meinem Beispiel:
Entgegen der Intuition ist 1 != sum
-
Belli schrieb:
So ist es auch in meinem Beispiel:
Entgegen der Intuition ist 1 != sumJa. Aber aus völlig unterschiedlichen Gründen!