Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript multiplying incorrectly, causing incorrect rounding

When I pull the values I want to multiply, they're strings. So I pull them, parse them as floats (to preserve the decimal places), and multiply them together.

LineTaxRate = parseFloat(myRate) * parseFloat(myQuantity) * parseFloat(myTaxRateRound);

This has worked for 99% of my invoices but I discovered one very odd problem.

When it multiplied: 78 * 7 * 0.0725

Javascript is returning: 39.584999999999994

When you normally do the math in a calculator its: 39.585

When all is said and done, I take that number and round it using .toFixed(2)

Because Javascript is returning that number, it's not rounding to the desired value of: $39.59

I tried Math.round() the total but I still get the same number.

I have thought of rounding the number to 3 decimals then two, but that seems hacky to me.

I have searched everywhere and all I see is people mention parseFloat loses its precision, and to use .toFixed, however in the example above, that doesn't help.

Here is my test script i made to recreate the issue:

<script>
var num1 = parseFloat("78");
var num2 = parseFloat("7");
var num3 = parseFloat("0.0725");
var myTotal = num1 * num2 * num3;
var result = Math.round(myTotal*100)/100

alert(myTotal);
alert(myTotal.toFixed(2));
alert(result);
</script>
like image 265
matt anderson Avatar asked Sep 13 '11 18:09

matt anderson


People also ask

Does JavaScript use floating point?

JavaScript Numbers are Always 64-bit Floating Point JavaScript numbers are always stored as double precision floating point numbers, following the international IEEE 754 standard.

Why does JavaScript have rounding errors?

This post doesn't get into the details of floating-point arithmetic, but the short of it is most programming languages use a binary floating-point representation which can only approximate many decimal fractions. This results in rounding errors for the most common approaches to rounding in JavaScript.

How do you multiply numbers in JavaScript?

An asterisk ( * ) is used to represent the multiplication operator.

How do you round decimals after JavaScript?

The Math. round() method rounds a number to the nearest integer. 2.49 will be rounded down (2), and 2.5 will be rounded up (3).


2 Answers

Floating points are represented in binary, not decimal. Some decimal numbers will not be represented precisely. And unfortunately, since Javascript only has one Number class, it's not a very good tool for this job. Other languages have decent decimal libraries designed to avoid precisely this kind of error. You're going to have to either accept one-cent errors, implement a solution server-side, or work very hard to fix this.

edit: ooh! you can do 78 * 7 * 725 and then divide by 10000, or to be even more precise just put the decimal point in the right place. Basically represent the tax rate as something other than a tiny fraction. Less convenient but it'll probably take care of your multiplication errors.

like image 133
krasnerocalypse Avatar answered Sep 21 '22 10:09

krasnerocalypse


You might find the Accounting.js library useful for this. It has an "improved" toFixed() method.

like image 33
cyberwombat Avatar answered Sep 18 '22 10:09

cyberwombat