Dealing with float precision in Javascript
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.
Related videos on Youtube
Jeroen Ooms
#rstats developer and staff RSE for @ropensci at UC Berkeley.
Updated on October 06, 2021Comments
-
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 ofx
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 almost 12 yearsThis 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 almost 12 yearsYou 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 almost 12 yearsSo what would be an alternative way of converting
y
to"1.2"
. -
pilau almost 10 years@Jeroen I'm sure you've got it already, but just for the record,
Math.floor(y)
. -
Josh1billion about 8 years@pilau that would result in 1, not 1.2
-
santiago arizti over 4 years
Math.floor(y*10)/10
?
-
-
Jeroen Ooms almost 12 yearsDoesn't work for all combinations
y
andx
. -
Jeroen Ooms almost 12 yearsThis gets a bit problematic of
x
is an integer. -
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 over 8 yearsIEEE 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 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 about 6 yearsIf you happened to be someone who downvoted me for this answer, could you please explain why ? (the solution provided seems to work )
-
dopatraman over 5 yearstoFixed returns a string
-
joe cool about 5 yearsMath.m(0.07, 100) => 7.000000000000002
-
Rivenfall almost 4 yearsThe 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 almost 4 yearsreplace floor by round,
+
by parseFloat and 15 by a lower number if you can (toFixed argument could be calculated based on x) -
Rivenfall almost 4 yearsBasically 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 over 3 yearstoFixed() will convert the number to a string.
-
shaiis.com over 3 yearsThis is not working!
-
Tchakabam over 2 yearsdoing 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!)