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‘;
})());

本文作者:Maple Jan

本文链接:http://www.cnblogs.com/maplejan/p/3893545.html

JavaScript超大整数加法,布布扣,bubuko.com

时间: 2024-10-10 14:17:17

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

如果系统要使用超大整数(超过long长度范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算

package interview_10_10; import org.junit.Test; public class T1 { /** * 如果系统要使用超大整数(超过long长度范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算). */ @Test public void test1() { String number1 = "4324328732789"; String number2 = "2383244324324325898

大整数加法计算

普通数字的运算,我们可以直接运用已有类型int, long, long long等等计算,但要是数字非常大,这些类型是远远装不下的. 故而很多情况下需要我们自己来设置大整数运算,本篇记录的是大整数的加法运算的方法. 对于加法运算,第一个方法是模拟手算.先来看看手算的步骤: 手算的时候,我们会先把个位相加,有进位则向前进一位,然后计算下一位,重复此步骤.若两个数的位数不同,计算时我们会把位数长的放在上面,位数短的放在下面.短位的数加完后,长位的数则和0相加. 实现加法计算的思路很简单,首先把数字都

A——大整数加法(HDU1002)

题目: I have a very simple problem for you. Given two integers A and B, your job is to calculate the Sum of A + B. InputThe first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line co

日常记录(c语言)--字符串实现大整数加法

运行环境:CentOs 64位--vim 最近在看<剑指offer>这本书,看了前面的关于面试的能力,顿时觉得自己的编程能力差得好远. 可能我对鲁棒的代码理解还不深,我觉得鲁棒应该就是代码可以应对各种不同的输入,都能有相应的处理,并给出相应的输出. 下面是我看了之后对之前做过的大整数加法做了一些完善,之前的只能实现对纯数字字符进行求和,甚至连对空指针的处理都没有,好惭愧.我会用注释来记录自己对此算法的理解. 1 #include <stdio.h> 2 #include <s

Functions类,一个Javascript的函数加法类,将两个函数加起来,顺序执行

以下是类的代码: 1 var Functions = { 2 oFunctions: null, 3 add: function (oFunc, oNewFunc) { 4 var oNew = function () { 5 oFunc(); 6 oNewFunc(); 7 }; 8 return oNew; 9 } 10 }; 以下是测试代码: 1 function one() { 2 alert(1); 3 } 4 5 function two() { 6 alert(2); 7 } 8

AC日记——大整数加法 openjudge 1.6 10

10:大整数加法 总时间限制:  1000ms 内存限制:  65536kB 描述 求两个不超过200位的非负整数的和. 输入 有两行,每行是一个不超过200位的非负整数,可能有多余的前导0. 输出 一行,即相加后的结果.结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342. 样例输入 22222222222222222222 33333333333333333333 样例输出 55555555555555555555 来源 程序设计实习2007 思路: 模拟: 来,上代码:

【华为OJ】【039-无线OSS-高精度整数加法】

[华为OJ][算法总篇章] [华为OJ][039-无线OSS-高精度整数加法] [工程下载] 题目描述 在计算机中,由于处理器位宽限制,只能处理有限精度的十进制整数加减法,比如在32位宽处理器计算机中, 参与运算的操作数和结果必须在-231~231-1之间.如果需要进行更大范围的十进制整数加法,需要使用特殊 的方式实现,比如使用字符串保存操作数和结果,采取逐位运算的方式.如下: 9876543210 + 1234567890 = ? 让字符串 num1="9876543210",字符串

uva 424(Integer Inquiry)高精度大整数加法

这是一道很标准的大整数加法,我却wa了4次,没提交一次就查到一些细节问题,比如说我们考虑前导 0的问题,还有就是没有对输入数组处理, 使得他们每次输入时高位的置0,还有就是没考虑到最后相加后的进位, 这些问题一一改正之后,还是wa了,原来是因为,我把if语句中的==只写了一个...真坑啊,,,我就说怎么会 不过,明明写的对的,大数相加竟然还wa了四次,还有就是这道题最后不写换行也会wa...看来还是有必要从基础练起提高代码能力: 贴代码: #include<stdio.h> #include&

单链表大整数加法

单链表大整数加法,节点是char型. First     List:   head->1->8->9 Second List:   head->9->8->1 Result  List:    head->1->1->7->0 实现了单链表(单链表类模板),现在使用单链表实现大整数加法 1 #include "stdafx.h" 2 #include "SingleList.h" 3 #include &l