I'd like to round at most 2 decimal places, but only if necessary.
Input:
10
1.7777777
9.1
Output:
10
1.78
9.1
How can I do this in JavaScript
?
I'd like to round at most 2 decimal places, but only if necessary.
Input:
10
1.7777777
9.1
Output:
10
1.78
9.1
How can I do this in JavaScript
?
toFixed(2)
here 2 is number of digits upto which we want to round this num.If the value is a text type:
If the value is a number:
There is a downside that values like 1.5 will give "1.50" as the output. A fix suggested by @minitech:
It seems like
Math.round
is a better solution. But it is not! In some cases it will NOT round correctly:toFixed() also will NOT round correctly in some cases (tested in Chrome v.55.0.2883.87)!
Examples:
I guess, this is because 1.555 is actually something like float 1.55499994 behind the scenes.
Solution 1 is to use a script with required rounding algorithm, for example:
https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview
Solution 2 is to avoid front end calculations and pull rounded values from the backend server.
This question is complicated.
Suppose we have a function,
roundTo2DP(num)
, that takes a float as an argument and returns a value rounded to 2 decimal places. What should each of these expressions evaluate to?roundTo2DP(0.014999999999999999)
roundTo2DP(0.0150000000000000001)
roundTo2DP(0.015)
The 'obvious' answer is that the first example should round to 0.01 (because it's closer to 0.01 than to 0.02) while the other two should round to 0.02 (because 0.0150000000000000001 is closer to 0.02 than to 0.01, and because 0.015 is exactly halfway between them and there is a mathematical convention that such numbers get rounded up).
The catch, which you may have guessed, is that
roundTo2DP
cannot possibly be implemented to give those obvious answers, because all three numbers passed to it are the same number. IEEE 754 binary floating point numbers (the kind used by JavaScript) can't exactly represent most non-integer numbers, and so all three numeric literals above get rounded to a nearby valid floating point number. This number, as it happens, is exactly0.01499999999999999944488848768742172978818416595458984375
which is closer to 0.01 than to 0.02.
You can see that all three numbers are the same at your browser console, Node shell, or other JavaScript interpreter. Just compare them:
So when I write
m = 0.0150000000000000001
, the exact value ofm
that I end up with is closer to0.01
than it is to0.02
. And yet, if I convertm
to a String...... I get 0.015, which should round to 0.02, and which is noticeably not the 56-decimal-place number I earlier said that all of these numbers were exactly equal to. So what dark magic is this?
The answer can be found in the ECMAScript specification, in section 7.1.12.1: ToString applied to the Number type. Here the rules for converting some Number m to a String are laid down. The key part is point 5, in which an integer s is generated whose digits will be used in the String representation of m:
The key part here is the requirement that "k is as small as possible". What that requirement amounts to is a requirement that, given a Number
m
, the value ofString(m)
must have the least possible number of digits while still satisfying the requirement thatNumber(String(m)) === m
. Since we already know that0.015 === 0.0150000000000000001
, it's now clear whyString(0.0150000000000000001) === '0.015'
must be true.Of course, none of this discussion has directly answered what
roundTo2DP(m)
should return. Ifm
's exact value is 0.01499999999999999944488848768742172978818416595458984375, but its String representation is '0.015', then what is the correct answer - mathematically, practically, philosophically, or whatever - when we round it to two decimal places?There is no single correct answer to this. It depends upon your use case. You probably want to respect the String representation and round upwards when:
On the other hand, you probably want to respect the binary floating point value and round downwards when your value is from an inherently continuous scale - for instance, if it's a reading from a sensor.
These two approaches require different code. To respect the String representation of the Number, we can (with quite a bit of reasonably subtle code) implement our own rounding that acts directly on the String representation, digit by digit, using the same algorithm you would've used in school when you were taught how to round numbers. Below is an example which respects the OP's requirement of representing the number to 2 decimal places "only when necessary" by stripping trailing zeroes after the decimal point; you may, of course, need to tweak it to your precise needs.
Example usage:
The function above is probably what you want to use to avoid users ever witnessing numbers that they have entered being rounded wrongly.
(As an alternative, you could also try the round10 library which provides a similarly-behaving function with a wildly different implementation.)
But what if you have the second kind of Number - a value taken from a continuous scale, where there's no reason to think that approximate decimal representations with fewer decimal places are more accurate than those with more? In that case, we don't want to respect the String representation, because that representation (as explained in the spec) is already sort-of-rounded; we don't want to make the mistake of saying "0.014999999...375 rounds up to 0.015, which rounds up to 0.02, so 0.014999999...375 rounds up to 0.02".
Here we can simply use the built-in
toFixed
method. Note that by callingNumber()
on the String returned bytoFixed
, we get a Number whose String representation has no trailing zeroes (thanks to the way JavaScript computes the String representation of a Number, discussed earlier in this answer).A precise rounding method. Source: Mozilla
Examples:
MarkG's answer is the correct one. Here's a generic extension for any number of decimal places.
Usage:
Unit test: