Categories

# How to deal with floating point number precision in JavaScript?

I have the following dummy test script:

``````function test() {
var x = 0.1 * 0.2;
document.write(x);
}
test();``````

This will print the result `0.020000000000000004` while it should just print `0.02` (if you use your calculator). As far as I understood this is due to errors in the floating point multiplication precision.

Does anyone have a good solution so that in such case I get the correct result `0.02`? I know there are functions like `toFixed` or rounding would be another possibility, but I’d like to really have the whole number printed without any cutting and rounding. Just wanted to know if one of you has some nice, elegant solution.

Of course, otherwise I’ll round to some 10 digits or so.

• Actually, the error is because there is no way to map `0.1` to a finite binary floating point number.

Sep 22, 2009 at 8:14

• Most fractions can’t be converted to a decimal with exact precision. A good explanation is here: docs.python.org/release/2.5.1/tut/node16.html

Jan 10, 2011 at 18:35

• possible duplicate of Is JavaScript’s Math broken?

Nov 2, 2011 at 3:18

• @SalmanA: That your JavaScript runtime hides this problem from you doesn’t mean I’m wrong.

Nov 19, 2012 at 10:45

• Disagree with Aaron, there are ways to code 0.1 perfectly and completely in binary. But IEEE 754 does not necessarily defines this. Imagine a representation where you would code the integer part in binary on the one hand, the decimal part on the other hand, up to n decimals, in binary too, like a normal integer > 0, and finally, the position of the decimal point. Well, you would represent 0.1 perfectly, with no error. Btw, since JS uses a finite number of decimals internally, they devs might as well coded the guts to not make that mistake on the last decimals.

Nov 14, 2016 at 5:59

From the Floating-Point Guide:

What can I do to avoid this problem?

That depends on what kind of
calculations you’re doing.

• If you really need your results to add up exactly, especially when you
work with money: use a special decimal
datatype.
• If you just don’t want to see all those extra decimal places: simply
format your result rounded to a fixed
number of decimal places when
displaying it.
• If you have no decimal datatype available, an alternative is to work
with integers, e.g. do money
calculations entirely in cents. But
this is more work and has some
drawbacks.

Note that the first point only applies if you really need specific precise decimal behaviour. Most people don’t need that, they’re just irritated that their programs don’t work correctly with numbers like 1/10 without realizing that they wouldn’t even blink at the same error if it occurred with 1/3.

If the first point really applies to you, use BigDecimal for JavaScript, which is not elegant at all, but actually solves the problem rather than providing an imperfect workaround.

• I noticed your dead link for BigDecimal and while looking for a mirror, I found an alternative called BigNumber: jsfromhell.com/classes/bignumber

Dec 1, 2011 at 4:52

• @bass-t: Yes, but floats can exactly represent integers up to the length of the significand, and as per ECMA standard it’s a 64bit float. So it can exactly represent integers up to 2^52

Jul 25, 2012 at 13:15

• @Karl: The decimal fraction 1/10 cannot be represented as a finite binary fraction in base 2, and that’s what Javascript numbers are. So it is in fact exactly the same problem.

Dec 23, 2014 at 15:44

• I learned today that even integers have precision problems in javascript. Consider that `console.log(9332654729891549)` actually prints `9332654729891548` (ie off by one!)

Jul 10, 2015 at 21:01

• @mlathe: Doh.. `;P`… Between `2⁵²`=`4,503,599,627,370,496` and `2⁵³`=`9,007,199,254,740,992` the representable numbers are exactly the integers. For the next range, from `2⁵³` to `2⁵⁴`, everything is multiplied by `2`, so the representable numbers are the even ones, etc. Conversely, for the previous range from `2⁵¹` to `2⁵²`, the spacing is `0.5`, etc. This is due to simply increasing|decreasing the base|radix 2|binary exponent in/of the 64-bit float value (which in turn explains the rarely documented ‘unexpected’ behavior of `toPrecision()` for values between `0` and `1`).

Mar 2, 2016 at 19:42

I like Pedro Ladaria’s solution and use something similar.

``````function strip(number) {
return (parseFloat(number).toPrecision(12));
}
``````

Unlike Pedros solution this will round up 0.999…repeating and is accurate to plus/minus one on the least significant digit.

Note: When dealing with 32 or 64 bit floats, you should use toPrecision(7) and toPrecision(15) for best results. See this question for info as to why.

• Any reason why you picked 12?

Dec 27, 2015 at 1:09

• `toPrecision` returns a string instead of a number. This might not always be desirable.

Mar 13, 2016 at 23:42

• parseFloat(1.005).toPrecision(3) => 1.00

May 27, 2016 at 11:27

• @user2428118, I know, I meant to show the rounding error, The outcome is 1.00 instead of 1.01

Jul 9, 2016 at 7:39

• What @user2428118 said may not be obvious enough: `(9.99*5).toPrecision(2)` = 50 instead of 49.95 because toPrecision counts the whole number, not just decimals. You can then use `toPrecision(4)`, but if your result is >100 then you’re out of luck again, because it’ll allow the first three numbers and one decimal, that way shifting the dot, and rendering this more or less unusable. I ended up using `toFixed(2)` instead

Nov 15, 2018 at 11:38

For the mathematically inclined: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

The recommended approach is to use correction factors (multiply by a suitable power of 10 so that the arithmetic happens between integers). For example, in the case of `0.1 * 0.2`, the correction factor is `10`, and you are performing the calculation:

``````> var x = 0.1
> var y = 0.2
> var cf = 10
> x * y
0.020000000000000004
> (x * cf) * (y * cf) / (cf * cf)
0.02
``````

A (very quick) solution looks something like:

``````var _cf = (function() {
function _shift(x) {
var parts = x.toString().split('.');
return (parts.length < 2) ? 1 : Math.pow(10, parts.length);
}
return function() {
return Array.prototype.reduce.call(arguments, function (prev, next) { return prev === undefined || next === undefined ? undefined : Math.max(prev, _shift (next)); }, -Infinity);
};
})();

Math.a = function () {
var f = _cf.apply(null, arguments); if(f === undefined) return undefined;
function cb(x, y, i, o) { return x + f * y; }
return Array.prototype.reduce.call(arguments, cb, 0) / f;
};

Math.s = function (l,r) { var f = _cf(l,r); return (l * f - r * f) / f; };

Math.m = function () {
var f = _cf.apply(null, arguments);
function cb(x, y, i, o) { return (x*f) * (y*f) / (f * f); }
return Array.prototype.reduce.call(arguments, cb, 1);
};

Math.d = function (l,r) { var f = _cf(l,r); return (l * f) / (r * f); };
``````

In this case:

``````> Math.m(0.1, 0.2)
0.02
``````

I definitely recommend using a tested library like SinfulJS

• Il love this elegant workaround but seems not to be perfect: jsfiddle.net/Dm6F5/1 Math.a(76.65, 38.45) returns 115.10000000000002

Apr 16, 2014 at 12:29

• Math.m(10,2332226616) is giving me “-19627406800” which is a negative value… I hope there must be a upper limit – might be that is causing this issue. Please suggest

Jul 15, 2014 at 6:07

• This all looks great, but seems to have a mistake or two in there somewhere.

Mar 12, 2015 at 2:50

• Very quick solution he said…broken fix no one ever said.

Dec 11, 2015 at 13:27

• Don’t use the above code. It’s absolutely not a ‘quick solution’ if it does not work. This is a math related question, so accuracy is required.

Jun 9, 2017 at 13:55