Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Genauigkeit von String to Single Konvertierung (https://www.delphipraxis.net/203853-genauigkeit-von-string-single-konvertierung.html)

Harry Stahl 31. Mär 2020 23:21

Delphi-Version: 10.3 Rio

Genauigkeit von String to Single Konvertierung
 
Wenn ich einen String mit dem Inhalt "29,7" zu einem Variablen Wert des Typs "Single" per StrToFloat (oder String.tosingle) konvertiere, erhalte ich als Ergebnis "29,7000007629395".

Erst ab Variablen Typ "Double" aufwärts erhalte ich 29.7 als Wert.

Mir ist zwar bekannt, dass Single nur 4 Byte hat und man daher von einer "geringen Rechengenauigkeit" spricht (double hat 8 Byte), aber ich habe das immer auf Berechnungsergebnisse bezogen (also multiplizieren, dividieren, etc.), wieso gibt es hier bei so einer einfachen Konvertierung eine Ungenauigkeit?

jaenicke 1. Apr 2020 06:00

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Harry Stahl (Beitrag 1460957)
wieso gibt es hier bei so einer einfachen Konvertierung eine Ungenauigkeit?

Weil die Zahlen im PC im Binärsystem dargestellt werden, Stichwort Zweierkomplement (übrigens im Studium ein Lieblingsthema bei einigen :lol:). Hier im Video ist das auf den ersten Blick gut zu sehen (hab nur kurz auf die Tafel geschaut, nicht zugehört):
https://www.youtube.com/watch?v=hHpSwBf0DCA

dummzeuch 1. Apr 2020 08:19

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Harry Stahl (Beitrag 1460957)
Mir ist zwar bekannt, dass Single nur 4 Byte hat und man daher von einer "geringen Rechengenauigkeit" spricht (double hat 8 Byte), aber ich habe das immer auf Berechnungsergebnisse bezogen (also multiplizieren, dividieren, etc.), wieso gibt es hier bei so einer einfachen Konvertierung eine Ungenauigkeit?

Auch diese "einfachen Konvertierungen" sind Berechnungen. Und so simpel sind die nun mal nicht, da von der Dezimal- in die Binärdarstellung und zurück konvertiert werden muss (du hast also in Deinem Beispiel schon zwei Konvertierungen). Das geht für manche Zahlen einfach und ohne Rundungs-Fehler, für andere sind die Fehler relativ groß.

Uwe Raabe 1. Apr 2020 08:29

AW: Genauigkeit von String to Single Konvertierung
 
Das eigentlich Problem ist, daß sich der Wert 29,7 weder als Single noch als Double exakt darstellen lässt. Der Compiler erzeugt daher eine die dem Wert nächste Binärdarstellung:

Double: 11101.10110011001100110011001100110011001100110011 0011 = 29.69999999999999928945726423989981412887573242187 5
Single: 11101.101100110011001101 = 29.700000762939453125

Durch die begrenzte Anzahl der Ziffern bei der Darstellung erscheint der Double-Wert exakt, obwohl er es auch nicht ist.

Andreas13 1. Apr 2020 09:11

AW: Genauigkeit von String to Single Konvertierung
 
Ganz allgemein: Mit einer endlichen Anzahl von Bits (4, 8,10) lassen sich nicht unendlich viele reelle Zahlen exakt darstellen.
Gruß, Andreas

Redeemer 1. Apr 2020 18:19

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Harry Stahl (Beitrag 1460957)
Wenn ich einen String mit dem Inhalt "29,7" zu einem Variablen Wert des Typs "Single" per StrToFloat (oder String.tosingle) konvertiere, erhalte ich als Ergebnis "29,7000007629395".

Erst ab Variablen Typ "Double" aufwärts erhalte ich 29.7 als Wert.

Mir ist zwar bekannt, dass Single nur 4 Byte hat und man daher von einer "geringen Rechengenauigkeit" spricht (double hat 8 Byte), aber ich habe das immer auf Berechnungsergebnisse bezogen (also multiplizieren, dividieren, etc.), wieso gibt es hier bei so einer einfachen Konvertierung eine Ungenauigkeit?

Ein Computer kann grundsätzlich keine Gleitkommazahlen speichern, deren letzte Nachkommastelle nicht 5 ist. Zahlen, deren letzte Nachkommastelle 5 ist, zwar in den allermeisten Fällen auch nicht, aber wenn du eine Zahl siehst, die nicht auf 5 endet, kann sie ein Computer niemals als Gleitkommazahl speichern. 29,7 endet nicht auf 5, kann also nicht gespeichert werden. Exakte Kommazahlen mit 4 Nachkommastellen können als Currency (=Int64, das als Zehntausendstel behandelt wird) abgelegt werden. Für alle anderen Fälle musst du dir selbst was schreiben.

Luckie 1. Apr 2020 19:31

AW: Genauigkeit von String to Single Konvertierung
 
Gleitkommazahlen können nicht exakt binär dargestellt werden. Das ist alles. Wandele 29,7 einfach mal per Hand schriftlich in eine binäre Zahl um, dann siehst du es.

jfheins 1. Apr 2020 19:37

AW: Genauigkeit von String to Single Konvertierung
 
Um solche grundlegenden Effekte einfacher zu sehen, finde ich auch Minifloats nett: https://de.wikipedia.org/wiki/Minifloat

Da wird ein einzelnes Byte als Gleitkommazahl genutzt. Die kleinste positive Zahl > 0 ist dann 0.125 und es geht bis zu 122880 - mit entsprechenden lücken.
Deine 29.7 wären da zwischen den beiden möglichen Werten 28 und 32 und würden im besten Fall auf 28 gerundet. Solche Rundungen sind prinzipiell (wie schon weiter oben beschrieben) unvermeidlich, nur in der Magnitude beeinflussbar durch die Menge an Bits.

Harry Stahl 1. Apr 2020 22:05

AW: Genauigkeit von String to Single Konvertierung
 
Tja, man lernt nie aus...

Danke für die Erläuterungen. Ist gut zu wissen, wenn man irgendwelche Eingaben aus Edit-feldern übernimmt bzw. Positionsangaben für Objekte (unter FMX sind die Positionsangaben für Controls ja auch Single-Werte und nicht Integer, immerhin), vor allen Dingen, wenn man etwas berechnen will, das "relativ" genau sein sollte...

p80286 1. Apr 2020 22:27

AW: Genauigkeit von String to Single Konvertierung
 
Es gibt ja auch andere Möglichkeiten:https://de.wikipedia.org/wiki/BCD-Code
Lesen und sich eine eigene Meinung bilden.

Gruß
K-H

P.S.
Meine Ausbilderin (ende der 70er) sagte immer Rechner sind schnell oder genau. Beides auf einmal geht nicht.

freimatz 2. Apr 2020 17:27

AW: Genauigkeit von String to Single Konvertierung
 
Da hat sie sicher recht. Allerdings ungenau UND langsam geht auch recht einfach. :duck:

Rollo62 3. Apr 2020 06:42

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von p80286 (Beitrag 1461043)
Es gibt ja auch andere Möglichkeiten:https://de.wikipedia.org/wiki/BCD-Code
Lesen und sich eine eigene Meinung bilden.

Gruß
K-H

P.S.
Meine Ausbilderin (ende der 70er) sagte immer Rechner sind schnell oder genau. Beides auf einmal geht nicht.

Wenn man den Wertebereich genau kennt, und auch die gewünschte Auflösung fix ist kann man ja auch mit integer arbeiten.
Z.B. Bereich ist innerhalt +/-100000 mit einer Auflösung von 0.001, dann kann man einfach intern mit IntVariable * 1000 rechnen, und nur bei Anzeigen wieder um 1000 korrigieren.
Die internen Berechnungen sind dann sehr schnell, mit Integer, nur bei den Ein- Ausgaben muss man konvertieren.
Das ist dann sehr exakt, nur bei Berecnungen muss man aufpassen das man nicht das Integer-Limit überschreitet.
Man könnte sich einen eigenen Typ dafür bauen und/oder mit record helpern eine Überlaufprüfung o.ä. einbauen.

himitsu 3. Apr 2020 08:28

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Rollo62 (Beitrag 1461125)
mit einer Auflösung von 0.001, dann kann man einfach intern mit IntVariable * 1000 rechnen, und nur bei Anzeigen wieder um 1000 korrigieren.
Die internen Berechnungen sind dann sehr schnell, mit Integer, nur bei den Ein- Ausgaben muss man konvertieren.
Das ist dann sehr exakt, nur bei Berecnungen muss man aufpassen das man nicht das Integer-Limit überschreitet.
Man könnte sich einen eigenen Typ dafür bauen und/oder mit record helpern eine Überlaufprüfung o.ä. einbauen.

Delphi-Referenz durchsuchenCurrency :stupid:

Rollo62 3. Apr 2020 10:06

AW: Genauigkeit von String to Single Konvertierung
 
Ja kann man nehmen, aber wenn z.B. Auflösung 0.0000001 gebraucht wird muss man sich was selber basteln, oder nicht ?
Currency wäre natürlich eine gute Basis.

Zitat:

Currency is a fixed-point data type. The maximum error when converting from floating-point to Currency is 0.00005.
Ich meine Curreny nutzt */ 10000 fix, oder kann man das irgendwo einstellen ?

Uwe Raabe 3. Apr 2020 11:09

AW: Genauigkeit von String to Single Konvertierung
 
Nein, Currency kennt nur 4 Nachkommastellen.

Andreas13 3. Apr 2020 12:05

AW: Genauigkeit von String to Single Konvertierung
 
Es stellt sich die Frage, was für einen wichtiger ist: "Schnell" ein "bißchen falsches" Ergebnis zu bekommen, oder etwas langsamer ein Korrektes. Ich persönlich ziehe für meine numerischen Berechnungsroutinen immer den korrekten Weg vor und benutze durchweg die Multipräzisions-Arithmetik-Bibliotheken von Wolfgang Ehrhardt. Diese arbeiten intern mit zusammengesetzten, "sehr langen" Integer-Zahlen, wodurch die hohe Genauigkeit gewährleistet wird. Diese kostet allerdings oft viel Rechenzeit. Aber die heutigen Prozessoren merken das gar nicht…
Gruß, Andreas

himitsu 3. Apr 2020 15:18

AW: Genauigkeit von String to Single Konvertierung
 
Ähnlich dem BCD, wo eine Ziffer in 4 Bit gespeichert ist, kann man auch gern mit Strings rechnen, also wo die Ziffern dann als Char jeweils 8 Byte belegen,
aber von der Mathematik dahinter gibt es praktisch keinen Unterschied.

https://www.delphipraxis.net/135492-...-math-lib.html
In Bezug auf die Speicherung von Dezimalzahlen gibt es da natürlich keine Probleme,
aber auch im 10er-System gibt es die selben Beschränkung, wie im 2er.

1 / 3 lässt sich nicht "genau" speichern, selbst wenn man hierfür eine Milliarde Dezimalstellen nach dem Komma verwendet. (2 GB)

0.333333333.................



Aber man könnte hier mit Exponenten arbeiten, wenn die Exponenten beliebig groß sind und man die Basis nicht auf Biegen und Brechen normieren muß, dann ließe sich praktisch alles Speichern.
Ebenfalls könnte man Bruchzahlen speichern, also direkt z.B. die 1 und die 3 von dem ⅓.

Harry Stahl 4. Apr 2020 22:11

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Andreas13 (Beitrag 1461168)
Es stellt sich die Frage, was für einen wichtiger ist: "Schnell" ein "bißchen falsches" Ergebnis zu bekommen, oder etwas langsamer ein Korrektes. Ich persönlich ziehe für meine numerischen Berechnungsroutinen immer den korrekten Weg vor und benutze durchweg die Multipräzisions-Arithmetik-Bibliotheken von Wolfgang Ehrhardt. Diese arbeiten intern mit zusammengesetzten, "sehr langen" Integer-Zahlen, wodurch die hohe Genauigkeit gewährleistet wird. Diese kostet allerdings oft viel Rechenzeit. Aber die heutigen Prozessoren merken das gar nicht…
Gruß, Andreas

Gibt es hier irgendwo eine fertige Funktionssammlung (frei oder käuflich) zu beziehen?
Brauch ich im Moment zwar nicht, aber falls mal doch, wär es gut zu wissen.... (Tante Google hat da nichts ausgespuckt)

jaenicke 4. Apr 2020 22:53

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Harry Stahl (Beitrag 1461286)
Gibt es hier irgendwo eine fertige Funktionssammlung (frei oder käuflich) zu beziehen?
Brauch ich im Moment zwar nicht, aber falls mal doch, wär es gut zu wissen.... (Tante Google hat da nichts ausgespuckt)

Das liegt daran, dass der Autor leider verstorben ist und seine Webseite nicht mehr online ist.
Es gibt aber einen Snapshot von der Seite:
https://github.com/moe123/www.wolfgang-ehrhardt.de
Und dort auch die entsprechende Bibliothek:
https://github.com/moe123/www.wolfga...2018-11-27.zip

jfheins 5. Apr 2020 10:08

AW: Genauigkeit von String to Single Konvertierung
 
Und es liegt auch daran, dass für geschätzt 99,999% aller Anwendungsfälle die normalen Gleitkommazahlen ausreichen (ggf. mit Rundung). Es macht einfach keinen Unterschied, ob die Linie genau 3 Pixel breit ist oder ob sie erst 3,00000015 pixel breit sein sollte und dann gerundet wird.

Was mir so als use case in den Sinn kommt ist typischerweise Finanzen, Kryptographie und Tschenrechner.

Soweit ich mich erinnere, haben die Leute sich bei WinXP ein bisschen über den Taschenrechner lustig gemacht, weil der eben auch solche Ungenauigkeiten hatte. Dann hat MS dem Taschenrechner in Win7 einen ordentliche, arbitrary precision Kern verpasst. Fast keiner hat's gemerkt oder gelobt ;-) (Aber inzwischen kann der TR auch sowas wie 1200000000000000000047 - 1200000000000000000000 rechnen)

himitsu 5. Apr 2020 10:44

AW: Genauigkeit von String to Single Konvertierung
 
Es gibt auch noch was von negaH, das sauschnell ist. (DECMath, Hagen Reddmann)
Ich weiß grade nicht wie es dort aussieht, aber da wollte sich auch jemand aus der DP darum kümmern den Code auch für neuere Delphis zur Verfügung zu stellen (da damals nur als DCU verfügbar war)

Zitat:

typischerweise Finanzen, Kryptographie und Tschenrechner
in Bezug auf Finanzen reichen die Festkommatypen (ala Currency) meistens aus,
so lange Einem die hunderstel Cent (4 Nachkommastellen) und einige 100 Billion Euro ausreichen.

und der Kryptographie nimmt man zwar große Zahlen, aber dort fast ausschließelich Ganzzahlige sehr große,
das geht dann auch in die Richtung, wie ein 32 Bit-Delphi mit 64 Bit umgeht,
wo also "eine" Zahl aus zwei oder mehr Integern zusammengesetzt ist.

himitsu 5. Apr 2020 11:00

AW: Genauigkeit von String to Single Konvertierung
 
[deleted]

Andreas13 5. Apr 2020 15:49

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von himitsu (Beitrag 1461305)
Zitat:

typischerweise Finanzen, Kryptographie und Tschenrechner
in Bezug auf Finanzen reichen die Festkommatypen (ala Currency) meistens aus,
so lange Einem die hunderstel Cent (4 Nachkommastellen) und einige 100 Billion Euro ausreichen.

Das stimmt nicht ganz: Rundungsfehler durch die binäre Zahlenkodierung, die begrenzte Wortlänge des Prozessors etc. lauern auf uns fast überall. Hier habe ich ein anschauliches kaufmännisches Beispiel (= recht einfache Berechnungen) aus dem Buch: Muller + Brisebarre + de Dinechin et al.: Handbook of Floating-Point Arithmetic. Boston: Birkhäuser, 2010, (ISBN 978-0-8176-4 704-9) S. 10 - 11:

Das Angebot der "Chaotic Bank Society":
Sie zahlen zunächst e - 1 $ auf Ihr Konto ein, wobei e = 2. 7182818… ist die Basis der natürlichen Logarithmen. Im ersten Jahr nehmen wir 1 $ von Ihrem Konto als Bearbeitungsgebühren. Das zweite Jahr ist besser für Sie: Wir multiplizieren Ihr Kapital mit 2, und wir nehmen 1 $ Bearbeitungsgebühren von Ihrem Konto. Das dritte Jahr ist sogar noch besser: Wir vervielfachen Ihr Kapital durch 3, und wir nehmen immer nur noch 1 $ an Bearbeitungsgebühren. Und so weiter: Im n-ten Jahr wird Ihr Kapital mit n multipliziert, und wir nehmen nur 1 Dollar Gebühren. Interessant, nicht wahr?
Wie hoch wäre Ihr Kapital nach 25 Jahren?

Versucht mal obiges Angebot mit Single-, Double-, Currency- und Extended-Genauigkeit zu testen. Und dann können wir uns gemeinsam wundern.
Gruß, Andreas

TurboMagic 5. Apr 2020 19:28

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von himitsu (Beitrag 1461305)
Es gibt auch noch was von negaH, das sauschnell ist. (DECMath, Hagen Reddmann)
Ich weiß grade nicht wie es dort aussieht, aber da wollte sich auch jemand aus der DP darum kümmern den Code auch für neuere Delphis zur Verfügung zu stellen (da damals nur als DCU verfügbar war)

Naja, DEC als Krypto Bibliothek wird ja, wenngleich mit niedrigem Tempo, weiterentwickelt. Heute wurde beispielsweise ein Bug beseitigt.

Nur DECMath wurde schon länger entfernt, da nur als D7 oder so DCU verfügbar. Ich wüsste auch nicht wer das übernommen hätte. Da hätte Hagen ja den Quellcode rausrücken müssen. Da habe ich aber keine Kenntnis darüber. DEC ist noch Arbeit genug, auch wenn sich da das eine oder andere in den letzten Jahren getan hat.

freimatz 6. Apr 2020 12:25

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von jfheins (Beitrag 1461302)
Und es liegt auch daran, dass für geschätzt 99,999% aller Anwendungsfälle die normalen Gleitkommazahlen ausreichen (ggf. mit Rundung).
...
Was mir so als use case in den Sinn kommt ist typischerweise Finanzen, Kryptographie und Tschenrechner.

Und geschätzt 99,8% aller Anwendungsfälle benötigen gar keine Gleitkommazahlen. (Wenn nicht TDateTime als double definiert wäre :wall:)

Und wer bei Finanzen Fließkomma nimmt gehört virtuell ...

Andreas13 6. Apr 2020 17:31

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von freimatz (Beitrag 1461396)
Zitat:

Zitat von jfheins (Beitrag 1461302)
Und es liegt auch daran, dass für geschätzt 99,999% aller Anwendungsfälle die normalen Gleitkommazahlen ausreichen (ggf. mit Rundung).
...
Was mir so als use case in den Sinn kommt ist typischerweise Finanzen, Kryptographie und Tschenrechner.

Und geschätzt 99,8% aller Anwendungsfälle benötigen gar keine Gleitkommazahlen. (Wenn nicht TDateTime als double definiert wäre :wall:)

Und wer bei Finanzen Fließkomma nimmt gehört virtuell ...

Ja, aber es kommt wirklich darauf an, für welche Zielgruppe man programmiert. Aber in der Technik, der gesamten Industrie, Ingenieur- und Naturwissenschaften braucht man zuverlässige Fließkomma-Berechnungen.
Mir fällt dazu ein Zitat vom "The Father of Floating Point" Prof. Dr. William Kahan (University of California, Berkeley) ein, der bekanntlich der Hauptarchitekt der Standards IEEE 754, IEEE 854 und IEEE 754r für die binären Gleitkommazahlen ("floating-point") ist, nach welchen die meisten unserer heutigen Prozessoren arbeiten. Er schrieb bereits im Jahre 1998 in einem Workshop-Beitrag über Dr. James Gosling (= "Dr. Java"), den Entwickler der Programmiersprache Java:
We agree with James Gosling about some things like ...
...
"95% of the folks out there are completely clueless about floating-point."
(James Gosling, 28 Feb. 1998)
(Maybe more than 95% ?: 1 March 1998, W. Kahan)
...
Das ist schon 22 Jahre her. Vielleicht wären heutzutage 99 % treffender...
Andreas

Redeemer 6. Apr 2020 23:03

AW: Genauigkeit von String to Single Konvertierung
 
Zitat:

Zitat von Andreas13 (Beitrag 1461321)
Das Angebot der "Chaotic Bank Society":
Sie zahlen zunächst e - 1 $ auf Ihr Konto ein, wobei e = 2. 7182818… ist die Basis der natürlichen Logarithmen. Im ersten Jahr nehmen wir 1 $ von Ihrem Konto als Bearbeitungsgebühren. Das zweite Jahr ist besser für Sie: Wir multiplizieren Ihr Kapital mit 2, und wir nehmen 1 $ Bearbeitungsgebühren von Ihrem Konto. Das dritte Jahr ist sogar noch besser: Wir vervielfachen Ihr Kapital durch 3, und wir nehmen immer nur noch 1 $ an Bearbeitungsgebühren. Und so weiter: Im n-ten Jahr wird Ihr Kapital mit n multipliziert, und wir nehmen nur 1 Dollar Gebühren. Interessant, nicht wahr?
Wie hoch wäre Ihr Kapital nach 25 Jahren?

Exakte Lösung: 25!e-sum(i=1;25;25!/i!)=15511210043330985984000000 e - 26652630354867072870693626
Numerische Lösungen:
Currency läuft bei der Berechnung für das 18. Jahr über.
1,5511210043330986E25 Delphi Extended
1,55112100433309861E25 Delphi Double
1,55112100433655498E25 Delphi Real48
1,55112076204817268E25 Delphi Single
1.551121004333098598400000003993872967323020890367 14552103610609810902462093999452735830887464108224 05958563231326504588526568754471550871321071511028 65877113031301246014269485947628156339035631478711 56972992927463959295378944403635902120260128114229 22313584223061180730596742377705289915144746694475 71765160508839459336338872383753196167221729140084 08174885201783691426388619978768865531323118535402 96935132579638126446952478348226578947288519178106 17781233401594055691040321590882201736459569823189 83576440408501342622021037730943274224144511437305 07152135683657708095677651120107759880605933613348 87623261771817480734410462774503249855758903025858 69911940277896932577548947296379441152499806651387 03945047390025867346621461272142961349666226182108 72695781997452163483694977937913381018485218277696 61754835986000967476233623861761063114702374959896 83244412722845433289358770989410202014274865145376 89535607054925229658200499120673138102661633964476 23628162987616065094362331757119278048209290555851 58236935322280549346093132963461058740654005374192 47677708355911819747675693712901378560713651778669 97931702493494721257361195123847186012238814637677 12722473351719813105096004887329666997611226438824 31479723969411331531960466717554616891283716351868 13994710337926333417096117724340263241126891726855 88792815973341240411885154432701216689096314639830 09978990008722755195406595058471067994822268098769 63303747291358036140174827459667579289634528150803 68253091530679796464656985926303187771471523090861 36065061715164522738784611354074952513726360974946 56039646541458858796075909681192962495110133421155 44819985771722994490313918182408598176122453110625 74591169349402523418996815901688696723377571156091 70072292208685849130844754758257019940278213507914 98166946886825456038719192553043078845960587978370 03347244591119333590346079381954256694073107837219 33247781048120121896075526893236023455770809887225 34810420772451347935461156084362437017435480228239 22559760804442565816753931503823148559605618238340 34744874760918148873772361146935820729137193550727 78518215627135770680812276472172702654725610074861 66588214391218906867367130029323735726017595848330 52442292727671467414360149211485363973833778677970 28508409906494296792769856861898977448447438021512 40224683859908687373538562542464740954057544917750 30797039732844954737644542762735245237821769200312 23083815968813598249665040371444008754885242844956 10815714710103809452472855113169849371253705634007 77569455614975853827444786365708317189821517395860 89568336769347793424220928780305804313696004710640 60120578457459017962608987107680998265372166730171 71552663089995959634861333788237138558214346778984 51463891214543327001686282548111614109449236925218 48770289602488971694917432865092216438082263294017 94514026323322533973103973760576676535163204324726 58430380533664963359848416627509384813851591111228 40097985233174471899577097597994574401395209375595 20279627770633530918788298081281794400221601973756 92787364229556555705724015912072278296173349441915 11570874137950251130442286114860282770673985838722 45727245695100078688147484750204795338668818271535 24614441317803722355359830604654842877184349597238 60273376226934553216173687765193470643343951239086 27784196075087827104944773669868914461184642437721 09432767417654171846730641402959136954307980191949 80295033188124985726393161784018920609632198659814 06100968138174080569252616515193753342340853705790 16941950615567101585464690380642434483220667815415 67830211036156076664570959191257605113039930671400 38505463543226353476234794904639287798040991945474 50131428588001563989984646910763702908587333364442 95562891565772491614838243280456415431605340E25 Eine recht genaue Darstellung

Bin enttäuscht, hatte größere Unterschiede erwartet.

himitsu 6. Apr 2020 23:12

AW: Genauigkeit von String to Single Konvertierung
 
Die ersten 5 Dezimalstellen sind identisch, also ist es egal.

Was kommt denn raus, wenn du bei/nach jeder Transaktion alles auf 2 bzw. 4 Nachkommastellen rundest?
Beim Einzahlen/Auszahlen natürlich die jeweiligen Beträge immer auf 2 Nachkommastellen.

Andreas13 7. Apr 2020 12:45

AW: Genauigkeit von String to Single Konvertierung
 
Es tut mir leid, aber ich habe es halt mit Zitaten. Diesmal eines von Karl Nickel über den Umgang mit ausgedruckten Ergebnissen einer numerischen Rechnung:

Der (naive) Anfänger glaubt an jede einzelne Ziffer.
Der (erfahrene) Programmierer vertraut auf die Hälfte der Stellen.
Der (wissende) Pessimist mißtraut sogar dem Vorzeichen.

Sorry, aber ich bin ein unverbesserlicher Pessimist…
Bitte den Algorithmus noch einmal überprüfen: Leider ist keine einzige Stelle korrekt. Zwischen den Lösungen der von Delphi angebotenen Fließkomma-Typen (Single, Double, Extended und Currency) liegen astronomische Unterschiede, nicht nach, sondern vor dem Komma. Bitte daher selber nachrechnen.
Warum ich es so spannend mache: Um uns die Augen zu öffnen, denn – und dann muß ich wieder eine Berühmtheit bemühen – nach dem Mathematiker- & Informatiker-Pionier Richard Hamming gilt:

The purpose of computing is insight, not numbers.

Und vielleicht verhilft uns diese simple Berechnung zu einer numerischen Einsicht & Erkenntnis.
Andreas

Andreas13 16. Apr 2020 21:18

AW: Genauigkeit von String to Single Konvertierung
 
Ich habe absichtlich einige Zeit gewartet, um zu testen, ob die beide Jungs mit ihrer Behauptung recht hätten:
Zitat:

Zitat von Andreas13 (Beitrag 1461445)
We agree with James Gosling about some things like ...
...
"95% of the folks out there are completely clueless about floating-point."
(James Gosling, 28 Feb. 1998)
(Maybe more than 95% ?: 1 March 1998, W. Kahan)
...
Das ist schon 22 Jahre her. Vielleicht wären heutzutage 99 % treffender...
Andreas

Anscheinend haben sie doch recht gehabt! Offenbar interessiert sich hier so gut wie niemand für die Genauigkeit von numerischen Berechnungen. Schade. Anderseits kann ich gut verstehen, wenn sich Integer-Programmierer nicht für Real-Zahlen interessieren. Jeder spezialisiert sich halt auf ein anderes Gebiet.
Nur für den Fall, daß sich hier zufällig auch mal ein Floating-Point-Interessierter verirrt, hier folgt die Auflösung des „Rätsels“ von # 23:
Die Lösung vo Redeamer:
Zitat:

Zitat von Redeemer (Beitrag 1461471)
Zitat:

Zitat von Andreas13 (Beitrag 1461321)
Das Angebot der "Chaotic Bank Society":
Sie zahlen zunächst e - 1 $ auf Ihr Konto ein, wobei e = 2. 7182818… ist die Basis der natürlichen Logarithmen. Im ersten Jahr nehmen wir 1 $ von Ihrem Konto als Bearbeitungsgebühren. Das zweite Jahr ist besser für Sie: Wir multiplizieren Ihr Kapital mit 2, und wir nehmen 1 $ Bearbeitungsgebühren von Ihrem Konto. Das dritte Jahr ist sogar noch besser: Wir vervielfachen Ihr Kapital durch 3, und wir nehmen immer nur noch 1 $ an Bearbeitungsgebühren. Und so weiter: Im n-ten Jahr wird Ihr Kapital mit n multipliziert, und wir nehmen nur 1 Dollar Gebühren. Interessant, nicht wahr?
Wie hoch wäre Ihr Kapital nach 25 Jahren?

Exakte Lösung: 25!e-sum(i=1;25;25!/i!)=15511210043330985984000000 e - 26652630354867072870693626
Numerische Lösungen:
Currency läuft bei der Berechnung für das 18. Jahr über.
1,5511210043330986E25 Delphi Extended
1,55112100433309861E25 Delphi Double
1,55112100433655498E25 Delphi Real48
1,55112076204817268E25 Delphi Single
1.551121004333098598400000003993872967323020890367 14552103610609810902462093999452735830887464108224 0595856323132650458
… und weitere über 3500 Ziffern

ist leider keine „Erlösung“, denn Deine Formel ist falsch. Darüber hinaus hast Du gemogelt, weil Du nicht einmal Deine eigene Formel mit den verschiedenen Real-Typen berechnet hast, sondern nur Deine allerletzte Operation: 15511210043330985984000000 e - 26652630354867072870693626. Du hast dabei allerdings Deine „Zwischenergebnisse“ per Hand, mittels MatLab, Maple, Mathematica, MPA-Bibliotheken oder auf einem anderen Weg zuvor ausgerechnet und diese Zahlen als Input für die „Berechnung“ benutzt. Wenn man die Genauigkeit verschiedener Real-Typen vergleichen will, muß man schon die gesamte Berechnung damit durchführen, nicht nur einen willkürlichen Schritt. Hättest Du wenigstens Deine eigene (= falsche) Formel 25!e - sum(i=1;25;25!/i!) verwendet, dann wären folgende „Guthaben“ rausgekommen:
Guthaben Single : nach 25 Jahren = ---> Überlauf!
Guthaben Currency: nach 25 Jahren = ---> Überlauf!
Guthaben Real : nach 25 Jahren = ---> Überlauf!
Guthaben Double : nach 25 Jahren = -4.1341454764160250E+0050
Guthaben Extended: nach 25 Jahren = -4.1341454764160244E+0050
Ich denke, dieses Ergebnis brauchen wir nicht weiter zu kommentieren.
Apropos:
Die korrekte Formel für das Guthaben lautet: Guthaben nach n Jahren = n!*((e – 1) – (1/1! + 1/2! + 1/3! … + 1/n!)) .
Und das korrekte Guthaben nach 25 Jahren beträgt genau 0,03993873… $, also knapp 4 Cent.

Die Berechnung des Guthabens im vorliegenden Fall über die Formel mit den Fakultäten ist bereits ein grober Verstoß gegen das „kleine ABC“ der Gleitkomma–Arithmetik & jedweder numerischen Rechenregeln, weil es hier um die Differenzbildung zweier riesengroßer Zahlen handelt. Die Fakultät von 25, also 25! = 15511210043330985984000000 ist eine Zahl mit 26 Ziffern. Dabei verliert unser „Double“ durch arithmetische Rundung „hinten“ bereits 8 bis 9 Ziffern. Selbst bei Extended bußen wir immer noch 6 ..7 Ziffern ein. Wenn davon eine ähnlich große Zahl subtrahiert werden sollen, dann gehen uns genauso viele Nachkommastellen „hinten“ – also genau im Ergebnis – flöten. Kein Wunder, daß hierbei ein ziemlich „ungewöhnliches“ Resultat rauskommt, welches wir getrost in den Papierkorb werfen können. Daher ist dieser Weg über Fakultäten – selbst bei der Verwendung von Multipräzisionsarithmetik – nicht zu empfehlen.
Allerdings geht es bei der Beispiel-Aufgabe um die Demonstration des möglichen verheerenden Effektes winziger Rundungsfehler, die je nach verwendetem Floating-Point-Type Single, Double, Extended bei ca. 1E-8, 1E-15 und 1E-18 liegen, aber sich u. U. beachtlich aufschaukeln können.
Und vor allem, man sollte seine Ergebnisse und Formeln stets gewissenhaft überprüfen und ausgiebig testen, bevor man eine Vielzahl von falschen Ziffern raushaut… Numerische Mathematik bringt einen oft zur Verzweiflung, aber sie macht einen vor allem etwas bescheidener…
Viel einfacher und anschaulicher ist daher folgende For - Schleife:
Delphi-Quellcode:

VAR
  i : Integer;
  Guthaben_s: Single;
  Guthaben_c: Currency;
  Guthaben_r: Real48;
  Guthaben_d: Double;
  Guthaben_x: Extended;

CONST
  Br = 25;
  St = 20;

      Guthaben_s:= exp(1) - 1;
      Guthaben_c:= exp(1) - 1;
      Guthaben_r:= exp(1) - 1;
      Guthaben_d:= exp(1) - 1;
      Guthaben_x:= exp(1) - 1;

      WriteLn('StartGuthaben: e - 1 => Single : ', Guthaben_s:Br:St);
      WriteLn('StartGuthaben: e - 1 => Currency: ', Guthaben_c:Br:St);
      WriteLn('StartGuthaben: e - 1 => Real   : ', Guthaben_r:Br:St);
      WriteLn('StartGuthaben: e - 1 => Double : ', Guthaben_d:Br:St);
      WriteLn('StartGuthaben: e - 1 => Extended: ', Guthaben_x:Br:St);
      WriteLn;    
           
      For i := 1 To 25 Do
      Begin
        Guthaben_s := Guthaben_s*i - 1;
        // Guthaben_c := Guthaben_c*i - 1; // Überlauf nach 21 Jahren!
        Guthaben_r:= Guthaben_r*i - 1;
        Guthaben_d := Guthaben_d*i - 1;
        Guthaben_x := Guthaben_x*i - 1;
        // WriteLn('Guthaben Double : nach ' + (i).ToString + ' Jahren = ', Guthaben_d:Br:St);      
        // WriteLn('Guthaben Extended: nach ' + (i).ToString + ' Jahren = ', Guthaben_x:Br:St);      
      End;

      WriteLn;
      WriteLn('Guthaben Single : nach ' + (i-1).ToString + ' Jahren = ', Guthaben_s:Br:St);
      // WriteLn('Guthaben Currency: nach ' + (i-1).ToString + ' Jahren = ', Guthaben_c:Br:St);
      WriteLn('Guthaben Currency: nach ' + (i-1).ToString + ' Jahren = ','---> Überlauf nach 21 Jahren!');
      WriteLn('Guthaben Real   : nach ' + (i-1).ToString + ' Jahren = ', Guthaben_r:Br:St);
      WriteLn('Guthaben Double : nach ' + (i-1).ToString + ' Jahren = ', Guthaben_d:Br:St);
      WriteLn('Guthaben Extended: nach ' + (i-1).ToString + ' Jahren = ', Guthaben_x:Br:St);
      WriteLn;
      WriteLn('Guthaben KORREKT : nach 25 Jahren = 0.0399387...');
Obige Berechnung liefert folgende Ergebnisse:

Guthaben Single : nach 25 Jahren = 5.68654735142289E+0017 (= 569 tausend Billionen!)
Guthaben Currency: nach 25 Jahren = ---> Überlauf nach 21 Jahren!
Guthaben Real : nach 25 Jahren = -1.30694632129600E+0013 (= -13 Billionen SCHULDEN!)
Guthaben Double : nach 25 Jahren = 1.20180724741045E+0009 (= 1,20 Milliarden!)
Guthaben Extended: nach 25 Jahren = 1.05291085275662E+0006 (= 1,05 Millionen!)

Guthaben KORREKT : nach 25 Jahren = 0.0399387...

Auch Excel rechnet uns arm:
Guthaben Excel Professional (2016): nach 25 Jahren = -2242373258,57016 (= -2,24 Milliarden SCHULDEN!)
Und je nach verwendetem Taschenrechner bekommen wir weitere recht „interessante“ Resultate.

Für die halbwegs korrekte Berechnung des Guthabens im 25-ten Jahr brauchen wir mindestens 30 wertvolle Ziffern, die Delphi von Haus nicht bietet. Interessant ist dabei, daß alle (korrekten) Zwischenergebnisse im Bereich 1,72 … 0 liegen: Es geht also um ganz „normale“ Alltags-Zahlen. Leider versagen hier alle „eingebauten“ Typen von Delphi. Excel – ein tolles Programm! – rechnet hier u .a. wegen eines winzigen Rundungsfehlers in der 15-ten Stelle bei der Zahl e) etwas falscher als Delphi‘s Double und bekommt für den Kontoinhaber anstelle des „erwarteten“ Milliarden-Guthabens einen beinahe doppelt so hohen Schuldenberg raus...
Dieses einfache Beispiel sollte uns zeigen, daß bei Gleitkomma-Berechnungen stets Vorsicht geboten ist. Selbst zuverlässige, fehlertolerante Algorithmen, Multipräzisions-Arithmetik und ausgiebige Tests sind keine Garantie vor gelegentlichen bösen Überraschungen.

Aber ich denke, es genügt: Schließlich interessiert es hier eh niemanden.
Gruß, Andreas

himitsu 16. Apr 2020 22:03

AW: Genauigkeit von String to Single Konvertierung
 
und dennoch ist alles falsch, denn im Bankenwesen speichert keine Bank massenhaft Nachkommastellen.

4-6 Dezimalstellen und beim Ein-/Auszahlen nur die "normalen" 2 Dezimalstellen.
Wenn man hier also "normal" nach den jeweiligen Iterationen rundet, dann ist es fast egal, welchen Typ man hier verwendet.

Egal was ihr anstellt, es ist unmöglich 1.7182818… € oder was auch immer einzuzahlen.


Diese Berechnung als Beispiel für grundsätzlichen Rundungsprobleme OK, aber mit dem Beispiel an einem Konto ist absolut abwägig.

Jost Riedel 17. Apr 2020 23:21

AW: Genauigkeit von String to Single Konvertierung
 
Natürlich nicht. Geld, egal welche Währung, sind Integer. Die Unterteilung in Euro und Cent ist Augenwischerei - Euro ist nur eine Bezeichnung für einhundert Cent. Genauso, wie hundert ein anderes Wort für einhundert ist.

Addieren und subtrahieren kann man Geldbeträge mit Integers und einem impliziten Dezimalpunkt (Sorry, Komma). Und wenn man noch Multiplizieren und Dividieren will wie die Banken, dann braucht man 4 implizite Nachkommastellen - so wie z.B. beim Delphi Typ Currency.

Die BCD Darstellung macht nichts wirklich genauer - nur anders. Und BCD stellt nur die Mantisse anders dar. Eigentlich gar nicht erforderlich. Der Exponent und implizierte Basis geben den Takt an - die Mantisse ist nur ein Integer. Aber wenn die implizierte Basis 2 ist, dann ist ein Teilen oder Multiplizieren mit dieser Basis (und das ist ist eine sehr häufige Operation) bei einer binär codierten Mantisse ein simples Shiften. Oder bei einer Basis 10 und einer BCD codierten Mantisse ebenfalls.

Fließkommazahlen haben immer eine recht konstante relative Genauigkeit. Und finanzielle Berechnungen eine absolute (auf einen Pfennig, oder Cent, genaue), und die kann bei kleinen Beträgen relativ schlecht sein.

32 bit floating point braucht man im Prinzip nur für eine Sache: Um die selben spaßig schlechten Ergebnisse zu erhalten wie uralte FORTRAN Programme.

p80286 18. Apr 2020 18:24

AW: Genauigkeit von String to Single Konvertierung
 
Andreas13 hat es doch schön ausgeführt, wenn man sich blind auf ein Programm verläßt kann man verlassen sein.
Nachdem ich vor ein paar Jahren "unerklärliche Rundungsfehler" hatte, war klar, das Single oder Double selbst für dreistellige Beträge mit relativ einfachen Prozentbrüchen nicht geeignet ist. Aber es gibt ja Currency.
Bleib die Frage warum diese Krüppeltypen überhaupt existieren, wenn die Genauigkeit auf dem Stand eines Rechenschiebers stehen geblieben ist.

Gruß
K-H

himitsu 18. Apr 2020 23:46

AW: Genauigkeit von String to Single Konvertierung
 
Wenn dir was Besseres einfällt, dann darfst es gern patentieren und reich werden.

Es sind halt Typen, die vielen Ansprüchen gerecht werden müssen
und aufgrund der Größe geht es nicht ohne Kompromisse.

Redeemer 19. Apr 2020 10:15

AW: Genauigkeit von String to Single Konvertierung
 
Dezimale Gleitkommazahlen. Im Prinzip die beiden Komponenten einer in Wissenschaftlicher Notation aufgeschriebener Zahl hintereinander als Integers gespeichert (Exponent ggf. mit Bias statt vorzeichenbehaftetem Integer), nur wäre die Mantisse wohl sinnvollerweise nicht normiert. Der Exponent ist zur Basis 10 zu verstehen und kann deshalb um 2 bis 3 Bits (=lb(10)) gekürzt werden.

Zitat:

Zitat von Andreas13 (Beitrag 1462293)
Darüber hinaus hast Du gemogelt, weil Du nicht einmal Deine eigene Formel mit den verschiedenen Real-Typen berechnet hast, sondern nur Deine allerletzte Operation: 15511210043330985984000000 e - 26652630354867072870693626.

Nein.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:44 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz