From dd27a0adc7566319e231836fcf1aed5d4e495f57 Mon Sep 17 00:00:00 2001 From: Tejo Kumar Reddy Chenchu Date: Thu, 24 Sep 2015 01:12:13 -0700 Subject: [PATCH] Fix rounding issue with the `precision` param of `_.floor`. --- lodash.js | 11 +++++++++-- test/test.js | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/lodash.js b/lodash.js index 5888858c9..876cdae18 100644 --- a/lodash.js +++ b/lodash.js @@ -4081,8 +4081,15 @@ return function(number, precision) { precision = precision ? toInteger(precision) : 0; if (precision) { - precision = pow(10, precision); - return func(number * precision) / precision; + // Shift the decimal point with exponential notation to avoid floating-point funny bussiness. + // See [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round#Examples) + // for more details. + var pair = (+number + 'e').split('e'), + value = func(pair[0] + 'e' + (+pair[1] + precision)); + + // Shift back. + pair = (value + 'e').split('e'); + return +(pair[0] + 'e' + (pair[1] - precision)); } return func(number); }; diff --git a/test/test.js b/test/test.js index 364e18117..d6d1ea59c 100644 --- a/test/test.js +++ b/test/test.js @@ -11362,6 +11362,7 @@ } }); }()); + /*--------------------------------------------------------------------------*/ QUnit.module('lodash.mapKeys'); @@ -16222,13 +16223,30 @@ assert.strictEqual(actual, isCeil ? 5 : 4); }); - QUnit.test('`_.' + methodName + '` should return a rounded number with a precision of `0`', function(assert) { + QUnit.test('`_.' + methodName + '` should work with a precision of `0`', function(assert) { assert.expect(1); var actual = func(4.006, 0); assert.strictEqual(actual, isCeil ? 5 : 4); }); + QUnit.test('`_.' + methodName + '` should work with a positive precision', function(assert) { + assert.expect(2); + + var actual = func(4.016, 2); + assert.strictEqual(actual, isFloor ? 4.01 : 4.02); + + actual = func(4.1, 2); + assert.strictEqual(actual, 4.1); + }); + + QUnit.test('`_.' + methodName + '` should work with a negative precision', function(assert) { + assert.expect(1); + + var actual = func(4160, -2); + assert.strictEqual(actual, isFloor ? 4100 : 4200); + }); + QUnit.test('`_.' + methodName + '` should coerce `precision` to an integer', function(assert) { assert.expect(3); @@ -16244,18 +16262,18 @@ assert.strictEqual(actual, expected); }); - QUnit.test('`_.' + methodName + '` should return a rounded number with a positive precision', function(assert) { - assert.expect(1); + QUnit.test('`_.' + methodName + '` should work with exponential notation and `precision`', function(assert) { + assert.expect(3); - var actual = func(4.016, 2); - assert.strictEqual(actual, isFloor ? 4.01 : 4.02); - }); + var actual = func(5e1, 2); + assert.deepEqual(actual, 50); - QUnit.test('`_.' + methodName + '` should return a rounded number with a negative precision', function(assert) { - assert.expect(1); + actual = func('5e', 1); + assert.deepEqual(actual, NaN); + + actual = func('5e1e1', 1); + assert.deepEqual(actual, NaN); - var actual = func(4160, -2); - assert.strictEqual(actual, isFloor ? 4100 : 4200); }); });