JS加法乘法错误解决number-precision JS 加法乘法错误解决 number-precision
问题描述
⼀个项⽬中,需要计算 0.56 * 100 然后转换成字符串,结果计算错误,所以调研使⽤这个库实现。
但是计算 0.59 * 100 结果正确。这是 JS 内部的问题。
当然还有经典的 0.1 + 0.2 = 0.30000000000000004 问题
己所不欲勿施于人议论文
坚果英语怎么读我具体使⽤ number-precision 这个库,可以实现 JS 精确四则运算。
安装
npm install number-precision --save
主要⽅法
可以计算加减乘除(plus,minus,times, divides)以及求相近值(strip, round)
NP.strip(num) // strip a number to nearest right number
NP.plus(num1, num2, num3, ...) // addition, num + num2 + num3, two numbers is required at least.
NP.minus(num1, num2, num3, ...) // subtraction, num1 - num2 - num3
NP.times(num1, num2, num3, ...) // multiplication, num1 * num2 * num3
NP.divide(num1, num2, num3, ...) // division, num1 / num2 / num3
具体使⽤
import NP from 'number-precision';
NP.strip(0.09999999999999998); // = 0.1
排卵期有几天时间
NP.plus(0.1, 0.2); // = 0.3, not 0.30000000000000004
NP.plus(2.3, 2.4); // = 4.7, not 4.699999999999999
NP.minus(1.0, 0.9); // = 0.1, not 0.09999999999999998
NP.times(3, 0.3); // = 0.9, not 0.8999999999999999
NP.times(0.362, 100); // = 36.2, not 36.199999999999996
NP.divide(1.21, 1.1); // = 1.1, not 1.0999999999999999
如果你想避免下⾯的警告(报错:数值转换整数越界,结果不精确),可以在⽂档开头增加下⾯的提⽰
PS: If you want to get rid of XXX is beyond boundary when transfer to integer, the results may not be accurate, u this at the beginning of your app to turn off boundary checking.
正⽂已经结束,后⾯是简单的源码分析,看⼀下作者如何实现精确计算。
源码分析
这⾥使⽤ TS 实现精确计算。
type numType = number | string;
/**
* @desc 解决浮动运算问题,避免⼩数点后产⽣多位数和计算精度损失。
* 问题⽰例:2.3 + 2.4 = 4.699999999999999,1.0 - 0.9 = 0.09999999999999998
*/
/**
* 把错误的数据转正
* strip(0.09999999999999998)=0.1
*/
function strip(num: numType, precision = 15): number {
return +parFloat(Number(num).toPrecision(precision));
}
/**
* Return digits length of a number
* @param {*number} num Input number创城口号
*/
function digitLength(num: numType): number {
// Get digit length of e
const eSplit = String().split(/[eE]/);
const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
return len > 0 ? len : 0;
/**
玄麦柑桔颗粒* 把⼩数转成整数,⽀持科学计数法。如果是⼩数则放⼤成整数
* @param {*number} num 输⼊数
*/
function float2Fixed(num: numType): number {
if (String().indexOf('e') === -1) {
return String().replace('.', ''));
}
const dLen = digitLength(num);
return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
}
/**
* 检测数字是否越界,如果越界给出提⽰
* @param {*number} num 输⼊数
*/
function checkBoundary(num: number) {
if (_boundaryCheckingState) {
if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
console.warn(`${num} is beyond boundary when transfer to integer, the results may not be accurate`); }
}
}
/**
* 精确乘法
*/
function times(num1: numType, num2: numType, ...others: numType[]): number {
if (others.length > 0) {
return times(times(num1, num2), others[0], ...others.slice(1));
}
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
const baNum = digitLength(num1) + digitLength(num2);
const leftValue = num1Changed * num2Changed;
checkBoundary(leftValue);
return leftValue / Math.pow(10, baNum);
}
/**
* 精确加法
*/
function plus(num1: numType, num2: numType, ...others: numType[]): number {
if (others.length > 0) {
return plus(plus(num1, num2), others[0], ...others.slice(1));
}
const baNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baNum) + times(num2, baNum)) / baNum;
}
/**
* 精确减法
*/
function minus(num1: numType, num2: numType, ...others: numType[]): number {
if (others.length > 0) {
return minus(minus(num1, num2), others[0], ...others.slice(1));
}
const baNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
return (times(num1, baNum) - times(num2, baNum)) / baNum;
}
* 精确除法
*/
function divide(num1: numType, num2: numType, ...others: numType[]): number {
if (others.length > 0) {
return divide(divide(num1, num2), others[0], ...others.slice(1));怎么样做面包
}
const num1Changed = float2Fixed(num1);
const num2Changed = float2Fixed(num2);
checkBoundary(num1Changed);
checkBoundary(num2Changed);
/
/ fix: 类似 10 ** -4 为 0.00009999999999999999,strip 修正
return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1)))); }
韩剧介绍/**
* 四舍五⼊
*/
function round(num: numType, ratio: number): number {
const ba = Math.pow(10, ratio);
return und(times(num, ba)), ba);
}
let _boundaryCheckingState = true;
/**
* 是否进⾏边界检查,默认开启
* @param flag 标记开关,true 为开启,fal 为关闭,默认为 true
*/
// 这⾥可以设置边界检查(默认是true)
function enableBoundaryChecking(flag = true) {
_boundaryCheckingState = flag;
}
// 输出上⾯的⽅法
北京天安门广场export { strip, plus, minus, times, divide, round, digitLength, float2Fixed, enableBoundaryChecking }; export default {
strip,
plus,
minus,
times,
divide,
round,
digitLength,
float2Fixed,
enableBoundaryChecking,
};
参考链接