Dealing with float precision in Javascript

242,897

Solution 1

From this post: How to deal with floating point number precision in JavaScript?

You have a few options:

  • Use a special datatype for decimals, like decimal.js
  • Format your result to some fixed number of significant digits, like this: (Math.floor(y/x) * x).toFixed(2)
  • Convert all your numbers to integers

Solution 2

You could do something like this:

> +(Math.floor(y/x)*x).toFixed(15);
1.2

Edit: It would be better to use big.js.

big.js

A small, fast, easy-to-use library for arbitrary-precision decimal arithmetic.

>> bigX = new Big(x)
>> bigY = new Big(y)
>> bigY.div(bigX).round().times(bigX).toNumber() // => 1.2

Solution 3

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

Quick solution:

var _cf = (function() {
  function _shift(x) {
    var parts = x.toString().split('.');
    return (parts.length < 2) ? 1 : Math.pow(10, parts[1].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); };

> Math.m(0.1, 0.2)
0.02

You can check the full explanation here.

Solution 4

Check out this link.. It helped me a lot.

http://www.w3schools.com/jsref/jsref_toprecision.asp

The toPrecision(no_of_digits_required) function returns a string so don't forget to use the parseFloat() function to convert to decimal point of required precision.

Share:
242,897

Related videos on Youtube

Jeroen Ooms
Author by

Jeroen Ooms

#rstats developer and staff RSE for @ropensci at UC Berkeley.

Updated on October 06, 2021

Comments

  • Jeroen Ooms
    Jeroen Ooms over 2 years

    I have a large amount of numeric values y in javascript. I want to group them by rounding them down to the nearest multiple of x and convert the result to a string.

    How do I get around the annoying floating point precision?

    For example:

    0.2 + 0.4 = 0.6000000000000001
    

    Two things I have tried:

    >>> y = 1.23456789 
    >>> x = 0.2 
    >>> parseInt(Math.round(Math.floor(y/x))) * x; 
    1.2000000000000002
    

    and:

    >>> y = 1.23456789 
    >>> x = 0.2 
    >>> y - (y % x)
    1.2000000000000002
    
    • Vatev
      Vatev almost 12 years
      This is actually normal behavior for double you just don't see it in print statements in most languages. Have you tried rounding your numbers?
    • Pointy
      Pointy almost 12 years
      You can't really "get around" it, as it's an intrinsic aspect of binary floating-point math systems. That's true for both your "x" and your "y" values, apparently; if "x" is 0.3 that can't be represented exactly. "Rounding" to arbitrary fractions is going to result in imprecision.
    • Jeroen Ooms
      Jeroen Ooms almost 12 years
      So what would be an alternative way of converting y to "1.2".
    • pilau
      pilau almost 10 years
      @Jeroen I'm sure you've got it already, but just for the record, Math.floor(y).
    • Josh1billion
      Josh1billion about 8 years
      @pilau that would result in 1, not 1.2
    • santiago arizti
      santiago arizti over 4 years
      Math.floor(y*10)/10?
  • Jeroen Ooms
    Jeroen Ooms almost 12 years
    Doesn't work for all combinations y and x.
  • Jeroen Ooms
    Jeroen Ooms almost 12 years
    This gets a bit problematic of x is an integer.
  • Karl
    Karl over 9 years
    "Convert all your numbers to integers", I've wondered about this. As we know, JavaScript has one number type Number, an IEEE 754 float. If that's the case, then why does converting a float to an integer work, (and it does)? Does JavaScript actually have an integer data type that simply isn't accessible via a reserved word?
  • rich remer
    rich remer over 8 years
    IEEE 754 can exactly represent integers up to something like 2^50. So, if you're working within a known range, you can scale your values to take advantage of the 50 bits (or whatever) of precision, instead of wasting the precision normally reserved for large numbers.
  • paul23
    paul23 over 6 years
    @richremer a floating point has the property that the accuracy (for normal values) does not depend on the size. - So whether you convert it to integers (by say multiplying the values with some constant) the accuracy is equal.
  • prahaladp
    prahaladp about 6 years
    If you happened to be someone who downvoted me for this answer, could you please explain why ? (the solution provided seems to work )
  • dopatraman
    dopatraman over 5 years
    toFixed returns a string
  • joe cool
    joe cool about 5 years
    Math.m(0.07, 100) => 7.000000000000002
  • Rivenfall
    Rivenfall almost 4 years
    The number of "significant digits" is the number of digits using the scientific notation (no leading or trailing zeros) and it's a choice based on circumstances. - toPrecision's argument seems to be a number of significant digits. - toFixed is for a number of trailing digits.
  • Rivenfall
    Rivenfall almost 4 years
    replace floor by round, + by parseFloat and 15 by a lower number if you can (toFixed argument could be calculated based on x)
  • Rivenfall
    Rivenfall almost 4 years
    Basically the problem is this, you have js numbers y and x and you want the nearest (from y) multiple of x. The toPrecision method doesn't help i.e. parseFloat((150).toPrecision(1)) === 200
  • jefelewis
    jefelewis over 3 years
    toFixed() will convert the number to a string.
  • shaiis.com
    shaiis.com over 3 years
    This is not working!
  • Tchakabam
    Tchakabam over 2 years
    doing string/float-parsing conversion for a rounding problem isn't exactlxy what I would call performing at scale :D (better: implement/use a toPrecision function that operates/returns solely on numbers!)