Präzision mit Floats

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Präzision mit Floats

Beitrag von Niesi »

Moin,

ich weiß: Das Thema ist schon etliche Male durchgekaut worden, aber ich möchte hier doch noch mal fragen, ob es Wissen oder Ideen zu meinem Problem gibt.

Ich muss Übersetzungen von Planetenradsätzen vergleichen, dabei möchte ich den bestmöglichen Radsatz ermitteln. Leider ergibt die mangelhafte Genauigkeit einige Probleme - und ich verstehe es einfach nicht. Das Beispielprojekt hat sich in vier Tagen unterschiedlich intensivem Suchens nach einer Lösung so ergeben - im Moment sind es drei Übersetzungen, welche ich vergleiche und dann die herausbekommen möchte, welche am dichtesten an der geforderten Übersetzung ist. Dabei soll aber nur auf den oberen oder unteren Wert gegangen werden, wenn einer davon WIRKLICH dichter dran ist, bei Gleichstand soll die "mittlere" Lösung beibehalten werden.

Das klappt jedoch nicht, da teilweise die Berechnungen mit den Extended kleine schmutzige Abweichungen bekommen. Diese Abweichungen entstehen aber nicht bei allen Berechnungen - WARUM?

Die Übersetzungen (i_ZS, i_ZSup und i_ZSdown) werden ganz und gar sauber berechnet.
Bei den Deltas dagegen geht irgendetwas schief - aber was?

Wenn ich die geforderte Übersetzung nicht als Zahlenwert eingebe, sondern aus zwei Integers berechne, dann sind zwei Deltawerte "sauber", nur der dritte nicht. Wie kann das denn sein???

Ich würde mich sehr freuen, wenn Ihr dazu was sagen könnt oder Ideen habt.


Bildschirmfoto vom 2024-07-05 15-08-11.png
Bildschirmfoto vom 2024-07-05 15-08-11.png (61.52 KiB) 1110 mal betrachtet

Precision-06.7z
(148.3 KiB) 38-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Joh
Lazarusforum e. V.
Beiträge: 280
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Präzision mit Floats

Beitrag von Joh »

ersetze abs() durch
if delta < 1 then delta := -delta;
just my two Beer

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

Joh hat geschrieben: Fr 5. Jul 2024, 16:12 ersetze abs() durch
if delta < 1 then delta := -delta;
die Funktion abs() hatte ich auch schon verdächtigt, aber die hat keinen Einfluss ...


Bildschirmfoto vom 2024-07-05 16-21-02.png
Bildschirmfoto vom 2024-07-05 16-21-02.png (73.63 KiB) 1101 mal betrachtet
Precision-07.7z
(148.29 KiB) 44-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Joh
Lazarusforum e. V.
Beiträge: 280
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Präzision mit Floats

Beitrag von Joh »

ähem...

ich hatte abs() entfernt und schon waren die Werte passig...
unter Windows 64bit.

Abs() verwendet direkte Registerzugriffe, da ist es womöglich sehr hardwareabhängig.
just my two Beer

Joh
Lazarusforum e. V.
Beiträge: 280
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Präzision mit Floats

Beitrag von Joh »

Niesi hat geschrieben: Fr 5. Jul 2024, 16:23 Precision-07.7z
Hier wird mir die Ausgabe-Form gar nicht angezeigt.

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

Joh hat geschrieben: Fr 5. Jul 2024, 16:31
Niesi hat geschrieben: Fr 5. Jul 2024, 16:23 Precision-07.7z
Hier wird mir die Ausgabe-Form gar nicht angezeigt.


Merkwürdig - ich lade es noch mal hoch. Ich hatte abs() auch entfernt, es ergab aber keinen Unterschied. Im Moment habe ich kein Lazarus unter Windows bereit.

Mein System ist

Bildschirmfoto vom 2024-07-05 17-12-04.png
Bildschirmfoto vom 2024-07-05 17-12-04.png (57.2 KiB) 1086 mal betrachtet

Ausgabe ist :

Bildschirmfoto vom 2024-07-05 17-08-16.png
Bildschirmfoto vom 2024-07-05 17-08-16.png (72.86 KiB) 1086 mal betrachtet

Precision-07.7z
(148.29 KiB) 38-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Joh
Lazarusforum e. V.
Beiträge: 280
Registriert: Sa 26. Mai 2012, 17:31
OS, Lazarus, FPC: Win 10 (L 2.2.6 x64 FPC 3.2.2)
CPU-Target: 64Bit

Re: Präzision mit Floats

Beitrag von Joh »

Ich habe das Fenster von Version 06 um den Zusatzcode von Version 07 ergänzt...
anders, aber auch mit NKs.

Unbenannt.PNG
Unbenannt.PNG (39.5 KiB) 1075 mal betrachtet

PS: In deiner Ausgabe zu delta_up steht delta_down; ich habs mal markiert
just my two Beer

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

Joh hat geschrieben: Fr 5. Jul 2024, 17:38 Ich habe das Fenster von Version 06 um den Zusatzcode von Version 07 ergänzt...
anders, aber auch mit NKs.

Moin, stimmt, da bae ich schlampig kopiert - die Berechnung war mit den richtigen Werten.

Ich werde mal Lazarus auf einen Windowsrechner bringen und schauen, was da rum kommt, sonst muss ich wohl doch noch die Sprache wechseln :mrgreen: ...


Bildschirmfoto vom 2024-07-06 07-05-48.png
Bildschirmfoto vom 2024-07-06 07-05-48.png (73.76 KiB) 1049 mal betrachtet


Precision-08.7z
(148.49 KiB) 38-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

So, nun das Ganze aus der Windows-Welt:

(Jetzt verstehe ich das mit dem Programmfenster - sorry,
war mir nicht bewusst, dass das Fenster aus den sichtbaren
Bereich rutschen kann wenn ich zwei Monitore benutze. Nun
hab ich es selbst erlebt ... :roll: )

Aber nun zum Kernproblem zurück:

Unter Windows wird in diesem Beispiel nur ein Wert mit Abweichung berechnet ... :shock:

Weiß jemand, ob die auftretende Ungenauigkeit am Pascal Compiler liegt?




2024-07-06 05_53_28-Form1.png
2024-07-06 05_53_28-Form1.png (27.54 KiB) 1042 mal betrachtet


Precision-08win.7z
(216.11 KiB) 40-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6764
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von af0815 »

Hast du dir bei deinem Problem eigentlich schon überlegt wieweit die Nachkommastellen von Relevanz sind ? Fliesskommawerte können nicht alle Zahlen über ihre Grenzen hinaus genau abblilden. Das sieht man auch an deinen Ausgaben. Nur welche Relevanz hat eine technisch gegeben Ungenauigkeit in der zB. 20zigsten Stelle.

Auch ein genauer Vergleich von solchen Zahlen ohne Berücksichtigung der Relevanz ist ganz einfach Problematisch. Ich glaube corpsmann und wp haben dazu hier im Forum einiges geschrieben.

Noch was, laut hier https://wiki.lazarus.freepascal.org/IEEE_754_formats ist extended 80 Bit, ABER NICHT auf allen Plattformen, weil 80 Bit auf etlichen Plattformen auf 64 Bit gemappt werden)
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

af0815 hat geschrieben: Sa 6. Jul 2024, 09:38 Hast du dir bei deinem Problem eigentlich schon überlegt wieweit die Nachkommastellen von Relevanz sind ? Fliesskommawerte können nicht alle Zahlen über ihre Grenzen hinaus genau abblilden. Das sieht man auch an deinen Ausgaben. Nur welche Relevanz hat eine technisch gegeben Ungenauigkeit in der zB. 20zigsten Stelle.

Auch ein genauer Vergleich von solchen Zahlen ohne Berücksichtigung der Relevanz ist ganz einfach Problematisch. Ich glaube corpsmann und wp haben dazu hier im Forum einiges geschrieben.

Noch was, laut hier https://wiki.lazarus.freepascal.org/IEEE_754_formats ist extended 80 Bit, ABER NICHT auf allen Plattformen, weil 80 Bit auf etlichen Plattformen auf 64 Bit gemappt werden)
Ja, habe ich - im Prinzip reichen mir 3 bis max. 4 Nachkommastellen in dieser Anwendung aus. Das sind dann tausendstel bis zehntausendstel Millimeter. Drüber gestolpert bin ich, weil ich die Zahlenwerte vergleiche und falsche Ergebnisse bekam. (Zähnezahlen sollten nur geändert werden, wenn der eine Wert kleiner ist. Sie waren genau gleich, aber durch den Fehler wurde trotzdem gewechselt.)

Dazu kommt, dass es keine Rundungsfehler sind - die Ergebnisse sind ohne Rest. es wäre möglich, die Berechnung auch mit Integerwerten auszuführen, indem alles mit dem Faktor 1000 versehen wird. (Ist aber auch nur bei diesen speziellen Zähnezahlen so, Zähnezahlen werden vorzugsweise als Primzahlen ausgeführt, da geht so etwas nicht.)

Und dass die Berechnungen mal sauber ausgeführt werden und mal nicht - das macht mich nervös.

Da wüsste ich gern mehr drüber ...

Wichtig ist für mich auch, ab welcher Stelle das auftreten kann - Floats sind ja letztendlich im Rechner Zahlen mit einer bestimmten Stellenzahl - je größer die Zahl, desto weniger Nachkommastellen, wenn ich jetzt nicht ganz daneben liege. Mein Erwartung ist, dass eine Zahl, die mit 19 Digits dargestellt wird, dann korrekt ist.

Die Beiträge von Corpsmann und wp kenne ich, habe ich gelesen und stimme denen auch zu.

Aber dass auch die Art und Weise, wie ich die Gleichungen im Quelltext programmiere, das Ergebnis beeinflusst, da wurde noch nicht drüber berichtet.
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

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

Re: Präzision mit Floats

Beitrag von wp_xyz »

Da steht in den Screenshots der wert 3.14. Soll das die Zahl pi sein? Wenn ja, warum rechnest du nicht mit dem genauen Wert, der in der Math-Unit definiert ist? Mit 3.14 darfst du dich nicht über ungenaue Ergebnisse wundern.

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

wp_xyz hat geschrieben: Sa 6. Jul 2024, 10:16 Da steht in den Screenshots der wert 3.14. Soll das die Zahl pi sein? Wenn ja, warum rechnest du nicht mit dem genauen Wert, der in der Math-Unit definiert ist? Mit 3.14 darfst du dich nicht über ungenaue Ergebnisse wundern.
Nein, soll nicht pi sein. Die User geben eine Übersetzung sowie eine erlaubte Abweichung ein, die App sucht dazu einen Radsatz.
Zanräder haben immer ganze Zähnezahlen, zumindest am Anfang. Daher wird der verlangte Wert selten ganz genau getroffen. In diesem Fall werden zwei Radsätze mit 3,12 gefunden und verglichen. Der zuerst gefundene hat eine "bessere" Zähnezahl im Planetenrad, er soll nur ersetzt werden, wenn der nächste dichter an der geforderten Übersetzung ist. Er wurde aber ersetzt, obwohl rechnerisch beide eine Abweichung von exakt 0,02 haben ...
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

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

Re: Präzision mit Floats

Beitrag von wp_xyz »

Ich verstehe das Problem immer noch nicht. Wenn ich mir die Screenshots ansehe, zeigen sie für mich alle dasselbe an, von den Rundungsfehlern abgesehen. Und wenn du nur 3-4 Nachkommastellen brauchst, sind die lächerlich klein.

P.S. In der Erklärungsspalte deines Memo-Output für delta_up steht i_ZsDown, was ja wohl nicht so sein sollte (sondern i_ZsUp), oder?

P.P.S. Falls es um die Rundungsfehler-Nachkommastellen geht: Führe einen Datentyp "float" (= extended, double, oder sogar single) ein, damit hast du mehr Flexibilität. Und lass dir mal die volle Auflösung anzeigen:

Code: Alles auswählen

type
  float = extended;  
  
var
  i_req, i_ZS, i_ZSup, i_ZSdown: float;
  delta, delta_up, delta_down: float;      
  
function FloatToStr(x: float): String;
begin
  str(x, Result);
end; 

Benutzeravatar
Niesi
Lazarusforum e. V.
Beiträge: 581
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 3.9 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Präzision mit Floats

Beitrag von Niesi »

wp_xyz hat geschrieben: Sa 6. Jul 2024, 12:02 Ich verstehe das Problem immer noch nicht. Wenn ich mir die Screenshots ansehe, zeigen sie für mich alle dasselbe an, von den Rundungsfehlern abgesehen. Und wenn du nur 3-4 Nachkommastellen brauchst, sind die lächerlich klein.

P.S. In der Erklärungsspalte deines Memo-Output für delta_up steht i_ZsDown, was ja wohl nicht so sein sollte (sondern i_ZsUp), oder?

P.P.S. Falls es um die Rundungsfehler-Nachkommastellen geht: Führe einen Datentyp "float" (= extended, double, oder sogar single) ein, damit hast du mehr Flexibilität. Und lass dir mal die volle Auflösung anzeigen:

Code: Alles auswählen

type
  float = extended;  
  
var
  i_req, i_ZS, i_ZSup, i_ZSdown: float;
  delta, delta_up, delta_down: float;      
  
function FloatToStr(x: float): String;
begin
  str(x, Result);
end; 
Stimmt, indie Textausgabe hatte ich die falsche Berechnungszeile kopiert und dann nicht komplett korrigiert. :oops:
Sorry dafür.

Der Quelltext für die Berechnung war stets korrekt.

Noch einmal zu meinem Problem: Ich vergleiche zwei delta (delta und delta_up), welche mathematisch ganz genau beide eine Abweichung von 0,02 darstellen. In dem Fall sollen keine Änderungen vorgenommen werden.

Da aber delta = 0.0200000000000001 und delta_up = 0.0199999999999999

als Ergebnis geliefert werden, ist beim Vergleich delta_up kleiner als delta.
Das führt dazu, dass Zähnezahlen geändert werden.
Und das ist dann Mist.

Mit meinem kleinen Beispiel wollte ich nur demonstrieren, dass es diese Abweichungen gibt und dass durch verändern des Berechnungsweges der Fehler manchmal verschwindet.

Es ist auch irgendwie kein Rundungsfehler, 3.12 und 3.14 sind beide glatt teilbar.

Ich kann mir schon mit RoundTo helfen. Getriebe sind meist nicht mit so großen Zahlen behaftet - aber was ist mit Apps für die Astronomie? Schwanken dann die Entfernungen um einige Lichtjahre, je nachdem, wie die Berechnung programmiert wird?

Ganz konkret:

Mit dem folgenden Code werden alle drei delta falsch.

Code: Alles auswählen

begin
  i_req := 3.14;
  z_H := -54;
  z_Z := 25;
  i_ZS := 1 - z_H / z_Z;
  i_ZSup := 1 - (z_H + 1) / z_Z;
  i_ZSdown := 1 - (z_H - 1) / z_Z;
  delta := abs(i_req - i_ZS);
  delta_up := abs(i_req - i_ZSup);
  delta_down := abs(i_req - i_ZSdown);
  with MyMemo.Lines do
  begin
    add('  - - - - - - - - - - - - - - - - - - - - - - - - -');
    add('  z_Z, z_H und i_req als input:');
    add('                                Eingabewert:   z_Z = ' + IntToStr(z_Z));
    add('                                Eingabewert:   z_H = ' + IntToStr(z_H));
    add('                                Eingabewert: i_req = ' + FloatToStr(i_req));
    add(' ');
    add(' i_ZS := 1 - z_H / z_Z;               =       i_ZS = ' + FloatToStr(i_ZS));
    add(' i_ZSup := 1 - (z_H + 1) / z_Z;       =     i_ZSup = ' + FloatToStr(i_ZSup));
    add(' i_ZSdown := 1 - (z_H - 1) / z_Z;     =   i_ZSdown = ' + FloatToStr(i_ZSdown));
    add(' delta := abs(i_req - i_ZS);          =      delta = ' + FloatToStr(delta));
    add(' delta_up := abs(i_req - i_ZSup);     =   delta_up = ' + FloatToStr(delta_up));
    add(' delta_down := abs(i_req - i_ZSdown); = delta_down = ' + FloatToStr(delta_down));
    add('  ');
  end; 
Mit diesem Code werden zwei der delta richtig ermittelt.

Code: Alles auswählen

i_reqBuff := 314;
  i_req := i_reqBuff / 100;
  i_ZS := 1 - z_H / z_Z;
  i_ZSup := 1 - (z_H + 1) / z_Z;
  i_ZSdown := 1 - (z_H - 1) / z_Z;
  delta := abs(i_req - i_ZS);
  delta_up := abs(i_req - i_ZSup);
  delta_down := abs(i_req - i_ZSdown);
  with MyMemo.Lines do
  begin
    add('  - - - - - - - - - - - - - - - - - - - - - - - - -');
    add('  z_Z, z_H als input; i_req berechnet:');
    add('                                Eingabewert:   z_Z = ' + IntToStr(z_Z));
    add('                                Eingabewert:   z_H = ' + IntToStr(z_H));
    add(' ');
    add('                        i_req := 314 / 100 = i_req = ' + FloatToStr(i_req));
    add(' ');
    add(' i_ZS := 1 - z_H / z_Z;               =       i_ZS = ' + FloatToStr(i_ZS));
    add(' i_ZSup := 1 - (z_H + 1) / z_Z;       =     i_ZSup = ' + FloatToStr(i_ZSup));
    add(' i_ZSdown := 1 - (z_H - 1) / z_Z;     =   i_ZSdown = ' + FloatToStr(i_ZSdown));
    add(' delta := abs(i_req - i_ZS);          =      delta = ' + FloatToStr(delta));
    add(' delta_up := abs(i_req - i_ZSup);     =   delta_up = ' + FloatToStr(delta_up));
    add(' delta_down := abs(i_req - i_ZSdown); = delta_down = ' + FloatToStr(delta_down));
    add('  ');
  end; 
Im ersten Fall wird i_req mit 3.14 hart in den Code geschrieben.
Im zweiten Fall berechne ich i_req mit 314 / 100.

Warum sind die Ergebnisse unterschiedlich?


Bildschirmfoto vom 2024-07-06 16-31-49.png
Bildschirmfoto vom 2024-07-06 16-31-49.png (61.4 KiB) 973 mal betrachtet

Precision-09.7z
(148.13 KiB) 40-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Antworten