Genauigkeit beim Rechnen

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6857
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: Genauigkeit beim Rechnen

Beitrag von af0815 »

Das ist ein Thema, seit ich TurboPascal auf DOS kenne und das sind doch ein paar Tage.
Ein alter Hut, So wie schon beschrieben und das nicht zum ersten mal hier im Forum, auch mit Kommentaren von PascalDragon, alles was float ist, kann nicht alle Zahlen exakt abbilden. Und wenn man, bewusst oder unbewusst, die verschiedenen Typen untereinander konvertiert, wird der Fehler nicht besser. Etwas Geschichte dazu.
u.a. viewtopic.php?t=13105

Genauso ist es schon diskutiert worden warum float Zahlen nicht mit dem "=" Operator direkt vergleichen sollte, eben wegen dieser Ungenauigkeiten bei den Abbildung.
u.a. https://docwiki.embarcadero.com/RADStud ... ommawerten

Nicht nur Lazarus/FPC haben das wie man sieht
u.a. https://mycsharp.de/forum/threads/98035 ... as-theorie
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: 612
Registriert: So 26. Jun 2016, 19:44
OS, Lazarus, FPC: Linux Mint Cinnamon, Laz 4.1 Fpc 3.2.3 und allerlei mit FpcUpDeLuxe
Kontaktdaten:

Re: Genauigkeit beim Rechnen

Beitrag von Niesi »

Ich bin mal Deinen Links gefolgt und habe mir das angeschaut.

Da stehen aber auch Sachen, die so nicht stimmen. Z. B., dass extended auf double gemappt wird - und dass es aus gewissen Gründen float gibt.

Habe mal mein Beispiel mit float und double durchgespielt. Ist interessant.

Aber wie geschrieben, es gibt hier einige nicht ganz richtige Behauptungen im Forum.

Extended ist 10 byte oder 80 bit groß, wenn der Rechner das hergibt. So steht es auch im Free-Pascal Wiki. Wird also mitnichten auf double gemappt.

Aber das war auch nicht der Punkt für mich: Dass ich im Quelltext besser nicht direkt mit Zahlen arbeite,
sondern diese erst der entsprechenden Type zuweise, das ist für mich die nicht ganz unwichtige Erkenntnis ...
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

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

Re: Genauigkeit beim Rechnen

Beitrag von Niesi »

Ich habe die Erkenntnisse aus diesem Thread in mein Projekt eingearbeitet - Danke an alle, die geantwortet haben.

Auch habe ich noch eine Variante entdeckt:

Wird eine Zahl in den Quelltext geschrieben, entstehen Ungenauigkeiten nur dann, wenn die Zahl direkt hinter dem Zuweisungsoperator eingegeben wird.

Steht aber an erster Stelle z. B. "pi", dann wird das Ergebnis mit der maximal möglichen Genauigkeit verarbeitet.

Jetzt würde ich gern herausfinden, ob das so sein soll oder ob es sich zufällig so ergeben hat.

Und sehr wichtig ist mir: Bleibt das so?


Auswahl_003.png
Auswahl_003.png (64.95 KiB) 525 mal betrachtet

ExtendedTest~02.7z
(161.83 KiB) 112-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
Zvoni
Beiträge: 408
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Genauigkeit beim Rechnen

Beitrag von Zvoni »

https://www.freepascal.org/docs-html/rtl/system/pi.html
Return the value of PI.
Declaration
Source position: mathh.inc line 105
function Pi: ValReal;
https://www.freepascal.org/docs-html/rt ... lreal.html
Largest available floating point type
Declaration
Source position: systemh.inc line 189
type ValReal = Extended;
1) und 2)
1) "single" geteilt durch "Integer", ergibt "single", dann multipliziert mit "Extended", ergibt "extended"
2) "Extended" multipliziert mit "single", ergibt "extended", dann geteilt durch "Integer", ergibt "extended"

3) und 4)
3) "Integer" geteilt durch "Integer", ergibt "single", multipliziert mit "extended", ergibt "extended" (Siehe auch "1" oben drüber)
4) "Extended" multipliziert mit "Integer", ergibt "extended", dann geteilt durch "Integer", ergibt "extended" (Siehe auch "2" oben drüber)
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

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

Re: Genauigkeit beim Rechnen

Beitrag von Niesi »

Zvoni hat geschrieben: Di 24. Jun 2025, 10:48
...

1) und 2)
1) "single" geteilt durch "Integer", ergibt "single", dann multipliziert mit "Extended", ergibt "extended"
2) "Extended" multipliziert mit "single", ergibt "extended", dann geteilt durch "Integer", ergibt "extended"

3) und 4)
3) "Integer" geteilt durch "Integer", ergibt "single", multipliziert mit "extended", ergibt "extended" (Siehe auch "1" oben drüber)
4) "Extended" multipliziert mit "Integer", ergibt "extended", dann geteilt durch "Integer", ergibt "extended" (Siehe auch "2" oben drüber)

Sieht ganz witzig aus, was Du da aufgestellt hast - ist aber nicht der Kern der Sache. Wenn ich eine Zeile

Code: Alles auswählen

a_rad := 15.0 / 180 * pi; 
eingebe, dann wird mit 0.2617993956013791926310 weiter gearbeitet. ( = 15.000000447034835815400000° )

Wenn ich die Zeile umstelle, auf

Code: Alles auswählen

a_rad := pi * 15.0 / 180;
dann wird mit 0.261799387799149436561 gearbeitet. ( = 15.000000000000000001700000° )

Ab der 8. Nachkommastelle sind die Ergebnisse als rad-Werte unterschiedlich, in Winkelgrad ab der 7. Nachkommastelle ...

Das ist für mich nicht nur wichtig, sondern auch schwer verständlich.
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
Zvoni
Beiträge: 408
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Genauigkeit beim Rechnen

Beitrag von Zvoni »

Niesi hat geschrieben: Di 24. Jun 2025, 12:47
Zvoni hat geschrieben: Di 24. Jun 2025, 10:48
...

1) und 2)
1) "single" geteilt durch "Integer", ergibt "single", dann multipliziert mit "Extended", ergibt "extended"
2) "Extended" multipliziert mit "single", ergibt "extended", dann geteilt durch "Integer", ergibt "extended"

3) und 4)
3) "Integer" geteilt durch "Integer", ergibt "single", multipliziert mit "extended", ergibt "extended" (Siehe auch "1" oben drüber)
4) "Extended" multipliziert mit "Integer", ergibt "extended", dann geteilt durch "Integer", ergibt "extended" (Siehe auch "2" oben drüber)

Sieht ganz witzig aus, was Du da aufgestellt hast - ist aber nicht der Kern der Sache. Wenn ich eine Zeile
Doch, ist es, weil nur bei 2 und 4 erhälst du bereits bei der ERSTEN Rechenoperation die höchstmögliche "Auflösung"/Genauigkeit --> 80 Bit (Sofern Target 64-Bit ist).
Die zweite Rechenoperation erhält dann nämlich als ersten Operanden bereits einen Extended

Bei 1 und 3 ergibt die ERSTE Rechenoperation einen "Single" (32-Bit Genauigkeit).
Als Analogie ist das, wie wenn du ein Foto in geringer Auflösung schiesst, und es dann vergrösserst: Es wird "unscharf"

Du hast 2 Rechenoperationen: Multiplikation und Division.
Von der Präferenz sind beide gleichwertig, also wird von links nach rechts gerechnet, so wie die Operanden dem Code vor die Füsse fallen.

Wenn du es nicht glaubst mach mal folgendes:

Code: Alles auswählen

a_rad := pi * (15.0 / 180);  //KLAMMERN!!
Was kommt dabei raus (Ich hab nur 32-Bit-Lazarus/FPC zur Verfügung)?
Zuletzt geändert von Zvoni am Di 24. Jun 2025, 13:34, insgesamt 3-mal geändert.
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Mathias
Beiträge: 6967
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Genauigkeit beim Rechnen

Beitrag von Mathias »

Wem das alles zu ungenau ist, der könnte mal die s hier anschauen: https://gmplib.org/
Damit kann man bis fast unendlich viele Stellen rechnen. Das einzige Limit ist die Kapazität des PCs.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Genauigkeit beim Rechnen

Beitrag von Niesi »

Mathias hat geschrieben: Di 24. Jun 2025, 13:04 Wem das alles zu ungenau ist, der könnte mal die s hier anschauen: https://gmplib.org/
Damit kann man bis fast unendlich viele Stellen rechnen. Das einzige Limit ist die Kapazität des PCs.
Danke. Hab ich mir angeschaut - das bringt mich in meinem Pascal-Programm nicht weiter, oder?

Davon mal abgesehen: Ich brauche die "normale" Genauigkeit von Pascal, die immer besser war und ist, als Calc (oder auch Windoofs Excel). Für mich sollten die ersten zehn Nachkommastellen reichen, dann komme ich klar.
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

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

Re: Genauigkeit beim Rechnen

Beitrag von Niesi »

Zvoni hat geschrieben: Di 24. Jun 2025, 13:00
...

Wenn du es nicht glaubst mach mal folgendes:

Code: Alles auswählen

a_rad := pi * (15.0 / 180);  //KLAMMERN!!
Was kommt dabei raus (Ich hab nur 32-Bit-Lazarus/FPC zur Verfügung)?
Probier ich später mal aus, da muss ich mich reindenken.

Davon mal ab: Es wäre ein Bug, wenn ohne Klammern was anderes rauskommt als mit Klammern - wir hantieren hier mit Mathematik. Da ist das exakt definiert. Und da steht auch Pascal nicht drüber.

Zusätzlich habe ich noch mal die Compilerdirektive {$MINFPCONSTPREC 64} ausprobiert. Ok, da wird im Wiki schon klar gesagt, dass 80-bit nicht unterstützt wird. Ist trotzdem interessant

Tables.png
Tables.png (85.67 KiB) 442 mal betrachtet

Für mich ist wichtig: Kann es sein, dass sich am derzeitigen Stand etwas ändert?

Denn ich bin voll und ganz zufrieden mit der Variante, dass Zahlen im Quelltext nicht direkt an erster Stelle stehen dürfen oder über eine extended-Variable eingebunden werden. Das ist voll und ganz genau genug ...
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Benutzeravatar
photor
Beiträge: 525
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 3.2 (Gtk2) FPC 3.2.2
CPU-Target: 64Bit

Re: Genauigkeit beim Rechnen

Beitrag von photor »

Hallo Niesi,
Niesi hat geschrieben: Di 24. Jun 2025, 18:10
Davon mal ab: Es wäre ein Bug, wenn ohne Klammern was anderes rauskommt als mit Klammern - wir hantieren hier mit Mathematik. Da ist das exakt definiert. Und da steht auch Pascal nicht drüber.
Naja. Das stimmt nicht ganz. Es geht hier um diskrete Berechnungen, die jeweils selbst Fehler-behaftet sind. Und die Größe des Fehlers hängt auch noch vom Bereich ab, in dem man rechnet (und wenn ich mich nicht irre, ist der am geringsten, wenn man die Werte/Ergebnisse im Bereich von 1 hält).

Wenn man also mehrere Rechnungen hintereinander ausführt, kann das Ergebnis durchaus davon abhängen, in welcher Reihenfolge das geschieht. In der numerischen Mathematik kann es sogar sinnvoll sein, sich vorher getrennt um die 10-ner-Potenzen zu kümmern (also die Größenordnung vorher zu bestimmen) und nur noch um die Faktoren davor zu bestimmen - wenn es wirklich um die letzte Genauigkeit gehen soll.

Ciao,
Photor


PS: ich bin KEIN Mathematiker; daher nagelt mich bitte nicht auf irgendwelche Definitionen fest.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6857
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: Genauigkeit beim Rechnen

Beitrag von af0815 »

Niesi hat geschrieben: Di 24. Jun 2025, 18:10 Davon mal ab: Es wäre ein Bug, wenn ohne Klammern was anderes rauskommt als mit Klammern - wir hantieren hier mit Mathematik. Da ist das exakt definiert. Und da steht auch Pascal nicht drüber.
Es geht hier nicht unbedingt um Mathematik, sondern um Signifikanz von Stellen und wieviele Stellen bei einem Datentyp verwendet werden und somit auch der Fehler bei der Darstellung von floatzahlen sich ändert.

Ich gebe dir recht, wenn all Operanden von Haus aus die maximale Darstellung nutzen so muss es egal sein. Wird das aber nicht gemacht, so hat der beschränkte Darstellungsbereich einen Einfluß. Und zwar weil ein Floatfehler da ist, zB. bei Single, der bei der späteren Erweiterung auf Double oder Extended sehr wohl in den hinteren Kommastellen einen Einfluss hat.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Joh
Lazarusforum e. V.
Beiträge: 297
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: Genauigkeit beim Rechnen

Beitrag von Joh »

eine ähnliche Problematik hatte ich damals unter Foxpro.
Dort habe ich mich häufig mit Konstrukten wie

Code: Alles auswählen

x = 0.00 + y + z...
beholfen.

hierzuSprache würde also ein

Code: Alles auswählen

var x: extended;
x := 1.0;  // wahrscheinlich keine Nachkommastelle nötig
y := x * (Kladeradatsch)
jegliche Zwischenergebnisse in den Extended-Bereich setzen.
just my two Beer

Benutzeravatar
Zvoni
Beiträge: 408
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Genauigkeit beim Rechnen

Beitrag von Zvoni »

Joh hat geschrieben: Mi 25. Jun 2025, 08:11 eine ähnliche Problematik hatte ich damals unter Foxpro.
Dort habe ich mich häufig mit Konstrukten wie

Code: Alles auswählen

x = 0.00 + y + z...
beholfen.

hierzuSprache würde also ein

Code: Alles auswählen

var x: extended;
x := 1.0;  // wahrscheinlich keine Nachkommastelle nötig
y := x * (Kladeradatsch)
jegliche Zwischenergebnisse in den Extended-Bereich setzen.
Korrekt.

Was niesi als "Zahlen im Quellcode" nennt, sind ja literale (bzw. vergleichbar mit untypisierten Konstanten), und da wäre mir kein Compiler bekannt, welcher auf die höchst-mögliche "Auflösung" geht, sondern genau das Gegenteil: Der Compiler geht auf die kleinst-mögliche Auflösung.
Das hat dann nur bedingt mit "Mathematik" zu tun (obwohl ich niesi zustimme: Man sollte erwarten können, dass dasselbe herauskommt).
Der Compiler versucht halt, den bestmöglich effizientesten Maschinencode zu erstellen, was er ja auch macht, SOFERN man ihm nicht "abweichende" Spielregeln mitgibt (Klammern, expliziter Typ usw.)

Mal schauen, vielleicht schaut PascalDragon hier vorbei, und kann uns genaueres dazu sagen
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Warf
Beiträge: 2148
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Genauigkeit beim Rechnen

Beitrag von Warf »

Das Problem ist ganz Fundamental das in den meisten Anwendungen Floats einfach keinen Sinn machen. Floats können sowohl mit sehr großen als auch mit sehr kleinen Werten arbeiten, mit einem Datentypen und Hardwareseitig einem Instruktionsset.
Der Gegenzug dafür ist ungenauigkeit die vor allem an vielen Stellen schwer abschätzbar ist.
Das ist toll für manche sachen wie Physik simulationen wo Rundungen nicht stören und wo man je nach Situation mit sehr großen oder sehr kleinen werten Arbeiten kann. Andere sachen wo das auch "gut genug" ist sind spiele, Grafikanwendungen oder Signalverarbeitung.
Alles wo man eben keine exakten berechnungen braucht solang größenordnung stimmt und Wert ungefähr.

Das Gegenstück zu Floats ist Fixpunkt Arithmetik. Hierbei wählt man sich einen festen Wertebereich inklusive Rundungsverhalten zur Compilezeit aus. Damit hat man exakte berechnungen und erwartbare Rundungsfehler, aber dafür muss die Größenordnung und Wertebereich bereits zur Compilezeit feststehen.
Beispiel hierfür ist alles mit finanzen, du wirst niemals mit Geldbeträgen im bereich 10^-9 oder 10^20 arbeiten, sondern nur so bis zu 4 Nachkommastellen, dafür soll die berechnung ganz genau arbeiten, bzw. der Rundungsfehler erwartbar sein.

So ganz Zeitgemäß ist das allerdings nicht mehr. Mit Generics oder Templates kann man typagnostisch programmieren, Haskells generische Typvariablen oder C++ template system sind hierfür schöne Beispiele, und modernen Techniken der Kontroll und Datenflussanalyse kann man die Datentypen inferrieren und wertebereiche sogar inferieren (moderne C++ Kompiler haben z.B. SMT solver mittlerweile eingebaut um Wertebereiche im Datenfluss abzuschätzen).
D.h. Theoretisch könnte man fast alles was man heute mit Floats macht auch transparent mit Fixpunktarithmetik lösen, wobei der Compiler automatisch die notwendigen Wertebereiche variablen und konstanten zuweise könnte.

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

Re: Genauigkeit beim Rechnen

Beitrag von Niesi »

Das mit den Klammern habe ich probiert - es gibt einen Einfluss, wenn zu den Zahlen (= untypisierten Konstanten) im Code noch andere "Sachen" dazukommen. Das ist ein wenig merkwürdig, finde ich, ich erkenne da keine Struktur.

Insgesamt ist alles recht genau. Sofern keine Zahl als untypisierte Konstante am Anfang der Berechnung steht, wird es sehr genau. Besser als in Calc oder Excel.

Ungenau wird es unter Umständen wieder, wenn untypisierte Konstanten im Code mit Klammern verwendet werden - da wäre ich nun nicht drauf gekommen. Ist das nun ein Bug? Ich denke: ja.

Meine Meinung ist, dass für FreePascal ein Type als Standard entwickelt werden sollte, der plattformübergreifend Berechnungen mit beliebig vielen Nachpunktstellen zulässt. Das wäre mal wieder ein großes Argument für die Nutzung von FreePascal und Lazarus, denke ich ...

Bleibt für mich die Frage: Wird das so bleiben, dass ich mit

Code: Alles auswählen

a_rad := pi * 15 / 180;       |  a_rad =  0.261799387799149436561 in degree: a_rad * 180 / pi = 15.000000000000000001700
ein gutes Ergebnis habe und dies da

Code: Alles auswählen

a_rad := 15.0 / 180 * pi;     |  a_rad =  0.261799395601379192631 in degree: a_rad * 180 / pi = 15.000000447034835815400
einfach lassen muss?

Auswahl_018.png
Auswahl_018.png (67.03 KiB) 224 mal betrachtet
Auswahl_019.png
Auswahl_019.png (107.99 KiB) 224 mal betrachtet
ExtendedTest~03.7z
(173.81 KiB) 213-mal heruntergeladen
Wissen ist das einzige Gut, das sich vermehrt, wenn es geteilt wird ...

Antworten