Autor Beitrag
WeBsPaCe
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: Sa 05.11.11 19:14 
Hoi... verstehe nicht ganz, wie IEEE 754 Floats (z.B. Single) gespeichert werden. Beispiel:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var
x: Single;
begin
x := 10000.0005;
ShowMessage(FloatToStr(x));
end;


Ich komme da (nach Normierung, Exponent schon gespeichert) auf:
ausblenden Quelltext
1:
2:
3:
4:
10000,0005 (dezimal)
1,001110001000000000000001000001100010010011011101001011... (binär)
  1234567890123456789012345678901234567890
           10        20        30

Und da steht nun mal die 1 erst an der 24sten Stelle, trotzdem speichert er irgendwie eine Dezimalstelle und ich bekomm eben zurück, was am nähsten dran ist. Nehme ich x := 10000.0004 steht sie an 25ster Stelle und es passiert, was ich mir eben schon vorher gewünscht habe: die Dezimalstellen werden verschluckt und ShowMessage bringt 10000 statt 10000.0004

Frage also: warum ist die 24ste Stelle meine Grenze, wenn doch für die Mantisse beim Single-Typ nur 23 Bit zur Verfügung stehen?!

Also werd wohl aufm Schlauch stehen, aber wollte grad da nicht mehr weiterdenken. Hoffe einfach, es hat jemand ne Antwort parat. ;-) Grüße! Und Danke schonmal.

//EDIT: Ausprobieren ergibt: er "rundet" auf die 23ste Stelle. Also falls 0 an der 23sten Stelle steht, wird bei 24 geschaut: wenn 1, dann auch 23ste zur 1, sonst 0 lassen. Kann das jemand bestätigen?! :suspect:


Moderiert von user profile iconNarses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Sa 05.11.2011 um 21:50

_________________
Steht der Bauer im Gemüse, hat er später grüne Füße.
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Sa 05.11.11 22:01 
Hallo,

die ab 10000.00 nächst größere Zahl bei single ist 10000+2^(-10)=10000.000976525. (13 Binärstellen werden für den Vorkommateil verbraucht, deshalb -10) Der Compiler versteht also anscheinend die 10000.0005 zunächst als double und bei der Zuweisung auf single rundet er richtig auf. Bei 10000.0004 rundet er entsprechend richtig nach unten ab. Bei mir gibt showMessage übrigens auch genau 10000.0009756525 aus, weil da sicher single zunächst in double gewandelt wird, was dann eine nicht vorhandenen Geanauigkeit vortäuscht, denn die 9 ist ja schon falsch.

Gruß GuaAck

Moderiert von user profile iconNarses: Beiträge zusammengefasst

Nachtrag: Folgender Code hilft vielleicht (Memo1 ist ein TMemo im Formular):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
PROCEDURE TForm1.Button1Click(Sender: TObject);
TYPE
  t_vx = RECORD CASE boolean OF
      true: (s: single);
      false: (i: integer);
  END;
VAR
  x: t_vx;
  j: integer;
BEGIN
  x.s := 10000.0;
  FOR j := 0 TO 9 DO
    BEGIN
      Memo1.Lines.Add(floattostr(x.s));
      x.i := x.i + 1;
    END;
END;
WeBsPaCe Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: Sa 05.11.11 22:51 
Hi, danke für die Antworten!

Leider versteh ich die Syntax vom hervorgehobenen Code gar nicht...?! (ist aber glaub ich nicht weiter tragisch, s.u.)

user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Nachtrag: Folgender Code hilft vielleicht (Memo1 ist ein TMemo im Formular):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
PROCEDURE TForm1.Button1Click(Sender: TObject);
TYPE
  t_vx = RECORD CASE boolean OF
      true: (s: single);
      false: (i: integer);

  END;
VAR
  x: t_vx;
  j: integer;
BEGIN
  x.s := 10000.0;
  FOR j := 0 TO 9 DO
    BEGIN
      Memo1.Lines.Add(floattostr(x.s));
      x.i := x.i + 1;
    END;
END;


user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Der Compiler versteht also anscheinend die 10000.0005 zunächst als double und bei der Zuweisung auf single rundet er richtig auf. Bei 10000.0004 rundet er entsprechend richtig nach unten ab. Bei mir gibt showMessage übrigens auch genau 10000.0009756525 aus, weil da sicher single zunächst in double gewandelt wird, was dann eine nicht vorhandenen Geanauigkeit vortäuscht, denn die 9 ist ja schon falsch.


Das kann so doch leider nicht richtig sein, oder?! Siehe z.B.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
var
x: Single;
begin
x := 1000.00003;
ShowMessage(FloatToStr(x));
x := 1000.00004;
ShowMessage(FloatToStr(x));
x := 1000.00005;
ShowMessage(FloatToStr(x));
end;

1000 verbraucht 10 Stellen im Binärsystem, also 9 von der Mantisse. Mit .00003 wandert die erste 1 auf Platz 25 (es wird schön 1000 in der ShowMessage ausgegeben), mit .00004 auf Platz 24 und ich bekomm eine Überraschungs-1 auf Position 23, damit innerhalb der Mantisse und schön 1000 + 2^(-23+9) in der ShowMessage.

Bin für Berichtigungen offen... :nixweiss:

_________________
Steht der Bauer im Gemüse, hat er später grüne Füße.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: Sa 05.11.11 23:32 
Bei normalisierten Single- und Double-Werten werden die werthöchsten Mantissenbits nicht gespeichert (bei Extended schon). Deshalb kann man im Prinzip bei Singles in 23 Bits praktisch 24 Bits unterbringen.
WeBsPaCe Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: So 06.11.11 00:08 
user profile iconGammatester hat folgendes geschrieben Zum zitierten Posting springen:
Bei normalisierten Single- und Double-Werten werden die werthöchsten Mantissenbits nicht gespeichert (bei Extended schon). Deshalb kann man im Prinzip bei Singles in 23 Bits praktisch 24 Bits unterbringen.


Hi! Ja, das ist klar, deswegen fang ich z.B. oben auch nicht bei 1 an zu zählen, sondern erst nach dem Komma:

user profile iconWeBsPaCe hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Quelltext
1:
2:
3:
4:
10000,0005 (dezimal)
1,001110001000000000000001000001100010010011011101001011... (binär)
  1234567890123456789012345678901234567890
           10        20        30

Das Bit ist bei meiner Rechnung leider schon berücksichtigt. ;-)

_________________
Steht der Bauer im Gemüse, hat er später grüne Füße.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: So 06.11.11 00:55 
Irgendwie verstehe ich Dein Problem nicht ganz. Wann man erstmal die Mantissenbits allein betrachten ohne die 2-er Potenz des Exponenten haben wir:
ausblenden Quelltext
1:
2:
3:
4:
Mantissenbits 32109876543210987654321
1000.0003 = 1.111 1010 0000 0000 0000 0100 11101010010010101000110000010101010
1000.0004 = 1.111 1010 0000 0000 0000 0110 10001101101110001011101011000111001
1000.0005 = 1.111 1010 0000 0000 0000 1000 00110001001001101110100101111000111
Jetzt wird auf die letzte Stelle gerundet, dabei werden 1000.0003 und 1000.0004 aufgerundet, 1000.0005 abgerundet. Das ergibt jetzt als Hex geschrieben:
ausblenden Quelltext
1:
2:
3:
1000.0003 =     7    A    0    0    0    5
1000.0004 =     7    A    0    0    0    7
1000.0005 =     7    A    0    0    0    8
Mit Vorzeichen und Exponent ergibt sich genau die Darstellung der Werte als Hexbytes:
ausblenden Quelltext
1:
2:
3:
1000.0003 = 447A0005
1000.0004 = 447A0007
1000.0005 = 447A0008
WeBsPaCe Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: So 06.11.11 01:16 
Hi, danke für deine Antwort!

user profile iconGammatester hat folgendes geschrieben Zum zitierten Posting springen:
Jetzt wird auf die letzte Stelle gerundet, [...]


Das ist genau, worum es mir geht! :-) Du hattest jetzt andere Zahlen genommen, wie ich. Ich schreib's nochmal mit meinen Zahlen hin:

ausblenden Quelltext
1:
2:
3:
1000,00003 = 1, 111101000 00000000000000 0111110111010100010000010011010101010100...
1000,00004 = 1, 111101000 00000000000000 1010011111000101101011000100011100011011...
                                         ^^wird hier abgeschnitten oder gerundet?


Mir ist einfach aufgefallen, dass - obwohl die ersten 23 Zeichen (also die komplette Mantisse für Single) komplett gleich sind - unterschiedliche Ergebnisse angezeigt werden => dachte also, ich hätte was falsch gemacht.

Dann aber festgestellt, dass es wohl auf die 24ste Stelle mit ankommt, siehe:
user profile iconWeBsPaCe hat folgendes geschrieben Zum zitierten Posting springen:
//EDIT: Ausprobieren ergibt: er "rundet" auf die 23ste Stelle. Also falls 0 an der 23sten Stelle steht, wird bei 24 geschaut: wenn 1, dann auch 23ste zur 1, sonst 0 lassen. Kann das jemand bestätigen?! :suspect:


Und wollte jetzt also nur wissen: wird da gerundet, sobald mehr als 23 Stellen da sind?

Hoffe, mein Problem kommt rüber. ;-)

_________________
Steht der Bauer im Gemüse, hat er später grüne Füße.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: So 06.11.11 01:48 
Ja es wird auf die 23. Stelle gerundet, allerdings mit round-to-even. D.h. nicht immer wird aufgerundet, wenn in der 24. Stelle ein 1 steht, bei Deinem Beispiel nicht für 1000+1/32768.0 = 1000 + 2^-15:
ausblenden Quelltext
1:
2:
3:
1000.00003 = 1.111 1010 0000 0000 0000 0000 01111101110101000100000100110101011
1000.00004 = 1.111 1010 0000 0000 0000 0000 10100111110001011010110001000111001
1000+2^-15 = 1.111 1010 0000 0000 0000 0000 10000000000000000000000000000000000
Die Hexwerte sind jetzt:
ausblenden Quelltext
1:
2:
3:
1000.00003 = 447A0000
1000.00004 = 447A0001
1000+2^-15 = 447A0000
Also wenn das Rundungsbit an der 24.Stelle ein 1 und der Rest 0 ist (das sogenannte Sticky-Bit als or aller restlichen ist Bits ist 0), dann wird auf even gerundet. Also wie oben für 1000+2^-15 oder für
ausblenden Quelltext
1:
2:
3:
Bin: 1000 + 2^-14 + 2^-15 = 1.111 1010 0000 0000 0000 0001 100000000000000
     gerundet             = 1.111 1010 0000 0000 0000 0010 100000000000000
Hex: 447A0002

Für diesen Beitrag haben gedankt: WeBsPaCe
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: So 06.11.11 19:55 
Hallo,

a) Zur Syntax: Dies ist ein varianter Record (gefährlich, deshalb gibt der Compiler eine Warnung.) x ist eine 32-Bit Variable. Bei x.s werden die Bits als single interpretiert, bei x.i als integer. x.i+1 inkementiert also das letzte Bit der Mantisse von x.s. Ist wohl klar, warum variante Records "gefährlich" sind.

b) Dein Beispiel bestätigt das Runden: Im Dezimalsystem wird ab 0.5 aufgerundet, darunter wird abgerundet. Im Binärsystem bedeutet das bei Deinem Problem: Wenn auf Platz 24 eine 1 steht, dann wird aufgerundet, also wird auf Platz 23 eine 1 addiert (bzw. gesetzt, wenn es vorher null ist.) Die 1 auf Platz 24 ist ja eben halb (=0.5) so viel Wert wie die 1 auf Platz 23.

Gruß
GuaAck

Für diesen Beitrag haben gedankt: WeBsPaCe
WeBsPaCe Threadstarter
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 2322
Erhaltene Danke: 1

FireFox 3, Internet Explorer 6 SP1
D1, D3Prof, D6Pers, D7Pers+Indy, VisualStudio Express
BeitragVerfasst: Di 08.11.11 15:39 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
b) Dein Beispiel bestätigt das Runden: Im Dezimalsystem wird ab 0.5 aufgerundet, darunter wird abgerundet. Im Binärsystem bedeutet das bei Deinem Problem: Wenn auf Platz 24 eine 1 steht, dann wird aufgerundet, also wird auf Platz 23 eine 1 addiert (bzw. gesetzt, wenn es vorher null ist.) Die 1 auf Platz 24 ist ja eben halb (=0.5) so viel Wert wie die 1 auf Platz 23.

Hatte das wohl falsch verstanden. Dachte, du meinst, dass da "noch im Dezimalsystem" gerundet wird. Weil mein Beispiel ja grad blöderweise genau mit .0004 und .0005 war, was ja aber gar nichts mit Stelle 23 bzw. 24 zu tun hat, wo in Wirklichkeit (im Binärsystem) gerundet wird.

Danke euch beiden! Wie kann man sowas denn rausfinden/nachlesen, ohne (wie ich...) alle möglichen Kombinationen auszuprobieren und erst dann zu merken wie es vielleicht sein könnte?

Grüße!

_________________
Steht der Bauer im Gemüse, hat er später grüne Füße.
Gammatester
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 328
Erhaltene Danke: 101



BeitragVerfasst: Di 08.11.11 16:31 
Freizugängliche Quellen sind u.a. Brent/Zimmermann Modern Computer Arithmetic (zB Kap. 3.1.9 Rounding), Vorlesungsunterlagen wie Floating Point Arithmetic oder Goldbergs What Every Computer Scientist Should Know About Floating-Point Arithmetic (z.B. Hier).

Die langen binären Darstellungen habe ich mit dem Beispielrechner T_RCalc aus meinem MPArith-Paket berechnet.