One of the things that bothers me about the native rounding functions is the fact that there is no way to specify precision. If this is something that you need to do you can use the following code to define Math.$round(...), Math.$ceil(...), and Math.$floor(...):

(function(arr,i,name) {
  while(name = arr[i++]) {
    Math["$"+name] = Function("a","b","return Math."+name+"(a*(b=Math.pow(10,b||0)))/b");
  }
})(["floor","ceil","round"],0);

This code Makes the following functions available:

  • Math.$ceil(number [, precision]) → Number:
    Returns the specified number rounded up just as Math.ceil(number) does, but also gives the ability to specify the precision of the rounded number.

  • Math.$floor(number [, precision]) → Number:
    Returns the specified number rounded down just as Math.floor(number) does, but also gives the ability to specify the precision of the rounded number.

  • Math.$round(number [, precision]) → Number:
    Returns the specified number rounded up or down just as Math.round(number) does, but also gives the ability to specify the precision of the rounded number.

Specifying a positive precision will round according to that digit to the right of the decimal point. Specifying a negative precision will round according to that digit to the left of the decimal point.

Categories: BlogJavaScriptJScriptMath

14 Comments

ildar · November 9, 2012 at 12:30 PM

Hmmm. Number object has these methods

Math.PI.toFixed(3)
Math.PI.toExponential(3)
Math.PI.toPrecision(3)

    Chris West · November 9, 2012 at 2:58 PM

    I would agree with you that you can do something like the following if you want to round a number using a non-negative precision:

    var num = +(4.495).toFixed(2);
    

    On the other hand, if you want to rounding using a negative precision, you cannot use your method:

    var num = +(95).toFixed(-1);
    

    Instead of getting 100, we would get a RangeError. Also, the Math.$ceil(...) and Math.$floor(...) functions cannot be effectively duplicated by the functions that you mentioned.

    Thanks for the note though! 8)

      ildar · November 9, 2012 at 3:05 PM

      Negative precision? What is this? How to explain the result Math.$round(95, -2) == 100?

        Chris West · November 9, 2012 at 5:16 PM

        If you need to round to the nearest multiple of 100, you can specify a precision of -2. To tell you the truth, I cannot remember where I first learned this.

        Chris West · November 9, 2012 at 5:19 PM

        It seems I actually got the idea from Java’s MathUtils.

          ildar · November 13, 2012 at 12:29 AM

          Thank you. Very interesting idea. I didn’t know it.

ildar · May 17, 2013 at 3:57 AM

The MDN pages have the example the similar to your solution – https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/ceil. I decided to share them here. The main difference is in usage of parsing of a string presentation of numbers against exponentiation. Maybe the more common solution is a modulo adjustment like this – http://with-love-from-siberia.blogspot.ru/2013/05/modulo-adjustment.html 🙂

rJbueno · August 20, 2013 at 2:02 PM

Lifesaver, thanks a mill!!!

miguel guerrero · January 16, 2014 at 1:44 PM

And the examples???

    Chris West · February 10, 2014 at 5:19 PM

    I used Chrome’s JS console and wrote the following quick example:

    var funcs = ['$ceil', '$floor', '$round'];
    var arg2 = [-1, 0, 1];
    funcs.map(function(fn) {
      return arg2.map(function(arg2) {
        return 'Math.' + fn + '(45.67, ' + arg2 + ') -> ' + Math[fn](45.67, arg2);
      }).join('\n');
    }).join('\n---\n');
    

    This results in the following:

    Math.$ceil(45.67, -1) -> 50
    Math.$ceil(45.67, 0) -> 46
    Math.$ceil(45.67, 1) -> 45.7
    ---
    Math.$floor(45.67, -1) -> 40
    Math.$floor(45.67, 0) -> 45
    Math.$floor(45.67, 1) -> 45.6
    ---
    Math.$round(45.67, -1) -> 50
    Math.$round(45.67, 0) -> 46
    Math.$round(45.67, 1) -> 45.7
    

Justin James · July 11, 2014 at 11:54 AM

Awesome. Thanks Chris!!!!

Travis · November 19, 2015 at 11:29 PM

This is great, however at least in chrome the following examples do not work:
Math.$round(35.855,2) -> 35.85
Math.$round(1.005,2)->1
Apparently this is because of Javascript’s handling of floating point.
You can read more here :
http://stackoverflow.com/questions/10015027/javascript-tofixed-not-rounding

    Travis · November 20, 2015 at 12:22 AM

    Apparently IEEE 754 recommends ties to zero (that is, rounding midway to the even number, I’ve formally called this banker’s rounding). Though if that were the reason for this error, I would expect the following to follow that pattern too, but it does not:
    Math.$round(123.455,2) -> 123.46
    https://en.wikipedia.org/wiki/IEEE_floating_point

Leave a Reply

Your email address will not be published. Required fields are marked *