This blog has moved to
http://blog.matthias-reining.com

Die bestehenden Artikel bleiben vorerst alle bei blogspot. Neue Artikel veröffentliche ich allerdings nur noch auf http://blog.matthias-reining.com

Samstag, 4. Oktober 2008

Javascript und Mathematik (oder Fließkommaarithmetik)

Ausgerechnet heute, am Feiertag (03. Oktober), hat doch in einem Projekt der Kunde ein böses Problem entdeckt… Die Applikation funktioniert nicht mehr! (zumindest ein ganz spezieller Fall) normal ;-)

In der entsprechenden Applikation (Webapplikation) werden im Frontend in Javascript einige Berechnungen durchgeführt (eher trivial, dafür allerdings ziemlich viel). Berechnungen in Javascript? Spart den Serverrroundtrip, der per AJAX notwendig wäre… Zur Kontrolle wird aber natürlich nochmal alles im Backend in Java mit BigDecimal nachgerechnet. …und da passen die Ergebnisse jetzt leider nicht zusammen. Die Applikation wirft einen Fehler und funktioniert nicht mehr.

Die Berechnung

function roundNumber(value, maxDecimalPlaces ) {
var e = Math.pow(10, maxDecimalPlaces);
return (Math.round(value * e) / e);
}

var x = 234.7;
var factor = 0.95;
var result = roundNumber( x * factor, 2 );
alert(result);

Das Ergebnis ist 222,96
Eigentlich hätte man aber ein leicht anderes Ergebnis erwartet… sauber gerechnet ist x*factor=222,965. Kaufmännische gerundet sollte das Ergebnis 222,97 sein.

Das Problem liegt natürlich an Fließkommazahlen und deren Rundungsfehler. Vergisst man nur mal schnell wenn man ein "bischen" in JavaScript hackt.

Das Ergebnis in Javascript für x * factor:

234.7 * 0.95 = 222.96499999999997

Und somit wird hier natürlich anschließend auch falsch gerundet.

Abhilfe schafft eine modifizierte round Methode:

function roundNumber(value, maxDecimalPlaces ) {
var e = Math.pow(10, maxDecimalPlaces);
//fliesskommaaritmetic
value = value + 0.0000000000001;
value = (Math.round(value * e) / e);
return value;
}

http://de.selfhtml.org/javascript/objekte/math.htm#round

http://www.galileocomputing.de/openbook/javainsel7/javainsel_02_004.htm#mjf9723d99079baea563298aa74cd42cb9

Keine Kommentare:

Kommentar veröffentlichen