diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 699a912ccc3..93e9bda5593 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -571,7 +571,15 @@ var utils = { * @param {Number} decimals the number of decimals. eg: round_decimals(3.141592,2) -> 3.14 */ round_decimals: function (value, decimals) { - return utils.round_precision(value, Math.pow(10,-decimals)); + /** + * The following decimals introduce numerical errors: + * Math.pow(10, -4) = 0.00009999999999999999 + * Math.pow(10, -5) = 0.000009999999999999999 + * + * Such errors will propagate in round_precision and lead to inconsistencies between Python + * and JavaScript. To avoid this, we parse the scientific notation. + */ + return utils.round_precision(value, parseFloat('1e' + -decimals)); }, /** * performs a half up rounding with arbitrary precision, correcting for float loss of precision diff --git a/addons/web/static/tests/core/util_tests.js b/addons/web/static/tests/core/util_tests.js index 3403c9effaf..96954e9d2f8 100644 --- a/addons/web/static/tests/core/util_tests.js +++ b/addons/web/static/tests/core/util_tests.js @@ -136,6 +136,66 @@ QUnit.module('core', {}, function () { assert.strictEqual(child.bar(), 'Child bar'); }) + QUnit.test('round_decimals', function (assert) { + assert.expect(21); + + var round_di = utils.round_decimals; + + assert.strictEqual(String(round_di(1.0, 0)), '1'); + assert.strictEqual(String(round_di(1.0, 1)), '1'); + assert.strictEqual(String(round_di(1.0, 2)), '1'); + assert.strictEqual(String(round_di(1.0, 3)), '1'); + assert.strictEqual(String(round_di(1.0, 4)), '1'); + assert.strictEqual(String(round_di(1.0, 5)), '1'); + assert.strictEqual(String(round_di(1.0, 6)), '1'); + assert.strictEqual(String(round_di(1.0, 7)), '1'); + assert.strictEqual(String(round_di(1.0, 8)), '1'); + assert.strictEqual(String(round_di(0.5, 0)), '1'); + assert.strictEqual(String(round_di(-0.5, 0)), '-1'); + assert.strictEqual(String(round_di(2.6745, 3)), '2.6750000000000003'); + assert.strictEqual(String(round_di(-2.6745, 3)), '-2.6750000000000003'); + assert.strictEqual(String(round_di(2.6744, 3)), '2.674'); + assert.strictEqual(String(round_di(-2.6744, 3)), '-2.674'); + assert.strictEqual(String(round_di(0.0004, 3)), '0'); + assert.strictEqual(String(round_di(-0.0004, 3)), '0'); + assert.strictEqual(String(round_di(357.4555, 3)), '357.456'); + assert.strictEqual(String(round_di(-357.4555, 3)), '-357.456'); + assert.strictEqual(String(round_di(457.4554, 3)), '457.455'); + assert.strictEqual(String(round_di(-457.4554, 3)), '-457.455'); + }); + + QUnit.test('round_precision', function (assert) { + assert.expect(26); + + var round_pr = utils.round_precision; + + assert.strictEqual(String(round_pr(1.0, 1)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.1)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.01)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.001)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.0001)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.00001)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.000001)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.0000001)), '1'); + assert.strictEqual(String(round_pr(1.0, 0.00000001)), '1'); + assert.strictEqual(String(round_pr(0.5, 1)), '1'); + assert.strictEqual(String(round_pr(-0.5, 1)), '-1'); + assert.strictEqual(String(round_pr(2.6745, 0.001)), '2.6750000000000003'); + assert.strictEqual(String(round_pr(-2.6745, 0.001)), '-2.6750000000000003'); + assert.strictEqual(String(round_pr(2.6744, 0.001)), '2.674'); + assert.strictEqual(String(round_pr(-2.6744, 0.001)), '-2.674'); + assert.strictEqual(String(round_pr(0.0004, 0.001)), '0'); + assert.strictEqual(String(round_pr(-0.0004, 0.001)), '0'); + assert.strictEqual(String(round_pr(357.4555, 0.001)), '357.456'); + assert.strictEqual(String(round_pr(-357.4555, 0.001)), '-357.456'); + assert.strictEqual(String(round_pr(457.4554, 0.001)), '457.455'); + assert.strictEqual(String(round_pr(-457.4554, 0.001)), '-457.455'); + assert.strictEqual(String(round_pr(-457.4554, 0.05)), '-457.45000000000005'); + assert.strictEqual(String(round_pr(457.444, 0.5)), '457.5'); + assert.strictEqual(String(round_pr(457.3, 5)), '455'); + assert.strictEqual(String(round_pr(457.5, 5)), '460'); + assert.strictEqual(String(round_pr(457.1, 3)), '456'); + }); }); });