Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
-
- Beiträge: 724
- Registriert: Do 27. Sep 2012, 00:07
- OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
- CPU-Target: x86_64-win64
- Wohnort: Hamburg
Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Ich habe eine Funktion in der Form:
function PreisRunden(const Value:Extended):Extended;
Meistens wird der Preis gleich beim Funktionsaufruf ausgeführt etwa so:
Brutto:= PreisRunden(Netto * ((StSatz / 100) +1));
Wobei die Variablen Netto und StSatz vom Typ Currency sind.
Bei Fpc 3.0.4(32Bit) wurden alle Dezimalstellen weitergereicht also als Extended, jetzt bei Fpc 3.2.3. (64bit) wird immer als Currency (4.Dezimalstellen) weitergereicht. Das führt zum Fehler.
Wenn die Variablen Netto und StSatz vom Typ Extended sind, dann ist das Ergebnis richtig.
Ist es jetzt bei Fpc irgendetwas geändert worden oder habe ich etwas falsch gemacht?
Ein Beispielprogramm liegt als Anhang bei.
function PreisRunden(const Value:Extended):Extended;
Meistens wird der Preis gleich beim Funktionsaufruf ausgeführt etwa so:
Brutto:= PreisRunden(Netto * ((StSatz / 100) +1));
Wobei die Variablen Netto und StSatz vom Typ Currency sind.
Bei Fpc 3.0.4(32Bit) wurden alle Dezimalstellen weitergereicht also als Extended, jetzt bei Fpc 3.2.3. (64bit) wird immer als Currency (4.Dezimalstellen) weitergereicht. Das führt zum Fehler.
Wenn die Variablen Netto und StSatz vom Typ Extended sind, dann ist das Ergebnis richtig.
Ist es jetzt bei Fpc irgendetwas geändert worden oder habe ich etwas falsch gemacht?
Ein Beispielprogramm liegt als Anhang bei.
- Dateianhänge
-
rundung-pub.zip
- (1.59 KiB) 78-mal heruntergeladen
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Bei Currency wird die Zahl mit 10 000 multipliziert und als Integer gespeichert (https://www.freepascal.org/docs-html/ref/refsu5.html). Da kannst du nicht mehr als 4 Dezimalstellen erwarten.
Ich finde, die Rechnung ist richtig. Bei der zweiten Rechnung berechnest du Netto1 * (StSatz1/100+1), wobei Netto1 und StSatz1 Currency-Typen sind; daher ist auch das Ergebnis ein Currency und hat nur 4 Dezimalstellen. Das wird als Argument an die PreisRunden()-Funktion übergeben und dabei in einen Extended umgewandelt. Dabei können die verloren gegangenen Dezimalstellen natürlich nicht mehr zurückgewonnen werden.
Seltsam ist für mich eher, warum unter 32-Bit und unter Delphi das in deinen Augen richtige Ergebnis herauskommt.
Ich ziehe für mich daraus den Schluss, weiterhin die Finger von diesem seltsamen Datentyp zu lassen (auch wenn viele Forumsmitglieder anderer Meinung sind).
Ich finde, die Rechnung ist richtig. Bei der zweiten Rechnung berechnest du Netto1 * (StSatz1/100+1), wobei Netto1 und StSatz1 Currency-Typen sind; daher ist auch das Ergebnis ein Currency und hat nur 4 Dezimalstellen. Das wird als Argument an die PreisRunden()-Funktion übergeben und dabei in einen Extended umgewandelt. Dabei können die verloren gegangenen Dezimalstellen natürlich nicht mehr zurückgewonnen werden.
Seltsam ist für mich eher, warum unter 32-Bit und unter Delphi das in deinen Augen richtige Ergebnis herauskommt.
Ich ziehe für mich daraus den Schluss, weiterhin die Finger von diesem seltsamen Datentyp zu lassen (auch wenn viele Forumsmitglieder anderer Meinung sind).
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Hast du mal die aktuelle FPC version mit 32 Bit probiert?
Ich hatte bereits vor 2 Jahren schonmal rausgefunden das der Currency typ für 32 Bit irgendwie Kaputt ist, und andere ergebnisse als auf 64 bit rauswirft: https://lazarusforum.de/viewtopic.php?p=112744#p112744
Vielleicht liegt es daran
Ich hatte bereits vor 2 Jahren schonmal rausgefunden das der Currency typ für 32 Bit irgendwie Kaputt ist, und andere ergebnisse als auf 64 bit rauswirft: https://lazarusforum.de/viewtopic.php?p=112744#p112744
Vielleicht liegt es daran
-
- Beiträge: 724
- Registriert: Do 27. Sep 2012, 00:07
- OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
- CPU-Target: x86_64-win64
- Wohnort: Hamburg
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
@wp
Ich weiß, dass Currency 4 Dezimalstellen hat. Ich rechne in Extended und runde optional auf maximal 4 Dezimalstellen und speichere das Ergebnis als Currency.
Es wird nirgendwo eine Currency-Zahl mit 10000 multipliziert. Es geht um wie der Eingabe-Parameter von der Funktion PreisRunden-Funktion gehandt habt wird. Zwei unterschiedliche FreePascal-Versionen compilieren es komplett anders.
Seltsam ist, dass unter fpc 3.0.4 (32Bit) damit:
PreisRunden(Netto * ((StSatz / 100) +1));
an die Funktion PreisRunden immer Extended übergeben wird, egal ob die Variable Netto und StSatz als Currency oder Extended definiert wird, während es bei fpc 3.2.3(64Bit) der Parameter von PreisRunden den Typ von den Variablen Netto und StSatz bekommt. Ich habe es eigentlich im Beispielprogramm kommentiert und wenn man das Programm laufen läßt, dann sieht man es auch.
Meinst du mit seltsamen Datentypen Extended? Mit Double bekommt man gleiches Ergebnis.
@warf:
Ich aktualisiere gerade fpc, dann schaue ich nach und schreibe das Ergebnis hier.
Ich weiß, dass Currency 4 Dezimalstellen hat. Ich rechne in Extended und runde optional auf maximal 4 Dezimalstellen und speichere das Ergebnis als Currency.
Es wird nirgendwo eine Currency-Zahl mit 10000 multipliziert. Es geht um wie der Eingabe-Parameter von der Funktion PreisRunden-Funktion gehandt habt wird. Zwei unterschiedliche FreePascal-Versionen compilieren es komplett anders.
Seltsam ist, dass unter fpc 3.0.4 (32Bit) damit:
PreisRunden(Netto * ((StSatz / 100) +1));
an die Funktion PreisRunden immer Extended übergeben wird, egal ob die Variable Netto und StSatz als Currency oder Extended definiert wird, während es bei fpc 3.2.3(64Bit) der Parameter von PreisRunden den Typ von den Variablen Netto und StSatz bekommt. Ich habe es eigentlich im Beispielprogramm kommentiert und wenn man das Programm laufen läßt, dann sieht man es auch.
Ich habe mit Delphi nicht ausprobiert und wenn du 0,3738 mit 1,07 multiplizierst und das Ergebnis auf 4 Stellen kaufmännisch aufrundet bekommt man 0,4000 und nicht 0,3999.wp_xyz hat geschrieben: Mo 13. Jun 2022, 18:57 Seltsam ist für mich eher, warum unter 32-Bit und unter Delphi das in deinen Augen richtige Ergebnis herauskommt.
Meinst du mit seltsamen Datentypen Extended? Mit Double bekommt man gleiches Ergebnis.
@warf:
Ich aktualisiere gerade fpc, dann schaue ich nach und schreibe das Ergebnis hier.
-
- Beiträge: 724
- Registriert: Do 27. Sep 2012, 00:07
- OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
- CPU-Target: x86_64-win64
- Wohnort: Hamburg
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Tatsächlich bei fpc 3.2.3 (32 Bit) wird auch in beiden Fällen das Zwischenergebnis als Extended übergeben und somit ist das Endergebnis richtig.Warf hat geschrieben: Mo 13. Jun 2022, 19:20 Hast du mal die aktuelle FPC version mit 32 Bit probiert?
Ich hatte bereits vor 2 Jahren schonmal rausgefunden das der Currency typ für 32 Bit irgendwie Kaputt ist, und andere ergebnisse als auf 64 bit rauswirft: https://lazarusforum.de/viewtopic.php?p=112744#p112744
Vielleicht liegt es daran
Heißt es dann nicht, dass bei 64 Bit irgendetwas kaputt ist?
Soweit ich mich erinnern kann, wurde immer bei Berechnungen auf den Daten-Typ des Parameters umgewandelt. Hieß es nicht implizite Typumwandlung?
- Winni
- Beiträge: 1577
- Registriert: Mo 2. Mär 2009, 16:45
- OS, Lazarus, FPC: Laz2.2.2, fpc 3.2.2
- CPU-Target: 64Bit
- Wohnort: Fast Dänemark
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Hi!
Currency ist intern ein Int64 .
----
Wertebereich: -922337203685477.5808 .. 922337203685477.5807
Genauigkeit: 19 Stellen
Speicherbedarf: 8 Byte bzw. 64 Bit
----
aus https://wiki.freepascal.org/Currency/de
Ich hab allerdings auch schon gemerkt, dass da was vergurkt ist.
Seitdem lasse ich die Finger davon und nehme Double:
Für mein Konto reichen 15 Stellen Genauigkeit ....
Winni
Currency ist intern ein Int64 .
----
Wertebereich: -922337203685477.5808 .. 922337203685477.5807
Genauigkeit: 19 Stellen
Speicherbedarf: 8 Byte bzw. 64 Bit
----
aus https://wiki.freepascal.org/Currency/de
Ich hab allerdings auch schon gemerkt, dass da was vergurkt ist.
Seitdem lasse ich die Finger davon und nehme Double:
Für mein Konto reichen 15 Stellen Genauigkeit ....
Winni
-
- Beiträge: 724
- Registriert: Do 27. Sep 2012, 00:07
- OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
- CPU-Target: x86_64-win64
- Wohnort: Hamburg
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Liebe Leute, es hat bei diesem Fehler mit Currency nichts zu tun.
Die Eingabeparameter Value der Funktion:
function PreisRunden(const Value: extended): extended;
ist ein Fließkomma-Typ. Während bei 32Bit-fpc die Parameterübergabe der Berechnung:
PreisRunden(Netto * ((StSatz / 100) +1));
in Fließkommatyp stattfindet, findet es bei 64Bit-fpc in Currency. Also irgendetwas bei 64Bit-fpc ist falsch. Für mich ist es ein Fehler. Warum wird die Berechnung bei 64Bit-Fpc in Currency umgewandelt, obwohl die Variable Value ein Fließkommatyp ist.
Die Eingabeparameter Value der Funktion:
function PreisRunden(const Value: extended): extended;
ist ein Fließkomma-Typ. Während bei 32Bit-fpc die Parameterübergabe der Berechnung:
PreisRunden(Netto * ((StSatz / 100) +1));
in Fließkommatyp stattfindet, findet es bei 64Bit-fpc in Currency. Also irgendetwas bei 64Bit-fpc ist falsch. Für mich ist es ein Fehler. Warum wird die Berechnung bei 64Bit-Fpc in Currency umgewandelt, obwohl die Variable Value ein Fließkommatyp ist.
-
- Beiträge: 945
- Registriert: Mi 3. Jun 2020, 07:18
- OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
- CPU-Target: Aarch64 bis Z80 ;)
- Wohnort: München
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Auf Plattformen, auf denen Extended existiert, ist Currency auf Extended abgebildet. Auf allen anderen Plattformen (und das schließt auf x86 eben auch einzig Win64 ein) ist er auf einen Fixed Comma 64-bit Integer abgebildet. Das heißt alle Berechnungen mit Currency finden eben auch nur mit 4 Nachkommastellen statt. Wenn du mehr erwartest, dann verlässt du dich auf ein Implementierungsdetail, welches nirgends garantiert ist.Soner hat geschrieben: Mo 13. Jun 2022, 20:11 Es wird nirgendwo eine Currency-Zahl mit 10000 multipliziert. Es geht um wie der Eingabe-Parameter von der Funktion PreisRunden-Funktion gehandt habt wird. Zwei unterschiedliche FreePascal-Versionen compilieren es komplett anders.
Seltsam ist, dass unter fpc 3.0.4 (32Bit) damit:
PreisRunden(Netto * ((StSatz / 100) +1));
an die Funktion PreisRunden immer Extended übergeben wird, egal ob die Variable Netto und StSatz als Currency oder Extended definiert wird, während es bei fpc 3.2.3(64Bit) der Parameter von PreisRunden den Typ von den Variablen Netto und StSatz bekommt. Ich habe es eigentlich im Beispielprogramm kommentiert und wenn man das Programm laufen läßt, dann sieht man es auch.
Der Typ eines Ausdrucks hängt in Pascal grundsätzlich nicht davon ab wohin der Wert des Ausdrucks zugewiesen wird, sondern einzig von den im Ausdruck selbst involvierten Typen. Sind also alle im Ausdruck involvierten Typen Currency, so wird auch in Currency berechnet und nicht in einem Fließkommatyp.Soner hat geschrieben: Di 14. Jun 2022, 07:28 in Fließkommatyp stattfindet, findet es bei 64Bit-fpc in Currency. Also irgendetwas bei 64Bit-fpc ist falsch. Für mich ist es ein Fehler. Warum wird die Berechnung bei 64Bit-Fpc in Currency umgewandelt, obwohl die Variable Value ein Fließkommatyp ist.
FPC Compiler Entwickler
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Das macht den Currency Typen übrigens herzlichst Nutzlos, da das dazu führt das 32 und 64 bit unterschiedliche Ergebnisse rauswerfen.PascalDragon hat geschrieben: Di 14. Jun 2022, 09:24 Auf Plattformen, auf denen Extended existiert, ist Currency auf Extended abgebildet. Auf allen anderen Plattformen (und das schließt auf x86 eben auch einzig Win64 ein) ist er auf einen Fixed Comma 64-bit Integer abgebildet. Das heißt alle Berechnungen mit Currency finden eben auch nur mit 4 Nachkommastellen statt. Wenn du mehr erwartest, dann verlässt du dich auf ein Implementierungsdetail, welches nirgends garantiert ist.
Was ganz einfaches als beispiel, berechnung eines Zinssatzes von 4.65% über 10 Zeiteinheiten, von einem Startwert von 1000:
Code: Alles auswählen
var
val: Currency;
i: Integer;
begin
val := 1000;
for i:=0 to 9 do
val += val * 0.0465;
WriteLn(val);
64 bit: 1.575404800000000000E+03 = 1575,4048
Für eine so kleine Rechnung ist die Abweichung schon ziemlich groß. Aber vor allem ist hier weniger das Problem der Wert der Abweichung, sondern eher die Tatsache das wenn man also die Architektur wechselt plötzlich alle Berechnungen was anderes rauswerfen als vorher. Und Programme sollten deterministisch sein, wenn man das selbe reinsteckt sollte das selbe rauskommen.
Ein bisschen spekulation, aber wenn eine Bank von heut auf morgen nach einem softwareupdate bei allen Berechnungen um ein unterschiedliches Ergebnis von paar hundertstel Cent rauskommt würde da sehr wahrscheinlich die Hütte brennen
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Ich habe den Currency-Teil der Rechnung aus dem 1.Post einmal mit Integer nachvollzogen - Integer, denn Currency sind die mit 10000 multiplizierten Float-Zahlen. Also, wir haben Netto1 = 0.3738 - das ergibt den Integer 3738. Dann StSatz1 = 7 - das wird durch 100 dividiert und dann wird 1 addiert; als Integer haben wir damit den Wert 10700. Die beiden werden multipliziert - das ergibt 39996600. Damit das Ergebnis wieder ein Currency-Wert ist müssen wir noch durch 10000 divieren und auf 4 Dezimalstellen begrenzen. Das letztere ist die große Frage: Wird gerundet? Dann wäre das Ergebnis so wie Soner fordert 0.4000 (und wie 32-bit und Delphi liefern). Oder wird abgeschnitten? Dann wäre das Ergebnis 0.3999 (so wie extended auf Win-64bit liefert). PascalDragon, was meinst du?
-
- Beiträge: 724
- Registriert: Do 27. Sep 2012, 00:07
- OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
- CPU-Target: x86_64-win64
- Wohnort: Hamburg
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Das erklärt alles. Danke für den Hinweis. Merkwürdig ist es schon, wenn die Berechnung mit gleiche Variablentypen komplett andere Ergebnisse liefern. Das ist kein gutes Zeugnis für den Compiler.PascalDragon hat geschrieben: Di 14. Jun 2022, 09:24 Der Typ eines Ausdrucks hängt in Pascal grundsätzlich nicht davon ab wohin der Wert des Ausdrucks zugewiesen wird, sondern einzig von den im Ausdruck selbst involvierten Typen. Sind also alle im Ausdruck involvierten Typen Currency, so wird auch in Currency berechnet und nicht in einem Fließkommatyp.
Viele Finanzprogramme werden jetzt bei 64Bit-Version falsch rechnen.
Ich muss dann erst bei 32 Bit bleiben und alle Zwischenvariablen in Double/Extended/Float ändern, dann auf 64Bit umsteigen.
EDIT: Ich muss zugeben, dass es Fehler von mir war für die Zwischenvariablen Currency zuverwenden. Ich habe blind vertraut, dass es automatisch in Fließkommazahl berechnet und am Ende abgeschnitten wird.
Das Problem liegt bei Parameterübergabe, vergieß in der Funktion PreisRunden alles was nach Writeln steht.wp_xyz hat geschrieben: Di 14. Jun 2022, 10:17 Ich habe den Currency-Teil der Rechnung aus dem 1.Post einmal mit Integer nachvollzogen - Integer, denn Currency sind die mit 10000 multiplizierten Float-Zahlen. Also, wir haben Netto1 = 0.3738 - das ergibt den Integer 3738. Dann StSatz1 = 7 - das wird durch 100 dividiert und dann wird 1 addiert; als Integer haben wir damit den Wert 10700. Die beiden werden multipliziert - das ergibt 39996600. Damit das Ergebnis wieder ein Currency-Wert ist müssen wir noch durch 10000 divieren und auf 4 Dezimalstellen begrenzen. Das letztere ist die große Frage: Wird gerundet? Dann wäre das Ergebnis so wie Soner fordert 0.4000 (und wie 32-bit und Delphi liefern). Oder wird abgeschnitten? Dann wäre das Ergebnis 0.3999 (so wie extended auf Win-64bit liefert). PascalDragon, was meinst du?
Bei 64Bit 0,399900 übergeben, also Currency, während bei 32Bit 0,399966 übergeben werden, vielleicht auch mehr Dezimalstellen, nur ich gebe 6 Stellen aus.
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Nein. Das Problem liegt darin, wie der Int64-Wert 39996600 als Currency-Wert interpretiert wird. 32-bit und 64-bit verhalten sich dabei offensichtlich unterschiedlich - ich behaupte, dass der 32-bit Compiler das Ergebnis nach der Division durch 10000 rundet, der 64-Bit Compiler aber abschneidet.
Einfaches Testprogramm:
Code: Alles auswählen
program Project1;
var
a, b, c: Currency;
begin
a := 0.3738;
b := 1.07;
c := a * b;
WriteLn(c);
ReadLn;
end.
mit Laz 2.2.2/FPC 3.2.2/64 bit: 3.999000000000000000E-01
mit Laz 2.2.2/FPC 3.2.2/32 bit: 4.000000000000000000E-01
mit Delphi XE 10.3.3: 4.00000000000000E-0001 (sowohl für 32-bit und 64-bit Plattform).
Ich denke, allein wegen dieses Unterschieds solltest du einen Bugreport schreiben. Leider habe ich z.Zt keinen 64-bit FPC/main fertig, das sollte vorher noch getestet werden.
-
- Beiträge: 2118
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Es ist nicht falsch, um genau zu sein ist es gesetzlich korrekt für Geldwerte Fixpunktzahlen mit 4 Nachkommastellen zu nehmen. Tatsächlich gilt die verwendung von Fixpunktzahlen als "Best Practice" wenn man mit finanzen rechnet. Dafür gibt es mehrere Gründe, der erste ist das Geld in der echten Welt in Basis 10 mit 2 nachkommastellen berechnet wird, und Prozentsätze auch mit 2 Nachkommastellen angegeben werden, also maximal 4 Nachkommastellen brauchen.Soner hat geschrieben: Di 14. Jun 2022, 12:46 Das erklärt alles. Danke für den Hinweis. Merkwürdig ist es schon, wenn die Berechnung mit gleiche Variablentypen komplett andere Ergebnisse liefern. Das ist kein gutes Zeugnis für den Compiler.
Viele Finanzprogramme werden jetzt bei 64Bit-Version falsch rechnen.
Ich muss dann erst bei 32 Bit bleiben und alle Zwischenvariablen in Double/Extended/Float ändern, dann auf 64Bit umsteigen.
EDIT: Ich muss zugeben, dass es Fehler von mir war für die Zwischenvariablen Currency zuverwenden. Ich habe blind vertraut, dass es automatisch in Fließkommazahl berechnet und am Ende abgeschnitten wird.
Winni hat gesagt das im 15 Stellen Genauigkeit reichen, was auch mehr als genug würde, allerdings hat double keine 15 (dezimal) stellen Genauigkeit. Double hat 48 bit genauigkeit, was 48/log2(10) ~ 14,45 Dezimalstellen an Information entspricht. Das heist aber nicht das man damit 15 Dezimalstellen darstellen kann.
Z.B. um die Zahl 0.2 darzustellen braucht genau 1 Dezimal-Nachkommastelle, aber unendlich viele bits. Der grund dafür ist das 0.2 = 1/5 da 5 aber kein multiples von 2 ist kann man es nicht in endlicher representation als Kommazahl darstellen (nur periodisch). Basis 10 ist eine Kombination aus 2*5 (Primfaktorzerlegung) und damit können im 10er System alle Zahlen die eine Kombination aus 2 und 5 sind endlich dargestellt werden. Also z.B. 0.2 was 1/5 is oder 0.1 was 1/(2*5) ist. 1/3 hingegen nicht, das ist 1,3333... periode.
Also hat man keine 15 dezimalstellen, man hat nicht mal die eine dezimalstelle die man für 0.2 braucht.
Im klartext bedeutet das das Fließkommazahlen für alle Zahlen die nicht ein vielfaches von 2 sind, einen Fehler epsilon von 2^-48 haben. Das ist kein großer Fehler, aber es ist ein Fehler nach wie vor. Da man in Finanzen eigentlich immer mit Zahlen die sich endlich im 10er System darstellen lassen rechnet (also den preis von 1,33.. periode hab ich noch nie gesehen), bedeutet das das zumindest mal die Preise selbst, sowie die Addition von diesen Preisen Fehlerfrei sind. Bei Fließkommazahlen ist dies nicht der Fall.
Das führt zu solchen effekten:
Code: Alles auswählen
var a: Double;
begin
a := 0.1;
a := a+0.2;
WriteLn(a = 0.3); // gibt false weil rundungsfehler sich in der addition akkumuliert
Allerdings ist es natürlich zwar so das bei der Addition das ganze Fehlerfrei ist, dafür die Multiplikation allerdings ungenauer ist, wenn man über die nachkommastellen hinaus geht (wie man bei meinem Beispiel oben sehen kann).
Das ist tatsächlich für gewöhnlich kein Problem, da Eurowerte tatsächlich nur auf 2 Nachkommastellen (auf cents) genau sein müssen. Auf deiner Bank hast du keine halben Cents, d.h. Transaktionen können generell auf 2 Nachkommastellen gerundet werden. Wenn man das bei meinem beispiel oben machen würde, also jeden zinssatz der drauf gerechnet wird auf 2 Nachkommastellen zu runden vor der addition, interresiert einen der 4 Stellen Rundungsfehler auch nicht mehr.
An diesem Punkt ist auch die Genauigkeit von Fließkomma ausreichend, wenn man sowieso ständig rundet, was bedeutet das Effektiv egal ob man Fließ-oder Fixpunkt benutzt man genug genauigkeit hat. Allerdings macht Fixpunkt einem das leben grundsätzlich einfacher, weil man direkt die Vergleichsoperatoren benutzen kann,
Also zusammengefasst, Währungswerte müssen am Ende des Tages nur auf 2 Stellen genau sein, und in der Rechnung, um mit 2 Nachkommastellen Prozenten zu rechnen nur 4 Nachkommastellen genau sein. Und da sind Fixkommawerte einfach besser da sie a. einfacher zu benutzen sind (kein komisches Epsiolon Wertebereich checking) und b. Echtweltwerte tatsächlich genau darstellen können (was mindestens die Ausgabe einfacher macht) und c. effizienter berechnet werden können.
Darum ist die allgemeine Empfehlung immer das man Fixpunkt für Währungen nehmen sollte. Und soweit ich weiß gibt es dazu genaue regulatorien. Es ist im Grunde beides Erlaubt (Excel benutzt z.B. Double, während .Net den fixpunkt typen "decimal" dafür empfiehlt), allerdings muss man sich genau an die Rundungsvorschriften halten wann und wie man rundet.
Das Problem was ich hier aber Sehe ist Konsistenz, mit den Rundungsfehlern kann man leben, aber es sollte niemals passieren das nach einem Update plötzlich die Rechnung anders ist und die Bücher nicht mehr validiert werden können
-
- Beiträge: 945
- Registriert: Mi 3. Jun 2020, 07:18
- OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
- CPU-Target: Aarch64 bis Z80 ;)
- Wohnort: München
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
Auf der gleichen Plattform kommt ja auch immer das gleiche raus. Irgendeinen Tod muss man hier sterben, denn Extended gibt es einfach auf allen anderen CPU Architekturen schlicht und ergreifend nicht. Delphi ist dabei den gleichen Schritt wie FPC gegangen und hat für nicht-i386 Currency zu 'nem 64-bit Fixed Point Typ gemacht (wobei FPC das auf x86 nur für Win64 macht).Warf hat geschrieben: Di 14. Jun 2022, 10:08 Aber vor allem ist hier weniger das Problem der Wert der Abweichung, sondern eher die Tatsache das wenn man also die Architektur wechselt plötzlich alle Berechnungen was anderes rauswerfen als vorher. Und Programme sollten deterministisch sein, wenn man das selbe reinsteckt sollte das selbe rauskommen.
Vom generierten Assemblycode schaut es so aus, als ob abgeschnitten würde, allerdings habe ich mich jetzt nicht im Detail damit beschäftigt.wp_xyz hat geschrieben: Di 14. Jun 2022, 10:17 Ich habe den Currency-Teil der Rechnung aus dem 1.Post einmal mit Integer nachvollzogen - Integer, denn Currency sind die mit 10000 multiplizierten Float-Zahlen. Also, wir haben Netto1 = 0.3738 - das ergibt den Integer 3738. Dann StSatz1 = 7 - das wird durch 100 dividiert und dann wird 1 addiert; als Integer haben wir damit den Wert 10700. Die beiden werden multipliziert - das ergibt 39996600. Damit das Ergebnis wieder ein Currency-Wert ist müssen wir noch durch 10000 divieren und auf 4 Dezimalstellen begrenzen. Das letztere ist die große Frage: Wird gerundet? Dann wäre das Ergebnis so wie Soner fordert 0.4000 (und wie 32-bit und Delphi liefern). Oder wird abgeschnitten? Dann wäre das Ergebnis 0.3999 (so wie extended auf Win-64bit liefert). PascalDragon, was meinst du?
Das hat nichts mit merkwürdig zu tun, sondern einfach damit, dass es auf anderen Architekturen den entsprechenden Basistyp (nämlich Extended) nicht gibt, das heißt es würde sich so oder so immer anders verhalten als auf x86-Systemen (exklusive Win64). Sowohl die Delphi, als auch die FPC Dokumentation dokumentieren Currency als einen Typ mit 4 Nachkommastellen. Wenn du dich auf die 5. Nachkommastelle verlässt, bist du demnach außerhalb des dokumentierten Bereichs und damit im Bereich der Implementierungsdetails.Soner hat geschrieben: Di 14. Jun 2022, 12:46Das erklärt alles. Danke für den Hinweis. Merkwürdig ist es schon, wenn die Berechnung mit gleiche Variablentypen komplett andere Ergebnisse liefern. Das ist kein gutes Zeugnis für den Compiler.PascalDragon hat geschrieben: Di 14. Jun 2022, 09:24 Der Typ eines Ausdrucks hängt in Pascal grundsätzlich nicht davon ab wohin der Wert des Ausdrucks zugewiesen wird, sondern einzig von den im Ausdruck selbst involvierten Typen. Sind also alle im Ausdruck involvierten Typen Currency, so wird auch in Currency berechnet und nicht in einem Fließkommatyp.
Edit: außerdem schreiben beide Dokumentationen, dass durch die Verwendung von Currency Rundungsfehler minimiert werden, das heißt sie sind nicht ausgeschlossen.
FPC Compiler Entwickler
Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.
...das Problem ist im Grunde, dass nicht jede beliebige reelle Zahl des Dezimalsystems im Binären Zahlensystem (ohne unendlich viele Stellen) darstellbar ist.
Die hier vorliegende Ursache dürfte aber die unterschiedliche Behandlung (abschneiden) im 64Bit System sein, was ich im Grunde als Bug sehe. (wie das PascalDragon ja sehr schön ausgeführt hat!)
Die hier vorliegende Ursache dürfte aber die unterschiedliche Behandlung (abschneiden) im 64Bit System sein, was ich im Grunde als Bug sehe. (wie das PascalDragon ja sehr schön ausgeführt hat!)
Gruß, Michael