Js大数运算精度问题,如何实现两个大数相加?

更新日期: 2022-02-15阅读: 1.8k标签: 精度

先从一个例子讲起

var number1 = 10000000000000000000000000 + 11111111111111111111111111   
//理论上number1的值应该是21111111111111111111111111(javascript中会表示为科学计数法:2.111111111111111e+25)
var number2 = 21111111111111111111111000
console.log(number1 === number2)  //true

这个不用算简单看一下都知道计算结果不对,最后几位肯定应该都是1的,可是为什么会得到一个不对的值呢?


JavaScript Number的精度丢失问题

因为JavaScript的Number类型是遵循 IEEE 754 规范表示的,这就意味着JavaScript能精确表示的数字是有限的,JavaScript可以精确到个位的最大整数是9007199254740992,也就是2的53次方,超过这个范围就会精度丢失,造成JavaScript无法判断大小,从而会出现下面的现象:

Math.pow(2, 53);    // 9007199254740992
Math.pow(2, 53) === Math.pow(2, 53) + 1;    // true
9007199254740992 === 9007199254740992 + 1;    // true

可以从下面这张图上看到JavaScript Number能够精确表示的上下限:



解决方案

当有两个整数 a 和 b ,在通常情况下我们有“+”运算符对其进行相加运算:

let sum = a + b;

但是 JS 在存放整数的时候是有一个安全范围的,一旦数字超过这个范围便会损失精度。

我们不能拿精度损失的数字进行运行,因为运算结果一样是会损失精度的。

所以,我们要用字符串来表示数据!(不会丢失精度)

JS 中整数的最大安全范围可以查到是:9007199254740991
假如我们要进行 9007199254740991 + 1234567899999999999

我们要先准备两个字符串变量和一个方法:

const a = "9007199254740991"
const b = "1234567899999999999"

function add(a ,b){
   //...
}

然后将字符串长度对齐:

const a = "9007199254740991"
const b = "1234567899999999999"

function add(a, b){
   //取两个数字的最大长度
   let maxLength = Math.max(a.length, b.length)
   //用0去补齐长度
   a = a.padStart(maxLength , 0)    //"0009007199254740991"
   b = b.padStart(maxLength , 0)   //"1234567899999999999"
}

然后从个位开始相加:

const a = "9007199254740991";
const b = "1234567899999999999";

function add(a, b) {
    if (typeof a === 'number') a = String(a)
    if (typeof b === 'number') b = String(b)

    //取两个数字的最大长度
    const maxLength = Math.max(a.length, b.length)

    //用0去补齐长度
    a = a.padStart(maxLength, 0)
    b = b.padStart(maxLength, 0)

    //定义加法过程中需要用到的变量
    let t = 0
    let f = 0  // 进位
    let sum = ''

    for(let i = maxLength; i--;) {
        t = parseInt(a[i]) + parseInt(b[i]) + f
        f = Math.floor(t/10)
        sum = t % 10 + sum
    }

    if (f === 1) {
        sum = '1' + sum
    }
    return sum
}

运行:

add(a ,b).    // 结果为:1243575099254740990

add(1234567899999999999, '1234567899999999999')   // 结果为: "2469135799999999999"

链接: https://www.fly63.com/article/detial/11188

JavaScript浮点数精度

0.1 + 0.2 是否等于 0.3 作为一道经典的面试题,已经广外熟知,说起原因,大家能回答出这是浮点数精度问题导致,也能辩证的看待这并非是 ECMAScript 这门语言的问题,今天就是具体看一下背后的原因。

js浮点数运算时出现精度问题以及保留指定精度位

因为toFixed可能会出现bug,比如value为: 310.275,保留2位小数,为310.27;或者是value为: 139.605 ,保留2位小数,为: 139.60

如何处理 JavaScript 中的浮点数精度?

ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。它表示 1 与大于 1 的最小浮点数之间的差。Number.EPSILON实际上是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了

都知道0.1+0.2 = 0.30000000000000004,那要怎么让它等于0.3

小学数学老师教过我们,0.1 + 0.2 = 0.3,但是为什么在我们在浏览器的控制台中输出却是0.30000000000000004?除了加法有这个奇怪的现象,带小数点的减法和乘除计算也会得出意料之外的结果

Js精度丢失原因以及解决方案

由于计算机的底层是由二进制实现的,有些运算的数字无法全部显示出来。就像一些无理数不能完全显示出来一样,如圆周率 3.1415926...,0.3333... 等。JavaScript遵循IEEE754规范

JS中浮点数精度问题_小数四舍五入和浮点数的研究

最近在做项目的时候,涉及到商品价格的计算,经常会出现计算出现精度问题。刚开始草草了事,直接用toFixed就解决了问题,并没有好好的思考一下这个问题

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!