From: Alanscut Date: Sun, 14 Jun 2020 15:14:42 +0000 (+0800) Subject: fix #5596: floating number calculation converter X-Git-Tag: 2.30.0~15^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3d1c1cad67f1b60b86d1f85daf7890a5813b6b4;p=thirdparty%2Fmoment.git fix #5596: floating number calculation converter --- diff --git a/src/lib/duration/constructor.js b/src/lib/duration/constructor.js index 6033769b7..ee8a94f5b 100644 --- a/src/lib/duration/constructor.js +++ b/src/lib/duration/constructor.js @@ -1,6 +1,7 @@ import { normalizeObjectUnits } from '../units/aliases'; import { getLocale } from '../locale/locales'; import isDurationValid from './valid.js'; +import multiply from '../utils/float-calculate'; export function Duration(duration) { var normalizedInput = normalizeObjectUnits(duration), @@ -19,9 +20,9 @@ export function Duration(duration) { // representation for dateAddRemove this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 + multiply(seconds, 1e3) + // 1000 + multiply(minutes, 6e4) + // 1000 * 60 + multiply(hours, 36e5); //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 // Because of dateAddRemove treats 24 hours as different from a // day when working around DST, we need to store them separately this._days = +days + weeks * 7; diff --git a/src/lib/utils/float-calculate.js b/src/lib/utils/float-calculate.js new file mode 100644 index 000000000..f7427e91f --- /dev/null +++ b/src/lib/utils/float-calculate.js @@ -0,0 +1,33 @@ +export default function multiply(a, b) { + var bi1 = toBigInt(parseFloat(a)), + bi2 = toBigInt(parseFloat(b)), + mag1 = bi1.magnification, + mag2 = bi2.magnification, + num1 = bi1.num, + num2 = bi2.num; + return (num1 * num2) / (mag1 * mag2); +} + +function toBigInt(floatNum) { + var bigInt = { + num: 0, + magnification: 1, + }, + strNum, + len, + mag, + intNum; + + if (Math.floor(floatNum) === floatNum) { + bigInt.num = floatNum; + return bigInt; + } + + strNum = floatNum.toString(); + len = strNum.length - strNum.indexOf('.') - 1; + mag = Math.pow(10, len); + intNum = Number(floatNum.toString().replace('.', '')); + bigInt.num = intNum; + bigInt.magnification = mag; + return bigInt; +} diff --git a/src/test/moment/duration.js b/src/test/moment/duration.js index a1e97472b..4d6c4898a 100644 --- a/src/test/moment/duration.js +++ b/src/test/moment/duration.js @@ -248,6 +248,13 @@ test('instantiation from another duration', function (assert) { }); test('explicit cloning', function (assert) { + var duration = moment.duration(1.1234, 'hours'); + assert.equal(duration.milliseconds(), 240, + 'Float number calculation will not lose accuracy' + ); +}); + +test('float number calculation', function (assert) { var durationA = moment.duration(5, 'milliseconds'), durationB = durationA.clone(); durationA.add(5, 'milliseconds');