2008-10-30 8 views
25

Ich habe von "Fehler" gehört, wenn Sie Gleitkommavariablen verwenden. Jetzt versuche ich, dieses Rätsel zu lösen, und ich denke, ich bekomme einen Rundungs-/Gleitkommafehler. Also werde ich endlich die Grundlagen des Gleitkommafehlers herausfinden.Was ist ein einfaches Beispiel für Gleitkomma-/Rundungsfehler?

Was ist ein einfaches Beispiel für Gleitkomma-/Rundungsfehler (vorzugsweise in C++)?

Bearbeiten: Zum Beispiel sagen, ich habe ein Ereignis, das Wahrscheinlichkeit p von Erfolg hat. Ich mache dieses Ereignis 10 mal (p ändert sich nicht und alle Versuche sind unabhängig). Wie hoch ist die Wahrscheinlichkeit von genau 2 erfolgreichen Versuchen? Ich habe dies codiert als:

double p_2x_success = pow(1-p, (double)8) * pow(p, (double)2) * (double)choose(8, 2); 

Ist dies eine Gelegenheit für Gleitkommafehler?

+0

Ich denke, was Sie wirklich brauchen, ist dies: [Was jeder Informatiker Über Gleitkommaarithmetik wissen sollten] (http://docs.sun.com/source/ 806-3568/ncg_goldberg.html). – Patrick

+0

Lesen Sie diese: http://blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1 –

+0

Siehe einfaches Java-Beispiel, sollte in C identisch sein: http://stackoverflow.com/ a/15790782/254109 – xmedeko

Antwort

9

Im Allgemeinen bezieht sich der Gleitkommafehler auf eine Zahl, die nicht in der IEEE-Gleitkommadarstellung gespeichert werden kann.

Integer werden mit dem am weitesten rechts liegenden Bit mit der Nummer 1 gespeichert, und jedes Bit auf der linken Seite ist doppelt so groß (2,4,8, ...). Es ist leicht zu sehen, dass dies jede ganze Zahl bis zu 2^n speichern kann, wobei n die Anzahl der Bits ist.

Die Mantisse (Dezimalteil) einer Gleitkommazahl wird auf ähnliche Weise gespeichert, bewegt sich jedoch von links nach rechts, und jedes nachfolgende Bit ist die Hälfte des Werts des vorherigen. (Es ist tatsächlich ein wenig komplizierter als das, aber es wird für jetzt tun).

So sind Zahlen wie 0,5 (1/2) einfach zu speichern, aber nicht jede Zahl < 1 kann durch Hinzufügen einer festen Anzahl von Brüchen der Form 1/2, 1/4, 1/8 erstellt werden. ...

Ein wirklich einfaches Beispiel ist 0,1 oder 1/10. Dies kann mit einer unendlichen Reihe gemacht werden (die ich nicht wirklich stören kann), aber wenn ein Computer 0,1 speichert, ist es nicht genau diese Nummer, die gespeichert wird.

Wenn Sie Zugang zu einem Unix-Rechner haben, ist es einfach, das zu sehen.

Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> 0.1 
0.10000000000000001 
>>> 

Sie werden wirklich vorsichtig mit Gleichheit Tests mit Schwimmern und verdoppelt sein wollen, in welcher Sprache Sie sind in

(Für Ihr Beispiel ist 0.2 eine andere dieser lästigen Zahlen, die nicht in IEEE-Binärdateien gespeichert werden können, aber solange Sie Ungleichheiten statt Gleichheiten testen, wie p < = 0.2, dann sind Sie in Ordnung .)

5

Eine einfache C eine, die caught ht mich eine Weile zurück,

char *c = "90.1000"; 
double d = 0; 
sscanf(c,"%f",&d); 
printf("%0.4f",d); 

>> 90.0999 

Diese in einer Funktion war, die Winkel in DMS in Radiant umgewandelt, die nicht im obigen Fall getan hat.

+2

Wie ein anonymer Benutzer mit 'sscanf' festgestellt hat, erfordert der Konvertierungsspezifikator" f "ein' float' Argument, kein 'double' (jedoch bedeutet" f "' double' zu ​​'printf') - Ja, es ist verwirrend. Der "lf" modifizierte Konvertierungsspezifizierer sollte verwendet werden, um 'sscanf' mit einem' double' arbeiten zu lassen. –

26
for(double d = 0; d != 0.3; d += 0.1); // never terminates 
19

Bild sagt mehr als tausend Worte - versuchen Gleichung zu zeichnen f(k):
enter image description here
und Sie werden solche XY-Graph (X und Y sind in logarithmischen Skala) erhalten.
.
Wenn der Computer 32-Bit-Gleitkommazahlen ohne Rundungsfehler darstellen könnte, dann sollten wir für jede k Null erhalten. Stattdessen steigt der Fehler wegen der Gleitkomma-Fehlerakkumulation mit größeren Werten von k an.

hth!

3

Hier ist eine, die mich erwischt hat.

round(256.49999) == 256 
roundf(256.49999) == 257 

verdoppelt und schwimmt ..