127 lines
3.6 KiB
JavaScript
127 lines
3.6 KiB
JavaScript
/**
|
|
* Gamp v0.2.1 - A simple arithmetic API with workaround to floating-point issue
|
|
*
|
|
* https://github.com/jsconan/gamp
|
|
*
|
|
* Copyright (c) 2016 Jean-Sébastien CONAN
|
|
* Released under the MIT license.
|
|
*/
|
|
|
|
// 2016 - OAT - modified AMD loader to be able to compile it
|
|
define(function() {
|
|
'use strict';
|
|
|
|
/**
|
|
* Computes the precision of a decimal number.
|
|
* This precision will be then used as a correction factor to normalize
|
|
* the value in order to prevent the floating-point round error.
|
|
* @param {number} val
|
|
* @returns {number}
|
|
*/
|
|
function precision(val) {
|
|
var digits = String(val);
|
|
var point = digits.indexOf('.');
|
|
return point < 0 ? 1 : Math.pow(10, digits.length - point - 1);
|
|
}
|
|
|
|
/**
|
|
* Computes the approached precision for a list of decimal numbers.
|
|
* This precision will be then used as a correction factor to normalize
|
|
* the values in order to prevent the floating-point round error.
|
|
* @param {number} ...
|
|
* @returns {number}
|
|
*/
|
|
function gamp() {
|
|
var i = arguments.length - 1;
|
|
var factor = -Infinity;
|
|
while (i >= 0) {
|
|
factor = Math.max(factor, precision(arguments[i--]));
|
|
}
|
|
return Math.abs(factor);
|
|
}
|
|
|
|
/**
|
|
* Makes the translation of a floating point number to an integer value using a precision factor
|
|
* @param {number} val
|
|
* @param {number} factor
|
|
* @returns {number}
|
|
*/
|
|
gamp.normalize = function normalize(val, factor) {
|
|
return Math.round(factor * Number(val));
|
|
};
|
|
|
|
/**
|
|
* Adjusts the number of digits to prevent round-off error
|
|
* @param {number} val
|
|
* @param {number} [digits=16]
|
|
* @returns {number}
|
|
*/
|
|
gamp.round = function round(val, digits) {
|
|
return Number(Number(val).toPrecision('undefined' === typeof digits ? 16 : digits));
|
|
};
|
|
|
|
/**
|
|
* Computes the addition of two decimal values
|
|
* @param {number} a
|
|
* @param {number} b
|
|
* @returns {number}
|
|
*/
|
|
gamp.add = function add(a, b) {
|
|
var factor = gamp(a, b);
|
|
return gamp.round((gamp.normalize(a, factor) + gamp.normalize(b, factor)) / factor);
|
|
};
|
|
|
|
/**
|
|
* Computes the subtraction of two decimal values
|
|
* @param {number} a
|
|
* @param {number} b
|
|
* @returns {number}
|
|
*/
|
|
gamp.sub = function sub(a, b) {
|
|
var factor = gamp(a, b);
|
|
return gamp.round((gamp.normalize(a, factor) - gamp.normalize(b, factor)) / factor);
|
|
};
|
|
|
|
/**
|
|
* Computes the multiplication of two decimal values
|
|
* @param {number} a
|
|
* @param {number} b
|
|
* @returns {number}
|
|
*/
|
|
gamp.mul = function mul(a, b) {
|
|
var factor = gamp(a, b);
|
|
return gamp.round((gamp.normalize(a, factor) * gamp.normalize(b, factor)) / (factor * factor), 15);
|
|
};
|
|
|
|
/**
|
|
* Computes the division of two decimal values
|
|
* @param {number} a
|
|
* @param {number} b
|
|
* @returns {number}
|
|
*/
|
|
gamp.div = function div(a, b) {
|
|
var factor = gamp(a, b);
|
|
return gamp.round(gamp.normalize(a, factor) / gamp.normalize(b, factor));
|
|
};
|
|
|
|
/**
|
|
* Computes the power of a decimal value
|
|
* @param {number} a
|
|
* @param {number} b
|
|
* @returns {number}
|
|
*/
|
|
gamp.pow = function pow(a, b) {
|
|
var factor = gamp(a);
|
|
var ta = gamp.normalize(a, factor);
|
|
var ib = Math.floor(b);
|
|
var fb = b - ib;
|
|
var res = ib ? Math.pow(ta, ib) / Math.pow(factor, ib) : 1;
|
|
if (fb) {
|
|
res = gamp.div(gamp.mul(res, Math.pow(ta, fb)), Math.pow(factor, fb));
|
|
}
|
|
return gamp.round(res, 15);
|
|
};
|
|
|
|
return gamp;
|
|
});
|