0

Every javascript programmer knows that javascript Math.round() does not produce correct rounding for decimal numbers in many cases, due to faulty floating point arithmetics.

Most found solutions tell to use simple prototype extension:

Number.prototype.round = function (decimalPlaces) {
    decimalPlaces = decimalPlaces || 0;
    var power = Math.pow(10, decimalPlaces)

    if (this > 0) {
        return Math.round(this * power) / power;
    } else {
        return -(Math.round(Math.abs(this) * power) / power);
    }
};

But this one fails on (1.005).round(2), which returns 1 instead of expected 1.01.

So how to correctly round decimal numbers in javascript? See the solution bellow (with unit tests).

petriq
  • 969
  • 1
  • 11
  • 24

1 Answers1

0

Correct Number prototype extension for rounding decimal numbers:

Number.prototype.round = function (decimalPlaces) {
    decimalPlaces = decimalPlaces || 0;

    var sign = (this < 0) ? -1 : 1,
        exp = -decimalPlaces,
        value;

    // Shift
    value = Math.abs(this).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))) * sign;
};

This extension is a tweek of decimalAdjust(), mentioned at the Mozilla Developer Network Documentation for Math.round() :

QUnit tests for this solution:

test("Number.prototype.round", function () {
    var value;

    value = 0;
    equal(value.round(0), 0, "Value: 0, decimals: 0, expected result: 0");

    value = 33.12;
    equal(value.round(1), 33.1, "Value: 33.12, decimals: 1, expected result: 33.1");

    value = 33.15;
    equal(value.round(1), 33.2, "Value: 33.15, decimals: 1, expected result: 33.2");

    value = 33.123;
    equal(value.round(2), 33.12, "Value: 33.123, decimals: 2, expected result: 33.12");

    value = 1000033.125;
    equal(value.round(2), 1000033.13, "Value: 1000033.125, decimals: 2, expected result: 1000033.13");

    value = 17.6949;
    equal(value.round(2), 17.69, "Value: 17.6949, decimals: 2, expected result: 17.69");

    value = 33.1234;
    equal(value.round(3), 33.123, "Value: 33.1234, decimals: 3, expected result: 33.123");

    value = 33.12359;
    equal(value.round(3), 33.124, "Value: 33.12359, decimals: 3, expected result: 33.124");

    value = 33.12343;
    equal(value.round(4), 33.1234, "Value: 33.12343, decimals: 4, expected result: 33.1234");

    value = 33.12346;
    equal(value.round(4), 33.1235, "Value: 33.12346, decimals: 4, expected result: 33.1235");

    value = 33.123456789;
    equal(value.round(5), 33.12346, "Value: 33.123456789, decimals: 5, expected result: 33.12346");

    value = 33.123456789;
    equal(value.round(8), 33.12345679, "Value: 33.123456789, decimals: 8, expected result: 33.12345679");

    value = -123456.123456789;
    equal(value.round(8), -123456.12345679, "Value: -123456.123456789, decimals: 8, expected result: -123456.12345679");

    value = -110.385;
    equal(value.round(2), -110.39, "Value: -110.385, decimals: 2, expected result: -110.39");
});
John Slegers
  • 45,213
  • 22
  • 199
  • 169
petriq
  • 969
  • 1
  • 11
  • 24