FloatToStr erzeugt Fehler

Für Fehler in Lazarus, um diese von anderen verifizieren zu lassen.
Antworten
MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

FloatToStr erzeugt Fehler

Beitrag von MitjaStachowiak »

___________

Edit: Ich hatte vor kurzem noch ein anderes Problem mit FloatToStr. Es lieferte teilweise falsche Werte. Um keine Verwirrung zu stiften, hier der Link: viewtopic.php?f=18&t=6409
___________

Hallo,
ich habe gerade so ein kleines Tool geschrieben, womit man Gleitkommazahlen Hexadezimal eingeben kann, um zu sehen, welche Bits wofür gut sind. Jedoch erzeugt FloatToStr bei manchen Werten ein Exception. Rekonstruieren kann man das am besten mit folgendem Code:

Code: Alles auswählen

var
 c : Cardinal;
 f : Single;
 s : AnsiString;
 
[...]
 
 c := 4294967295;
 f := PSingle(@c)^;
 s := FloatToStr(f);
 ShowMessage(s);


4294967295 ist der größte Wert, den man in eine 32-Bit-Zahl rein packen kann. Eigentlich sollte das doch auch als Single interpretiert funktionieren, oder?
Man kann mit der Variable f jedenfalls vor FloatToStr noch herumrechnen...
Zuletzt geändert von MitjaStachowiak am Mi 7. Nov 2012, 12:17, insgesamt 1-mal geändert.

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: FloatToStr erzeugt Fehler

Beitrag von MAC »

Probier das ganze mal mit

Code: Alles auswählen

c := 1;


Was kommt raus ?
Sinnloses: 1,4 * 10 hoch -45

Wieso:
Wahrscheinlich weil du einen Pointer auf C nimmst und dann den Kompiler sagst, das dieser Pointer auf einen Typ von Cardinal in wirklichkeit ein Pointer auf Single ist.
Dabei wird der Wert nicht von Cardinal in Single umgewandelt.
Wahrscheinlich wird es dann ein unterschied von Single und Cardinal sein... Da wird Wikipedia dir bestimmt was sagen können.

Ach ja, der Debugger sagt bei deiner Zahl das f den wert hat: -nan(0x7fffff).

Code: Alles auswählen

Signatur := nil;

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: FloatToStr erzeugt Fehler

Beitrag von MitjaStachowiak »

Ja, es ist schon Absicht, dass der Wert nicht korrekt umgewandelt wird. Ich wundere mich nur, dass es dadurch zu einem Fehler kommt. Single und Cardinal haben ja beide 32 Bit.

Ich dachte, Single-Werte funktionieren so:
Wenn (Bit 31-24)2 > 0, dann X = 1, sonst X = 0
Wert = (X,Bit 23-1)2 * 2 ^ ((Bit 31-24)2 - 126 - X) * (-1)^Bit 32

[Edit] Hier Steht noch etwas dazu: http://www.informatik.uni-ulm.de/ni/Leh ... Float2.pdf. [/Edit]

FloatToStr macht aber eine Ausnahme, wenn die Exponenten-Bits (31-24) FF sind:
0000807F = +Inf
000080FF = -Inf

Wenn dazu noch ein Stellen-Bit (32-1) 1 ist, kommt ein Fehler. Ob der Absicht ist oder nicht, ist noch die Frage. Anscheinend beachten die Normalen Rechenoperatoren diese Ausnahme nicht und rechnen, wie sonst auch. :roll:
Zuletzt geändert von MitjaStachowiak am Mo 12. Sep 2011, 17:43, insgesamt 1-mal geändert.

MitjaStachowiak
Lazarusforum e. V.
Beiträge: 394
Registriert: Sa 15. Mai 2010, 13:46
CPU-Target: 64 bit
Kontaktdaten:

Re: FloatToStr erzeugt Fehler

Beitrag von MitjaStachowiak »

Der Fehler scheint nur bei NaN-Werten aufzutreten. Deswegen habe ich dafür folgende Ausnahme gemacht:

Code: Alles auswählen

if ((PByte(@c+3)^ = 127) or (PByte(@c+3)^ = 255)) and (PByte(@c+2)^ >= 128) and ((PByte(@c+2)^ > 128) or (PWord(@c)^ <> 0)) then Label2.Caption := 'NaN'
  else Label2.Caption := FloatToStr(PSingle(@c)^);

c ist der Cardinal- bzw. Single-Wert, Label2 Das Ausgabefeld. Könnte man vielleicht noch vereinfachen, aber für meinen Zweck sollte das so gehen...
Wen's interessiert: Hier (http://www.mitjastachowiak.de/?/Projects/HexEdit) könnt ihr euch das fertige Programm ansehen ;-)

indianer-frank
Beiträge: 134
Registriert: So 30. Nov 2008, 21:53

Re: FloatToStr erzeugt Fehler

Beitrag von indianer-frank »

Vielleicht solltest Du Dich erst einmal näher mit den gut dokumentierten Grundlagen der IEEE Floating-Point-Arithmetik bekannt machen, bevor Du so im Nebel stocherst: Für den Anfang reicht zB http://de.wikipedia.org/wiki/IEEE_754; hier speziell Abschnitt 5.5 Keine Zahl (NaN) . Dein NAN-Test ist beweitem nicht erschöpfend, und die Aussage
MitjaStachowiak hat geschrieben: Man kann mit der Variable f jedenfalls vor FloatToStr noch herumrechnen...
stimmt so nur für Quiet-NANs (wobei 'rechnen' hier etwas euphemistisch ist, etwa im Sinne von 1+f wirft keinen Fehler). Dies gilt (bei normalen Einstellungen für die FPU) aber nicht für Signalling-NANs, wie zB (mit Deinen Bezeichnungen) in

Code: Alles auswählen

c := $7FBFFFFF;  //Signalling-NAN
f := PSingle(@c)^;
f := 1+f;

Hier wirft das 1+f eine EInvalidOp : Invalid floating point operation

Gruß Frank

PS: Das FloatToStr nicht mit Quiet-NANs zurecht kommt ist im übrigen eine FPC-Spezialität, Delphi zB kann's durchaus und liefert 'NAN'.

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: FloatToStr erzeugt Fehler

Beitrag von MAC »

indianer-frank hat geschrieben:PS: Das FloatToStr nicht mit Quiet-NANs zurecht kommt ist im übrigen eine FPC-Spezialität, Delphi zB kann's durchaus und liefert 'NAN'.


Kann mal jemand das bei Delphi XE2 ausprobieren ^^

Code: Alles auswählen

Signatur := nil;

Antworten