Funktionparameter-Typen werden bei 3.2.3. anders behandelt.

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Soner
Beiträge: 510
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.

Beitrag von Soner »

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.
Dateianhänge
rundung-pub.zip
(1.59 KiB) 15-mal heruntergeladen

wp_xyz
Beiträge: 4263
Registriert: Fr 8. Apr 2011, 09:01

Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.

Beitrag von wp_xyz »

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).

Warf
Beiträge: 1662
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.

Beitrag von Warf »

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

Soner
Beiträge: 510
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.

Beitrag von Soner »

@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.
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.
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.

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.

Soner
Beiträge: 510
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.

Beitrag von Soner »

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
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.

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?

Benutzeravatar
Winni
Beiträge: 1281
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.0.12, fpc 3.2
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.

Beitrag von Winni »

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

Soner
Beiträge: 510
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.

Beitrag von Soner »

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.

PascalDragon
Beiträge: 535
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.

Beitrag von PascalDragon »

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.
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:
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.
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.
FPC Compiler Entwickler

Warf
Beiträge: 1662
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.

Beitrag von Warf »

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.
Das macht den Currency Typen übrigens herzlichst Nutzlos, da das dazu führt das 32 und 64 bit unterschiedliche Ergebnisse rauswerfen.
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);  
32 Bit: 1.575405300000000000E+03 = 1575,4053
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

wp_xyz
Beiträge: 4263
Registriert: Fr 8. Apr 2011, 09:01

Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.

Beitrag von wp_xyz »

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?

Soner
Beiträge: 510
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.

Beitrag von Soner »

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.
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.

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 Problem liegt bei Parameterübergabe, vergieß in der Funktion PreisRunden alles was nach Writeln steht.
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.

wp_xyz
Beiträge: 4263
Registriert: Fr 8. Apr 2011, 09:01

Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.

Beitrag von wp_xyz »

Soner hat geschrieben:
Di 14. Jun 2022, 12:46
Das Problem liegt bei Parameterübergabe.
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. 
Output (alles auf Win 11)
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.

Warf
Beiträge: 1662
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.

Beitrag von Warf »

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.
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.

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
Das führt dann zu dem ersten Problem, Fließkommazahlen sind einfach viel schwerer zu benutzen, da man im grunde sich nicht wirklich auf <, >, <> oder = verlassen kann, sondern immer den Wertebereich von +/- epsilon überprüfen muss.

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

PascalDragon
Beiträge: 535
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.

Beitrag von PascalDragon »

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.
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).
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?
Vom generierten Assemblycode schaut es so aus, als ob abgeschnitten würde, allerdings habe ich mich jetzt nicht im Detail damit beschäftigt.
Soner hat geschrieben:
Di 14. Jun 2022, 12:46
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.
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.
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.
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

Benutzeravatar
six1
Beiträge: 636
Registriert: Do 1. Jul 2010, 19:01

Re: Funktionparameter-Typen werden bei 3.2.3. anders behandelt.

Beitrag von six1 »

...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!)
Gruß, Michael

Antworten