I was wondering how can I subtract two negative Floating-Point numbers in javascript. I tried:
alert(-0.2-0.1);
and the result is -0.30000000000000004. Am I doing something wrong? What do I have to do to get -0.3 ?
No, nothing wrong with your code, most decimal fractions cannot be represented exactly
in binary, use
number.toFixed(x)
Where x is the number of decimals you want and number is the result of the subtraction.
Another possible solution might be this:
Number((-0.2-0.1).toFixed(x))
Where x should be the tolerance in decimals you'd like.
Running this with an x of 16, gives me an output of -0.3.
-0.3 === Number((-0.2-0.1).toFixed(16)) // true, and also with every 0 < x < 16
Let me know.
You are doing nothing wrong, what you are seeing is the side effect of computers storing numbers in base 2. In base 10, 1/3 can't be precisely represented: .33333333 (with a bar over the 3). The same is true for 1/10 and 1/5 in base 2 or binary. The answer you see is merely the result of a rounding error. If you are working with money, it is often advised to just store values as cents to avoid some floating point errors.
As far as fixing the result you can do something like:
var SIGDIG= 100000000;
alert( Math.floor((-0.2-0.1)*SIGDIG)/SIGDIG );
The reason of your problem is explained here:
Why does modulus operator return fractional number in javascript?
A possible solution could be:
<script type="text/javascript">
var result = (-20-10)/100;
alert("My result is "+result);
</script>
toFixed() is what you must be looking for.
E.g
number.toFixed(x);
where x is the number of digits after the decimal point. It is optional with default value of 0.
More here : Javascript Number.toFixed() Method
Javascript uses IEEE 754 that is designed to balance the need for accuracy and limitations of computer hardware.
it's still subject to limitations and can lead to rounding errors and imprecise calculations in some cases.
a simplified example will be
> 0.05 - 0.02
< 0.030000000000000002 // this is the result!!!
the result is unexpected and this I call bug and makes arithmetic operations on floating-point useless.
you can work around the problem as suggested with toFixed but this will require you to know the number of digits after decimal point in advance and toFixed returns a string.
if you dont know the number of digits after decimal point in advance, here how the problem can be solved:
const getLongestDecimalLength = ( ...numbers ) => numbers.reduce( ( previousLength, number ) => {
const numberParts = number.toString().split( '.' );
if ( numberParts.length <= 1 ) return previousLength;
return numberParts[ 1 ].length > previousLength ? numberParts[ 1 ].length : previousLength;
}, 0 );
const price = 0.05;
const tax = 0.02;
const decimalLength = getLongestDecimalLength(price, tax);
const cost = parseFloat((price - tax).toFixed(decimalLength)); // 0.03
Related
Is there a way to determine whether dividing one number by another will result in whole number in JavaScript? Like 18.4 / 0.002 gives us 9200, but 18.4 / 0.1 gives us 183.99999999999997. The problem is that both of them may be any float number (like 0.1, 0.01, 1, 10, ...) which makes it impossible to use the standard function modulo or trying to subtract, and floating point precision issues mean we will sometimes get non-whole-number results for numbers that should be whole, or whole-number results for ones that shouldn't be.
One hacky way would be
Convert both numbers to strings with toString()
Count the precision points (N) by stripping off the characters before the . (including the .) and taking the length of the remaining part
Multiply with 10^N to make them integers
Do modulo and get the result
Updated Demo: http://jsfiddle.net/9HLxe/1/
function isDivisible(u, d) {
var numD = Math.max(u.toString().replace(/^\d+\./, '').length,
d.toString().replace(/^\d+\./, '').length);
u = Math.round(u * Math.pow(10, numD));
d = Math.round(d * Math.pow(10, numD));
return (u % d) === 0;
}
I don't think you can do that with JavaScript's double-precision floating point numbers, not reliably across the entire range. Maybe within some constraints you could (although precision errors crop up in all sorts of -- to me -- unexpected locations).
The only way I see is to use any of the several "big decimal" libraries for JavaScript, that don't use Number at all. They're slower, but...
I Assume that you want the reminder to be zero when you perform the division.
check for the precision of the divisor, and multiply both divisor and divident by powers of 10
for example
you want to check for 2.14/1.245 multiply both divident and divisor by 1000 as 1.245 has 3 digits precision, now the you would have integers like 2140/1245 to perform modulo
Divide first number by second one and check if result is integer ?
Only, when you check that the result is integer, you need to specify a rounding threshold.
In javascript, 3.39/1.13 is slightly more than 3.
Example :
/**
* Returns true iif a is an integer multiple of b
*/
function isIntegerMultiple(a, b, precision) {
if (precision === undefined) {
precision = 10;
}
var quotient = a / b;
return Math.abs(quotient - Math.round(quotient)) < Math.pow(10, -precision);
}
console.log(isIntegerMultiple(2, 1)); // true
console.log(isIntegerMultiple(2.4, 1.2)); // true
console.log(isIntegerMultiple(3.39, 1.13)); // true
console.log(isIntegerMultiple(3.39, 1.13, 20)); // false
console.log(isIntegerMultiple(3, 2)); // false
Have a look at this for more details on floating point rounding issues: Is floating point math broken?
I am trying to fix the number to 2 digits after decimal and for that i am using toFixedfunction of javascript. Below are the strange results i am getting, please check and help me.
var number = 11.995;
number.toFixed(2); // giving me 11.99 which is correct
var number = 19.995;
number.toFixed(2); // giving me 20.00 which is incorrect
Can anyone tell me why it is happening.
Thanks for your help.
This is how floating point math works. The value 19.995 is not exact binary (base 2). To make it more clear, think of an exact number when you divide 10/3.
For more in-depth explanations, read this: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
In your case you can work with strings instead (at least it seems like that is what you want):
number.toString().substr(0, n);
Or define a function like this (made in 2 minutes, just an example):
Number.toFixed = function(no, n) {
var spl = no.toString().split('.');
if ( spl.length > 1 ) {
return spl[0]+'.'+spl[1].substr(0,n);
}
return spl[0];
}
Number.toFixed(19.995, 2); // 19.99
toFixed rounds the value. Since 19.995 is exactly halfway between 19.99 and 20.00, it has to choose one of them. Traditionally, rounding prefers the even result (this prevents bias, since round-ups and round-downs will be equal).
I have create a function which done all for me..
function toFixed(number, precision) {
var multiplier = Math.pow(10, precision + 1),
wholeNumber = Math.floor(number * multiplier);
return Math.round(wholeNumber / 10) * 10 / multiplier;
}
//Call this function to retrive exect value
toFixed((+adjustmentval), 2);
David has answered your doubt I'm guessing. Just providing an alternate solution here.
You can use the Math.floor() method of the Math object for this.
Something like this, Math.floor(number*100)/100
Can anyone tell me why it is happening.
The IEEE-754 double-precision binary floating point number standard used by JavaScript's number type (and similar times in several other languages) does not perfectly store all numbers, it stores some numbers imprecisely, in a way that lets it A) Store them in just 64 bits, and B) Calculate with them quickly.
For 11.995, the actual value is 11.99499988555908203125, just slightly less than 11.995.
For 19.995, the actual value is 19.9950008392333984375, just slightly more than 19.995.
That explains why when you round them using the usual round-to-nearest-half-up operation, 11.995 (which is really 11.99499988555908203125) rounds down to 11.99 but 19.995 (which is really 19.9950008392333984375) rounds up to 20.00.
(This site has a handy calculator for visualizing this stuff.)
More here on SO:
Is floating point math broken?
How to deal with floating point number precision in JavaScript?
var quantity = $(this).find('td:eq(2) input').val()*1;
var unitprice = $(this).find('td:eq(3) input').val()*1;
var totaltax = 0;
$(this).find('td:eq(4) input[name^=taxamount]').each(function(){
totaltax = (totaltax*1)+($(this).val()*1);
});
var subtotal = (unitprice+totaltax);
alert(subtotal+' is unit subtotal, to mulitply by '+quantity);
var total = subtotal*quantity;
$(this).find('td:last').html('$'+total);
In this case, based on my DOM, the results are all integers (especially because I'm making sure I apply the *1 modifier to values to ensure they are numbers, not strings).
In this case, these are teh values returned within the first 7 lines of the above code (and verified through alert command)
quantity: 10
unitprice: 29
totaltax: 3.48
subtotal = 32.48
When I multiply subtotal*quantity for the total variable, total returns:
total: 324.79999999999995
So at the end, I get the td:last filled with $324.79999999999995 rather than $324.80 which would be more correct.
Bizarre, I know. I tried all sorts of alerts at different points to ensure there were no errors etc.
This has been asked one bizillion times.
Please read: What Every Computer Scientist Should Know About Floating-Point Arithmetic
You're coming up against a familiar issue with floating point values: certain values can't be precisely represented in a finite binary floating point number.
See here:
How to deal with floating point number precision in JavaScript?
This is the way floating point numbers work. There's nothing bizarre going on here.
I'd recommend that you round the value appropriately for display.
That's the joy of floating point arithmetic -- some base 10 decimals cannot be represented in binary.
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems
Computers can't handle decimals very well in binary since in real mathematics there are literally an infinite number of values between 0.01 and 0.02 for example. So they need to store approximations, and when you do arithmetic on those approximations the results can get a little away from the true result.
You can fix it with (Math.round(total*100)/100).toFixed(2);
As others have mentioned, this is the way its meant to work. A suggested workaround can be found below:
var v = "324.32999999999995";
function roundFloat(n, d) {
var a= Math.pow(10, d);
var b= Math.round(n * a) / a;
return b;
}
$("body").append(roundFloat(v,3));
Where v would be replaced with the desired value.
You can view the working example at: http://jsfiddle.net/QZXhc/
You could try rounding to 2 decimal digits as workaround
I was wondering how can I subtract two negative Floating-Point numbers in javascript. I tried:
alert(-0.2-0.1);
and the result is -0.30000000000000004. Am I doing something wrong? What do I have to do to get -0.3 ?
No, nothing wrong with your code, most decimal fractions cannot be represented exactly
in binary, use
number.toFixed(x)
Where x is the number of decimals you want and number is the result of the subtraction.
Another possible solution might be this:
Number((-0.2-0.1).toFixed(x))
Where x should be the tolerance in decimals you'd like.
Running this with an x of 16, gives me an output of -0.3.
-0.3 === Number((-0.2-0.1).toFixed(16)) // true, and also with every 0 < x < 16
Let me know.
You are doing nothing wrong, what you are seeing is the side effect of computers storing numbers in base 2. In base 10, 1/3 can't be precisely represented: .33333333 (with a bar over the 3). The same is true for 1/10 and 1/5 in base 2 or binary. The answer you see is merely the result of a rounding error. If you are working with money, it is often advised to just store values as cents to avoid some floating point errors.
As far as fixing the result you can do something like:
var SIGDIG= 100000000;
alert( Math.floor((-0.2-0.1)*SIGDIG)/SIGDIG );
The reason of your problem is explained here:
Why does modulus operator return fractional number in javascript?
A possible solution could be:
<script type="text/javascript">
var result = (-20-10)/100;
alert("My result is "+result);
</script>
toFixed() is what you must be looking for.
E.g
number.toFixed(x);
where x is the number of digits after the decimal point. It is optional with default value of 0.
More here : Javascript Number.toFixed() Method
Javascript uses IEEE 754 that is designed to balance the need for accuracy and limitations of computer hardware.
it's still subject to limitations and can lead to rounding errors and imprecise calculations in some cases.
a simplified example will be
> 0.05 - 0.02
< 0.030000000000000002 // this is the result!!!
the result is unexpected and this I call bug and makes arithmetic operations on floating-point useless.
you can work around the problem as suggested with toFixed but this will require you to know the number of digits after decimal point in advance and toFixed returns a string.
if you dont know the number of digits after decimal point in advance, here how the problem can be solved:
const getLongestDecimalLength = ( ...numbers ) => numbers.reduce( ( previousLength, number ) => {
const numberParts = number.toString().split( '.' );
if ( numberParts.length <= 1 ) return previousLength;
return numberParts[ 1 ].length > previousLength ? numberParts[ 1 ].length : previousLength;
}, 0 );
const price = 0.05;
const tax = 0.02;
const decimalLength = getLongestDecimalLength(price, tax);
const cost = parseFloat((price - tax).toFixed(decimalLength)); // 0.03
I just read on MDN that one of the quirks of JS's handling of numbers due to everything being "double-precision 64-bit format IEEE 754 values" is that when you do something like .2 + .1 you get 0.30000000000000004 (that's what the article reads, but I get 0.29999999999999993 in Firefox). Therefore:
(.2 + .1) * 10 == 3
evaluates to false.
This seems like it would be very problematic. So what can be done to avoid bugs due to the imprecise decimal calculations in JS?
I've noticed that if you do 1.2 + 1.1 you get the right answer. So should you just avoid any kind of math that involves values less than 1? Because that seems very impractical. Are there any other dangers to doing math in JS?
Edit:
I understand that many decimal fractions can't be stored as binary, but the way most other languages I've encountered appear to deal with the error (like JS handles numbers greater than 1) seems more intuitive, so I'm not used to this, which is why I want to see how other programmers deal with these calculations.
1.2 + 1.1 may be ok but 0.2 + 0.1 may not be ok.
This is a problem in virtually every language that is in use today. The problem is that 1/10 cannot be accurately represented as a binary fraction just like 1/3 cannot be represented as a decimal fraction.
The workarounds include rounding to only the number of decimal places that you need and either work with strings, which are accurate:
(0.2 + 0.1).toFixed(4) === 0.3.toFixed(4) // true
or you can convert it to numbers after that:
+(0.2 + 0.1).toFixed(4) === 0.3 // true
or using Math.round:
Math.round(0.2 * X + 0.1 * X) / X === 0.3 // true
where X is some power of 10 e.g. 100 or 10000 - depending on what precision you need.
Or you can use cents instead of dollars when counting money:
cents = 1499; // $14.99
That way you only work with integers and you don't have to worry about decimal and binary fractions at all.
2017 Update
The situation of representing numbers in JavaScript may be a little bit more complicated than it used to. It used to be the case that we had only one numeric type in JavaScript:
64-bit floating point (the IEEE 754 double precision floating-point number - see: ECMA-262 Edition 5.1, Section 8.5 and ECMA-262 Edition 6.0, Section 6.1.6)
This is no longer the case - not only there are currently more numerical types in JavaScript today, more are on the way, including a proposal to add arbitrary-precision integers to ECMAScript, and hopefully, arbitrary-precision decimals will follow - see this answer for details:
Difference between floats and ints in Javascript?
See also
Another relevant answer with some examples of how to handle the calculations:
Node giving strange output on sum of particular float digits
In situations like these you would tipically rather make use of an epsilon estimation.
Something like (pseudo code)
if (abs(((.2 + .1) * 10) - 3) > epsilon)
where epsilon is something like 0.00000001, or whatever precision you require.
Have a quick read at Comparing floating point numbers
(Math.floor(( 0.1+0.2 )*1000))/1000
This will reduce the precision of float numbers but solves the problem if you are not working with very small values.
For example:
.1+.2 =
0.30000000000000004
after the proposed operation you will get 0.3 But any value between:
0.30000000000000000
0.30000000000000999
will be also considered 0.3
There are libraries that seek to solve this problem but if you don't want to include one of those (or can't for some reason, like working inside a GTM variable) then you can use this little function I wrote:
Usage:
var a = 194.1193;
var b = 159;
a - b; // returns 35.11930000000001
doDecimalSafeMath(a, '-', b); // returns 35.1193
Here's the function:
function doDecimalSafeMath(a, operation, b, precision) {
function decimalLength(numStr) {
var pieces = numStr.toString().split(".");
if(!pieces[1]) return 0;
return pieces[1].length;
}
// Figure out what we need to multiply by to make everything a whole number
precision = precision || Math.pow(10, Math.max(decimalLength(a), decimalLength(b)));
a = a*precision;
b = b*precision;
// Figure out which operation to perform.
var operator;
switch(operation.toLowerCase()) {
case '-':
operator = function(a,b) { return a - b; }
break;
case '+':
operator = function(a,b) { return a + b; }
break;
case '*':
case 'x':
precision = precision*precision;
operator = function(a,b) { return a * b; }
break;
case '÷':
case '/':
precision = 1;
operator = function(a,b) { return a / b; }
break;
// Let us pass in a function to perform other operations.
default:
operator = operation;
}
var result = operator(a,b);
// Remove our multiplier to put the decimal back.
return result/precision;
}
Understanding rounding errors in floating point arithmetic is not for the faint-hearted! Basically, calculations are done as though there were infinity bits of precision available. The result is then rounded according to rules laid down in the relevant IEEE specifications.
This rounding can throw up some funky answers:
Math.floor(Math.log(1000000000) / Math.LN10) == 8 // true
This an an entire order of magnitude out. That's some rounding error!
For any floating point architecture, there is a number that represents the smallest interval between distinguishable numbers. It is called EPSILON.
It will be a part of the EcmaScript standard in the near future. In the meantime, you can calculate it as follows:
function epsilon() {
if ("EPSILON" in Number) {
return Number.EPSILON;
}
var eps = 1.0;
// Halve epsilon until we can no longer distinguish
// 1 + (eps / 2) from 1
do {
eps /= 2.0;
}
while (1.0 + (eps / 2.0) != 1.0);
return eps;
}
You can then use it, something like this:
function numericallyEquivalent(n, m) {
var delta = Math.abs(n - m);
return (delta < epsilon());
}
Or, since rounding errors can accumulate alarmingly, you may want to use delta / 2 or delta * delta rather than delta.
You need a bit of error control.
Make a little double comparing method:
int CompareDouble(Double a,Double b) {
Double eplsilon = 0.00000001; //maximum error allowed
if ((a < b + epsilon) && (a > b - epsilon)) {
return 0;
}
else if (a < b + epsilon)
return -1;
}
else return 1;
}
As I found it while working with monetary values, I found a solution just by changing the values to cents, so I did the following:
result = ((value1*100) + (value2*100))/100;
Working with monetary values, we have only two decimal houses, thats why I multiplied and dived by 100.
If you're going to work with more decimal houses, you'll have to multiply the amount of decimal houses by then, having:
.0 -> 10
.00 -> 100
.000 -> 1000
.0000 -> 10000
...
With this, you'll always dodge working with decimal values.
Convert the decimals into integers with multiplication, then at the end convert back the result by dividing it with the same number.
Example in your case:
(0.2 * 100 + 0.1 * 100) / 100 * 10 === 3