toLocaleString() changes behaviour after using toFixed method? - javascript

I was working on 'Formatting a number as price' problem on codewars and thought to have finally solved it with this code:
var numberToPrice = function(number) {
if (typeof number !== 'number') {
return 'NaN';
}
let newPrice = number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
return newPrice;
}
One test failed because of rounding problem (Expected: '13,422.12', instead got: '13,422.13'), others passed.
When I changed code to this:
var numberToPrice = function(number) {
if (typeof number !== 'number') {
return 'NaN';
}
let price = (Math.floor(100 * number) / 100).toFixed(2);
let newPrice = price.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
return newPrice;
}
in order to try to avoid rounding problem, to LocaleString didn't work the same. I got many errors like this: Expected: '245,123,215.00', instead got: '245123215.00'
What is going on here?

Once you use toFixed, price is a string, not a number, so toLocaleString will not change it. Given that you have used Math.floor(100 * number) / 100, you have already converted price to only have two significant digits, so toFixed(2) is not necessary, and leaving price as a number allows toLocaleString to format it.
var numberToPrice = function(number) {
if (typeof number !== 'number') {
return 'NaN';
}
let price = Math.floor(100 * number) / 100;
let newPrice = price.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
return newPrice;
}
console.log(numberToPrice(245123215))
console.log(numberToPrice(13422.126))

Related

JavaScript / reactJS - round up last decimal (without hardcoded decimal to calculate)

By using JavaScript to calculate, For Example (in live can be any value)
1000/0.997 = 1003.0090270812437
By using PC calculator to calculate
1000/0.997 = 1003.009027081244 // auto round up last decimal
But if !!!
this is correct and same as window, in this situation no need round up
500/0.997 = 501.5045135406219 // this is correct and same as window calculator
My prefer output is the auto round up value 1003.009027081244
Question: In JavaScript, how to round up the last digit of decimal?
What I have tried:
Math.round(1003.0090270812437) // 1003
const result = Number((1000/0.997).toPrecision(16))
const result = Number((1000 / 0.997).toPrecision(16))
console.log(result)
Maybe you could use string based solution
Convert a decimal number to string, then split it by the ..
Then take a decimal part length substracted by 1, and use it in toFixed on the original number.
You will probably need some additional checks, to see if there is a decimal part of a number
const decimal = 1003.0090270812437;
const text = decimal.toString().split('.')[1];
console.log(decimal.toFixed(text.length - 1)); // 1003.009027081244
Option 1: playing with numbers and decimals
const countDecimals = value => {
let text = value.toString()
if (text.indexOf('e-') > -1) {
let [base, trail] = text.split('e-')
let deg = parseInt(trail, 10)
return deg - 1
}
if (Math.floor(value) !== value) return value.toString().split(".")[1].length - 1 || 0
return 0
}
const round = number => Math.round(number * Math.pow(10, countDecimals(number - 1))) / Math.pow(10, countDecimals(number - 1))
Option 2: playing with strings
let round = number => {
let str = (number).toString()
let [num, dec] = str.split(".")
let leading_zeros = ""
for (const char of dec) {
if (char !== '0') break
leading_zeros += '0'
}
dec = Math.round(parseFloat(dec.substring(0, dec.length - 1) + "." + dec[dec.length - 1])).toString()
return parseFloat(num + "." + leading_zeros + dec)
}
There is no nice javascript way that I know to achieve this. Due to my knowledge this is the way to go:
Math.round(1003.0090270812437*1000000000000)/1000000000000
Edit:
If you do not want to round to a fixed number of decimals, then I would write a little function to count the given decimals before to know your exponent of 10:
var countDecimals = function(value) {
if (Math.floor(value) !== value)
return value.toString().split(".")[1].length || 0;
return 0;
}
var temp = Math.pow(10, countDecimals-1);
Math.round(1003.0090270812437*temp)/temp;
You can just use toFixed(${Amount of decimals you want to show})
Example:
(2321/912).toFixed(1) will show one fraction of the decimal number
(2322/ 1232).toFixed((2322/ 1232).toString().length - 1 ) will round you up the last digit

Use Intl.NumberFormat without rounding

I'm using Intl.NumberFormat to format numbers:
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 1,
maximumFractionDigits: 4,
minimumSignificantDigits: 1,
maximumSignificantDigits: 4
})
formatter.format(0.99999) // results: '1'. desired result: '0.9999'
formatter.format(0.006393555) // results: '0.006394'. desired result: '0.006393'
formatter.format(0.9972620384752073) // results: '0.9973'. desired result: '0.9972'
formatter.format(12345.67) // results: '12,350'. desired result: '12,345.67'
formatter.format(200001) // results: '200,000'. desired result: '200,001'
As you can see the numbers are being rounded automatically, which is undesirable behavior in my case.
Is there a way to tell the formatter not to round?
I Didn't found any option or combination of options to achieve that.
I don't think this is possible with current spec and there are few proposals for the new spec, but you can still use formatToParts method and add custom function to format number parts as you wish.
For your first use case it could look something like:
const trauncateFractionAndFormat = (parts, digits) => {
return parts.map(({ type, value }) => {
if (type !== 'fraction' || !value || value.length < digits) {
return value;
}
let retVal = "";
for (let idx = 0, counter = 0; idx < value.length && counter < digits; idx++) {
if (value[idx] !== '0') {
counter++;
}
retVal += value[idx];
}
return retVal;
}).reduce((string, part) => string + part);
};
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 0,
maximumFractionDigits: 20
})
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.99999), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.006393555), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(0.9972620384752073), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(12345.67), 4));
console.log(trauncateFractionAndFormat(formatter.formatToParts(20001), 4));
NumberFormat will always round up, but you can play around this one extra function.
function roundDownSignificantDigits(number, decimals) {
let significantDigits = (parseInt(number.toExponential().split('e-')[1])) || 0;
let decimalsUpdated = (decimals || 0) + significantDigits - 1;
decimals = Math.min(decimalsUpdated, number.toString().length);
return (Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals));
}
and then
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 1,
maximumFractionDigits: 4,
minimumSignificantDigits: 1,
maximumSignificantDigits: 4
})
result:
formatter.format(roundDownSignificantDigits(0.99999,4)); // "0.9999"
formatter.format(roundDownSignificantDigits(0.006393555,4)); // "0.006393"
formatter.format(roundDownSignificantDigits(0.9972620384752073,4)); // "0.9972"
Sometimes the above solutions round off the value,
here is the simplest Solution I'm using and its working fine for me,
let a = "2.2652";// string
let b = 2.2652; // decimal-number
let c = 22200223.26522200225; // decimal-number
let d = 2 // non-decimal
const formatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 20,
minimumSignificantDigits: 1,
maximumSignificantDigits: 20
});
const newFunc = (val)=>{
val = formatter.format((val))
if(val.includes(".")){
let number = val.toString().split(".")[0]+"."+val.split(".")[1].slice(0, 2)
return number
}else{
return val
}
}
console.log(newFunc(a))
console.log(newFunc(b))
console.log(newFunc(c))
console.log(newFunc(d))
I could get it using formatToParts. You can also do some javascript Array functions tricks to separate out the decimal part if needed.
export const formatNumberWithoutDecimals = (price) =>
new Intl.NumberFormat(i18n.language, {
minimumFractionDigits: 2,
}).formatToParts(price).reduce((result, part) => (part.type !== "decimal" && part.type !== "fraction") ? result + part.value : result, "");

BigDecimal in JavaScript

I'm very new to JavaScript (I come from a Java background) and I am trying to do some financial calculations with small amounts of money.
My original go at this was:
<script type="text/javascript">
var normBase = ("[price]").replace("$", "");
var salesBase = ("[saleprice]").replace("$", "");
var base;
if (salesBase != 0) {
base = salesBase;
} else {
base = normBase;
}
var per5 = (base - (base * 0.05));
var per7 = (base - (base * 0.07));
var per10 = (base - (base * 0.10));
var per15 = (base - (base * 0.15));
document.write
(
'5% Off: $' + (Math.ceil(per5 * 100) / 100).toFixed(2) + '<br/>' +
'7% Off: $' + (Math.ceil(per7 * 100) / 100).toFixed(2) + '<br/>' +
'10% Off: $' + (Math.ceil(per10 * 100) / 100).toFixed(2) + '<br/>' +
'15% Off: $' + (Math.ceil(per15 * 100) / 100).toFixed(2) + '<br/>'
);
</script>
This worked well except it always rounded up (Math.ceil). Math.floor has the same issue, and Math.round is also no good for floats.
In Java, I would have avoided the use of floats completely from the get-go, however in JavaScript there does not seem to be a default inclusion of something comparable.
The problem is, all the libraries mentioned are either broken or for a different purpose. The jsfromhell.com/classes/bignumber library is very close to what I need, however I'm having bizarre issues with its rounding and precision... No matter what I set the Round Type to, it seems to decide on its own. So for example, 3.7107 with precision of 2 and round type of ROUND_HALF_UP somehow winds up as 3.72 when it should be 3.71.
I also tried #JasonSmith BigDecimal library (a machined port from Java's BigDecimal), but it seems to be for node.js which I don't have the option of running.
How can I accomplish this using vanilla JavaScript (and be reliable) or is there a modern (ones mentioned above are all years old now) library that I can use that is maintained and is not broken?
Since we have native support for BigInt, it doesn't require much code any more to implement BigDecimal.
Here is a BigDecimal class based on BigInt with the following characteristics:
The number of decimals is configured as a constant, applicable to all instances.
Whether excessive digits are truncated or rounded is configured as a boolean constant.
An instance stores the decimal number as a BigInt, multiplied by a power of 10 so to include the decimals.
All calculations happen with those BigInt values.
The arguments passed to add, subtract, multiply and divide can be numeric, string, or instances of BigDecimal
These methods return new instances, so a BigDecimal is treated as immutable.
The toString method reintroduces the decimal point.
A BigDecimal can coerce to a number (via implicit call to toString), but that will obviously lead to loss of precision.
class BigDecimal {
// Configuration: constants
static DECIMALS = 18; // number of decimals on all instances
static ROUNDED = true; // numbers are truncated (false) or rounded (true)
static SHIFT = BigInt("1" + "0".repeat(BigDecimal.DECIMALS)); // derived constant
constructor(value) {
if (value instanceof BigDecimal) return value;
let [ints, decis] = String(value).split(".").concat("");
this._n = BigInt(ints + decis.padEnd(BigDecimal.DECIMALS, "0")
.slice(0, BigDecimal.DECIMALS))
+ BigInt(BigDecimal.ROUNDED && decis[BigDecimal.DECIMALS] >= "5");
}
static fromBigInt(bigint) {
return Object.assign(Object.create(BigDecimal.prototype), { _n: bigint });
}
add(num) {
return BigDecimal.fromBigInt(this._n + new BigDecimal(num)._n);
}
subtract(num) {
return BigDecimal.fromBigInt(this._n - new BigDecimal(num)._n);
}
static _divRound(dividend, divisor) {
return BigDecimal.fromBigInt(dividend / divisor
+ (BigDecimal.ROUNDED ? dividend * 2n / divisor % 2n : 0n));
}
multiply(num) {
return BigDecimal._divRound(this._n * new BigDecimal(num)._n, BigDecimal.SHIFT);
}
divide(num) {
return BigDecimal._divRound(this._n * BigDecimal.SHIFT, new BigDecimal(num)._n);
}
toString() {
const s = this._n.toString().padStart(BigDecimal.DECIMALS+1, "0");
return s.slice(0, -BigDecimal.DECIMALS) + "." + s.slice(-BigDecimal.DECIMALS)
.replace(/\.?0+$/, "");
}
}
// Demo
var a = new BigDecimal("123456789123456789876");
var b = a.divide("10000000000000000000");
var c = b.add("9.000000000000000004");
console.log(b.toString());
console.log(c.toString());
console.log(+c); // loss of precision when converting to number
I like using accounting.js for number, money and currency formatting.
Homepage - https://openexchangerates.github.io/accounting.js/
Github - https://github.com/openexchangerates/accounting.js
There are several implementations of BigDecimal in js:
js-big-decimal
big.js
bignumber.js
decimal.js
The last 3 come from the same author: see the differences.
Big.js is great, but too bulky for me.
I'm currently using the following which uses BigInt for arbitrary-precision. Only supports add, subtract, multiply, and divide. Calling set_precision(8); sets precision to 8 decimals.
Rounding mode is ROUND_DOWN.
class AssertionError extends Error {
/**
* #param {String|void} message
*/
constructor (message) {
super(message);
this.name = 'AssertionError';
if (Error.captureStackTrace instanceof Function) {
Error.captureStackTrace(this, AssertionError);
}
}
toJSON () {
return { name: this.name, message: this.message, stack: this.stack };
}
/**
* #param {Boolean} value
* #param {String|void} message
*/
static assert (value, message) {
if (typeof value !== 'boolean') {
throw new Error('assert(value, message?), "value" must be a boolean.');
}
if (message !== undefined && typeof message !== 'string') {
throw new Error('assert(value, message?), "message" must be a string.');
}
if (value === false) {
throw new AssertionError(message);
}
}
}
module.exports = AssertionError;
const AssertionError = require('./AssertionError');
let precision = 2;
let precision_multiplier = 10n ** BigInt(precision);
let max_safe_integer = BigInt(Number.MAX_SAFE_INTEGER) * precision_multiplier;
/**
* #param {Number} value
*/
const set_precision = (value) => {
AssertionError.assert(typeof value === 'number');
AssertionError.assert(Number.isFinite(value) === true);
AssertionError.assert(Number.isInteger(value) === true);
AssertionError.assert(value >= 0 === true);
precision = value;
precision_multiplier = 10n ** BigInt(precision);
max_safe_integer = BigInt(Number.MAX_SAFE_INTEGER) * precision_multiplier;
};
/**
* #param {Number} value
*/
const to_bigint = (value) => {
AssertionError.assert(typeof value === 'number');
AssertionError.assert(Number.isFinite(value) === true);
return BigInt(value.toFixed(precision).replace('.', ''));
};
/**
* #param {BigInt} value
* #param {Number} decimal_places
*/
const to_number = (value) => {
AssertionError.assert(typeof value === 'bigint');
AssertionError.assert(value <= max_safe_integer);
const value_string = value.toString().padStart(2 + precision, '0');
const whole = value_string.substring(0, value_string.length - precision);
const decimal = value_string.substring(value_string.length - precision, value_string.length);
const result = Number(`${whole}.${decimal}`);
return result;
};
/**
* #param {Number[]} values
*/
const add = (...values) => to_number(values.reduce((previous, current) => previous === null ? to_bigint(current) : previous + to_bigint(current), null));
const subtract = (...values) => to_number(values.reduce((previous, current) => previous === null ? to_bigint(current) : previous - to_bigint(current), null));
const multiply = (...values) => to_number(values.reduce((previous, current) => previous === null ? to_bigint(current) : (previous * to_bigint(current)) / precision_multiplier, null));
const divide = (...values) => to_number(values.reduce((previous, current) => previous === null ? to_bigint(current) : (previous * precision_multiplier) / to_bigint(current), null));
const arbitrary = { set_precision, add, subtract, multiply, divide };
module.exports = arbitrary;
const arbitrary = require('./arbitrary');
arbitrary.set_precision(2);
const add = arbitrary.add;
const subtract = arbitrary.subtract;
const multiply = arbitrary.multiply;
const divide = arbitrary.divide;
console.log(add(75, 25, 25)); // 125
console.log(subtract(75, 25, 25)); // 25
console.log(multiply(5, 5)); // 25
console.log(add(5, multiply(5, 5))); // 30
console.log(divide(125, 5, 5)); // 5
console.log(divide(1000, 10, 10)); // 10
console.log(divide(1000, 8.86)); // 112.86681715
console.log(add(Number.MAX_SAFE_INTEGER, 0)); // 9007199254740991
console.log(subtract(Number.MAX_SAFE_INTEGER, 1)); // 9007199254740990
console.log(multiply(Number.MAX_SAFE_INTEGER, 0.5)); // 4503599627370495.5
console.log(divide(Number.MAX_SAFE_INTEGER, 2)); // 4503599627370495.5
console.log(multiply(Math.PI, Math.PI)); // 9.86960437
console.log(divide(Math.PI, Math.PI)); // 1
console.log(divide(1, 12)); // 0.08333333
console.log(add(0.1, 0.2)); // 0.3
console.log(multiply(1.500, 1.3)); // 1.95
console.log(multiply(0, 1)); // 0
console.log(multiply(0, -1)); // 0
console.log(multiply(-1, 1)); // -1
console.log(divide(1.500, 1.3)); // 1.15384615
console.log(divide(0, 1)); // 0
console.log(divide(0, -1)); // 0
console.log(divide(-1, 1)); // -1
console.log(multiply(5, 5, 5, 5)); // 625
console.log(multiply(5, 5, 5, 123, 123, 5)); // 9455625
Wrapped #trincot 's great implementation of BigDecimal into an NPM module, combined with the BigInt polyfill JSBI and Reverse Polish notation algorithm.
With this module, it is quite intuitive to perform arbitrary arithmetic computation in JS now, even compatible with IE11.
npm install jsbi-calculator
import JBC from "jsbi-calculator";
const { calculator } = JBC;
const expressionOne = "((10 * (24 / ((9 + 3) * (-2)))) + 17) + 5";
const resultOne = calculator(expressionOne);
console.log(resultOne);
// -> '12'
const max = String(Number.MAX_SAFE_INTEGER);
console.log(max);
// -> '9007199254740991'
const expressionTwo = `${max} + 2`;
const resultTwo = calculator(expressionTwo);
console.log(resultTwo);
// -> '9007199254740993'
This is the link to the npm page. https://www.npmjs.com/package/jsbi-calculator.
Thanks once again for #trincot 's inspiration.

Get decimal portion of a number with JavaScript

I have float numbers like 3.2 and 1.6.
I need to separate the number into the integer and decimal part. For example, a value of 3.2 would be split into two numbers, i.e. 3 and 0.2
Getting the integer portion is easy:
n = Math.floor(n);
But I am having trouble getting the decimal portion.
I have tried this:
remainder = n % 2; //obtem a parte decimal do rating
But it does not always work correctly.
The previous code has the following output:
n = 3.1 // gives remainder = 1.1
What I am missing here?
Use 1, not 2.
js> 2.3 % 1
0.2999999999999998
var decimal = n - Math.floor(n)
Although this won't work for minus numbers so we might have to do
n = Math.abs(n); // Change to positive
var decimal = n - Math.floor(n)
You could convert to string, right?
n = (n + "").split(".");
How is 0.2999999999999998 an acceptable answer? If I were the asker I would want an answer of .3. What we have here is false precision, and my experiments with floor, %, etc indicate that Javascript is fond of false precision for these operations. So I think the answers that are using conversion to string are on the right track.
I would do this:
var decPart = (n+"").split(".")[1];
Specifically, I was using 100233.1 and I wanted the answer ".1".
Here's how I do it, which I think is the most straightforward way to do it:
var x = 3.2;
int_part = Math.trunc(x); // returns 3
float_part = Number((x-int_part).toFixed(2)); // return 0.2
A simple way of doing it is:
var x = 3.2;
var decimals = x - Math.floor(x);
console.log(decimals); //Returns 0.20000000000000018
Unfortunately, that doesn't return the exact value. However, that is easily fixed:
var x = 3.2;
var decimals = x - Math.floor(x);
console.log(decimals.toFixed(1)); //Returns 0.2
You can use this if you don't know the number of decimal places:
var x = 3.2;
var decimals = x - Math.floor(x);
var decimalPlaces = x.toString().split('.')[1].length;
decimals = decimals.toFixed(decimalPlaces);
console.log(decimals); //Returns 0.2
Language independent way:
var a = 3.2;
var fract = a * 10 % 10 /10; //0.2
var integr = a - fract; //3
note that it correct only for numbers with one fractioanal lenght )
You can use parseInt() function to get the integer part than use that to extract the decimal part
var myNumber = 3.2;
var integerPart = parseInt(myNumber);
var decimalPart = myNumber - integerPart;
Or you could use regex like:
splitFloat = function(n){
const regex = /(\d*)[.,]{1}(\d*)/;
var m;
if ((m = regex.exec(n.toString())) !== null) {
return {
integer:parseInt(m[1]),
decimal:parseFloat(`0.${m[2]}`)
}
}
}
The following works regardless of the regional settings for decimal separator... on the condition only one character is used for a separator.
var n = 2015.15;
var integer = Math.floor(n).toString();
var strungNumber = n.toString();
if (integer.length === strungNumber.length)
return "0";
return strungNumber.substring(integer.length + 1);
It ain't pretty, but it's accurate.
If precision matters and you require consistent results, here are a few propositions that will return the decimal part of any number as a string, including the leading "0.". If you need it as a float, just add var f = parseFloat( result ) in the end.
If the decimal part equals zero, "0.0" will be returned. Null, NaN and undefined numbers are not tested.
1. String.split
var nstring = (n + ""),
narray = nstring.split("."),
result = "0." + ( narray.length > 1 ? narray[1] : "0" );
2. String.substring, String.indexOf
var nstring = (n + ""),
nindex = nstring.indexOf("."),
result = "0." + (nindex > -1 ? nstring.substring(nindex + 1) : "0");
3. Math.floor, Number.toFixed, String.indexOf
var nstring = (n + ""),
nindex = nstring.indexOf("."),
result = ( nindex > -1 ? (n - Math.floor(n)).toFixed(nstring.length - nindex - 1) : "0.0");
4. Math.floor, Number.toFixed, String.split
var nstring = (n + ""),
narray = nstring.split("."),
result = (narray.length > 1 ? (n - Math.floor(n)).toFixed(narray[1].length) : "0.0");
Here is a jsPerf link: https://jsperf.com/decpart-of-number/
We can see that proposition #2 is the fastest.
A good option is to transform the number into a string and then split it.
// Decimal number
let number = 3.2;
// Convert it into a string
let string = number.toString();
// Split the dot
let array = string.split('.');
// Get both numbers
// The '+' sign transforms the string into a number again
let firstNumber = +array[0]; // 3
let secondNumber = +array[1]; // 2
In one line of code
let [firstNumber, secondNumber] = [+number.toString().split('.')[0], +number.toString().split('.')[1]];
Depending the usage you will give afterwards, but this simple solution could also help you.
Im not saying its a good solution, but for some concrete cases works
var a = 10.2
var c = a.toString().split(".")
console.log(c[1] == 2) //True
console.log(c[1] === 2) //False
But it will take longer than the proposed solution by #Brian M. Hunt
(2.3 % 1).toFixed(4)
I am using:
var n = -556.123444444;
var str = n.toString();
var decimalOnly = 0;
if( str.indexOf('.') != -1 ){ //check if has decimal
var decimalOnly = parseFloat(Math.abs(n).toString().split('.')[1]);
}
Input: -556.123444444
Result: 123444444
You could convert it to a string and use the replace method to replace the integer part with zero, then convert the result back to a number :
var number = 123.123812,
decimals = +number.toString().replace(/^[^\.]+/,'0');
n = Math.floor(x);
remainder = x % 1;
Math functions are faster, but always returns not native expected values.
Easiest way that i found is
(3.2+'').replace(/^[-\d]+\./, '')
The best way to avoid mathematical imprecision is to convert to a string, but ensure that it is in the "dot" format you expect by using toLocaleString:
function getDecimals(n) {
// Note that maximumSignificantDigits defaults to 3 so your decimals will be rounded if not changed.
const parts = n.toLocaleString('en-US', { maximumSignificantDigits: 18 }).split('.')
return parts.length > 1 ? Number('0.' + parts[1]) : 0
}
console.log(getDecimals(10.58))
You can simply use parseInt() function to help, example:
let decimal = 3.2;
let remainder = decimal - parseInt(decimal);
document.write(remainder);
I had a case where I knew all the numbers in question would have only one decimal and wanted to get the decimal portion as an integer so I ended up using this kind of approach:
var number = 3.1,
decimalAsInt = Math.round((number - parseInt(number)) * 10); // returns 1
This works nicely also with integers, returning 0 in those cases.
Although I am very late to answer this, please have a look at the code.
let floatValue = 3.267848;
let decimalDigits = floatValue.toString().split('.')[1];
let decimalPlaces = decimalDigits.length;
let decimalDivider = Math.pow(10, decimalPlaces);
let fractionValue = decimalDigits/decimalDivider;
let integerValue = floatValue - fractionValue;
console.log("Float value: "+floatValue);
console.log("Integer value: "+integerValue);
console.log("Fraction value: "+fractionValue)
I like this answer https://stackoverflow.com/a/4512317/1818723 just need to apply float point fix
function fpFix(n) {
return Math.round(n * 100000000) / 100000000;
}
let decimalPart = 2.3 % 1; //0.2999999999999998
let correct = fpFix(decimalPart); //0.3
Complete function handling negative and positive
function getDecimalPart(decNum) {
return Math.round((decNum % 1) * 100000000) / 100000000;
}
console.log(getDecimalPart(2.3)); // 0.3
console.log(getDecimalPart(-2.3)); // -0.3
console.log(getDecimalPart(2.17247436)); // 0.17247436
P.S. If you are cryptocurrency trading platform developer or banking system developer or any JS developer ;) please apply fpFix everywhere. Thanks!
2021 Update
Optimized version that tackles precision (or not).
// Global variables.
const DEFAULT_PRECISION = 16;
const MAX_CACHED_PRECISION = 20;
// Helper function to avoid numerical imprecision from Math.pow(10, x).
const _pow10 = p => parseFloat(`1e+${p}`);
// Cache precision coefficients, up to a precision of 20 decimal digits.
const PRECISION_COEFS = new Array(MAX_CACHED_PRECISION);
for (let i = 0; i !== MAX_CACHED_PRECISION; ++i) {
PRECISION_COEFS[i] = _pow10(i);
}
// Function to get a power of 10 coefficient,
// optimized for both speed and precision.
const pow10 = p => PRECISION_COEFS[p] || _pow10(p);
// Function to trunc a positive number, optimized for speed.
// See: https://stackoverflow.com/questions/38702724/math-floor-vs-math-trunc-javascript
const trunc = v => (v < 1e8 && ~~v) || Math.trunc(v);
// Helper function to get the decimal part when the number is positive,
// optimized for speed.
// Note: caching 1 / c or 1e-precision still leads to numerical errors.
// So we have to pay the price of the division by c.
const _getDecimals = (v = 0, precision = DEFAULT_PRECISION) => {
const c = pow10(precision); // Get precision coef.
const i = trunc(v); // Get integer.
const d = v - i; // Get decimal.
return Math.round(d * c) / c;
}
// Augmenting Number proto.
Number.prototype.getDecimals = function(precision) {
return (isFinite(this) && (precision ? (
(this < 0 && -_getDecimals(-this, precision))
|| _getDecimals(this, precision)
) : this % 1)) || 0;
}
// Independent function.
const getDecimals = (input, precision) => (isFinite(input) && (
precision ? (
(this < 0 && -_getDecimals(-this, precision))
|| _getDecimals(this, precision)
) : this % 1
)) || 0;
// Tests:
const test = (value, precision) => (
console.log(value, '|', precision, '-->', value.getDecimals(precision))
);
test(1.001 % 1); // --> 0.0009999999999998899
test(1.001 % 1, 16); // --> 0.000999999999999
test(1.001 % 1, 15); // --> 0.001
test(1.001 % 1, 3); // --> 0.001
test(1.001 % 1, 2); // --> 0
test(-1.001 % 1, 16); // --> -0.000999999999999
test(-1.001 % 1, 15); // --> -0.001
test(-1.001 % 1, 3); // --> -0.001
test(-1.001 % 1, 2); // --> 0
After looking at several of these, I am now using...
var rtnValue = Number(7.23);
var tempDec = ((rtnValue / 1) - Math.floor(rtnValue)).toFixed(2);
Floating-point decimal sign and number format can be dependent from country (.,), so independent solution, which preserved floating point part, is:
getFloatDecimalPortion = function(x) {
x = Math.abs(parseFloat(x));
let n = parseInt(x);
return Number((x - n).toFixed(Math.abs((""+x).length - (""+n).length - 1)));
}
– it is internationalized solution, instead of location-dependent:
getFloatDecimalPortion = x => parseFloat("0." + ((x + "").split(".")[1]));
Solution desription step by step:
parseFloat() for guaranteeing input cocrrection
Math.abs() for avoiding problems with negative numbers
n = parseInt(x) for getting decimal part
x - n for substracting decimal part
We have now number with zero decimal part, but JavaScript could give us additional floating part digits, which we do not want
So, limit additional digits by calling toFixed() with count of digits in floating part of original float number x. Count is calculated as difference between length of original number x and number n in their string representation.
This function splits float number into integers and returns it in array:
function splitNumber(num)
{
num = (""+num).match(/^(-?[0-9]+)([,.][0-9]+)?/)||[];
return [ ~~num[1], +(0+num[2])||0 ];
}
console.log(splitNumber(3.02)); // [ 3, 0.2 ]
console.log(splitNumber(123.456)); // [ 123, 0.456 ]
console.log(splitNumber(789)); // [ 789, 0 ]
console.log(splitNumber(-2.7)); // [ -2, 0.7 ]
console.log(splitNumber("test")); // [ 0, 0 ]
You can extend it to only return existing numbers and null if no number exists:
function splitNumber(num)
{
num = (""+num).match(/^(-?[0-9]+)([,.][0-9]+)?/);
return [ num ? ~~num[1] : null, num && num[2] ? +(0 + num[2]) : null ];
}
console.log(splitNumber(3.02)); // [ 3, 0.02 ]
console.log(splitNumber(123.456)); // [ 123, 0.456 ]
console.log(splitNumber(789)); // [ 789, null ]
console.log(splitNumber(-2.7)); // [ -2, 0.7 ]
console.log(splitNumber("test")); // [ null, null ]
You can also truncate the number
function decimals(val) {
const valStr = val.toString();
const valTruncLength = String(Math.trunc(val)).length;
const dec =
valStr.length != valTruncLength
? valStr.substring(valTruncLength + 1)
: "";
return dec;
}
console.log("decimals: ", decimals(123.654321));
console.log("no decimals: ", decimals(123));
The following function will return an array which will have 2 elements. The first element will be the integer part and the second element will be the decimal part.
function splitNum(num) {
num = num.toString().split('.')
num[0] = Number(num[0])
if (num[1]) num[1] = Number('0.' + num[1])
else num[1] = 0
return num
}
//call this function like this
let num = splitNum(3.2)
console.log(`Integer part is ${num[0]}`)
console.log(`Decimal part is ${num[1]}`)
//or you can call it like this
let [int, deci] = splitNum(3.2)
console.log('Intiger part is ' + int)
console.log('Decimal part is ' + deci)
For example for add two numbers
function add(number1, number2) {
let decimal1 = String(number1).substring(String(number1).indexOf(".") + 1).length;
let decimal2 = String(number2).substring(String(number2).indexOf(".") + 1).length;
let z = Math.max(decimal1, decimal2);
return (number1 * Math.pow(10, z) + number2 * Math.pow(10, z)) / Math.pow(10, z);
}
float a=3.2;
int b=(int)a; // you'll get output b=3 here;
int c=(int)a-b; // you'll get c=.2 value here

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