Rounding numbers to 8 decimals - javascript

I have this Function, it rounds all numbers to 8 decimals.
exports.roundDown = function(number, decimals) {
try {
if (!exports.isNumeric(number)) {
return number;
}
decimals = decimals || 8;
if (!exports.isNumeric(decimals)) {
return number;
}
const ret = ( Math.floor( number * Math.pow(10, decimals) ) / Math.pow(10, decimals)*1);
return ret; //(ret < 0.000001) ? 0 : ret;
} catch(e) {
return number;
}
}
The problem I have is that numbers like 0.00000003 are rounded to 0.00000002, instead to send the real number (0.00000003), other numbers work fine.
Any idea how to fix this?

Have you tried the toFixed?
var num = 0.00000002473;
var n = num.toFixed(8);
//n contains 0.00000002

The reason is, that 0.00000003 does not exists. So you can't never round a number to this value. On scanning, it is binary rounded to the nearest possible number. toPrecision(18) shows the number more exact:
(0.00000003).toPrecision(18) // "2.99999999999999973e-8"
And that is why toFixed()returns a string and not a number. In other words: It is impossible to round number to exact 8 decimal digits, except it is binary based number like 0.5, 0.125

Related

How to truncate decimals in JavaScript without Math library?

I need numbers to have only 2 decimals (as in money), and I was using this:
Number(parseFloat(Math.trunc(amount_to_truncate * 100) / 100));
But I can no longer support the Math library.
How can I achieve this without the Math library AND withou rounding the decimals?
You can use toFixed
Number(amount_to_truncate.toFixed(2))
If you are sure that your input always will be lower or equal than 21474836.47 ((2^31 - 1) / 100) (32bit) then:
if you need as string (to make sure result will have 2 decimals)
((amount_to_truncate * 100|0)/100).toFixed(2)
Otherwise
((amount_to_truncate * 100|0)/100)
Else: See Nina Schols's answer
console.log((((15.555 * 100)|0)/100)) // will not round: 15.55
console.log((((15 * 100)|0)/100).toFixed(2)) // will not round: 15.55
Make it simple
const trunc = (n, decimalPlaces) => {
const decimals = decimalPlaces ? decimalPlaces : 2;
const asString = n.toString();
const pos = asString.indexOf('.') != -1 ? asString.indexOf('.') + decimals + 1 : asString.length;
return parseFloat(n.toString().substring(0, pos));
};
console.log(trunc(3.14159265359));
console.log(trunc(11.1111111));
console.log(trunc(3));
console.log(trunc(11));
console.log(trunc(3.1));
console.log(trunc(11.1));
console.log(trunc(3.14));
console.log(trunc(11.11));
console.log(trunc(3.141));
console.log(trunc(11.111));
The only thing I see wrong with toFixed is that it rounds the precision which OP specifically states they don't want to do. Truncate is more equivalent to floor for positive numbers and ceil for negative than round or toFixed. On the MDN page for the Math.trunc there is a polyfill replacement function that would do what OP is expecting.
Math.trunc = Math.trunc || function(x) {
return x - x % 1;
}
If you just used that, then the code wouldn't have to change.
You could use parseInt for a non rounded number.
console.log(parseInt(15.555 * 100, 10) / 100); // 15.55 no rounding
console.log((15.555 * 100 | 0) / 100); // 15.55 no rounding, 32 bit only
console.log((15.555).toFixed(2)); // 15.56 rounding
Try using toFixed:
number.toFixed(2)
Truncate does also a rounding, so your statement: "I need numbers to have only 2 decimals ... without rounding the decimals" seems to me a little bit convoluted and would lead to a long discussion.
Beside this, when dealing with money, the problem isn't Math but how you are using it. I suggest you read the Floating-point cheat sheet for JavaScript - otherwise you will fail even with a simple calculation like 1.40 - 1.00.
The solution to your question is to use a well-tested library for arbitrary-precision decimals like bignumber.js or decimals.js (just as an example).
EDIT:
If you absolutely need a snippet, this is how i did it some time ago:
function round2(d) { return Number(((d+'e'+2)|0)+'e-'+2); }
You could parseInt to truncate, then divide by 100 and parseFloat.
var num = 123.4567;
num=parseInt(num*100);
num=parseFloat(num/100);
alert(num);
See fiddle
Edit: in order to deal with javascript math craziness, you can use .toFixed and an additional digit of multiplication/division:
var num = 123.4567;
num = (num*1000).toFixed();
num = parseInt(num/10);
num = parseFloat(num/100);
alert(num);
Updated fiddle
This was a lot easier than I thought:
const trunc = (number, precision) => {
let index = number.toString().indexOf(".");
let subStr;
// in case of no decimal
if (index === -1) {
subStr = number.toString();
}
// in case of 0 precision
else if (precision === 0) {
subStr = number.toString().substring(0, index);
}
// all else
else {
subStr = number.toString().substring(0, index + 1 + precision);
}
return parseFloat(subStr);
};
let x = trunc(99.12, 1);
console.log("x", x);
You can try this
function trunc(value){
return (!!value && typeof value == "number")? value - value%1 : 0;
}
console.log(trunc(1.4));
console.log(trunc(111.9));
console.log(trunc(0.4));
console.log(trunc("1.4"));

toFixed method without rounding to five digit

I have a number var x = 2.305185185185195;
x = x.toFixed(5);
x = 2.30519 but I require this without rounding i.e. 2.30518
I read some thread with two decimal places but could not find for five decimal places.
Any help would be appreciated.
You can use an apropriate factor and floor it and return the result of the division.
Basically this solution moves the point to the left with a factor of 10^d and gets an integer of that and divided the value with the former factor to get the right digits.
function getFlooredFixed(v, d) {
return (Math.floor(v * Math.pow(10, d)) / Math.pow(10, d)).toFixed(d);
}
var x = 2.305185185185195;
document.write(getFlooredFixed(x, 5));
If you need only a "part" of a number with a floating point without rounding, you can just "cut" it:
function cutNumber(number, digitsAfterDot) {
const str = `${number}`;
return str.slice(0, str.indexOf('.') + digitsAfterDot + 1);
}
const x = 2.305185185185195;
console.log(cutNumber(x, 5)); // 2.30518
This method is fast (https://jsfiddle.net/93m8akzo/1/) and its execution time doesn't depend on number or digitsAfterDot values.
You can also "play around" with both functions in a given fiddle for a better understanding of what they do.
You can read more about slice() method here - MDN documentation
NOTE This function is only an example, don't use it in production applications.
You should definitely add input values validation and errors handling!
The Math.trunc() function returns the integer part of a number by
removing any fractional digits
So you can multiply the number by 10^n where n is the desired number of precision, truncate the decimal part using Math.trunc(), divide by the same number (10^n) and apply toFixed() to format it (in order to get the form of 2.30 instead of 2.3 for example)
var x = 2.305185185185195;
console.log((Math.trunc(x*100000)/100000).toFixed(5));
I have sorted it out by adding a small amount if the decimal is 5, then rounding as usual:
function(value, decimals) {
var decimals = decimals || 2;
if( isNaN(value) ){ return 0; }
var decimalPart = value.toString().trim().split('.').pop(),
extra = decimalPart.substr(decimals, decimalPart.length - decimals);
if( extra == '5' &&
decimalPart.length > decimals
){
value = parseFloat(value) + (1 / ( Math.pow(10, decimals + 5) ) );
}
return Number( parseFloat( value ).toFixed( decimals ) );
}

How to get numbers with precision without round up or round down [duplicate]

This question already has answers here:
Truncate (not round off) decimal numbers in javascript
(32 answers)
Closed 8 years ago.
Im trying to get a number with precision to 2 decimals, for example this is what I want, if I have the numbers:
3.456 it must returns me 3.45
3.467 = 3.46
3.435 = 3.43
3.422 = 3.42
I don't want to round up or down or whatever just to get the numbers I see 2 places after .
Thanks
Okay, here is the answer
var a = 5.469923;
var truncated = Math.floor(a * 100) / 100; // = 5.46
Thanks everyone for helping.
Assuming Positive Numbers:
The code:
function roundDown(num,dec) {
return Math.floor(num*Math.pow(10,dec))/Math.pow(10,dec);
}
The test:
function test(num, expected) {
var val = roundDown(num,2);
var pass = val === expected;
var result = pass ? "PASS" : "FAIL";
var color = pass ? "GREEN" : "RED";
console.log("%c" + result + " : " + num + " : " + val, "background-color:" + color);
}
test(3.456, 3.45);
test(3.467, 3.46);
test(3.435, 3.43);
test(3.422, 3.42);
Basic idea:
Take number
Multiply the number to move decimal place to number of significant figures you want
Floor the number to remove the trailing numbers
Divide number back to get the correct value
If you want to have a trailing zero, you need to use toFixed(2) which will turn the number to a string.
function roundDown(num,dec) {
return Math.floor(num*Math.pow(10,dec))/Math.pow(10,dec).toFixed(2);
}
and the test cases would need to change to
test(3.456, "3.45");
test(3.467, "3.46");
test(3.435, "3.43");
test(3.422, "3.42");
Another option is a regular expression.
function roundDown(num,dec) {
var x = num.toString().match(/(\d*(\.\d{2}))?/);
return x ? parseFloat(x[0]) : "";
//return x ? parseFloat(x[0]).toFixed(2) : "";
}
Use String operation to achieve it.
var n = 4.56789;
var numbers = n.toString().split('.');
result = Number(numbers[0]+"."+numbers[1].substr(0,2));
alert(result);
Fiddle
You are looking at the number as if it were a string of digits, rather than a single value, so treat it like a string.-
function cutoff(n, cut){
var parts= String(n).split('.'), dec= parts[1];
if(!cut) return parts[0];
if(dec && dec.length>cut) parts[1]= dec.substring(0, cut);
return parts.join('.');
}
var n= 36.938;
cutoff(n,2)
/* returned value: (String)
36.93
*/
If you want a number, +cutoff(n,2) will do.
function truncateDec(num, decplaces) {
return (num*Math.pow(10,decplaces) - num*Math.pow(10,decplaces) % 1)/Math.pow(10,decplaces);
}
alert(truncateDec(105.678, 2)); // Returns 105.67
alert(truncateDec(105.678, 1)); // Returns 105.6
This could be simplified further if you do not require a dynamic number of decimal places
function truncateDec(num) {
return (num*100 - num*100 % 1)/100;
}
alert(truncateDec(105.678)); // Returns 105.67
How does it work?
The concept is that the main truncation works by getting the remainder from dividing the original decimal by 1. The remainder will be whatever is in the decimals places. The remainder operator is %
105.678 % 1 = 0.678
By subtracting this remainder from the original number, we will be left with only the integer.
105.678 - 0.678 = 105
To include x number of decimal places, we need to first multiply the original number by 10 to the power of that number of decimal places, thereby shifting the decimal backward by x positions. In this example, we will take x = 2.
105.678 * 10^2
= 105.678 * 100
= 10567.8
Now, we repeat the same procedure by subtracting the remainder again.
10567.8 % 1 = 0.8
10567.8 - 0.8 = 10567
And to return back to the number of places as requested, we divide it back by 10^x
10567 / 10^2
= 10567 / 100
= 105.67
Hope it helps!

How do I get the decimal places of a floating point number in Javascript?

What I would like to have is the almost opposite of Number.prototype.toPrecision(), meaning that when i have number, how many decimals does it have? E.g.
(12.3456).getDecimals() // 4
For anyone wondering how to do this faster (without converting to string), here's a solution:
function precision(a) {
var e = 1;
while (Math.round(a * e) / e !== a) e *= 10;
return Math.log(e) / Math.LN10;
}
Edit: a more complete solution with edge cases covered:
function precision(a) {
if (!isFinite(a)) return 0;
var e = 1, p = 0;
while (Math.round(a * e) / e !== a) { e *= 10; p++; }
return p;
}
One possible solution (depends on the application):
var precision = (12.3456 + "").split(".")[1].length;
If by "precision" you mean "decimal places", then that's impossible because floats are binary. They don't have decimal places, and most values that have a small number of decimal places have recurring digits in binary, and when they're translated back to decimal that doesn't necessarily yield the original decimal number.
Any code that works with the "decimal places" of a float is liable to produce unexpected results on some numbers.
There is no native function to determine the number of decimals. What you can do is convert the number to string and then count the offset off the decimal delimiter .:
Number.prototype.getPrecision = function() {
var s = this + "",
d = s.indexOf('.') + 1;
return !d ? 0 : s.length - d;
};
(123).getPrecision() === 0;
(123.0).getPrecision() === 0;
(123.12345).getPrecision() === 5;
(1e3).getPrecision() === 0;
(1e-3).getPrecision() === 3;
But it's in the nature of floats to fool you. 1 may just as well be represented by 0.00000000989 or something. I'm not sure how well the above actually performs in real life applications.
Basing on #blackpla9ue comment and considering numbers exponential format:
function getPrecision (num) {
var numAsStr = num.toFixed(10); //number can be presented in exponential format, avoid it
numAsStr = numAsStr.replace(/0+$/g, '');
var precision = String(numAsStr).replace('.', '').length - num.toFixed().length;
return precision;
}
getPrecision(12.3456); //4
getPrecision(120.30003300000); //6, trailing zeros are truncated
getPrecision(15); //0
getPrecision(120.000)) //0
getPrecision(0.0000005); //7
getPrecision(-0.01)) //2
Try the following
function countDecimalPlaces(number) {
var str = "" + number;
var index = str.indexOf('.');
if (index >= 0) {
return str.length - index - 1;
} else {
return 0;
}
}
Based on #boolean_Type's method of handling exponents, but avoiding the regex:
function getPrecision (value) {
if (!isFinite(value)) { return 0; }
const [int, float = ''] = Number(value).toFixed(12).split('.');
let precision = float.length;
while (float[precision - 1] === '0' && precision >= 0) precision--;
return precision;
}
Here are a couple of examples, one that uses a library (BigNumber.js), and another that doesn't use a library. Assume you want to check that a given input number (inputNumber) has an amount of decimal places that is less than or equal to a maximum amount of decimal places (tokenDecimals).
With BigNumber.js
import BigNumber from 'bignumber.js'; // ES6
// const BigNumber = require('bignumber.js').default; // CommonJS
const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Convert to BigNumber
const inputNumberBn = new BigNumber(inputNumber);
// BigNumber.js API Docs: http://mikemcl.github.io/bignumber.js/#dp
console.log(`Invalid?: ${inputNumberBn.dp() > tokenDecimals}`);
Without BigNumber.js
function getPrecision(numberAsString) {
var n = numberAsString.toString().split('.');
return n.length > 1
? n[1].length
: 0;
}
const tokenDecimals = 18;
const inputNumber = 0.000000000000000001;
// Conversion of number to string returns scientific conversion
// So obtain the decimal places from the scientific notation value
const inputNumberDecimalPlaces = inputNumber.toString().split('-')[1];
// Use `toFixed` to convert the number to a string without it being
// in scientific notation and with the correct number decimal places
const inputNumberAsString = inputNumber.toFixed(inputNumberDecimalPlaces);
// Check if inputNumber is invalid due to having more decimal places
// than the permitted decimal places of the token
console.log(`Invalid?: ${getPrecision(inputNumberAsString) > tokenDecimals}`);
Assuming number is valid.
let number = 0.999;
let noOfPlaces = number.includes(".") //includes or contains
? number.toString().split(".").pop().length
: 0;
5622890.31 ops/s (91.58% slower):
function precision (n) {
return (n.toString().split('.')[1] || '').length
}
precision(1.0123456789)
33004904.53 ops/s (50.58% slower):
function precision (n) {
let e = 1
let p = 0
while(Math.round(n * e) / e !== n) {
e *= 10
p++
}
return p
}
precision(1.0123456789)
62610550.04 ops/s (6.25% slower):
function precision (n) {
let cur = n
let p = 0
while(!Number.isInteger(cur)) {
cur *= 10
p++
}
return p
}
precision(1.0123456789)
66786361.47 ops/s (fastest):
function precision (n) {
let cur = n
let p = 0
while(Math.floor(cur) !== cur) {
cur *= 10
p++
}
return p
}
precision(1.0123456789)
Here is a simple solution
First of all, if you pass a simple float value as 12.1234 then most of the below/above logics may work but if you pass a value as 12.12340, then it may exclude a count of 0. For e.g, if the value is 12.12340 then it may give you a result of 4 instead of 5. As per your problem statement, if you ask javascript to split and count your float value into 2 integers then it won't include trailing 0s of it.
Let's satisfy our requirement here with a trick ;)
In the below function you need to pass a value in string format and it will do your work
function getPrecision(value){
a = value.toString()
console.log('a ->',a)
b = a.split('.')
console.log('b->',b)
return b[1].length
getPrecision('12.12340') // Call a function
For an example, run the below logic
value = '12.12340'
a = value.toString()
b = a.split('.')
console.log('count of trailing decimals->',b[1].length)
That's it! It will give you the exact count for normal float values as well as the float values with trailing 0s!
Thank you!
This answer adds to Mourner's accepted solution by making the function more robust. As noted by many, floating point precision makes such a function unreliable. For example, precision(0.1+0.2) yields 17 rather than 1 (this might be computer specific, but for this example see https://jsfiddle.net/s0v17jby/5/).
IMHO, there are two ways around this: 1. either properly define a decimal type, using e.g. https://github.com/MikeMcl/decimal.js/, or 2. define an acceptable precision level which is both OK for your use case and not a problem for the js Number representation (8 bytes can safely represent a total of 16 digits AFAICT). For the latter workaround, one can write a more robust variant of the proposed function:
const MAX_DECIMAL_PRECISION = 9; /* must be <= 15 */
const maxDecimalPrecisionFloat = 10**MAX_DECIMAL_PRECISION;
function precisionRobust(a) {
if (!isFinite(a)) return 0;
var e = 1, p = 0;
while ( ++p<=MAX_DECIMAL_PRECISION && Math.round( ( Math.round(a * e) / e - a ) * maxDecimalPrecisionFloat ) !== 0) e *= 10;
return p-1;
}
In the above example, the maximum precision of 9 means this accepts up to 6 digits before the decimal point and 9 after (so this would work for numbers less than one million and with a maximum of 9 decimal points). If your use-case numbers are smaller then you can choose to make this precision even greater (but with a maximum of 15). It turns out that, for calculating precision, this function seems to do OK on larger numbers as well (though that would no longer be the case if we were, say, adding two rounded numbers within the precisionRobust function).
Finally, since we now know the maximum useable precision, we can further avoid infinite loops (which I have not been able to replicate but which still seem to cause problems for some).

Formatting a number with exactly two decimals in JavaScript

I have this line of code which rounds my numbers to two decimal places. But I get numbers like this: 10.8, 2.4, etc. These are not my idea of two decimal places so how I can improve the following?
Math.round(price*Math.pow(10,2))/Math.pow(10,2);
I want numbers like 10.80, 2.40, etc. Use of jQuery is fine with me.
To format a number using fixed-point notation, you can simply use the toFixed method:
(10.8).toFixed(2); // "10.80"
var num = 2.4;
alert(num.toFixed(2)); // "2.40"
Note that toFixed() returns a string.
IMPORTANT: Note that toFixed does not round 90% of the time, it will return the rounded value, but for many cases, it doesn't work.
For instance:
2.005.toFixed(2) === "2.00"
UPDATE:
Nowadays, you can use the Intl.NumberFormat constructor. It's part of the ECMAScript Internationalization API Specification (ECMA402). It has pretty good browser support, including even IE11, and it is fully supported in Node.js.
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
console.log(formatter.format(2.005)); // "2.01"
console.log(formatter.format(1.345)); // "1.35"
You can alternatively use the toLocaleString method, which internally will use the Intl API:
const format = (num, decimals) => num.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
console.log(format(2.005)); // "2.01"
console.log(format(1.345)); // "1.35"
This API also provides you a wide variety of options to format, like thousand separators, currency symbols, etc.
This is an old topic but still top-ranked Google results and the solutions offered share the same floating point decimals issue. Here is the (very generic) function I use, thanks to MDN:
function round(value, exp) {
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
As we can see, we don't get these issues:
round(1.275, 2); // Returns 1.28
round(1.27499, 2); // Returns 1.27
This genericity also provides some cool stuff:
round(1234.5678, -2); // Returns 1200
round(1.2345678e+2, 2); // Returns 123.46
round("123.45"); // Returns 123
Now, to answer the OP's question, one has to type:
round(10.8034, 2).toFixed(2); // Returns "10.80"
round(10.8, 2).toFixed(2); // Returns "10.80"
Or, for a more concise, less generic function:
function round2Fixed(value) {
value = +value;
if (isNaN(value))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2)));
// Shift back
value = value.toString().split('e');
return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2);
}
You can call it with:
round2Fixed(10.8034); // Returns "10.80"
round2Fixed(10.8); // Returns "10.80"
Various examples and tests (thanks to #t-j-crowder!):
function round(value, exp) {
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
function naive(value, exp) {
if (!exp) {
return Math.round(value);
}
var pow = Math.pow(10, exp);
return Math.round(value * pow) / pow;
}
function test(val, places) {
subtest(val, places);
val = typeof val === "string" ? "-" + val : -val;
subtest(val, places);
}
function subtest(val, places) {
var placesOrZero = places || 0;
var naiveResult = naive(val, places);
var roundResult = round(val, places);
if (placesOrZero >= 0) {
naiveResult = naiveResult.toFixed(placesOrZero);
roundResult = roundResult.toFixed(placesOrZero);
} else {
naiveResult = naiveResult.toString();
roundResult = roundResult.toString();
}
$("<tr>")
.append($("<td>").text(JSON.stringify(val)))
.append($("<td>").text(placesOrZero))
.append($("<td>").text(naiveResult))
.append($("<td>").text(roundResult))
.appendTo("#results");
}
test(0.565, 2);
test(0.575, 2);
test(0.585, 2);
test(1.275, 2);
test(1.27499, 2);
test(1234.5678, -2);
test(1.2345678e+2, 2);
test("123.45");
test(10.8034, 2);
test(10.8, 2);
test(1.005, 2);
test(1.0005, 2);
table {
border-collapse: collapse;
}
table, td, th {
border: 1px solid #ddd;
}
td, th {
padding: 4px;
}
th {
font-weight: normal;
font-family: sans-serif;
}
td {
font-family: monospace;
}
<table>
<thead>
<tr>
<th>Input</th>
<th>Places</th>
<th>Naive</th>
<th>Thorough</th>
</tr>
</thead>
<tbody id="results">
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I usually add this to my personal library, and after some suggestions and using the #TIMINeutron solution too, and making it adaptable for decimal length then, this one fits best:
function precise_round(num, decimals) {
var t = Math.pow(10, decimals);
return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}
will work for the exceptions reported.
FAST AND EASY
parseFloat(number.toFixed(2))
Example
let number = 2.55435930
let roundedString = number.toFixed(2) // "2.55"
let twoDecimalsNumber = parseFloat(roundedString) // 2.55
let directly = parseFloat(number.toFixed(2)) // 2.55
One way to be 100% sure that you get a number with 2 decimals:
(Math.round(num*100)/100).toFixed(2)
If this causes rounding errors, you can use the following as James has explained in his comment:
(Math.round((num * 1000)/10)/100).toFixed(2)
I don't know why can't I add a comment to a previous answer (maybe I'm hopelessly blind, I don't know), but I came up with a solution using #Miguel's answer:
function precise_round(num,decimals) {
return Math.round(num*Math.pow(10, decimals)) / Math.pow(10, decimals);
}
And its two comments (from #bighostkim and #Imre):
Problem with precise_round(1.275,2) not returning 1.28
Problem with precise_round(6,2) not returning 6.00 (as he wanted).
My final solution is as follows:
function precise_round(num,decimals) {
var sign = num >= 0 ? 1 : -1;
return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals);
}
As you can see I had to add a little bit of "correction" (it's not what it is, but since Math.round is lossy - you can check it on jsfiddle.net - this is the only way I knew how to "fix" it). It adds 0.001 to the already padded number, so it is adding a 1 three 0s to the right of the decimal value. So it should be safe to use.
After that I added .toFixed(decimal) to always output the number in the correct format (with the right amount of decimals).
So that's pretty much it. Use it well ;)
EDIT: added functionality to the "correction" of negative numbers.
toFixed(n) provides n length after the decimal point; toPrecision(x)
provides x total length.
Use this method below
// Example: toPrecision(4) when the number has 7 digits (3 before, 4 after)
// It will round to the tenths place
num = 500.2349;
result = num.toPrecision(4); // result will equal 500.2
AND if you want the number to be fixed use
result = num.toFixed(2);
I didn't find an accurate solution for this problem, so I created my own:
function inprecise_round(value, decPlaces) {
return Math.round(value*Math.pow(10,decPlaces))/Math.pow(10,decPlaces);
}
function precise_round(value, decPlaces){
var val = value * Math.pow(10, decPlaces);
var fraction = (Math.round((val-parseInt(val))*10)/10);
//this line is for consistency with .NET Decimal.Round behavior
// -342.055 => -342.06
if(fraction == -0.5) fraction = -0.6;
val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
return val;
}
Examples:
function inprecise_round(value, decPlaces) {
return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
function precise_round(value, decPlaces) {
var val = value * Math.pow(10, decPlaces);
var fraction = (Math.round((val - parseInt(val)) * 10) / 10);
//this line is for consistency with .NET Decimal.Round behavior
// -342.055 => -342.06
if (fraction == -0.5) fraction = -0.6;
val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
return val;
}
// This may produce different results depending on the browser environment
console.log("342.055.toFixed(2) :", 342.055.toFixed(2)); // 342.06 on Chrome & IE10
console.log("inprecise_round(342.055, 2):", inprecise_round(342.055, 2)); // 342.05
console.log("precise_round(342.055, 2) :", precise_round(342.055, 2)); // 342.06
console.log("precise_round(-342.055, 2) :", precise_round(-342.055, 2)); // -342.06
console.log("inprecise_round(0.565, 2) :", inprecise_round(0.565, 2)); // 0.56
console.log("precise_round(0.565, 2) :", precise_round(0.565, 2)); // 0.57
Here's a simple one
function roundFloat(num,dec){
var d = 1;
for (var i=0; i<dec; i++){
d += "0";
}
return Math.round(num * d) / d;
}
Use like alert(roundFloat(1.79209243929,4));
Jsfiddle
Round down
function round_down(value, decPlaces) {
return Math.floor(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
Round up
function round_up(value, decPlaces) {
return Math.ceil(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
Round nearest
function round_nearest(value, decPlaces) {
return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
Merged https://stackoverflow.com/a/7641824/1889449 and
https://www.kirupa.com/html5/rounding_numbers_in_javascript.htm Thanks
them.
Building on top of Christian C. Salvadó's answer, doing the following will output a Number type, and also seems to be dealing with rounding well:
const roundNumberToTwoDecimalPlaces = (num) => Number(new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(num));
roundNumberToTwoDecimalPlaces(1.344); // => 1.34
roundNumberToTwoDecimalPlaces(1.345); // => 1.35
The difference between the above and what has already been mentioned is that you don't need the .format() chaining when you're using it[, and that it outputs a Number type].
#heridev and I created a small function in jQuery.
You can try next:
HTML
<input type="text" name="one" class="two-digits"><br>
<input type="text" name="two" class="two-digits">​
jQuery
// apply the two-digits behaviour to elements with 'two-digits' as their class
$( function() {
$('.two-digits').keyup(function(){
if($(this).val().indexOf('.')!=-1){
if($(this).val().split(".")[1].length > 2){
if( isNaN( parseFloat( this.value ) ) ) return;
this.value = parseFloat(this.value).toFixed(2);
}
}
return this; //for chaining
});
});
​
DEMO ONLINE:
http://jsfiddle.net/c4Wqn/
The trouble with floating point values is that they are trying to represent an infinite amount of (continuous) values with a fixed amount of bits. So naturally, there must be some loss in play, and you're going to be bitten with some values.
When a computer stores 1.275 as a floating point value, it won't actually remember whether it was 1.275 or 1.27499999999999993, or even 1.27500000000000002. These values should give different results after rounding to two decimals, but they won't, since for computer they look exactly the same after storing as floating point values, and there's no way to restore the lost data. Any further calculations will only accumulate such imprecision.
So, if precision matters, you have to avoid floating point values from the start. The simplest options are to
use a devoted library
use strings for storing and passing around the values (accompanied by string operations)
use integers (e.g. you could be passing around the amount of hundredths of your actual value, e.g. amount in cents instead of amount in dollars)
For example, when using integers to store the number of hundredths, the function for finding the actual value is quite simple:
function descale(num, decimals) {
var hasMinus = num < 0;
var numString = Math.abs(num).toString();
var precedingZeroes = '';
for (var i = numString.length; i <= decimals; i++) {
precedingZeroes += '0';
}
numString = precedingZeroes + numString;
return (hasMinus ? '-' : '')
+ numString.substr(0, numString.length-decimals)
+ '.'
+ numString.substr(numString.length-decimals);
}
alert(descale(127, 2));
With strings, you'll need rounding, but it's still manageable:
function precise_round(num, decimals) {
var parts = num.split('.');
var hasMinus = parts.length > 0 && parts[0].length > 0 && parts[0].charAt(0) == '-';
var integralPart = parts.length == 0 ? '0' : (hasMinus ? parts[0].substr(1) : parts[0]);
var decimalPart = parts.length > 1 ? parts[1] : '';
if (decimalPart.length > decimals) {
var roundOffNumber = decimalPart.charAt(decimals);
decimalPart = decimalPart.substr(0, decimals);
if ('56789'.indexOf(roundOffNumber) > -1) {
var numbers = integralPart + decimalPart;
var i = numbers.length;
var trailingZeroes = '';
var justOneAndTrailingZeroes = true;
do {
i--;
var roundedNumber = '1234567890'.charAt(parseInt(numbers.charAt(i)));
if (roundedNumber === '0') {
trailingZeroes += '0';
} else {
numbers = numbers.substr(0, i) + roundedNumber + trailingZeroes;
justOneAndTrailingZeroes = false;
break;
}
} while (i > 0);
if (justOneAndTrailingZeroes) {
numbers = '1' + trailingZeroes;
}
integralPart = numbers.substr(0, numbers.length - decimals);
decimalPart = numbers.substr(numbers.length - decimals);
}
} else {
for (var i = decimalPart.length; i < decimals; i++) {
decimalPart += '0';
}
}
return (hasMinus ? '-' : '') + integralPart + (decimals > 0 ? '.' + decimalPart : '');
}
alert(precise_round('1.275', 2));
alert(precise_round('1.27499999999999993', 2));
Note that this function rounds to nearest, ties away from zero, while IEEE 754 recommends rounding to nearest, ties to even as the default behavior for floating point operations. Such modifications are left as an exercise for the reader :)
Round your decimal value, then use toFixed(x) for your expected digit(s).
function parseDecimalRoundAndFixed(num,dec){
var d = Math.pow(10,dec);
return (Math.round(num * d) / d).toFixed(dec);
}
Call
parseDecimalRoundAndFixed(10.800243929,4) => 10.80
parseDecimalRoundAndFixed(10.807243929,2) => 10.81
Number(Math.round(1.005+'e2')+'e-2'); // 1.01
This worked for me: Rounding Decimals in JavaScript
With these examples you will still get an error when trying to round the number 1.005 the solution is to either use a library like Math.js or this function:
function round(value: number, decimals: number) {
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
Here is my 1-line solution: Number((yourNumericValueHere).toFixed(2));
Here's what happens:
1) First, you apply .toFixed(2) onto the number that you want to round off the decimal places of. Note that this will convert the value to a string from number. So if you are using Typescript, it will throw an error like this:
"Type 'string' is not assignable to type 'number'"
2) To get back the numeric value or to convert the string to numeric value, simply apply the Number() function on that so-called 'string' value.
For clarification, look at the example below:
EXAMPLE:
I have an amount that has upto 5 digits in the decimal places and I would like to shorten it to upto 2 decimal places. I do it like so:
var price = 0.26453;
var priceRounded = Number((price).toFixed(2));
console.log('Original Price: ' + price);
console.log('Price Rounded: ' + priceRounded);
In general, decimal rounding is done by scaling: round(num * p) / p
Naive implementation
Using the following function with halfway numbers, you will get either the upper rounded value as expected, or the lower rounded value sometimes depending on the input.
This inconsistency in rounding may introduce hard to detect bugs in the client code.
function naiveRound(num, decimalPlaces) {
var p = Math.pow(10, decimalPlaces);
return Math.round(num * p) / p;
}
console.log( naiveRound(1.245, 2) ); // 1.25 correct (rounded as expected)
console.log( naiveRound(1.255, 2) ); // 1.25 incorrect (should be 1.26)
Better implementations
By converting the number to a string in the exponential notation, positive numbers are rounded as expected.
But, be aware that negative numbers round differently than positive numbers.
In fact, it performs what is basically equivalent to "round half up" as the rule, you will see that round(-1.005, 2) evaluates to -1 even though round(1.005, 2) evaluates to 1.01. The lodash _.round method uses this technique.
/**
* Round half up ('round half towards positive infinity')
* Uses exponential notation to avoid floating-point issues.
* Negative numbers round differently than positive numbers.
*/
function round(num, decimalPlaces) {
num = Math.round(num + "e" + decimalPlaces);
return Number(num + "e" + -decimalPlaces);
}
// test rounding of half
console.log( round(0.5, 0) ); // 1
console.log( round(-0.5, 0) ); // 0
// testing edge cases
console.log( round(1.005, 2) ); // 1.01
console.log( round(2.175, 2) ); // 2.18
console.log( round(5.015, 2) ); // 5.02
console.log( round(-1.005, 2) ); // -1
console.log( round(-2.175, 2) ); // -2.17
console.log( round(-5.015, 2) ); // -5.01
If you want the usual behavior when rounding negative numbers, you would need to convert negative numbers to positive before calling Math.round(), and then convert them back to negative numbers before returning.
// Round half away from zero
function round(num, decimalPlaces) {
num = Math.round(Math.abs(num) + "e" + decimalPlaces) * Math.sign(num);
return Number(num + "e" + -decimalPlaces);
}
There is a different purely mathematical technique to perform round-to-nearest (using "round half away from zero"), in which epsilon correction is applied before calling the rounding function.
Simply, we add the smallest possible float value (= 1.0 ulp; unit in the last place) to the number before rounding. This moves to the next representable value after the number, away from zero.
/**
* Round half away from zero ('commercial' rounding)
* Uses correction to offset floating-point inaccuracies.
* Works symmetrically for positive and negative numbers.
*/
function round(num, decimalPlaces) {
var p = Math.pow(10, decimalPlaces);
var e = Number.EPSILON * num * p;
return Math.round((num * p) + e) / p;
}
// test rounding of half
console.log( round(0.5, 0) ); // 1
console.log( round(-0.5, 0) ); // -1
// testing edge cases
console.log( round(1.005, 2) ); // 1.01
console.log( round(2.175, 2) ); // 2.18
console.log( round(5.015, 2) ); // 5.02
console.log( round(-1.005, 2) ); // -1.01
console.log( round(-2.175, 2) ); // -2.18
console.log( round(-5.015, 2) ); // -5.02
This is needed to offset the implicit round-off error that may occur during encoding of decimal numbers, particularly those having "5" in the last decimal position, like 1.005, 2.675 and 16.235. Actually, 1.005 in decimal system is encoded to 1.0049999999999999 in 64-bit binary float; while, 1234567.005 in decimal system is encoded to 1234567.0049999998882413 in 64-bit binary float.
It is worth noting that the maximum binary round-off error is dependent upon (1) the magnitude of the number and (2) the relative machine epsilon (2^-52).
Put the following in some global scope:
Number.prototype.getDecimals = function ( decDigCount ) {
return this.toFixed(decDigCount);
}
and then try:
var a = 56.23232323;
a.getDecimals(2); // will return 56.23
Update
Note that toFixed() can only work for the number of decimals between 0-20 i.e. a.getDecimals(25) may generate a javascript error, so to accomodate that you may add some additional check i.e.
Number.prototype.getDecimals = function ( decDigCount ) {
return ( decDigCount > 20 ) ? this : this.toFixed(decDigCount);
}
Number(((Math.random() * 100) + 1).toFixed(2))
this will return a random number from 1 to 100 rounded to 2 decimal places.
Using this response by reference: https://stackoverflow.com/a/21029698/454827
I build a function to get dynamic numbers of decimals:
function toDec(num, dec)
{
if(typeof dec=='undefined' || dec<0)
dec = 2;
var tmp = dec + 1;
for(var i=1; i<=tmp; i++)
num = num * 10;
num = num / 10;
num = Math.round(num);
for(var i=1; i<=dec; i++)
num = num / 10;
num = num.toFixed(dec);
return num;
}
here working example: https://jsfiddle.net/wpxLduLc/
parse = function (data) {
data = Math.round(data*Math.pow(10,2))/Math.pow(10,2);
if (data != null) {
var lastone = data.toString().split('').pop();
if (lastone != '.') {
data = parseFloat(data);
}
}
return data;
};
$('#result').html(parse(200)); // output 200
$('#result1').html(parse(200.1)); // output 200.1
$('#result2').html(parse(200.10)); // output 200.1
$('#result3').html(parse(200.109)); // output 200.11
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="result"></div>
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
I got some ideas from this post a few months back, but none of the answers here, nor answers from other posts/blogs could handle all the scenarios (e.g. negative numbers and some "lucky numbers" our tester found). In the end, our tester did not find any problem with this method below. Pasting a snippet of my code:
fixPrecision: function (value) {
var me = this,
nan = isNaN(value),
precision = me.decimalPrecision;
if (nan || !value) {
return nan ? '' : value;
} else if (!me.allowDecimals || precision <= 0) {
precision = 0;
}
//[1]
//return parseFloat(Ext.Number.toFixed(parseFloat(value), precision));
precision = precision || 0;
var negMultiplier = value < 0 ? -1 : 1;
//[2]
var numWithExp = parseFloat(value + "e" + precision);
var roundedNum = parseFloat(Math.round(Math.abs(numWithExp)) + 'e-' + precision) * negMultiplier;
return parseFloat(roundedNum.toFixed(precision));
},
I also have code comments (sorry i forgot all the details already)...I'm posting my answer here for future reference:
9.995 * 100 = 999.4999999999999
Whereas 9.995e2 = 999.5
This discrepancy causes Math.round(9.995 * 100) = 999 instead of 1000.
Use e notation instead of multiplying /dividing by Math.Pow(10,precision).
I'm fix the problem the modifier.
Support 2 decimal only.
$(function(){
//input number only.
convertNumberFloatZero(22); // output : 22.00
convertNumberFloatZero(22.5); // output : 22.50
convertNumberFloatZero(22.55); // output : 22.55
convertNumberFloatZero(22.556); // output : 22.56
convertNumberFloatZero(22.555); // output : 22.55
convertNumberFloatZero(22.5541); // output : 22.54
convertNumberFloatZero(22222.5541); // output : 22,222.54
function convertNumberFloatZero(number){
if(!$.isNumeric(number)){
return 'NaN';
}
var numberFloat = number.toFixed(3);
var splitNumber = numberFloat.split(".");
var cNumberFloat = number.toFixed(2);
var cNsplitNumber = cNumberFloat.split(".");
var lastChar = splitNumber[1].substr(splitNumber[1].length - 1);
if(lastChar > 0 && lastChar < 5){
cNsplitNumber[1]--;
}
return Number(splitNumber[0]).toLocaleString('en').concat('.').concat(cNsplitNumber[1]);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
(Math.round((10.2)*100)/100).toFixed(2)
That should yield: 10.20
(Math.round((.05)*100)/100).toFixed(2)
That should yield: 0.05
(Math.round((4.04)*100)/100).toFixed(2)
That should yield: 4.04
etc.
/*Due to all told stuff. You may do 2 things for different purposes:
When showing/printing stuff use this in your alert/innerHtml= contents:
YourRebelNumber.toFixed(2)*/
var aNumber=9242.16;
var YourRebelNumber=aNumber-9000;
alert(YourRebelNumber);
alert(YourRebelNumber.toFixed(2));
/*and when comparing use:
Number(YourRebelNumber.toFixed(2))*/
if(YourRebelNumber==242.16)alert("Not Rounded");
if(Number(YourRebelNumber.toFixed(2))==242.16)alert("Rounded");
/*Number will behave as you want in that moment. After that, it'll return to its defiance.
*/
This is very simple and works just as well as any of the others:
function parseNumber(val, decimalPlaces) {
if (decimalPlaces == null) decimalPlaces = 0
var ret = Number(val).toFixed(decimalPlaces)
return Number(ret)
}
Since toFixed() can only be called on numbers, and unfortunately returns a string, this does all the parsing for you in both directions. You can pass a string or a number, and you get a number back every time! Calling parseNumber(1.49) will give you 1, and parseNumber(1.49,2) will give you 1.50. Just like the best of 'em!
You could also use the .toPrecision() method and some custom code, and always round up to the nth decimal digit regardless the length of int part.
function glbfrmt (number, decimals, seperator) {
return typeof number !== 'number' ? number : number.toPrecision( number.toString().split(seperator)[0].length + decimals);
}
You could also make it a plugin for a better use.
Here's a TypeScript implementation of https://stackoverflow.com/a/21323330/916734. It also dries things up with functions, and allows for a optional digit offset.
export function round(rawValue: number | string, precision = 0, fractionDigitOffset = 0): number | string {
const value = Number(rawValue);
if (isNaN(value)) return rawValue;
precision = Number(precision);
if (precision % 1 !== 0) return NaN;
let [ stringValue, exponent ] = scientificNotationToParts(value);
let shiftExponent = exponentForPrecision(exponent, precision, Shift.Right);
const enlargedValue = toScientificNotation(stringValue, shiftExponent);
const roundedValue = Math.round(enlargedValue);
[ stringValue, exponent ] = scientificNotationToParts(roundedValue);
const precisionWithOffset = precision + fractionDigitOffset;
shiftExponent = exponentForPrecision(exponent, precisionWithOffset, Shift.Left);
return toScientificNotation(stringValue, shiftExponent);
}
enum Shift {
Left = -1,
Right = 1,
}
function scientificNotationToParts(value: number): Array<string> {
const [ stringValue, exponent ] = value.toString().split('e');
return [ stringValue, exponent ];
}
function exponentForPrecision(exponent: string, precision: number, shift: Shift): number {
precision = shift * precision;
return exponent ? (Number(exponent) + precision) : precision;
}
function toScientificNotation(value: string, exponent: number): number {
return Number(`${value}e${exponent}`);
}
fun Any.twoDecimalPlaces(numInDouble: Double): String {
return "%.2f".format(numInDouble)
}

Categories

Resources