Geld mit Euro und Cent Runden [gelöst]

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
paulderfinne
Beiträge: 65
Registriert: Mi 27. Feb 2013, 18:24
OS, Lazarus, FPC: Linux (L 0.9.30.4-1.1 FPC 2.6.0)
CPU-Target: 32Bit

Geld mit Euro und Cent Runden [gelöst]

Beitrag von paulderfinne »

Hallo an Euch alle,

ich bin gerade dabei ein Rechnungsprogramm zu schreiben. Es generiert also Rechnungen. Dabei werden Menge und Einzelpreis miteinander Mal genommen. Beide Werte haben maximal 2 Nachkommastellen. Das Ergebnis soll natürlich auf ganze Cent gerundet werden und mit diesem gerundeten Wert soll weiter gerechnet werden. (Auch wenn das zu Rundungsfehlern führt, so denkt halt der Mensch). Dieses Vorhaben erwies sich als ziemlich schwierig. Weder ein Ruond noch ein RoundTo noch der Weg über einen String mit FloatToStrF noch ein +0.005 mit trunc führte zum Erfolg:

Code: Alles auswählen

 
var a,b,c,d : double;
a:=12.45;
b:=0.03;
c:=a*b;
d:=roundto(c,2); //Führt zu d=3.73 statt 3.74
d:=trunc((d+0.005)*100))/100 //Führt ebenfalls dazu, dass d=3.73 statt 3.74 ist.
 
Nach langen schlaflosen Nächten hatte ich eine Lösung.

Code: Alles auswählen

 
var a,b,c,d,e,g : double;
var f : integer;
a:=12.45;
b:=0.03;
c:=a*b;
d:=roundto(c,2); //Führt zu d=3.73 statt 3.74
e:=(d+0.005)*10000; //sic(!)
f:=trunc(e);
e:=f/100;
f:=trunc(e);
g:=f/100; //jetzt steht in g=3,74. Auch alle anderen Zahlen werden korrekt gerundet
 
Oder hat jemand eine "einfachere" Lösung. Man könnte das obige natürlich zu einer allgemeinen Funktion ausweiten, aber da es wohl ein Problem ist, das nur bei monetären Angelegenheiten auftaucht und wir dabei praktisch immer mit 2 Nachkommastellen arbeiten, lasse ich es dabei
Zuletzt geändert von paulderfinne am So 18. Jan 2015, 15:27, insgesamt 1-mal geändert.


paulderfinne
Beiträge: 65
Registriert: Mi 27. Feb 2013, 18:24
OS, Lazarus, FPC: Linux (L 0.9.30.4-1.1 FPC 2.6.0)
CPU-Target: 32Bit

Re: Geld mit Euro und Cent Runden

Beitrag von paulderfinne »

Nein das tut er eben nicht, weder mit round noch mit trunc. Es wird richig grundet, wenn die Varialble einen direkten Wert erhält. Sowas wie a=3.375. Berechne ich aber den Werrt wie oben, a=0.3; b=12.45; c=a*b, dann führt beisopielsweise ein d:=trunc((c+0.005)*100)/100; zu d=3.73;

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

Re: Geld mit Euro und Cent Runden

Beitrag von wp_xyz »

Schreib mal die richtigen Zahlen, so wie oben kann das nicht funktionieren: 12.45*0.03 ist lt. Excel 0.3735. Wieso soll da nach dem Runden auf zwei Dezimalen d=3.74 herauskommen?

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

Re: Geld mit Euro und Cent Runden

Beitrag von wp_xyz »

Falls b um 1 Dekade größer sein sollte (b=0.3) handelt es sich um Rundungsfehler: In Wirklichkeit ist c=a*b=3.73499999999999. Diese Zahl auf 2 Dezimalen gerundet ist tatsächlich 3.73. Zur Lösung des Rundungsproblems muss du noch eine sehr kleine Zahl addieren:

Code: Alles auswählen

 
function MyRoundTo(x: double; Decimals: Byte): Double;
const
  EPS = 1e-6;
var
  RV: Double;
begin
  RV:=IntPower(10, Decimals);
  Result := Round(AValue/RV + EPS)*RV;
end;
 

paulderfinne
Beiträge: 65
Registriert: Mi 27. Feb 2013, 18:24
OS, Lazarus, FPC: Linux (L 0.9.30.4-1.1 FPC 2.6.0)
CPU-Target: 32Bit

Re: Geld mit Euro und Cent Runden

Beitrag von paulderfinne »

Danke wp_xyz.

Ja ich hatte da die falsche Zahl hingeschrieben. Ich meinte b:=0.3. Deine Erklärung lässt aufhorchen. Danke dafür. So gibt das ganze Sinn. Warum meine Lösung trotzdem funktioniert versteh ich nicht. Werde aber deine implementieren.

OK. Funzt. Ist zwar euin bisschen Tricky, eine Millionstel Euro hinzuzufügen, damit richtig gerundet wird, aber OK.

PS. Wahrscheinlich sollte in deiner Function x statt AValue stehen, aber ansonsten wird sie offenbar funktionieren. Ich denke es würde Sinn machen, die Rundungsfunktion irgendwie entsprechend anzupassen.

paulderfinne
Beiträge: 65
Registriert: Mi 27. Feb 2013, 18:24
OS, Lazarus, FPC: Linux (L 0.9.30.4-1.1 FPC 2.6.0)
CPU-Target: 32Bit

Re: Geld mit Euro und Cent Runden

Beitrag von paulderfinne »

Vielleicht sollte ich noch hinzufügen, dass ich beim Basic vom Libreoffice genau die gleiche Problematik habe. Also vor dem Runden ein millionstel Euro hinzufügen und es klappt.

BeniBela
Beiträge: 321
Registriert: Sa 21. Mär 2009, 17:31
OS, Lazarus, FPC: Linux (Lazarus SVN, FPC 2.4)
CPU-Target: 64 Bit

Re: Geld mit Euro und Cent Runden [gelöst]

Beitrag von BeniBela »

Das Problem ist, dass double nicht für Dezimalzahlen geeignet ist.

Einfach

Code: Alles auswählen

var a,b,c,d : currency;
verwenden und dann geht es.

Oder meinen bigdecimal, wenn die GPL nicht gar zu schrecklich ist:

Code: Alles auswählen

var a,b,c,d : bigdecimal;

paulderfinne
Beiträge: 65
Registriert: Mi 27. Feb 2013, 18:24
OS, Lazarus, FPC: Linux (L 0.9.30.4-1.1 FPC 2.6.0)
CPU-Target: 32Bit

Re: Geld mit Euro und Cent Runden [gelöst]

Beitrag von paulderfinne »

Danke für den Tipp BeniBela. Habe nichts gegen GPL, wohl im Gegenteil.

Antworten