Verständnis des Gurus der Woche # 67: Doppelt oder Nichts

8

Vor kurzem las ich den Beitrag: Double or Nothing von GOTW von Herb Sutter Ich bin ein wenig verwirrt mit der Erklärung des folgenden Programms:

%Vor%

Angenommen, dieser Code läuft in einer Maschine 1 Sekunde lang. Ich stimme dem Punkt zu, dass Code wie dieser albern ist.

Wie auch immer, bei der Erklärung des Problems, wenn wir x von float in double ändern, wird es auf einigen Compilern den Computer für immer am Laufen halten. Die Erklärung basiert auf dem folgenden Zitat aus dem Standard.

Zitat aus Abschnitt 3.9.1 / 8 des C ++ Standards:

  

Es gibt drei Gleitkommatypen: float, double und long double. Der Typ double stellt mindestens so viel Genauigkeit wie float bereit, und der Typ long double liefert mindestens so viel Präzision wie double. Die Menge der Werte vom Typ float ist eine Teilmenge der Menge der Werte vom Typ double; Die Menge der Werte des Typs double ist eine Teilmenge der Menge der Werte des Typs long double.

Die Frage für den Code ist:

  

Wie lange würden Sie erwarten, dass es dauert, wenn Sie "double" in "float" ändern? Warum?

Hier ist die Erklärung:

  

Es wird wahrscheinlich entweder etwa 1 Sekunde dauern (bei einer bestimmten Implementierung kann floats etwas schneller, so schnell oder etwas langsamer als doubles sein) oder für immer, abhängig davon, ob float genau alle ganzzahligen Werte von 0 bis 1e8 darstellen kann inklusive.

     

Das obige Zitat aus dem Standard bedeutet, dass es Werte geben kann, die durch ein Double dargestellt werden können, aber nicht durch einen Float dargestellt werden können. Auf einigen populären Plattformen und Compilern kann double genau alle Integer-Werte in [0,1e8] darstellen, Float jedoch nicht.

     

Was ist, wenn float nicht genau alle Integer-Werte von 0 bis 1e8 darstellen kann? Dann beginnt das modifizierte Programm herunterzuzählen, wird aber schließlich einen Wert N erreichen, der nicht dargestellt werden kann und für den N-1 == N (wegen unzureichender Fließkomma-Genauigkeit) ... und

gilt

Meine Frage ist:

Wenn float nicht einmal 1e8 darstellen kann, sollten wir bereits einen Overflow haben, wenn wir float x = 1e8 initialisieren; Wie kommen wir dann dazu, dass der Computer für immer läuft?

Ich habe hier ein einfaches Beispiel versucht (nicht double , aber int )

%Vor%

Das bedeutet, wenn der Compiler die angegebene Zahl nicht mit int type darstellen kann, führt dies zu einem Überlauf.

Also habe ich falsch gelesen? Was für einen Punkt habe ich verpasst? Ändert x von double zu float undefiniertes Verhalten?

Danke!

    
taocp 16.05.2013, 14:51
quelle

2 Antworten

9

Das Schlüsselwort ist "genau".

float kann 1e8 darstellen, sogar genau, es sei denn, Sie haben einen Freak float -Typ. Aber das bedeutet nicht, dass es alle kleineren Werte genau darstellen kann, zum Beispiel 2^25+1 = 33554433 , das 26 Bits Genauigkeit benötigt, kann nicht genau in float dargestellt werden (normalerweise hat das 23 + 1 Bits Genauigkeit), noch kann 2^25-1 = 33554431 , was 25 Bits Genauigkeit benötigt.

Diese beiden Zahlen werden dann als 2^25 = 33554432 und dann als

dargestellt %Vor%

wird wiederholt. (Sie werden früher eine Schleife treffen, aber diese hat eine schöne Dezimaldarstellung;)

In Ganzzahlarithmetik haben Sie x - 1 != x für alle x , aber nicht in Gleitkommaarithmetik.

Beachten Sie, dass die Schleife auch dann enden kann, wenn float nur die üblichen 23 + 1 Bits Genauigkeit hat, da der Standard ermöglicht, dass Fließkommaberechnungen mit einer größeren Genauigkeit ausgeführt werden als der Typ und wenn die Berechnung wird mit genügend größerer Genauigkeit durchgeführt (zB die übliche double mit 52 + 1 Bits), jede Subtraktion ändert x .

    
Daniel Fischer 16.05.2013, 15:02
quelle
0

Probieren Sie diese einfache Modifikation aus, die den Wert aufeinanderfolgender x-Werte angibt.

%Vor%

Bei einigen Implementierungen von float werden Sie sehen, dass die Werte von float bei 1e8 oder in dieser Region hängen bleiben. Dies ist wegen der Art und Weise wie die Zahlen gespeichert werden. Float kann nicht alle möglichen Dezimalwerte darstellen (und kann auch keine eingeschränkte Repräsentation darstellen). Wenn Sie also mit sehr großen Werten in float arbeiten, haben Sie im Wesentlichen eine Dezimalzahl, die auf eine gewisse Stärke eingestellt ist. Nun, wenn dieser Dezimalwert in einem Wert endet, bei dem das letzte Bit abfällt, bedeutet dies, dass es aufgerundet wird. Was Sie am Ende haben, ist ein Wert, der sich nach unten (dann zurück) zu sich selbst verringert.

    
ChrisCM 16.05.2013 15:01
quelle

Tags und Links