Fließkommazahlen haben leider eine begrenzte Genauigkeit.
Der Wert 0,1 kann nicht exakt gespeichert werden. Als Double ist es ungefähr 0,100000000000000006, als Single ca. 0,100000001490116119.
Unter 32 Bit benutzt Delphi die x87 FPU für Berechnungen von Fließkommazahlen. Die arbeitet intern mit "Extended"-Werten (80 Bit; Double ist 64 Bit und Single nur 32 Bit).
Der Befehl "b := 1 / a;" macht also folgendes:
- Konstante 1.0 laden (ist exakt)
- Wert aus Variable "a" laden und von Double nach Extended kovertieren
- Rechnung durchführen (1.0 / Extended(a))
- Das Ergebnis ist ungefähr 9,9999999999999994 und liegt natürlich als Extended vor.
- Das Ergebnis passt nicht in "b", muss also nach Double konvertiert werden. Dabei wird gerundet! Und deshalb steht im Double "b" dann 10 (ein Wert, der exakt speicherbar ist).
Damit sollte klar sein, was anders läuft, wenn du "Trunc(1 / a)" aufrufst: der Wert bleibt Extended und wird nicht nach Double gerundet. Und Trunc(9,9999999999999994) ist nun mal 9, nicht 10.
Unter Delphi 64 Bit können die Ergebnisse übrigens wieder leicht anders aussehen, da hier SSE-Befehle zur Berechnungen von Fließkommazahlen verwendet werden. Extended gibt es da nicht mehr, nur noch Double und Single. Delphi benutzt dort für Zwischenwerte standardmäßig Double, selbst wenn man nur mit Single rechnet. Dieses Verhalten kann man mit der Direktive {$EXCESSPRECISION OFF} abschalten. Was natürlich auch wieder leicht andere Ergebnisse verursachen kann.
Wie Mikkey sagte, sollte man Fließkommazahlen nicht direkt per "=" vergleichen. In der "Math"
Unit gibt es dafür "SameValue" und "CompareValue".
Bei mir in XE6 liefert dein Test diese Ergebnisse für e1, e2, e3, e4:
Code:
32 Bit, Single: 10; 9; 9; 9
32 Bit, Double: 10; 9; 10; 9
32 Bit, Extended: 10; 10; 10; 10
64 Bit, Single: 10; 9; 9; 9
64 Bit, Single*: 10; 10; 10; 10 *{$EXCESSPRECISION OFF}
64 Bit, Double: 10; 10; 10; 10