Rundungsfehler ?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Rundungsfehler ?

Beitragvon Mathias » 27. Mai 2018, 21:50 Rundungsfehler ?

Wieso wird bei x.5 einmal aufgerundet, und das andere mal abgerundet ?

Folgender Code,
Code: Alles auswählen
var
  i: Integer;
  x: single;
begin
  x := 0.5;
  for i:= 0 to 10 do begin
    WriteLn('Input:', x: 10: 5, ' round: ', Round(x));
    x := x + 1.0;
  end;
  WriteLn();
end;

hat folgende Ausgabe:
Code: Alles auswählen
Input:   0.50000 round:   0
Input:   1.50000 round:   2
Input:   2.50000 round:   2
Input:   3.50000 round:   4
Input:   4.50000 round:   4
Input:   5.50000 round:   6
Input:   6.50000 round:   6
Input:   7.50000 round:   8
Input:   8.50000 round:   8
Input:   9.50000 round:  10
Input:  10.50000 round:  10


Wen ich x := 0.500001; einfüge, dann wird richtig gerundet.
Wen ich anstelle von Single Double nehme, habe ich den gleichen Fehler.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4342
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon m.fuchs » 27. Mai 2018, 22:24 Re: Rundungsfehler ?

Einen Blick ins Handbuch kann man schon mal werfen.
https://www.freepascal.org/docs-html/rtl/system/round.html
In the case of .5, the algorithm uses "banker's rounding": .5 values are always rounded towards the even number.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
m.fuchs
 
Beiträge: 1972
Registriert: 22. Sep 2006, 18:32
Wohnort: Berlin
OS, Lazarus, FPC: Winux (L 1.8.4, FPC 3.0.4) | 
CPU-Target: x86, x64, arm
Nach oben

Beitragvon MacWomble » 28. Mai 2018, 06:59 Re: Rundungsfehler ?

m.fuchs hat geschrieben:Einen Blick ins Handbuch kann man schon mal werfen.
https://www.freepascal.org/docs-html/rtl/system/round.html
In the case of .5, the algorithm uses "banker's rounding": .5 values are always rounded towards the even number.


Ich bezweifle, dass diese Regelung für eine Programmiersprache irgendeinen Sinn ergibt. Auch ich würde eine 'gewohnte' Rundung erwarten und nicht einen Spezialfall. Solche Sachen bringen einen in FPC wirklich zum Verzweifeln. :shock:
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
 
Beiträge: 610
Registriert: 17. Apr 2008, 00:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19 Cinnamon / CodeTyphon Generation V Plan 6.60 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon mischi » 28. Mai 2018, 07:39 Re: Rundungsfehler ?

MacWomble hat geschrieben:Ich bezweifle, dass diese Regelung für eine Programmiersprache irgendeinen Sinn ergibt. Auch ich würde eine 'gewohnte' Rundung erwarten und nicht einen Spezialfall. Solche Sachen bringen einen in FPC wirklich zum Verzweifeln. :shock:

.Net round macht das gleiche. IEEE 754 lautet auch so (https://en.wikipedia.org/wiki/Rounding# ... lf_to_even). So viel ich weiss, ist mit Bankers rounding die Summer der Mehrwertsteuer gleiche der Mehrwertsteuer der Summe bis auf einen Cent.
MiSchi macht die fink-Pakete
mischi
 
Beiträge: 205
Registriert: 10. Nov 2009, 18:49
OS, Lazarus, FPC: macOS, 10.13, lazarus 1.8.x, fpc 3.0.x | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon siro » 28. Mai 2018, 07:43 Re: Rundungsfehler ?

Ohje, das finde ich auch katastrophal,
aber in Delphi 6 ist das leider auch so. Grad nochmal probiert round 9.5 und round 10.5 gibt tatäschlich 10
Ich hatte schon recht früh meine eigene Rundungsfunktion geschrieben, nicht ohne Grund..... :cry:
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
siro
 
Beiträge: 323
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon theo » 28. Mai 2018, 08:10 Re: Rundungsfehler ?

theo
 
Beiträge: 8070
Registriert: 11. Sep 2006, 18:01

Beitragvon m.fuchs » 28. Mai 2018, 08:13 Re: Rundungsfehler ?

Verstehe den Unmut nicht. Das ist kein Spezialfall, sondern (wie von mischi schon erwähnt) einfach standardkonform.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
m.fuchs
 
Beiträge: 1972
Registriert: 22. Sep 2006, 18:32
Wohnort: Berlin
OS, Lazarus, FPC: Winux (L 1.8.4, FPC 3.0.4) | 
CPU-Target: x86, x64, arm
Nach oben

Beitragvon indianer-frank » 28. Mai 2018, 08:36 Re: Rundungsfehler ?

Die meisten Rechnungen würden ungenauer, da die Fehlerschranke für Floatingpoint-Operationen sich verdoppelt. Außerdem gibt es systematische Instabilitäten. Das folgende Programm addiert und subtrahiert 1e-100 zu 1. Das Ergebnis ist eine Katastrophe
Code: Alles auswählen
program t_rmf;
 
uses
  math;
 
const
  Max = 10000000;
  Max10 = Max div 10;
var
  x,y,d: double;
  dummy: TFPURoundingMode;
  i: longint;
begin
  d := 1e-100;
  writeln('Round to Nearest Even');
  dummy := SetRoundMode(rmNearest);
  x := 1;
  for i:=0 to Max do begin
    y := x + d;
    x := y - d;
    if i mod Max10 = 0 then writeln(i:12, x:30:15);
  end;
  writeln('Round up');
  SetRoundMode(rmUp);
  x := 1;
  for i:=0 to Max do begin
    y := x + d;
    x := y - d;
    if i mod Max10 = 0 then writeln(i:12, x:30:15);
  end;
end.
 

Mit den Ergebnissen
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.000000000222045
     2000000             1.000000000444089
     3000000             1.000000000666134
     4000000             1.000000000888179
     5000000             1.000000001110223
     6000000             1.000000001332268
     7000000             1.000000001554313
     8000000             1.000000001776357
     9000000             1.000000001998402
    10000000             1.000000002220446

Als Anregung kann man auch einmal https://stackoverflow.com/questions/452 ... table?rq=1 lesen.
indianer-frank
 
Beiträge: 134
Registriert: 30. Nov 2008, 21:53

Beitragvon mschnell » 28. Mai 2018, 09:13 Re: Rundungsfehler ?

siro hat geschrieben:Ohje, das finde ich auch katastrophal,

????
0.5 ist binär exakt darstellbar. Deshalb ist "round" nicht "natürlich" eindeutig definiert. Es ist also für den Eintelfall hochgradig egal (und man darf sich nicht darauf verlassen), ob round(0,5) 1 oder 0 ergibt. In entsprechenden Anwendungen ist das "banker's rounding" ein guter Kompromiss, in allen anderen in keinem Fall verkehrt.

Ich vermute, der Algorithmus ist bereits von der Hardware vorgegeben.

-Michael
mschnell
 
Beiträge: 3253
Registriert: 11. Sep 2006, 09:24
Wohnort: Krefeld
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ) | 
CPU-Target: X32 / X64 / ARMv5
Nach oben

Beitragvon Erwin » 28. Mai 2018, 09:58 Re: Rundungsfehler ?

Also wenn man etwas nachdenkt, fällt einem doch auf/ein, dass z.B. bei einfach Dezimalstelle zwischen der Ganzen Zahl und 0,5, jeweils 4 Zahlen sind (1,2,3,4 und 6,7,8,9).
Würde bei 0,5 immer nur in eine Richtung gerundet werden, würde eine Seite (Kunde oder Bank) von der Rundung profitieren.
Somit hat dieses Bank-Runden durchaus seine Richtigkeit/Sinn. Es ist um einiges gerechter.

Danke für den Hinweis, Mathias.
Habe mich damals schon gewundert, warum man bei dem Befehlt round vom Bankerrunden geschrieben wurde. Jetzt weiß ich es. Ärgerlich dass dies im Buch aber nicht genau erklärt wurde, was mit Bankerrundung gemeint ist. Ging bis jetzt auch immer davon aus, dass ab x.5 aufgerundet wird.

Wenn man ab 0,5 generell auf oder ab gerundet haben will, kommt man um einen eigenen aufwendigeren Code nicht herum.
Win 7 / Lazarus 1.6 / FP 3.0.0 / x86_64-win64-win32/win64
Erwin
 
Beiträge: 216
Registriert: 16. Sep 2009, 13:15
OS, Lazarus, FPC: Xubuntu 16.04 / x86_64_linux-gtk 2 / L 1.6+dfsg-1 / FPC 3.0.0 | 
Nach oben

Beitragvon MacWomble » 28. Mai 2018, 11:33 Re: Rundungsfehler ?

OK, so gesehen sehe ich es auch ein. Nur gab es mal eine Zeit, da lehrte man ab .5 aufzurunden. Das hat sich natürlich fest gesetzt.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
MacWomble
 
Beiträge: 610
Registriert: 17. Apr 2008, 00:59
Wohnort: Freiburg
OS, Lazarus, FPC: Mint 19 Cinnamon / CodeTyphon Generation V Plan 6.60 | 
CPU-Target: Intel i7 64/32 Bit
Nach oben

Beitragvon mschnell » 28. Mai 2018, 11:40 Re: Rundungsfehler ?

Lustig wirds, wenn man nicht sicher sein kann, ob es wirklich genau 0.5 ist:

Code: Alles auswählen
x := 0.5;
x := x / 3;
x := x * 3;
x := round (x);
writeln(x);
 
x := 1.5;
x := x / 3;
x := x * 3;
x := round (x);
writeln(x);


-Michael
mschnell
 
Beiträge: 3253
Registriert: 11. Sep 2006, 09:24
Wohnort: Krefeld
OS, Lazarus, FPC: svn (Window32, Linux x64, Linux ARM (QNAP) (cross+nativ) | 
CPU-Target: X32 / X64 / ARMv5
Nach oben

Beitragvon siro » 28. Mai 2018, 15:00 Re: Rundungsfehler ?

Der Satz von Erwin trifft es sehr gut : "GERECHTER"
"Somit hat dieses Bank-Runden durchaus seine Richtigkeit/Sinn. Es ist um einiges gerechter."
Da stimme ich absolut zu. Ob das nun für die jeweilige Anwendung sinvoller ist, bleibt mal außen vor.

Wenn ich ein Zeichenprogramm habe und mal nach oben und mal nach unten runde, wird es unweigerlich Pixelabweichungen geben,
die abhängig von gerade oder ungerade entstehen. Ich fand es in diesem Falle eher störend.
Code: Alles auswählen
 
  x1:=1.5;
  x2:=4.5;
  xd:=round(x2)-round(x1);   // Breite 2 Pixel ist falsch, es sind 3
 
  x1:=2.5;
  x2:=4.5;
  xd:=round(x2)-round(x1);   // Breite 2 Pixel ist richtig
 
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
siro
 
Beiträge: 323
Registriert: 23. Aug 2016, 13:25
Wohnort: Berlin
OS, Lazarus, FPC: Windows 7 Windows 8.1 Windows 10 | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 28. Mai 2018, 15:21 Re: Rundungsfehler ?

Das problem ist nunmal das es kein "richtiges" runden gibt. 0.5 ist genauso nach an 1 wie an 0 dran. Daher wird das Bänker runden verwendet, da wenn man sich alle möglichen .5er zahlen anschaut es genauso viele gibt die auf wie abgerundet werden. Wenn man das ganze finanziell betrachtet würde immer aufrunden dazu führen das auf dauer der Kunde mehr zahlt als eigentlich nötig, immer abrunden wäre wiederum unfäir dem Verkäufer gegenüber da dieser dann immer Geld verlieren würde. Den Kaufpreis Modulo 2 (die Entscheidung ob auf oder abgerundet wird) kann man praktisch als zuvallsvariable sehen Pr(x mod 2 = 1) = 0.5, was bedeutet das bei genung transaktionen über bankmänisches Runden der Käufer genauso oft bevorteilt werden sollte wie der Verkäufer.

Es ist nicht intuitiv, aber fair. In den meisten fällen ist es sogar egal. Um ehrlich zu sein (auch wenn ich denke das es sowas wohl geben wird) fällt mir kein Fall ein bei dem es wirklich wichtig wäre

indianer-frank hat geschrieben:Das folgende Programm addiert und subtrahiert 1e-100 zu 1. Das Ergebnis ist eine Katastrophe

Die mantissenlänge bei Extended ist 64 Bit (du verwendest sogar nur den kleinen double typen der noch weniger hat, da kenn ich aber die zahl ned auswendig). Wenn mich nicht alles täuscht dürfte, da 10^100 deutlich größer ist als 2^64, 1-10^-100 rein technisch nicht korrekt berechnet werden können. Wenn du so eine Rechnung mit Double (oder sogar extended) Produktiv verwendest ist das die eigentliche Katastrophe, nicht die Rundung. Bei solchen Größenunterschieden sollte man immer Fixpunktzahlen verwenden
Warf
 
Beiträge: 985
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon indianer-frank » 28. Mai 2018, 16:41 Re: Rundungsfehler ?

Warf hat geschrieben: Wenn mich nicht alles täuscht dürfte, da 10^100 deutlich größer ist als 2^64, 1-10^-100 rein technisch nicht korrekt berechnet werden können. Wenn du so eine Rechnung mit Double (oder sogar extended) Produktiv verwendest

Zwei Bemerkungen. Erstens hat das Null mit exakter Darstellung zu tun. Wenn Du
Code: Alles auswählen
program t_rmf;
uses
  math;
const
  Max = 10000000;
  Max10 = Max div 10;
var
  x,y,d: double;
  db: array[0..7] of byte absolute d;
  dummy: TFPURoundingMode;
  i: longint;
begin
  d := 134217728.0{2^27}
  d := sqr(1/d);        {d=2^(-54)}
  write('d intern: ');
  for i:=0 to 7 do write(db[i]:4);
  writeln;
  writeln('Round to Nearest Even');
  dummy := SetRoundMode(rmNearest);
  x := 1;
  for i:=0 to Max do begin
    y := x + d;
    x := y - d;
    if i mod Max10 = 0 then writeln(i:12, x:30:15);
  end;
  writeln('Round up');
  SetRoundMode(rmUp);
  x := 1;
  for i:=0 to Max do begin
    y := x + d;
    x := y - d;
    if i mod Max10 = 0 then writeln(i:12, x:30:15);
  end;
end.
 
Hier ist d exakt darstellbar, und das Ergebnis ist identisch
Code: Alles auswählen
d intern:    0   0   0   0   0   0 144  60
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.000000000222045
     2000000             1.000000000444089
     3000000             1.000000000666134
     4000000             1.000000000888179
     5000000             1.000000001110223
     6000000             1.000000001332268
     7000000             1.000000001554313
     8000000             1.000000001776357
     9000000             1.000000001998402
    10000000             1.000000002220446
 
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).
indianer-frank
 
Beiträge: 134
Registriert: 30. Nov 2008, 21:53

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste

porpoises-institution
accuracy-worried