how I should avoid decimal rounding in javascript
suppose I have input like
input : 99999999999.999999
Expected output : 99999999999.999999
but i am getting output like
100000000000
here, internally javascript rounding the decimal place.
please let me know how should I avoid this javascript rounding???.
For example:
var test = 99999999999.999999;
console.log(test); //This will print 100000000000 instead
As #Aliendroid suggested, you can use the BigDecimal.js library. In my perspective, this is the best way to handle double and floats in JavaScript
To answer to your question more specifically, you can actually do this:
var test_number = new BigDecimal('99999999999.999999');
console.log(test_number.setScale(6).toString());
and to your original question:
please let me know how should I avoid this javascript rounding???
Well you can't as there is not double number in JavaScript, only float. So for example if you do something like this:
console.log(99999999999.99); //This is a float number
This will actually output: 99999999999.99
It is NOT Rounding
It is floating point error
learn floating point number in programming !
use string if needed and some Big number library
Ref:
http://floating-point-gui.de/
https://github.com/dtrebbien/BigDecimal.js
Related
I am using toFixed but the method does not operate as expected
parseFloat(19373.315).toFixed(2);
//19373.31 Chrome
Expected Output : 19373.32
parseFloat(9373.315).toFixed(2);
// 9373.32 Working fine
Why does the first example round down, whereas the second example round up?
The problem is that binary floating point representation of most decimal fractions is not exact. The internal representation of 19373.315 may actually be something like 19373.314999999, so toFixed rounds down, while 19373.315 might be 19373.315000001, which rounds up.
Why does the first example round down, whereas the second example round up?
Look at the binary representation of the two values in memory.
const farr = new Float64Array(2);
farr[0] = 19373.315;
farr[1] = 9373.315;
const uarr = new Uint32Array(farr.buffer);
console.log(farr[0], uarr[1].toString(2).padStart(32, 0) + uarr[0].toString(2).padStart(32, 0));
console.log(farr[1], uarr[3].toString(2).padStart(32, 0) + uarr[2].toString(2).padStart(32, 0));
Without diving into the details, we can see that the second value has an additional '1' at the end, which is lost in the first larger value when it is fit into 64 bits.
Other answers have explained why, I would suggest using a library like numeral.js which will round things as you would expect.
Assuming toFixed casts to 32-bit float;
Check with this utility...
19373.315 is stored as 19373.314453125 (an error of -0.000546875) in 32-bit floating point format.
This is despite (19373.315).toFixed(4) coming out as 19373.3150.
Even if this is "expected" or "intended", I'd still report it as a bug.
It should use a double during the rounding check, and thus proper rounding during conversion to fixed string.
I think the spec even says so. :\
In the V8 javascript engine source, the Number.prototype.toFixed function invokes DoubleToFixedCString in this file ...
There's probably some inappropriate optimization in there... (Looking into it.)
I'd suggest submitting an additional test case for V8 with 19373.315 specifically.
(19373.3150).toFixed(39) yields 19373.314999999998690327629446983337402343750.
Rounding occurs once to bring it up to 19373.315 - which is correct - but not at the right digit when rounding to 2 digits.
I think this should have a second pass on rounding here to catch edge cases like this. I think it might have to round to n+1 digits, then again to n digits. Maybe there's some other clever way to fix it though.
function toFixedFixed(a,n) {
return (a|0) + parseFloat((a % 1).toFixed(n+1)).toFixed(n).substr(1);
}
console.log(toFixedFixed(19373.315,2)); // "19373.32"
console.log(toFixedFixed(19373.315,3)); // "19373.315"
console.log(toFixedFixed(19373.315,4)); // "19373.3150"
console.log(toFixedFixed(19373.315,37)); // "19373.3149999999986903276294469833374023438"
console.log(toFixedFixed(19373.315,38)); // "19373.31499999999869032762944698333740234375"
console.log(toFixedFixed(19373.315,39)); // "19373.314999999998690327629446983337402343750"
(Adopted from my comments on Vahid Rahmani's answer, who is correct.)
I am using Math.pow() function in my code but when I try to execute below condition, this function return infinity which is not required. I am looking for an alternate solutions.
math.pow(451939.27436410653, 299);
Please help if anyone any idea
Use logs
What result were you expecting? The result is extremely large and exceeds the ability of the conventional floating point format to represent. I would be surprised if this was really necessary in a real-world calculation. Can you provide some context?
If really necessary, perhaps you could resolve the difficulties by using logarithms. If y=Math.pow(451939,299) then
Math.log(y) = Math.log(451939) * 299.
You could do any multiplication/division by adding/subtracting logs, and then do a Math.exp at the end to generate your result.
This may be easier than using a special library like bignumber.js for arbitrary-precision arithmetic. For example, the code below returns "7.395117980030695 x 10^ 1690", which has 1691 digits before the decimal point.
let log10Y=Math.log(451939.27436410653)*299/Math.log(10);
let b = Math.floor(log10Y);
let a = log10Y-b;
console.log("Answer: ",10**a," x 10^",b);
If you want to store such enormous numbers, you can use a library like bignumber.js. It stores floating-point values with an exponent as large as necessary to store them.
I want to use toPrecision() to reduce the size of a number before I display it. However, I sometimes cannot multiply output of the function by another number without gaining a small rounding error. See the code sample below:
var x = 0.0197992182093305
alert (x.toPrecision(4)) //Correct: 0.01980
alert (Number(x.toPrecision(4))) //Correct: 0.0198
alert( Number(x.toPrecision(4)) * 100) //Incorrect: 1.9800000000000002
JSFiddle: http://jsfiddle.net/ueLsL460/4/ What's going on here?
Based on what I understand, Number(x.toPrecision(4)) * 100 creates a new Number object which will not inherit the precision of the parent.
If you still want it to be precise after Math, you need to put it in precision again.
alert((x * 100).toPrecision(4));
Technically, it's not an error. It's just the way javascript is supposed to work.
The use of primitive constructors is not that ideal, unless you are trying to do something trivial. Can you please try to do the code on the following fiddle and see if this will do for you?
http://jsfiddle.net/ueLsL460/5/
var x = 0.0197992182093305;
alert((x * 100).toPrecision(4));
Javascript doesn't have a decimal equivalent - so in your case floating points are used. What this means is that Number(x.toPrecision(4)) doesn't give you exactly 0.0198, but something the FP binary number closest to 0.0198. So any arithmetic you do will be subject to the loss of precision introduced in floating point arithmetic. You can see the same effect if you do
alert(0.0198 * 100);
By the way
alert(0.0198 * 10 * 10);
gives you no problem (the loss of precision does not build up enough to make it into the digits Javascript deems to display) - but that's for this particular number alone.
I need to parse a json that contains a long number (that was produces in a java servlet). The problem is the long number gets rounded.
When this code is executed:
var s = '{"x":6855337641038665531}';
var obj = JSON.parse(s);
alert (obj.x);
the output is:
6855337641038666000
see an example here: http://jsfiddle.net/huqUh/
why is that, and how can I solve it?
As others have stated, this is because the number is too big. However, you can work around this limitation by sending the number as a string like so:
var s = '{"x":"6855337641038665531"}';
Then instead of using JSON.parse(), you can use a library such as javascript-bignum to work with the number.
It's too big of a number. JavaScript uses double-precision floats for numbers, and they have about 15 digits of precision (in base 10). The highest integer that JavaScript can reliably save is something like 251.
The solution is to use reasonable numbers. There is no real way to handle such large numbers.
The largest number JavaScript can handle without loss of precision is 9007199254740992.
I faced this issue some time ago, I was able to solve using this lib: https://github.com/josdejong/lossless-json
You can check this example:
let text = '{"normal":2.3,"long":123456789012345678901,"big":2.3e+500}';
// JSON.parse will lose some digits and a whole number:
console.log(JSON.stringify(JSON.parse(text)));
// '{"normal":2.3,"long":123456789012345680000,"big":null}' WHOOPS!!!
// LosslessJSON.parse will preserve big numbers:
console.log(LosslessJSON.stringify(LosslessJSON.parse(text)));
// '{"normal":2.3,"long":123456789012345678901,"big":2.3e+500}'
Why is it if I do this in javascript, I get the following result:
1234.56 * 10 = 12345.599999999999
It should be 123456. How can I get around this problem?
Thanks.
Floating points are not exact, since there are ifinite numbers at their range [or in any range to be more exact], and only a finite number of bits to store this data.
Have a look at what every programmer should know about floating point arithmetics.
Another easy solution:
parseFloat((1234.56 * 10).toPrecision(12))
and the result will be: 12345.6, and YES... it works with decimal numbers.
As the others said, floating points and so on.
Easy solution would be to do something like this:
var answer = parseInt(1234.56 * 10);
Or just use Math.round?
All numbers in JS are internally defined by float and drop the less significant digits if needed.
(10000000000000000000000000000 + 1) == 10000000000000000000000000000
// this will return true
And javascript is well known for droping bits quite often in numbers. So handle with care