Autor |
Beitrag |
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Do 08.08.13 19:36
Moin!
Ich arbeite mich grade für Tau durch einige Untiefen der Fließkommaarithmetik. Unter anderem lese ich dazu auch in den Quellen der AMath von Gammatester und hoffe, er liest hier auch mit
Jedenfalls: dort definiert er:
Delphi-Quelltext 1: 2:
| const eps_x: extended = 1.084202172485504434E-19; |
In dieser Größenordnung ist auch das auf 1E-19 gerundete ExtendedEpsilon aus der normalen Math.pas. Allerdings: dieser Wert scheint nicht korrekt zu sein, wie ich eben mal überprüft habe (sieht mit halben Leerzeichen besser aus ):
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| > table(each(range(-50,-70,-1),n, {n, 2^n, 1 + 2^n} )) .... -55 2.775 557 561 562 891 35E-17 1.000 000 000 000 000 03 -56 1.387 778 780 781 445 68E-17 1.000 000 000 000 000 01 -57 6.938 893 903 907 228 38E-18 1.000 000 000 000 000 01 -58 3.469 446 951 953 614 19E-18 1 -59 1.734 723 475 976 807 09E-18 1 -60 8.673 617 379 884 035 47E-19 1 -61 4.336 808 689 942 017 74E-19 1 -62 2.168 404 344 971 008 87E-19 1 -63 1.084 202 172 485 504 43E-19 1 .... |
2^-63 ist zwar an sich klar wegen 64bit Sign+Exponent, aber das scheint sich auf die eigentliche Rechenoperation nicht so durchzuschlagen.
Delphi definiert ja gleich mal einen FuzzFactor von 1E3 dazu (vermutlich aus diesem Grund), aber der versaut mir grade die Division, da IsZero schon bei ziemlich großen Zahlen der Meinung ist, das wäre eine Null, so dass im Endeffekt mein Code dann 1.6E-19 / 1.6E-19 als 0/0 "erkennt":
Quelltext 1: 2:
| > 1_'eV' / const('ElectronCharge') = NAN | Ignoriert diesen Absatz. Das war Background, provoziert aber irrelevante Antworten.
Was habe ich hier nicht verstanden?
Viele Grüße,
Martok
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Zuletzt bearbeitet von Martok am Do 08.08.13 22:21, insgesamt 2-mal bearbeitet
|
|
Mathematiker
Beiträge: 2622
Erhaltene Danke: 1447
Win 7, 8.1, 10
Delphi 5, 7, 10.1
|
Verfasst: Do 08.08.13 21:29
Hallo Martok,
Martok hat folgendes geschrieben : | ... aber der versaut mir grade die Division, da IsZero schon bei ziemlich großen Zahlen der Meinung ist, das wäre eine Null, so dass im Endeffekt mein Code dann 1.6E-19 / 1.6E-19 als 0/0 "erkennt"
|
Es hilft Dir zwar nicht wirklich weiter, aber ich habe Folgendes getestet und es funktioniert ohne Arithmetikprobleme, d.h. jedes Mal ergibt sich 1.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure TForm1.Button1Click(Sender: TObject); const eps_y = 1.084202172485504434E-19; var eps_x,ergebnis:extended; begin eps_x:=1.084202172485504434E-19; ergebnis:=eps_x/1.084202172485504434E-19; memo1.lines.add(floattostr(ergebnis)); ergebnis:=1.084202172485504434E-19/1.084202172485504434E-19; memo1.lines.add(floattostr(ergebnis)); ergebnis:=eps_x/eps_y; memo1.lines.add(floattostr(ergebnis)); ergebnis:=eps_y/1.084202172485504434E-19; memo1.lines.add(floattostr(ergebnis)); ergebnis:=eps_y/eps_y; memo1.lines.add(floattostr(ergebnis)); ergebnis:=1.084202172485504434E-19/eps_y; memo1.lines.add(floattostr(ergebnis)); end; |
Dann habe ich E-19 gegen E-100 und noch einmal gegen E-4950 getauscht; wieder keine Probleme. Erst bei E-4951 gab es eine 0/0, genau nach Beschreibung des Extended-Typs.
Auch die math-Funktionen sin, cos, tan, sqrt und ln arbeiten bei E-4950 noch ohne Schwierigkeiten.
Könnte es sein, dass der Fehler wo anders liegt. Allerdings spekuliere ich nur.
Beste Grüße
Mathematiker
_________________ Töten im Krieg ist nach meiner Auffassung um nichts besser als gewöhnlicher Mord. Albert Einstein
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Do 08.08.13 22:17
Moin!
Ja, das ist ein komplett anderes Thema. Das Epsilon in der Nähe von 0 hat so genau gar nix mit der darstellbaren Präzision zu tun. Große Exponenten sind kein Thema, interessant wird es erst bei Operationen bei denen sich die Exponenten um mehr als eine bestimmte Stellenzahl unterscheiden. Bei Extended so ungefähr wenn |lg(x) - lg(y)| >= 19.
Der letzte Absatz (ich ärgere mich jetzt, ihn verwendet zu haben) war mehr zur Erklärung, warum ich mir das antue. Die Frage steht davor (und danach)
Aber wenn ihr es wissen wollt: Das tu ich damit. Ist hier aber nicht das Thema. Ich weiß mittlerweile, dass ich IsZero nicht verwenden sollte sondern eher die Größenordnungen vergleichen muss
Grüße,
Martok
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Fr 09.08.13 09:09
Mathematiker hat folgendes geschrieben : |
Ist schon etwas komisch. In der Delphi 5-Hilfe steht
Zitat: | Extended 3.6 x 10^–4951 .. 1.1 x 10^4932 |
was auch funktioniert.
Unter www.delphibasics.co....TL.asp?Name=Extended steht
Zitat: | It supports approximately 19 digits of precision in a range from 3.37 x 10^-4932 to 1.18 x 10^4932. |
|
Das ist beides richtig
Allerdings ist 3.6 x 10^–4951, genauer 3.64519953188247460E-4951 =2^(-16445) die kleinste positive denormalisierte Extendedzahl, also die kleinste Zahl größer als 0. Andererseits ist 3.37 x 10^-4932, genauer 3.362103143112093507E-4932 = 2^(-16382) die kleinste positive normalisierte Extendedzahl (alle Zahlen kleiner sind also denormal).
Für diesen Beitrag haben gedankt: Mathematiker
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Fr 09.08.13 10:42
Martok hat folgendes geschrieben : | Der letzte Absatz (ich ärgere mich jetzt, ihn verwendet zu haben) war mehr zur Erklärung, warum ich mir das antue. Die Frage steht davor (und danach) |
Ich weiß zwar immer noch nicht genau, was die Frage ist, aber die Antwort ist 42. Vielleicht entstehen ein paar Probleme durch die mangelnde Genauigkeit bei der Dezimalausgabe (die leider auf ca 17 Stellen beschränkt ist). Hier mal eine entsprechende Tabelle mit Hexdarstellung (mit der AMath-Funktion Ext2Hex) der Summe und als Zugabe auch für Differenzen: Man beachte 1 + 0.5*eps_x = 1 aber 1 - 0.5*eps_x <> 1:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| i 2^i 1+2^i (dec) 1+2^i (hex) -55 2.77555756156289135E-0017 1.000000000000000030 3FFF8000000000000100 -56 1.38777878078144568E-0017 1.000000000000000010 3FFF8000000000000080 -57 6.93889390390722838E-0018 1.000000000000000010 3FFF8000000000000040 -58 3.46944695195361419E-0018 1.000000000000000000 3FFF8000000000000020 -59 1.73472347597680709E-0018 1.000000000000000000 3FFF8000000000000010 -60 8.67361737988403547E-0019 1.000000000000000000 3FFF8000000000000008 -61 4.33680868994201774E-0019 1.000000000000000000 3FFF8000000000000004 -62 2.16840434497100887E-0019 1.000000000000000000 3FFF8000000000000002 -63 1.08420217248550443E-0019 1.000000000000000000 3FFF8000000000000001 -64 5.42101086242752217E-0020 1.000000000000000000 3FFF8000000000000000 -65 2.71050543121376108E-0020 1.000000000000000000 3FFF8000000000000000
i 2^i 1-2^i (dec) 1-2^i (hex) -55 2.77555756156289135E-0017 0.999999999999999970 3FFEFFFFFFFFFFFFFE00 -56 1.38777878078144568E-0017 0.999999999999999990 3FFEFFFFFFFFFFFFFF00 -57 6.93889390390722838E-0018 0.999999999999999990 3FFEFFFFFFFFFFFFFF80 -58 3.46944695195361419E-0018 1.000000000000000000 3FFEFFFFFFFFFFFFFFC0 -59 1.73472347597680709E-0018 1.000000000000000000 3FFEFFFFFFFFFFFFFFE0 -60 8.67361737988403547E-0019 1.000000000000000000 3FFEFFFFFFFFFFFFFFF0 -61 4.33680868994201774E-0019 1.000000000000000000 3FFEFFFFFFFFFFFFFFF8 -62 2.16840434497100887E-0019 1.000000000000000000 3FFEFFFFFFFFFFFFFFFC -63 1.08420217248550443E-0019 1.000000000000000000 3FFEFFFFFFFFFFFFFFFE -64 5.42101086242752217E-0020 1.000000000000000000 3FFEFFFFFFFFFFFFFFFF -65 2.71050543121376108E-0020 1.000000000000000000 3FFF8000000000000000 |
Für diesen Beitrag haben gedankt: Martok
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Fr 09.08.13 15:21
Danke
Gammatester hat folgendes geschrieben : | Vielleicht entstehen ein paar Probleme durch die mangelnde Genauigkeit bei der Dezimalausgabe (die leider auf ca 17 Stellen beschränkt ist) |
Das scheint auf jeden Fall ein Teil des Problems zu sein, in Memdump-Darstellung kann ich deine Tabelle 1:1 reproduzieren. Das Phänomen der Dezimal-Darstellung wird eher seltsamer
Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| > table(each(range(-55,-65,-1),n,{n, 2^n, 1+2^n, exthex(1+2^n), 1-2^n, exthex(1-2^n) })) -55 2.77555756156289135E-17 1.00000000000000003 3FFF8000000000000100 0.999999999999999972 3FFEFFFFFFFFFFFFFE00 -56 1.38777878078144568E-17 1.00000000000000001 3FFF8000000000000080 0.999999999999999986 3FFEFFFFFFFFFFFFFF00 -57 6.93889390390722838E-18 1.00000000000000001 3FFF8000000000000040 0.999999999999999993 3FFEFFFFFFFFFFFFFF80 -58 3.46944695195361419E-18 1 3FFF8000000000000020 0.999999999999999996 3FFEFFFFFFFFFFFFFFC0 -59 1.73472347597680709E-18 1 3FFF8000000000000010 0.999999999999999998 3FFEFFFFFFFFFFFFFFE0 -60 8.67361737988403547E-19 1 3FFF8000000000000008 0.999999999999999999 3FFEFFFFFFFFFFFFFFF0 -61 4.33680868994201774E-19 1 3FFF8000000000000004 1 3FFEFFFFFFFFFFFFFFF8 |
1+2^n ergibt genau deine Werte allerds mit einer Stelle weniger, 1-2^n gibt mehr und andere Stellen als dein Beispiel.
Ich verwende FloatToStrF(Value, ffGeneral, 22, 18, NeutralFormatSettings); (aha, da kommen die 18 Stellen her ). Was hast du aufgerufen?
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Mo 12.08.13 09:10
Martok hat folgendes geschrieben : | Das Phänomen der Dezimal-Darstellung wird eher seltsamer
...
Ich verwende FloatToStrF(Value, ffGeneral, 22, 18, NeutralFormatSettings); (aha, da kommen die 18 Stellen her ). Was hast du aufgerufen? |
In der Tat, aber es wird noch seltsamer Meine Werte wurden mit folgendem Programm erzeugt: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| program t_eps; {$i STD.INC} {$ifdef AppCons} {$apptype console} {$endif} {$ifdef BIT16} {$N+} {$endif} uses amath; var x,y: extended; i: integer; begin writeln('i':3, '2^i':28, '1+2^i (dec)':22, '1+2^i (hex)':22); for i:=55 to 65 do begin x := ldexp(1,-i); y := 1 + x; writeln(-i:3, x:28, y:22:18, Ext2Hex(y):22); end; writeln; writeln('i':3, '2^i':28, '1-2^i (dec)':22, '1-2^i (hex)':22); for i:=55 to 65 do begin x := ldexp(1,-i); y := 1 - x; writeln(-i:3, x:28, y:22:18, Ext2Hex(y):22); end; end. | Deine Werte kann ich mit TurboPascal 5 - 7 und Delphi 17/18 reproduzieren, Delphi 2 - 12 liefern meine oben genannten Werte (mit D6).
Hoffentlich interessiert's noch (die langen Wochenenden ...)
Für diesen Beitrag haben gedankt: Martok
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mo 12.08.13 16:23
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Mo 12.08.13 16:38
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mo 12.08.13 18:42
Gammatester hat folgendes geschrieben : | Aber man sollte das nicht zu verbissen sehen und als Bug bezeichnen, ob 17 oder 18 Stellen ist fast schon egal, wenn selbst 60 nicht ausreichen um exakt zu sein (hier 1 +- 2^-63): |
Wohl wahr.
Ich würde ja auf mpf oder sowas umbauen, aber deine TP-Kompatibilitätsverrenkungen führen leider dazu, dass mir der Code so gar nicht gefällt
Muss ich halt damit leben. Das mittlerweile oben durchgestrichene Beispiel umgehen wir dann mal durch assembler und eigene FPE-Behandlung, dann brauche ich nicht vorher auf 0 zu prüfen
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Di 13.08.13 18:08
Moderatives Zeugs
Achtung, ich hab mal dieses Thema etwas aufgeräumt und die Beiträge zu Extended mit 64bit-Delphi in einen eigenen Thread verschoben.
Das führt dazu, dass hier ein Beitrag von Mathemtiker fehlt. Der relevante Teil wurde aber in der Antwort von Gammatester zitiert, man kann dem Thema also noch folgen. Genau deswegen haben wir die Nur-Eine-Frage-Pro-Thema-Regel
/Moderatives Zeugs
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mi 14.08.13 02:18
So, und noch was zum Thema. So langsam verstehe ich mehr als Borland damals, hab ich den Verdacht
Gammatester hat folgendes geschrieben : | Andererseits ist 3.37 x 10^-4932, genauer 3.362103143112093507E-4932 = 2^(-16382) die kleinste positive normalisierte Extendedzahl (alle Zahlen kleiner sind also denormal). |
Mit anderen Worten: IsZero an sich ist keine dumme Idee, aber damals komplett sinnfrei implementiert worden. Das Kriterium hätte eigentlich sein müssen, "Wird 1/x eine ZE auslösen?" und die Antwort wäre also "ist die Zahl zwischen 2^-16382 und -2^16383", oder?
Könnte man ja reparieren.
€:/ Fun Fact: jetzt hab ich schon einen Bug in meiner CPU gefunden: SIN/COS verwenden offensichtlich unterschiedliche Tabellen, die bekannten Punkte (Nullstellen, +/-1) verhalten sich anders...
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Mi 14.08.13 09:56
Martok hat folgendes geschrieben : | Mit anderen Worten: IsZero an sich ist keine dumme Idee, aber damals komplett sinnfrei implementiert worden. Das Kriterium hätte eigentlich sein müssen, "Wird 1/x eine ZE auslösen?" und die Antwort wäre also "ist die Zahl zwischen 2^-16382 und -2^16383", oder?
Könnte man ja reparieren. |
Nein, dafür ist IsZero meiner Meinung nicht primär gedacht, eher für Differenzabschätzungen. Man muß auch zwischen der Implementierung und der Anwendung von IsZero unterscheiden. Die Implementierung Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| function IsZero(const A: Extended; Epsilon: Extended): Boolean; begin if Epsilon = 0 then Epsilon := ExtendedResolution; Result := Abs(A) <= Epsilon; end; | ist freundlich ausgedrückt dunkel mit dem FuzzFactor = 1000 und den zT willkürlichen Resolution-Konstanten: Quelltext 1: 2: 3:
| SingleResolution = 1E-7 * FuzzFactor; DoubleResolution = 1E-15 * FuzzFactor; ExtendedResolution = 1E-19 * FuzzFactor; | Während 1e-19 noch ca 1*eps_x ist, ist aber 1e-15 ca 5*eps_d! Weiter hätte man if Epsilon <= 0 schreiben sollen, aktuell ist eine echte 0 nicht Zero mit Epsilon=-1e-10!
Aber nicht jammern, wenn die Welt mit Delphi und SI-Einheiten programmiert wäre, würde alles viel einfacher sein (allerdings nicht unbedingt besser), da sperrige Konstanten wegfallen: u.a. Boltzmann, Planck (hurra, keine Quanteneffekte mehr!), Elementarladung (nicht so gut, keine Computer mehr).
Schlimm ist allerdings die Anwendung von IsZero in der RTL, Paradebeispiel dafür ist mal wieder die total blamable Implementation von sinh/tanh (tanh hier für D7-D12, in D17+ besser): Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| function Sinh(const X: Extended): Extended; begin if IsZero(X) then Result := 0 else Result := (Exp(X) - Exp(-X)) / 2; end;
function Tanh(const X: Extended): Extended; begin if IsZero(X) then Result := 0 else Result := SinH(X) / CosH(X); end; | Wie viele Gymnasiasten wissen (sollten), gilt für kleine Argumente sin(x) ~ x, sinh(x) ~ x, tanh(x) ~ x (Stichwort Taylor). Etwas besser (und selbstverständlich) genauer wäre also Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| function Sinh(const X: Extended): Extended; begin if IsZero(X) then Result := X else Result := (Exp(X) - Exp(-X)) / 2; end; | Warum sich das nicht bis EMBA rumgesprochen hat, weiß der Geier. Und warum für tanh(x) dann noch 4 (in Worten vier) Mal exp aufgerufen werden muß, ist auch unklar, ganz zu schweigen vom völlig uberflüssigen Crash für tanh(12345) in D7-D12, was ja bekanntermaßen = 1 ist. Fehlt eigentlich nur noch, daß man die gleiche Logik auf sin(x) und tan(x) anwendet.
Martok hat folgendes geschrieben : | €:/ Fun Fact: jetzt hab ich schon einen Bug in meiner CPU gefunden: SIN/COS verwenden offensichtlich unterschiedliche Tabellen, die bekannten Punkte (Nullstellen, +/-1) verhalten sich anders... |
Interessant, kannst Du mehr dazu sagen?
PS_1: Deine Absicht, Divisionsüberläufe zu vermeiden, kann man wie Du schon erwähnt hast mit try..except abfangen, oder aber zB wie folgt umgehen: Wenn x/y im Verdacht steht überzulaufen, hilft die Anweissung
Delphi-Quelltext 1: 2: 3:
| if (abs(y)<1.0) and (abs(x) >= abs(y)*MaxExtended) then begin end; |
Edit PS_2: Auf mögliche Antworten auf Deine möglichen Antworten must Du leider wegen des ultralangen bayrischen Wochenende bis Montag warten
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Do 15.08.13 00:22
Gammatester hat folgendes geschrieben : | Edit PS_2: Auf mögliche Antworten auf Deine möglichen Antworten must Du leider wegen des ultralangen bayrischen Wochenende bis Montag warten | Dann mach ich das Release halt ohne Antwort
Gammatester hat folgendes geschrieben : | Nein, dafür ist IsZero meiner Meinung nicht primär gedacht, eher für Differenzabschätzungen. |
Joa, das ist dann ja das was SameValue=IsZero(A-B) macht.
Meistens geht es doch aber darum, dass IsZero aufgerufen wird um die DivZero oder den Ln(0) zu vermeiden. Und dafür wäre ja dann halt die erste normalisierte Zahl <> 0 Maßgeblich, nicht irgendein Vergleichsepsilon. Und selbst wenn, müsste man doch das auf die Zahlen an sich beziehen, also z.B.: A = B <=> (A-B) / A < 1E-19.
Gammatester hat folgendes geschrieben : | Schlimm ist allerdings die Anwendung von IsZero in der RTL, Paradebeispiel dafür ist mal wieder die total blamable Implementation von sinh/tanh (tanh hier für D7-D12, in D17+ besser): Wie viele Gymnasiasten wissen (sollten), gilt für kleine Argumente sin(x) ~ x, sinh(x) ~ x, tanh(x) ~ x (Stichwort Taylor). |
Das hab ich dann gleich mal ordentlich nachgebaut.
Gammatester hat folgendes geschrieben : | PS_1: Deine Absicht, Divisionsüberläufe zu vermeiden, kann man wie Du schon erwähnt hast mit try..except abfangen |
... oder das die FPU machen lassen, z.B. so.
Gammatester hat folgendes geschrieben : | Martok hat folgendes geschrieben : | €:/ Fun Fact: jetzt hab ich schon einen Bug in meiner CPU gefunden: SIN/COS verwenden offensichtlich unterschiedliche Tabellen, die bekannten Punkte (Nullstellen, +/-1) verhalten sich anders... | Interessant, kannst Du mehr dazu sagen? |
Ich hab mal ein paar Werte berechnet von Sin/Cos im Abstand von Pi/4 (bzw an den Stellen direkt, die Hex-Darstellung hab ich von dir). Sin() liefert wie zu erwarten {0, 1, 0, -1}, aber Cos(Pi/4) ist nicht 0, sondern ~1E-19. Man kann mit anderer Hex-Darstellung ($...c234 ... $...c237) noch ein Minimum bei ~1E-20 finden, aber exakt 0 bzw irgendwas subnormales wirds nicht. Man sollte doch annehmen, dass die eine nur die um Pi/4 verschobene andere Funktion ist. Scheint aber nicht so.
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Mo 19.08.13 10:08
Moin, bin wieder online!
Eigentlich hättest Du es doch gleich besser machen können, also nur nur 'iszero(x) -> sinh := x', so hast Du immer noch die 'katastrophale Auslöschung' in Result := (Exp(X) - Exp(-X)) / 2; für kleine x, die größer als die IsZero-Grenze sind, zB für Quelltext 1: 2: 3:
| x = 1.00000000000000000E-0008 Simple 1.00000000000219271E-0008 -2.19269459360293961E-0012 AMath 1.00000000000000001E-0008 0.00000000000000000E+0000 | Der erste Wert ist sinh(x), der zweite der relative Fehler.
Martok hat folgendes geschrieben : | Ich hab mal ein paar Werte berechnet von Sin/Cos im Abstand von Pi/4 (bzw an den Stellen direkt, die Hex-Darstellung hab ich von dir). Sin() liefert wie zu erwarten {0, 1, 0, -1}, aber Cos(Pi/4) ist nicht 0, sondern ~1E-19. Man kann mit anderer Hex-Darstellung ($...c234 ... $...c237) noch ein Minimum bei ~1E-20 finden, aber exakt 0 bzw irgendwas subnormales wirds nicht. Man sollte doch annehmen, dass die eine nur die um Pi/4 verschobene andere Funktion ist. Scheint aber nicht so. |
Irgendwie scheinst Du da systematisch Pi/4 mit Pi/2 zu verwechseln, glücklicherweise ist cos(Pi/4) nicht 0 sondern sqrt(0.5) und cos(x) = sin(x+Pi/2), ich führe dies allerdings auf die fortgeschrittene Erstellungszeit Deines Beitrags zurück Im Übrigen bezweifele ich, daß für den Extended-Wert von Pi der sin gleich 0 sein soll (Test system: -5.42101086242752217E-0020, AMath: -5.01655761266833202E-0020), es sei denn Du rechnest symbolisch, wenn nicht ist ein Ergebniswert=0 falsch!
Soweit ich mich erinnere (irgendwelche Franzosen haben das mW ausgeknobelt, finde den Artikel gerade nicht), gibt es keine Double-Zahl x für die cos(x) exakt = 0 ist, man kann also getrost immer tan(x) = sin(x)/cos(x) berechnen; vermutlich gilt das auch für extended. Für die Umgebung von Pi/2 finde ich für cos(x) mit MPArith Quelltext 1: 2: 3: 4: 5:
| 1.570796326794896620 3FFFC90FDAA22168C233 +1.917576464337592266837039248E-19 1.570796326794896620 3FFFC90FDAA22168C234 +8.333742918520878328295864468E-20 1.570796326794896620 3FFFC90FDAA22168C235 -2.508278806334166011778663540E-20 1.570796326794896620 3FFFC90FDAA22168C236 -1.335030053118921035185319155E-19 1.570796326794896620 3FFFC90FDAA22168C237 -2.419232225604425469192771956E-19 | Der Extendedwert für Pi/2 ist die mittlere Zeile und hat (wie erwartet) den kleinsten Funktionswert.
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mo 19.08.13 16:28
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
Gammatester
Beiträge: 328
Erhaltene Danke: 101
|
Verfasst: Mo 19.08.13 16:42
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Mo 19.08.13 19:31
_________________ "The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
|
|
|