Rundungsfehler ?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Mathias
Beiträge: 6162
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Rundungsfehler ?

Beitrag von Mathias »

Wenn ich ein Zeichenprogramm habe und mal nach oben und mal nach unten runde, wird es unweigerlich Pixelabweichungen geben,

Genau dort habe ich es gemerkt, ich wollte ein gefülltes Dreieck zeichnen.
Da habe ich das Programm abgespeckt, bis ich das mit den 0.x entdeckte.

"Somit hat dieses Bank-Runden durchaus seine Richtigkeit/Sinn. Es ist um einiges gerechter."
Anscheinend ist die Kohle wieder mal wichtiger als die mathematische Genauigkeit. :evil:
In der Schule hatten wir mal, alles was grösser als x.5 ist, wird aufgerundet.

Ich habe das Problem mal umgangen, in dem ich Trunc(), anstelle von Round() verwende, da wird alles abgeschnitten, was nach dem Komma kommt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

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

Re: Rundungsfehler ?

Beitrag von Mathias »

theo hat geschrieben:https://www.freepascal.org/docs-html/rtl/math/setroundmode.html


Ich habe mir SetRoundMode angeguckt, da wird direkt ein FPU-Register umgestellt.

Code: Alles auswählen

begin
  SetRoundMode(rmUp);
  x := 0.39999;
 
  for i := 0 to 10 do begin
    DebugLn('Input:', x.ToString(), ' round: ', Round(x).ToString);
    x := x + 1.0;
  end;
  WriteLn();
end
Da wird es leider noch falscher gerundet.

Code: Alles auswählen

Input:0.3999899924 round: 1
Input:1.399990082 round: 2
Input:2.399990082 round: 3
Input:3.399990082 round: 4
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

indianer-frank
Beiträge: 134
Registriert: So 30. Nov 2008, 21:53

Re: Rundungsfehler ?

Beitrag von indianer-frank »

Das hat doch nichts mit Gerechtigkeit zu tun. Sie Dir noch mal die Grafik in https://stackoverflow.com/questions/452 ... table?rq=1 und Du siehst, daß bei Round-To-Nearest-Even der statistische Fehler um 0 verteilt ist, und bei Round-Up bei 10 Einheiten in der letzen Stelle. Ich vermute sehr stark, daß wenn Du trunc bzw. Round-Down verwendest, der Fehler ca 10 Einheiten in die andere Richtung geht.

Erwin
Beiträge: 286
Registriert: Mi 16. Sep 2009, 14:15
OS, Lazarus, FPC: Xubuntu 22.04 / x86_64_linux-gtk 2 / L 2.2.0 / FPC 3.2.2

Re: Rundungsfehler ?

Beitrag von Erwin »

Bei dem round geht es um das runden der Banken. Und darauf bezog sich auch meine Antwort mit dem Gerechter (eben aus der Sicht der Banken). Theoretisch ist es sogar gerecht. Aber trotz dieser mal auf und ab runden wird es dennoch immer wieder eine Seite paar Cent mehr haben. Deshalb gerechter, weil es in der Praxis selten insgesamt (bei mehren Transaktionen oder was auch immer) am ende der Ganzen Rundung, es gleich verteilt ist. Das wäre eher Zufall.

Was dem round selber betrifft: Das ist meiner Meinung nach totaler Quatsch, es sei denn man schreibt nur Finanzprogramme (so wie es die Banker und FPC und Pascal (Delphi) es gerne hätten (?)). Selbst bei einem Wirtschaftsspiel müsste das nicht mal zwingend sein, da es dann ja nur ein Spiel ist. Weil es sich um runden der Banker handelt, erklär es nur ('nur') wieso es abwechselnd auf und ab gerundet wird. Aber es erklärt nicht mal, wieso es round heißt? bankround order roundbank würde da besser passen, finde ich. Und es erklärt auch nicht, wieso es scheinbar keinen direkten Befehl für das in der Schule gelernte und verlässliche Runden gibt. Also ich zieh es auch lieber vor, dass ab 0,5 jedes mal aufgerundet wird. Das sich darauf verlassen können ist mir wichtiger, als dass beim Schreiben (nicht Finanzieller Programme bzw. Codeabschnitten) bzw. dessen Ausführung ... äh, ja was? Das der Programm mal bei 0,5 einen Ganze Zahl bekommt, und das andere mal der Anwender, und das Ganze dann gerecht verteilt wird, oder was? [rionie: Sehr wichtig!] Also damit habe ich allein schon deswegen eher Probleme, weil man dann jedes mal, wenn ein Ergebnis nicht wie erwartet exakt stimmt, auch noch überlegen muss, ob es diesmal auf oder abgerundet werden hätte sollen, um feststellen zu können, ob da wirklich ein Fehler vorliegt, wenn es nur um 1 Ziffer geht.

Es gibt zwar bei der uses Math den Befehl SetRoundMode. Aber habe keinen blassen Schimmer, was der kann, geschweige denn, was für Befehle man da verwenden muss/kann?

Die beste Alternative/Hilfe die mir dazu eingefallen ist, wäre dies:

Code: Alles auswählen

 
function FNormaleRundung(NormaleRundung: Real): Integer;
begin
  result:=trunc(NormaleRundung);
  if Frac(NormaleRundung)>= 0.5 then Result:=Result+1;
  if Frac(NormaleRundung)<= -0.5 then Result:=Result-1;
end;
 

Also bei einfachen Test hat es bei mir geklappt.

Edit: Jetzt erst ist mir aufgefallen, dass ja etwas weiter Oben ja ein Beispiel zu diesem Roundmode steht, bzw. mehre. Aber das scheint mir recht umständlich zu sein.
Lazarus 2.2.0 / FP 3.2.4

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

Re: Rundungsfehler ?

Beitrag von Mathias »

Es ist schon krass, wie alles für das Büro angepasst wird. Es fängt mit dem Dezimaltrenner an, geht über UTFxx, und jetzt Round auch noch.
Kunststück, wird die Software immer lahmer und fehleranfälliger wird. :roll:

PS: Habe das Runden gerade mit OpenOffice probiert. Genau der gleiche Mist. :roll:
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Rundungsfehler ?

Beitrag von Socke »

Habt ihr den englischsprachigen Wikipedia-Artikel zumindest mal angesehen?! Spätestens nach Lesen des Inhaltsverzeichnisses sollte unmissverständlich klar sein, dass der Begriff "Runden" einer weitergehenden Definition bedarf. Und wie es so im Leben ist, leben verschiedene Menschen verschiedene Leben und durchleben daher unterschiedliche Bedürfnisse beim Runden. Daraus entwickelten Sie unterschiedliche Definition für das "Runden".

Erwin hat geschrieben:Was dem round selber betrifft: Das ist meiner Meinung nach totaler Quatsch, es sei denn man schreibt nur Finanzprogramme (so wie es die Banker und FPC und Pascal (Delphi) es gerne hätten (?)). Selbst bei einem Wirtschaftsspiel müsste das nicht mal zwingend sein, da es dann ja nur ein Spiel ist. Weil es sich um runden der Banker handelt, erklär es nur ('nur') wieso es abwechselnd auf und ab gerundet wird.

Diese Wortklauberei möchte ich gerne mit deinem Wort "Quatsch" beschreiben. Beim Vergleich des englischen und des deutschen Wikipedia-Artikels fällt auf: Die Rundung zum nächsten geraden Wert hin heißt im englischen "bankers' rounding", über das du dich hier auslässt. Im Deutschen nennt man diese Art der Rundung "unverzerrte Rundung". Hier spricht man von einem "Kaufmännische Runden", wenn man alles >= 0,5 aufrundet.


Mathias hat geschrieben:
"Somit hat dieses Bank-Runden durchaus seine Richtigkeit/Sinn. Es ist um einiges gerechter."
Anscheinend ist die Kohle wieder mal wichtiger als die mathematische Genauigkeit. :evil:
In der Schule hatten wir mal, alles was grösser als x.5 ist, wird aufgerundet.

Dann tut es mir Leid um deine Lehrer; diese hätten später beibringen sollen, dass man auch anders runden kann.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

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

Re: Rundungsfehler ?

Beitrag von Warf »

indianer-frank hat geschrieben:Zwei Bemerkungen. Erstens hat das Null mit exakter Darstellung zu tun

Dann so ne ganz dumme frage, warum funktioniert das nur bei double, aber sobald ich den typen auf extended ändere kommt das raus:

Code: Alles auswählen

Round to Nearest Even
           0             1.000000000000000
     1000000             1.000000000000000
     2000000             1.000000000000000
     3000000             1.000000000000000
     4000000             1.000000000000000
     5000000             1.000000000000000
     6000000             1.000000000000000
     7000000             1.000000000000000
     8000000             1.000000000000000
     9000000             1.000000000000000
    10000000             1.000000000000000
Round up
           0             1.000000000000000
     1000000             1.000000000000000
     2000000             1.000000000000000
     3000000             1.000000000000000
     4000000             1.000000000000000
     5000000             1.000000000000000
     6000000             1.000000000000000
     7000000             1.000000000000000
     8000000             1.000000000000000
     9000000             1.000000000000000
    10000000             1.000000000000000


Funktioniert Rounding auf Extended anders als auf double, oder liegt es daran das dein d=2^(-54) wobei die Maschienengenauigkeit von Double durch eps =2^(-53) definiert ist, und damit ist dein d kleiner als der Rundungsfehler (wodurch wir wieder beim ursprungsproblem sind).

Zweitens: Das Problem ist grundsätzlicher Natur, da jede Summe, die nicht exakt darstellbar ist, noch oben gerundet wird. Wenn Du das nicht haben willst, bleibt nicht viel übrig: Hauptsächlich Integer-Addition und ein paar Additionen mit Zweier-Potenzen größer als 2^(-52).


Ja das habe ich selbst schon erwähnt das nennt sich fixpunktarithmethik. Und wird in allen Systemen angewendet die korrekt rechnen müssen. Und das ist nicht nur Addition sondern auch Integer Multiplikation und division kann verwendet werden für exakte fixpunktoperationen

indianer-frank
Beiträge: 134
Registriert: So 30. Nov 2008, 21:53

Re: Rundungsfehler ?

Beitrag von indianer-frank »

Warf hat geschrieben:Funktioniert Rounding auf Extended anders als auf double, oder liegt es daran das dein d=2^(-54) wobei die Maschienengenauigkeit von Double durch eps =2^(-53) definiert ist, und damit ist dein d kleiner als der Rundungsfehler (wodurch wir wieder beim ursprungsproblem sind).
Richtig, wenn Du d:=2^(-64) setzt (neben double -> extended) erhält man zB mit d := 4294967296.0; d := sqr(1/d);

Code: Alles auswählen

d intern:    0   0   0   0   0   0   0 128 191  63
Round to Nearest Even
           0             1.000000000000000
     1000000             1.000000000000000
     2000000             1.000000000000000
     3000000             1.000000000000000
     4000000             1.000000000000000
     5000000             1.000000000000000
     6000000             1.000000000000000
     7000000             1.000000000000000
     8000000             1.000000000000000
     9000000             1.000000000000000
    10000000             1.000000000000000
Round up
           0             1.000000000000000
     1000000             1.000000000000108
     2000000             1.000000000000217
     3000000             1.000000000000325
     4000000             1.000000000000434
     5000000             1.000000000000542
     6000000             1.000000000000651
     7000000             1.000000000000759
     8000000             1.000000000000867
     9000000             1.000000000000976
    10000000             1.000000000001084
 
Wie gesagt, das Problem liegt nicht an Exaktheit von d und nur bedingt an der Größe: Der Witz beim Roundup-Modus ist doch, dass jede Summe x+d mit d>0 mindestens auf die nächstgrößere FP-Zahl gerundet wird. Wenn d kleiner als Epsilon/2 ist, ist die nachfolgende Differenz (x+d)-d dann immer noch größer als x. In nächsten Schleifendurchlauf geht dann das Spiel erneut los.

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

Re: Rundungsfehler ?

Beitrag von Warf »

Achso, ich habe es am anfang nicht richtig verstanden.
Das ding ist, dein problem exsistiert nicht wirklich. Wenn du mit Zahlen hantierst sodass du unterschiede in der Fließkommaauflösung erkennen kannst (und wie in diesem beispiel abusen kannst), sind Fließkommazahlen einfach der falsche datentyp für dich.

Ich beschwere mich ja auch nicht das mein Auto nicht schwimmen kann, denn mein auto wurde nie fürs schwimmen gebaut. Genauso sind fließkommatypen nie dafür entwickelt worden präzise zu sein. Daher ist das zwar ein schönes theoretisches problem, aber praktisch nicht relevant.

indianer-frank
Beiträge: 134
Registriert: So 30. Nov 2008, 21:53

Re: Rundungsfehler ?

Beitrag von indianer-frank »

Warf hat geschrieben:Achso, ich habe es am anfang nicht richtig verstanden.
Das ding ist, dein problem exsistiert nicht wirklich. Wenn du mit Zahlen hantierst sodass du unterschiede in der Fließkommaauflösung erkennen kannst (und wie in diesem beispiel abusen kannst), sind Fließkommazahlen einfach der falsche datentyp für dich.

Ich beschwere mich ja auch nicht das mein Auto nicht schwimmen kann, denn mein auto wurde nie fürs schwimmen gebaut. Genauso sind fließkommatypen nie dafür entwickelt worden präzise zu sein. Daher ist das zwar ein schönes theoretisches problem, aber praktisch nicht relevant.
Das ist nicht mein Problem, ich habe nur ein Beispiel für Effekte mit Rundungs-Arten gegeben. Im übrigen sind Fließkommazahlen 100% exakt, auch die Standard-Operationen Addition, Subtraktion, etc sind korrekt gerundet. Also kein negativer Unterschied zu Integer (nur dass Integerdivision ja wohl offensichtlich nicht der normalen Division entspricht, 6 div 10 ist halt 0, und nicht 0.6 und noch nicht mal auf die nächste Integerzahl gerundet ist). Es gibt aber natürlich auch 'ungenaue' FP-Operationen, wie transzendente Funktionen (exp, ln, sin) und im gewissen besonders tragisch die Umwandlung von Dezimal nach Binär (wie gesagt, die Operation ist eindeutig definiert, aber nicht jede reelle oder rationale Zahl ist exakt darstellbar).

Im Übrigen weiß ich, wie ich mit diesen Umständen umgehen muss, ohne Gerechtigkeit und Quatsch zu bemühen. Ich sehe die Diskussion hier als erledigt an.

Gute Nacht.
Zuletzt geändert von indianer-frank am Mo 28. Mai 2018, 22:31, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Rundungsfehler ?

Beitrag von m.fuchs »

indianer-frank hat geschrieben:Im übrigen sind Fließkommazahlen 100% exakt,

Nein, schon laut Definition sind es immer nur Annäherungen. Fließkommazahlen sind *nicht* exakt.

indianer-frank hat geschrieben:nur dass Integerdivision ja wohl offensichtlich nicht der normalen Division entspricht, 6 div 10 ist halt 0, und nicht 0.6

Was ist denn eine "normale" Division? Es gibt halt verschiedene Arten. Und natürlich ist auch in Freepascal Integer-Division von 6 durch 10 nicht 0 sondern 0, Rest 6.
Wenn dann muss man sie schon korrekt durchführen und zum div noch ein mod machen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

indianer-frank
Beiträge: 134
Registriert: So 30. Nov 2008, 21:53

Re: Rundungsfehler ?

Beitrag von indianer-frank »

Kannst Du mir eine nicht-exakte IEEE-Fließkomma-Zahl nennen?

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Rundungsfehler ?

Beitrag von m.fuchs »

Ich glaube du hast das Prinzip hinter den Gleitkommazahlen nicht verstanden, wenn du diese Frage stellst.

Lies doch einmal hier nach: https://de.wikipedia.org/wiki/Gleitkommazahl
Ist für den Einstieg eigentlich ganz gut.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

indianer-frank
Beiträge: 134
Registriert: So 30. Nov 2008, 21:53

Re: Rundungsfehler ?

Beitrag von indianer-frank »

Ich stelle fest, Du kannst offensichtlich keine inexakte-FP-Zahl nennen.

Wie könntest Du auch, es da es ja keine gibt, siehe zB https://en.wikipedia.org/wiki/IEEE_754, wo die verschiedenen Formate beschrieben sind: kein Raum für Inexaktheit. Und der IEEE-Standard schreibt vor, dass die Standard-Operationen korrekt gerundet sind. Und Dein Wiki-Link sagt ja auch nur `Eine Gleitkommazahl ... ist eine approximative Darstellung einer reellen Zahl`. Kein Wort von Ungenauigkeit der Gleitkommazahl.

Du verwechselst 'Darstellung einer reellen Zahl' mit reeller Zahl. Die FP ist exakt, eine relle Zahl ist exakt, 1/10 ist keine (binäre, endliche) Fließkommazahl. Das heißt aber nicht, dass die nächsten FP bei 1/10 nicht exakt ist (für double ist das 0.1000000000000000055511151231257827021181583404541015625 = 3602879701896397 / 2^55 und das ist 100% exakt, single 0.100000001490116119384765625).

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Rundungsfehler ?

Beitrag von m.fuchs »

Och komm. Dass die Bitmuster im Speicher exakt sind ist ja wohl klar. Das hat aber auch wenig mit dem Thema zu tun.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Antworten