JavaScript超大整数加法

什么是「超大整数」?

JavaScript 采用 IEEE754标准 中的浮点数算法来表示数字 Number。

我也没花时间去详细了解 IEEE754标准 ,但对于处理超大整数,了解下面的几个知识点就足够了。

首先,JavaScript 实际上可以表示的最大数是: 1.7976931348623157e+308

Number.MAX_VALUE;    // 1.7976931348623157e+308

虽然这个数可以正确表示出来,但会存在「精度丢失」的问题。

那什么是「精度丢失」? 我们看看下面的例子:

num1 = 10000000000000000000000000 + 11111111111111111111111111;    // 2.111111111111111e+25
num2 = 21111111111111111111111000;    // 2.111111111111111e+25 num1 === num2;    // true

按照常规的数学预算, num1 的计算结果是 21111111111111111111111111,而 num2 的值是 21111111111111111111111000,两者是不可能相等。但实际上 JavaScript 可以精确表示到个位的最大整数是:9007199254740992

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

关于 JavaScript Number 的一些上下极限,更详细的资料可以看下图:

正因为 JavaScript 的 Number 类型存在这些限制,当我们需要处理两个「超大整数」的相加时,直接套用加法运算符会存在以下问题:

  • 当结果大于 Math.pow(2, 53)  时,会出现精度丢失,导致最终结果存在偏差
  • 当结果大于 Number.MAX_VALUE,直接返回 Infinity

为了解决这些问题,才产生了「超大整数」加法的需求,实现代码如下:

var largeIntegerAddition = function () {
    function isNumberString() {
        var result = true;
        for (var i = arguments.length; i--;) {
            if (typeof arguments[i] !== "string" !/^\d+$/.test(arguments[i])) {
                console.error("arguments format is incorrect!");
                result = false;
                break;
            }
        }
        return result;
    }

    function trimHeadZero(numberStr) {
        return numberStr.replace(/^0*/, "");
    }

    return function () {
        var bigNum1 = arguments[0],
            bigNum2 = arguments[1];

        if (!bigNum2) {
            return isNumberString(bigNum1) ? trimHeadZero(bigNum1) : "0";
        } else {
            if (!isNumberString(bigNum1, bigNum2)) {
                return "0";
            }

            bigNum1 = trimHeadZero(bigNum1);
            bigNum2 = trimHeadZero(bigNum2);

            var carry = 0,  // 进位
                bigNum1Split = bigNum1.split("").reverse(),
                bigNum2Split = bigNum2.split("").reverse(),
                result = "",
                maxNumSize = bigNum1Split.length > bigNum2Split.length ? bigNum1Split.length : bigNum2Split.length;

            for (var i = 0; i < maxNumSize; i++) {
                var n1 = bigNum1Split[i] ? +bigNum1Split[i] : 0,
                    n2 = bigNum2Split[i] ? +bigNum2Split[i] : 0,
                    sum = (n1 + n2 + carry).toString();
                if (sum.length > 1) {
                    carry = +sum.slice(0, 1);
                    result = sum.slice(1, 2) + result;
                } else {
                    carry = 0;
                    result = sum + result;
                }
            }

            if (carry !== 0) {
                result = carry + result;
            }

            if (arguments[2]) {
                var argumentArr = Array.prototype.slice.call(arguments, 0).slice(2);
                argumentArr.unshift(result);
                return largeIntegerAddition.apply(this, argumentArr);
            } else {
                return result;
            }
        }
    }
}();

 

测试用例:

// 测试用例
function unitTest(arg, result) {
    var res = largeIntegerAddition.apply(this, arg);
    console.log(res, res === result);
}
unitTest([], "");
unitTest(["012", 3], "15");
unitTest(["012", "0013", "214", 100002], "100241");
unitTest(["1.1111111111111111e+227", "1"], "1.1111111111111111e+227");
unitTest(["123"], "123");
unitTest(["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], "45");
unitTest(["0", "2", "3", "4", "123"], "132");
unitTest(["012", "3"], "15");
unitTest(["012", "0013", "214", "100002"], "100241");
unitTest(["99999999999999999999", "1"], "100000000000000000000");
unitTest(["99999999999999999999", "11111111111111111111"], "111111111111111111110");
unitTest(["99999999999999999999", "11111111111111111111", "11111111"], "111111111111122222221");
unitTest(["4810284728175829182", "92817475910285750182"], "97627760638461579364");
unitTest(["4810284728175829182", "92817475910285750182", "9728172845"], "97627760648189752209");
unitTest(["4810284728175829182", "92817475910285750182", "9728172845" , "92875018002020102"], "97720635666191772311");
unitTest([
    (function () {
        var str = "";
        for (var i = 500; i--;) {
            str += "9";
        }
        return str;
    })(),
    (function () {
        var str = "";
        for (var i = 500; i--;) {
            str += "1";
        }
        return str;
    })()
], (function () {
    var str = "";
    for (var i = 500; i--;) {
        str += "1";
    }
    return str + "0";
})());

 

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索return
, function
, 整数
, unittest
, result
, 超大数
, arguments
, 高精度加法
, javascript整数
javascript的split
javascript 加法、javascript加法运算、javascript 加减法、javascript date加法、javascript加法计算器,以便于您获取更多的相关知识。

时间: 2024-10-31 14:19:34

JavaScript超大整数加法的相关文章

java中实现超大整数相加减

 代码如下 复制代码 /**    * 整数加法    *    * @param lv    *            左值    * @param rv    *            右值    * @param result    *            相加的结果    * @数值存放说明 数值的每一位作为栈的一项存放在栈中,从栈底到栈顶依次是数值的高位到低位    * @算法描述 输入的加数倒序存放在栈中(即栈顶是数的最低位,栈底是数的最高位). 计算的时候,依次弹出栈中的数据,对

Java实现基于栈实现整数加法算法

整数是有最大上限的,如果整数超出最大上限位数,如 4398912120931092319+49832232849329019019210921029,此时整型变量无法保存这些数字.解 决的办法是,可利用字符串保存这些数字,再利用栈做按位加法. 1.用Java实现,首先使用链表LinkedList构造栈数据结构. import java.util.LinkedList; public class IntStack { private LinkedList<Integer> storage = n

最简单的JavaScript验证整数、小数、实数、有效位小数正则表达式_javascript技巧

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title> 验证数字最简单正则表达式大全 </

javascript 判断整数方法分享_javascript技巧

判断整数的方法有两种:正则判断和逐字判断. 由于逐字判断效率过于低下,这里就不予描述了,有兴趣的看客可以自己谷歌. 1.正则判断 复制代码 代码如下: var r = /^\+?[1-9][0-9]*$/; //正整数 console.log(r.test(1.23)); 效果测试: http://jsfiddle.net/wzsdp9Lc/ 扩展功能列表 复制代码 代码如下: "^\\d+$" //非负整数(正整数 + 0) "^[0-9]*[1-9][0-9]*$&quo

超大正整数加法与乘法最笨方法实现

using System.Text; private string AddNumber(string numA, string numB) { int lenA=0, lenB=0; int lenI=0, intTen=0; int intA=0, intB=0; StringBuilder result=new StringBuilder(""); lenA=numA.Length; lenB=numB.Length; if(lenA>lenB) lenI=lenA; els

JAVA面试题集

基础知识: 1.C++或Java中的异常处理机制的简单原理和应用. 当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常.违反语义规则包括2种情况.一种是JAVA类库内置的语义检查.例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException.另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常.所有的异常都是jav

javascript将浮点数转换成整数的三个方法_javascript技巧

Summary 暂时我就想到3个方法而已.如果读者想到其他好用方法,也可以交流一下 parseInt 位运算符 Math.floor Math.ceil Description 一.parseInt 1. 实例 parseInt("13nash");//13 parseInt("")// NaN parseInt("0xA") //10(十六进制) parseInt(" 13")//13 parseInt("070&

JavaScript将字符串转换为整数的方法_javascript技巧

本文实例讲述了JavaScript将字符串转换为整数的方法.分享给大家供大家参考.具体如下: var s='1'; var s2='2'; alert(parseInt(s) parseInt(s2)); 希望本文所述对大家的javascript程序设计有所帮助. 以上是小编为您精心准备的的内容,在的博客.问答.公众号.人物.课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javascript , 字符串 , 转换 整数 javascript转换成整数.javascript转换为整数

javascript解决小数的加减乘除精度丢失的方案_javascript技巧

原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. javascript(js)的小数点加减乘除问题,是一个js的bug如0.3*1 = 0.2999999999等,下面列出可以完美求出相应精度的四种js算法 function accDiv(arg1,arg2){ var t1=0,t2=0,r1,r2; try{t1=arg1.toString().split(".")[1].length}catch(e){} t