FPU - float und double
-
Hi,
Ich habe in C den Befehl: g=f+1
g und f sind float-Variablen. Was ich aber nicht verstehe ist, dass folgender Maschinenbefehl zur Addition von 5 auf die Variable f verwendet wird:fadd qword ptr [__real@3ff0000000000000 (12E6850h)]
1. Wieso ist das eine 8-Byte-Addition, wenn doch die Variablen f und g nur 4 Byte groß sind??
2. Wieso der Wert 3ff (=0.9375), wenns doch die 1 sein müsste?lg
-
Ob f und g nur 4 Byte groß sind, kann man ohne genaue Kenntnis des Compilers nicht bestimmen. Der Standard trifft keine Aussage über die maschinensprachliche Umsetzung des Typs "float". Wenn der Compiler entscheidet, in diesem Fall die FPU mit der doppelten Genauigkeit nach IEEE-754 zu füttern, dann darf er das. Der Microsoft-Compiler macht das besonders gerne bei Konstanten mit Punkt-Schreibweise ("1.0"). Manchmal gibt es dann eine Warnung.
Du hast keinen Maschinenbefehl angegeben, sondern eine assemblermäßige Aufbereitung des Debuggers. Der Maschinenbefehl sieht sicherlich so aus:
DC 05 50 68 2E 01
In reinem Intel-Assembler wäre das:
fadd qword ptr [12E6850]
Das "__real@3ff0000000000000" von Deinem Debugger ist lediglich ein Symbol, das der Compiler generiert hat, um den Wert 1.0 wiederzufinden. Die FPU kann nämlich nicht mit direkten Werten gefüttert werden, sondern muss auf den Speicher zugreifen. Der Compiler hat also eine Konstante 1.0 im Speicher generiert, auf die dann zugegriffen wird. Nachdem das Programm geladen wurde, ist die Konstante in der Speicherstelle 12E6850h gelandet. Dort steht dann sicherlich der 8-Byte-Double-Wert für 1.0: 00 00 00 00 00 00 F0 3F.
viele grüße
ralph
-
rkhb schrieb:
Wenn der Compiler entscheidet, in diesem Fall die FPU mit der doppelten Genauigkeit nach IEEE-754 zu füttern, dann darf er das. Der Microsoft-Compiler macht das besonders gerne bei Konstanten mit Punkt-Schreibweise ("1.0"). Manchmal gibt es dann eine Warnung.
Gemäß C Standard ist jedes Fließkommaliteral ohne Typspezifizierer "fFlL" vom Typ double.
Der Compiler macht hier nicht besonders gerne irgendwas, sondern hält sich an den Standard. Wird diese Fließkommakonstante einem nicht kompatiblen Typ zugewiesen, bei dem es zu "Verlusten" kommt ( sizeof(float)<sizeof(double) ), kann der Compiler warnen, muss es aber nicht.
-
Erstmal super und vielen Dank für die Antwort! Sehr verständlich!
Und wo wird denn die Double-Konstante genau abgelegt? Es ist der Datensegment des Arbeitsspeichers oder?
lg
-
Wutz schrieb:
Der Compiler macht hier nicht besonders gerne irgendwas, sondern hält sich an den Standard.
Der C-Typ "Double" muss nicht mit dem IEEE-Typ "Double" übereinstimmen, wobei die IEEE-754 überhaupt kein "Float" kennt. Und überhaupt hat das Ganze nichts mit dem Endprodukt zu tun, sondern nur mit den Konventionen im Quelltext. Sonst wäre C nämlich nicht plattformunabhängig. Selbstverständlich darf der Compiler auf die Idee kommen, sämtliche C-Floats als IEEE-Doubles abzuspeichern und zu verarbeiten. Intern arbeitet die FPU ja mit 80 Bit Genauigkeit. Das Programm darf nur nicht den Wertebereich des C-Standards verlassen. Gegenargumente nehme ich gerne mit genauer Fundstelle im Standard entgegen.
viele grüße
ralph
-
Jeffson schrieb:
Und wo wird denn die Double-Konstante genau abgelegt? Es ist der Datensegment des Arbeitsspeichers oder?
Ein Fließkommaliteral, oder wie du es hier nennst, eine Double-Konstante ist gemäß C Standard kein Objekt, im Gegensatz zu z.B. einem String-Literal.
Deshalb schreibt der C Standard auch hierfür nichts vor sondern überlässt die konkrete Implementierung dem Compilerbauer, wenn du Glück hast, findest du dort deine Frage beantwortet, d.h.double d=1.0 /* dürfte wohl ohne temporäres Objekt direkt im Code verdrahtet werden */ if( d==1.0 ) /* Standard schreibt nichts vor, ob überhaupt und wenn ja wo ein Objekt abgelegt wird */ printf("%f",1.0) /* ebenso */ ...
Der C Standard nennt nur "Objekte werden im Speicher abgelegt" und kennt auch kein Code/Daten/Text-Segment oder Stack/Heap, das sind alles nur Hilfsbegriffe (u.a. durchaus auch von Compilerbauern verwendet).
Zur Verdeutlichung vielleicht nochmal:&1.0 /* in C nicht-Standard */ &"hello" /* standardkonform */
-
rkhb schrieb:
Der C-Typ "Double" muss nicht mit dem IEEE-Typ "Double" übereinstimmen, wobei die IEEE-754 überhaupt kein "Float" kennt.
Habe ich nie behauptet, der Standard nennt zwar IEEE-754, schreibt aber nicht vor, dass dieser für Fließkommaobjekte verwendet werden muss, sondern überlässt dies (zum Glück) dem Compilerbauer.
rkhb schrieb:
Und überhaupt hat das Ganze nichts mit dem Endprodukt zu tun, sondern nur mit den Konventionen im Quelltext.
Die Konventionen im Quelltext sind der Standard.
rkhb schrieb:
Selbstverständlich darf der Compiler auf die Idee kommen, sämtliche C-Floats als IEEE-Doubles abzuspeichern und zu verarbeiten.
s.o.
rkhb schrieb:
Intern arbeitet die FPU ja mit 80 Bit Genauigkeit.
Irrelevant für den Standard.
rkhb schrieb:
Das Programm darf nur nicht den Wertebereich des C-Standards verlassen.
Der Standard definiert keinen Wertebereich, er schreibt nur Grenzen für die konkrete Implementierung durch den Compilerbauer vor. Und das ist auch gut so.
Für Fließkommatypen schreibt der C-Standard z.B. FLT_MAX,DBL_MAX,LDBL_MAX vor, die durch den Compilerbauer zu definieren sind und nur (absolut) >= als jeweils 1.0e+37 sein müssen.
Zu Größenangaben in Bytes für Fließkommatypen macht der Standard überhaupt keine Vorgaben, auch deswegen sind irgendwelche Vergleiche zu IEEE-754 o.ä. unzulässig, der Standard spricht hier jeweils von implementierungsabhängig.
-
rkhb schrieb:
Intern arbeitet die FPU ja mit 80 Bit Genauigkeit.
Das tut sie nur, wenn es auch so eingestellt ist. (Precision Control)