概述
解决方案
1、jsbi库
// https://github.com/GoogleChromeLabs/jsbi
import JSBI from 'jsbi';
export const compute = (left: number | undefined, right: number | undefined) => {
return (
JSBI.toNumber(
JSBI.add(
JSBI.BigInt(((left || 0) * 10000).toFixed(0)),
JSBI.BigInt(((right || 0) * 10000).toFixed(0)) ) ) / 10000 );
};
export const bigIntDivide = (left: number, right: number): number => {
return (
JSBI.toNumber(
JSBI.divide(JSBI.BigInt((left * 10000).toFixed(0)), JSBI.BigInt(right))) / 10000 ); };
export const bigIntMultiply = (left: number, right: number): number => { return ( JSBI.toNumber(JSBI.multiply(JSBI.BigInt((left * 10000).toFixed(0)), JSBI.BigInt(right))) / 10000 ); };
2、自定义函数
/**
* 乘法函数,用来得到精确的乘法结果
*/
export const accMul = (arg1: number = 0, arg2: number = 0) => {
let m = 0;
const s1 = arg1.toString();
const s2 = arg2.toString();
try {
m += s1.split('.')[1].length;
} catch (e) {}
try {
m += s2.split('.')[1].length;
} catch (e) {}
return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m);
};
/**
* 除法函数,用来得到精确的除法结果
*/
export const accDiv = (arg1: number = 0, arg2: number = 0) => {
let t1 = 0;
let t2 = 0;
try {
t1 = arg1.toString().split('.')[1].length;
} catch (e) {}
try {
t2 = arg2.toString().split('.')[1].length;
} catch (e) {}
const r1 = Number(arg1.toString().replace('.', ''));
const r2 = Number(arg2.toString().replace('.', ''));
return accMul((r1 / r2), Math.pow(10, t2 - t1));
};
/**
* 加法函数,用来得到精确的加法结果
*/
export const accAdd = (arg1: number = 0, arg2: number = 0) => {
let r1 = 0;
let r2 = 0;
try {
r1 = arg1.toString().split('.')[1].length;
} catch (e) {}
try {
r2 = arg2.toString().split('.')[1].length;
} catch (e) {}
const m = Math.pow(10, Math.max(r1, r2));
return (accMul(arg1, m) + accMul(arg2, m)) / m;
};
/**
* 减法函数,用来得到精确的减法结果
*/
export const accSub = (arg1: number = 0, arg2: number = 0) => {
let r1 = 0;
let r2 = 0;
try {
r1 = arg1.toString().split('.')[1].length;
} catch (e) {}
try {
r2 = arg2.toString().split('.')[1].length;
} catch (e) {}
const m = Math.pow(10, Math.max(r1, r2));
const n = r1 >= r2 ? r1 : r2;
return Number(((accMul(arg1, m) - accMul(arg2, m)) / m).toFixed(n));
};
原因
-
- “下面再以
0.1
例解释浮点误差的原因,0.1
转成二进制表示为0.0001100110011001100
(1100循环),1.100110011001100x2^-4
,” - 这里进行了左移
-
回到 JS 的实现中, 底层使用二进制存储数据, 数据格式为:
IEEE-754
, 用64 bits
的空间存储数据, 由于某些原因, 使用52bits
的空间存储有效数字, 但是实际存储了52 + 1 = 53bits
的有效数字信息(因为第 1 个有效数字始终是 1, 不需要存储), 11 bits 的指数位信息.那么它们各自的取值范围是多少呢?
有效数字: [0, 2^53 - 1] 指数位: [-1022, 1023] , 指数位还要考虑负指数的情况, 所以使用的是补码形式存储的数据, 还有一些其他的原因. 导致最终的结果不是[0, 2047]
- “下面再以
- blog.csdn.net/moguzhale/a…
- 在线进制转化:tool.oschina.net/hexconvert/
-
js支持的整数的有效范围是,-2的53次方至2的53次方。也就是 -9007199254740992 ~ 9007199254740992。可以在浏览器里输入在这个范围之外的数试试,返回的值多数跟输入不一样。
- Math.pow(2, 53) === Math.pow(2, 53) + 1; // true
- JavaScript 里最大的安全的整数为什么是2的53次方减一?
-
IEEE 754 的标准,使用64位固定长度表示,也就是标准的double双精度浮点数。