@lzwme/asmd-calc
Version:
支持浮点数精度的加减乘除四则运算 JS 库。
256 lines (255 loc) • 7.8 kB
JavaScript
;
/*
* @Author: renxia
* @Date: 2018-09-10 15:10:40
* @LastEditors: renxia
* @LastEditTime: 2025-04-02 16:47:52
* @Description: 支持浮点数精度的加减乘除四则运算
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.add = add;
exports.sub = sub;
exports.mul = mul;
exports.div = div;
exports.keepDotLength = keepDotLength;
exports.toFixed = toFixed;
var utils_1 = require("./utils");
/**
* addition 加法计算。与普通加法运算不同的是,任意参数为 `null/NaN/undefined`,均会被视为 `0` 而忽略
*
* ### Example (es module)
* ```js
* import { add } from 'asmd-calc';
* console.log(add(0.1, 0.2, 3));
* // => 3.3
* ```
*
* @returns 永远返回有效的数值,不存在 NaN(视作0处理)
*/
function add() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var total = Number(args[0]);
args.slice(1).forEach(function (value) {
if (!value)
return;
if (!total)
return (total = value);
var tDLen = (0, utils_1.getDecimalLen)(total);
var vDLen = (0, utils_1.getDecimalLen)(value);
var decimalLen = tDLen + vDLen;
if (decimalLen) {
var e = Math.pow(10, Math.max(tDLen, vDLen));
total = (Math.round(total * e) + Math.round(value * e)) / e;
}
else {
total += typeof value === 'number' ? value : Number(value) || 0;
}
});
return total;
}
/**
* subtraction 减法计算。与普通减法运算不同的是,任意参数为 `null/NaN/undefined`,均会被视为 `0` 而忽略
*
* ### Example (es module)
* ```js
* import { sub } from 'asmd-calc';
* console.log(sub(0.3, 0.2, 0.1));
* // => 0
* ```
*
* @param args 第一个值为减数,后续值均为被减数
* @returns 永远返回有效的数值,不存在 NaN(视作0处理)
*/
function sub() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!args.length)
return null;
args.forEach(function (value, idx) {
if (idx && value)
args[idx] = -value;
});
return add.apply(void 0, args);
}
/**
* multiplication 乘法计算。
* - 注意小数位不宜过长(总长度不超过18位,结果不超过18位)
* - 任意参数为 `null/NaN/undefined`,均会被视为 `0`
*
* ### Example (es module)
* ```js
* import { mul } from 'asmd-calc';
* console.log(mul(3, 0.2, 0.1));
* // => 0.06
* ```
*
* @returns 永远返回有效的数值,不存在 NaN(视作0处理)
*/
function mul() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var total = Number(args[0]);
if (!args.length)
return 0;
args.slice(1).forEach(function (value) {
if (typeof value !== 'number')
value = +value || 0;
if (!value || !total)
return (total = 0);
if (1 === total)
return (total = value);
var tDLen = (0, utils_1.getDecimalLen)(total);
var vDLen = (0, utils_1.getDecimalLen)(value);
var decimalLen = tDLen + vDLen;
if (decimalLen) {
var e = Math.pow(10, decimalLen);
total = tDLen ? Math.round(total * Math.pow(10, tDLen)) : total; // Number(toNonExponential(total).replace('.', ''));
value = vDLen ? Math.round(value * Math.pow(10, vDLen)) : value; // Number(toNonExponential(value).replace('.', ''));
total = (total * value) / e;
}
else {
total *= value;
}
});
return total;
}
/**
* division 除法计算。
*
* 任意参数为 `null/NaN/undefined`,均会被视为 `0`。于是会有如下情况:
* ```
* NaN / 1 = 0 / 1 = 0
* 0 / NaN = 0 / 0 = NaN
* 1 / NaN = 1 / 0 = Infinity
* ```
*
* ### Example (es module)
* ```js
* import { div } from 'asmd-calc';
* console.log(div(0.6, 0.1, 0.2));
* // => 30
* ```
*
* @param args 第一个参数为除数,后续参数均为被除数
* @returns 永远返回有效的数值。
*/
function div() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
if (!args.length)
return null;
var total = args[0];
args.slice(1).forEach(function (value) {
if (!value || !total) {
// null \ NaN \ undefined
total /= value;
return;
}
value = Number(value);
var tDLen = (0, utils_1.getDecimalLen)(total);
var vDLen = (0, utils_1.getDecimalLen)(value);
var decimalLen = vDLen - tDLen;
if (vDLen || tDLen) {
var e = Math.pow(10, decimalLen);
if (decimalLen < 0)
e = Number(e.toFixed(-decimalLen));
total = tDLen ? Math.round(total * Math.pow(10, tDLen)) : total; // Number(toNonExponential(total).replace('.', ''));
value = vDLen ? Math.round(value * Math.pow(10, vDLen)) : value; // Number(toNonExponential(value).replace('.', ''));
total = mul(total / value, e);
}
else {
total /= value;
}
});
return total;
}
/**
* 最多保留 N 位小数
*
* ### Example (es module)
* ```js
* import { keepDotDLength } from 'asmd-calc';
* console.log(keepDotDLength(0.66666, 2));
* // => 0.66
* console.log(keepDotDLength(0.66666, 2, false));
* // => 0.66
* console.log(keepDotDLength(0.66666, 2, true));
* // => 0.67
* ```
*
* @param value 数值
* @param precision 小数位数,应为 0-16 之间的整数
* @param isrounding 是否四舍五入取值。默认 false
*/
function keepDotLength(value, precision, type) {
if (type === void 0) { type = 'floor'; }
if ((0, utils_1.isNull)(value))
return null;
if (type === true)
type = 'round';
else if (!type)
type = 'floor';
return Number(toFixed(value, precision, type));
}
/**
* toFixed 方法重写 【解决 Number.toFixed 方法在不同浏览器表现不一致的问题】
*
* ### Example (es module)
* ```js
* import { toFixed } from 'asmd-calc';
* console.log(toFixed(0.66666, 2));
* // => 0.67
* console.log(toFixed(1.45, 1));
* // => 1.5
* console.log(toFixed(1.55, 1));
* // => 1.6
* console.log(toFixed(1.515, 2));
* // => 1.52
* ```
*
* @param value 数值
* @param precision 小数位数,应为 0-16 之间的整数
* @param type 进位处理方法:
* - round - 四舍五入
* - ceil 向上取整
* - floor 向下取整(截断)
*/
function toFixed(value, precision, type) {
if (type === void 0) { type = 'round'; }
if ((0, utils_1.isNull)(value))
return null;
if (!(type in Math))
throw new Error('type must be one of ["ceil", "round", "fround", "floor"]. current: ' + type);
value = Number(value);
precision = Math.max(Number(precision), 0);
if (!precision)
return String(Math[type](value));
var valList = (0, utils_1.toNonExponential)(value).split('.');
if (!valList[1]) {
valList[1] = new Array(precision + 1).join('0');
return valList.join('.');
}
else {
var result = String(Math[type](Math.pow(10, precision) * Number('0.' + valList[1])) / Math.pow(10, precision)).split('.');
// result = 1,则没有小数部分
if (!result[1]) {
result[1] = '';
valList[0] = String(Number(valList[0]) + Number(result[0]));
}
// 小数部分末尾补 0
if (result[1].length < precision) {
result[1] += new Array(precision - result[1].length + 1).join('0');
}
valList[1] = result[1];
return valList.join('.');
}
}