604

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Abs
  • 51,038
  • 92
  • 260
  • 394
  • 1
    Your code is exactly what I was looking for(to reduce float precision to 7 decimal places for smaller JSON file) Skipping Math.pow for speed val = Math.round(val * 10000000) / 10000000); – Pawel Jun 04 '16 at 21:44
  • As the [currently-accepted answer](http://stackoverflow.com/a/1726662/157247) gives arguably a wrong result for a broad range of values thanks to aggravating imprecision inherent in the numbers (`0.565`, `0.575`, `1.005`), can I suggest looking again at [this answer](http://stackoverflow.com/a/21323330/157247), which gets them correct? – T.J. Crowder Oct 27 '16 at 09:08
  • Maybe you want to include an sprintf library for JavaScript http://stackoverflow.com/questions/610406/javascript-printf-string-format – Thilo Oct 27 '16 at 09:27
  • 1
    After correctly rounding with the decimal place shifting and rounding method, you could use the [`number.toFixed(x)`](http://www.w3schools.com/jsref/jsref_tofixed.asp) method to convert it to a string with the required amount of zeroes. E.g. round `1.34` to `1.3` with the cross-browser method then add 1 zero and convert to string with `1.3.toFixed(2)` (to get `"1.30"`). – Edward Nov 19 '16 at 15:26
  • It's 2020 and there is no simple native way in JavaScript to simply round a number. wow. – Sliq Nov 26 '20 at 01:34

31 Answers31

1062

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.

Community
  • 1
  • 1
Christian C. Salvadó
  • 723,813
  • 173
  • 899
  • 828
  • 17
    Doesn't work consistently across all browsers, ie `(0.09).toFixed(1);` gives 0.0 in IE8 – ajbeaven Oct 10 '11 at 22:55
  • 42
    fixed doesn't round, you can do it first: (Math.round(0.09)).toFixed(1); – rekans Jan 20 '12 at 11:02
  • 32
    @rekans: This is wrong. `Math.Round(0.09)` will return `0` so this will always give `0.0`... – Chris May 11 '12 at 10:33
  • 3
    Also toFixed does round. In both firefox and IE `(0.19).toFixed(1)` gives a result of `0.2` – Chris May 11 '12 at 10:39
  • 28
    This is a bad idea in most situations, it converts the number to a string or float point number in some cases. – Ash Blue Jun 20 '12 at 15:19
  • 81
    Have to agree with @AshBlue here... this is only safe for formatting presentation of values. May break code with further calculations. Otherwise `Math.round(value*100)/100` works better for 2DP. – UpTheCreek Aug 02 '12 at 06:11
  • 7
    Still bad idea (Math.round(1.275*100)/100).toFixed(2) is 1.27 not 1.28 – allenhwkim Mar 14 '13 at 04:23
  • use 'Math.round((num + 0.00001) * 100) / 100' – shrishaster Dec 30 '13 at 09:49
  • @rekans: toFixed also rounds the number. You can try doing this for example (34629.29/1000).toFixed(2) and see that it returns 34.63, which is already rounded to 2 decimal points – Aram Jan 14 '14 at 14:33
  • 2
    One thing to be kept in mine is that `.toFixed` is not always reliable when talking about accuracy. For example, `1.345.toFixed(2)` yields a result of `"1.34"` which is not correct. A better way to do is by `Math.round(1.345*100)/100 //1.35`. – Derek 朕會功夫 Feb 26 '14 at 04:41
  • Just put your attention that if you use toFixed() method you will get typeof 0.123.toFixed(2) "string" So you should remember about parsing of obtained string – Artemis Mar 08 '14 at 19:57
  • Remember that (0.00001).toFixed(2) returns 0.00 without rounding. You will loose your number. – SBO Jul 29 '16 at 09:26
106

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>
astorije
  • 2,526
  • 2
  • 24
  • 39
  • 2
    How is there not a simple way to do this? ES6 to the rescue? – zero_cool Jul 12 '17 at 04:11
  • Thank you for posting the MDN polyfill. On the linked MDN page the polyfill is no longer there. I wonder why it was removed... – King Holly Apr 29 '19 at 20:43
  • How can I use it to get value upto first decimal place,like 3.0421 shuld return 3.0? – RIni Apr 28 '21 at 10:03
  • @RIni, you should be able to use `round(3.0421, 1)` to get `3` as a number or `round(3.0421, 1).toFixed(1)` to get `'3.0'` as a string. – astorije Apr 28 '21 at 14:23
45

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.

Hakan Fıstık
  • 11,376
  • 8
  • 74
  • 105
Miguel
  • 2,305
  • 2
  • 26
  • 25
  • 2
    precise_round(1.275,2) is 1.27? – allenhwkim Mar 14 '13 at 04:25
  • precise_round(6,2) returns 6 (no decimals as asked in the question) – Imre Apr 10 '13 at 12:41
  • 2
    @Imre Change the return value to (Math.round(num*Math.pow(10,decimals))/Math.pow(10,decimals)).toFixed(2); and you will no longer have that issue. – dkroy Aug 07 '13 at 08:26
  • @dkroy Nice idea, although the argument for `toFixed(...)` should be `decimals`, as in the [answer by @TIMINeutron](http://stackoverflow.com/a/16319855/706714) – Imre Aug 07 '13 at 09:52
  • @Imre my mistake, not sure why I inserted two. – dkroy Aug 07 '13 at 17:38
  • 6
    where do you declare "sign" and "dec" if your second function is picked up as is shouldn't it have them as undefined? – Ady Ngom Jan 28 '14 at 18:44
  • You're doing the power calculation twice. Isn't it better to do it once and store the result? – AlexMorley-Finch Jul 25 '14 at 13:58
  • Does not work in IE 11, because **Math** has no method **sign** here. – Armin Jan 28 '15 at 14:35
  • 2
    I've added a workarround for missign sign method in IE: https://gist.github.com/ArminVieweg/28647e735aa6efaba401 – Armin Jan 28 '15 at 14:45
  • 1
    @Armin Your fix also makes it work in Safari. The original function did not work in Safari. – Dave Apr 27 '15 at 19:21
  • Please note that this returns a string. To return a decimal again, wrap the return value in parseFloat() ... – sebilasse Apr 10 '17 at 13:11
19

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.

peterh
  • 9,698
  • 15
  • 68
  • 87
tfrascaroli
  • 1,041
  • 1
  • 11
  • 25
  • 2
    The "correction" is *mostly* safe, but e.g. `precise_round(1.27499,2)` now also returns 1.28... It's not `Math.round` that is lossy; the way that computers internally store floating point values is. Basically, you're doomed to fail with some values before the data even gets to your function :) – Imre Aug 07 '13 at 10:12
  • @Imre, you're absolutelly right. That's why I explain what is this 0.001 doing there, in case anyone wants to make it "more _precise_" or even delete it (if you happen to have a super computer with 2 Mbytes per float, wich I don't think anyone here does ;) – tfrascaroli Aug 30 '13 at 19:56
  • 1
    Actually, the [language specification](http://www.ecma-international.org/ecma-262/5.1/#sec-8.5) is pretty specific about using 64 bits for number values, so having/using a supercomputer wouldn't change anything :) – Imre Sep 04 '13 at 07:58
  • for the 0.001 you can replace by adding many zeros according to length of the decimals. so.. – Miguel Oct 26 '13 at 22:13
16

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)
Gerard de Visser
  • 5,103
  • 9
  • 39
  • 52
  • 6
    This is the best, simplest way to do it. However, due to floating point math, 1.275 * 100 = 127.49999999999999, which could cause minor errors in the rounding. To fix this, we can multiply by 1000 and divide by 10, as (1.275 * 1000)/10 = 127.5. As follows: `var answer = (Math.round((num * 1000)/10)/100).toFixed(2);` – James Gould Jun 13 '14 at 19:36
  • (Math.round((1.015 * 1000)/10)/100).toFixed(2) still gives 1.01, shouldn't it be 1.02 ? – gaurav5430 Dec 26 '19 at 05:12
14

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);
Syed Umar Ahmed
  • 4,963
  • 1
  • 18
  • 22
5

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
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 2
    Thanks. Here's a ditty to test this: http://jsfiddle.net/lamarant/ySXuF/. I'm applying toFixed() to the value prior to returning it which appends the correct number of zeroes to the end of the returned value. – lamarant Jul 07 '13 at 18:27
  • not working for value=0,004990845956707237 and inprecise_round(value,8) returns 0,00499085 but it must return 0,00499084 – MERT DOĞAN Jan 28 '18 at 13:05
4

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
3

@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/

vicmaster
  • 97
  • 3
  • 2
    I can appreciate the contribution, though I think adding DOM elements and jQuery into the mix seems out of the scope of the question. – Chris May Sep 05 '13 at 11:58
  • 1
    You shouldn't listen to the keyup event, as it looks verry bad and doesn't activate when you add something with script. I'd rather listen to the `input` event. This doesn't create a flickering effect and also fires when you access the field with JS – Le 'nton Nov 26 '15 at 21:29
3

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 :)

Community
  • 1
  • 1
Imre
  • 221
  • 3
  • 14
3

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

ow3n
  • 4,612
  • 4
  • 38
  • 47
3

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.

MERT DOĞAN
  • 2,022
  • 19
  • 25
2

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

HATCHA
  • 602
  • 1
  • 7
  • 15
2
Number(Math.round(1.005+'e2')+'e-2'); // 1.01

This worked for me: Rounding Decimals in JavaScript

Theraot
  • 18,248
  • 4
  • 45
  • 72
Max G
  • 66
  • 3
2

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);
}
David Webster
  • 1,496
  • 1
  • 11
  • 22
2

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).

Amr Ali
  • 1,315
  • 13
  • 10
2

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);
Devner
  • 5,855
  • 9
  • 53
  • 82
1

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);
}
Kamran Ahmed
  • 9,682
  • 18
  • 56
  • 96
1
Number(((Math.random() * 100) + 1).toFixed(2))

this will return a random number from 1 to 100 rounded to 2 decimal places.

Johnathan Ralls
  • 121
  • 1
  • 12
1

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/

Community
  • 1
  • 1
ZiTAL
  • 2,989
  • 6
  • 32
  • 48
1

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>
Vishnu T Asok
  • 237
  • 4
  • 14
1

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).
remondo
  • 87
  • 4
0
(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.

ann
  • 584
  • 1
  • 9
  • 19
0

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>
bamossza
  • 2,712
  • 1
  • 21
  • 23
0

/*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.
*/
0

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!

Aaron Dake
  • 151
  • 1
  • 5
0

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.

Draken
  • 3,049
  • 13
  • 32
  • 49
leo_lo
  • 26
  • 2
0

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}`);
}
Patrick Berkeley
  • 2,096
  • 19
  • 26
0

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].

H. Almidan
  • 76
  • 1
  • 5
-3

I found a very simple way that solved this problem for me and can be used or adapted:

td[row].innerHTML = price.toPrecision(price.toFixed(decimals).length
-5

100% working!!! Try it

<html>
     <head>
      <script>
      function replacePonto(){
        var input = document.getElementById('qtd');
        var ponto = input.value.split('.').length;
        var slash = input.value.split('-').length;
        if (ponto > 2)
                input.value=input.value.substr(0,(input.value.length)-1);

        if(slash > 2)
                input.value=input.value.substr(0,(input.value.length)-1);

        input.value=input.value.replace(/[^0-9.-]/,'');

        if (ponto ==2)
 input.value=input.value.substr(0,(input.value.indexOf('.')+3));

if(input.value == '.')
 input.value = "";
              }
      </script>
      </head>
      <body>
         <input type="text" id="qtd" maxlength="10" style="width:140px" onkeyup="return replacePonto()">
      </body>
    </html>
  • Welcome to SO. Please read this [how-to-answer](http://stackoverflow.com/help/how-to-answer) and follow the guideline to answer. – thewaywewere May 05 '17 at 20:47