JavaScript 10进制大整数四则运算:加 减 乘 除

var digits = [
        '0', '1', '2', '3', '4', '5',
        '6', '7', '8', '9', 'a', 'b',
        'c', 'd', 'e', 'f', 'g', 'h',
        'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z'
    ];

    var digitsMap = new Map();
    for (var i = 0; i < len(digits); i++) {
        digitsMap.set(digits[i], i);
    }


    function charCode(s, i) {
        if (isNumber(i) && strNonEmpty(s)) {
            return s.charCodeAt(i);
        }
        throw new Error("First param string and second param integer!");
    }
    function toLowerCase(s) {
        if (strNonEmpty(s)) {
            return s.toLowerCase();
        }
        throw new Error("First param string!");
    }
    function toUpperCase(s) {
        if (strNonEmpty(s)) {
            return s.toUpperCase();
        }
        throw new Error("First param string!");
    }

    function parseInt10(i) {
        if (isNumber(i)) {
            return Math.floor(i);
        }
        else {
            return parseInt(i);
        }
    }

    var numRegExp = /^[+-]?(0[box]?)?\w*$/;

    function checkRadixAndNumber(s, radix) {
        if ((lt(radix, 2) || gt(radix, 36)) && numRegExp.test(s)) {
            throw new Error("Radix between 2 and 36.");
        }
        s = toLowerCase(s);
        var sign = '+';
        if (eq(s.charAt(0), '-')) {
            sign = '-';
            s = s.substring(1);
        } else if (eq(s.charAt(0), '+')) {
            // sign = '+';
            s = s.substring(1);
        }

        if (eq(s.charAt(0), '0')) {
            radix = 8;
            s = s.substring(1);
            if (eq(s.charAt(0), 'o')) {
                // radix = 8;
                s = s.substring(1);
            }
            else if (eq(s.charAt(0), 'x')) {
                radix = 16;
                s = s.substring(1);
            } else if (eq(s.charAt(0), 'b')) {
                radix = 2;
                s = s.substring(1);
            }
        }

        for (var i = 0; i < len(s); i++) {
            if (nlt(digitsMap.get(s.charAt(i)), radix)) {
                throw new Error("Input number cannot greater than radix: " + radix);
            }
        }
        // for (var i = 0; i < len(s); i++) {
        //     if (!eq(s.charAt(i), '0')) {
        //         s = s.substring(i);
        //         break;
        //     }
        // }
        s = str2ListBySeparator(s, '');
        s = clearOpenZeroI(s);
        return [list2StrWithJoint(s, ''), radix, sign];
    }

    function checkBigIntegerNumber10(a) {
        if (oExist(a) && oExist(a.length)) {
            for (var i = 0; i < len(a); i++) {
                if (!((a[i] >= 0 && a[i] <= 9) || (a[i] >= '0' && a[i] <= '9'))) {
                    throw "Not a integer number string."
                }
            }
        } else {
            throw "Not a integer number string.";
        }
    }

    function initZero(nums) {
        for (var i = 0; i < len(nums); i++) {
            nums[i] = 0;
        }
    }

    function clearOpenZeroI(nums) {
        var openZero = 0;
        while (eq(nums[openZero], 0)) {
            openZero++;
        }
        nums = nums.slice(openZero);
        if (eq(len(nums), 0)) {
            nums = [0];
        }
        return nums;
    }

    function clearOpenZeroS(nums) {
        var openZero = 0;
        while (eq(nums[openZero], '0')) {
            openZero++;
        }
        nums = nums.slice(openZero);
        if (eq(len(nums), 0)) {
            nums = '0';
        }
        return nums;
    }

    var int10RegExp = /^[+-]?\d*$/;

    function whatSign(s) {
        return s.startsWith('-') ? '-' : '+';
    }

    function getRidOfSign(s) {
        if (eq(s.charAt(0), '-')) {
            s = s.substring(1);
        } else if (eq(s.charAt(0), '+')) {
            s = s.substring(1);
        }
        return s;
    }

    /**
     * 
     * @param {String} a 
     * @param {String} b 
     */
    function addInt10(a, b) {
        //check decimal format
        if (!(int10RegExp.test(a) && int10RegExp.test(b))) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }
        //calc sign
        var asign = whatSign(a);
        var bsign = whatSign(b);

        a = getRidOfSign(a);
        b = getRidOfSign(b);


        checkBigIntegerNumber10(a);
        checkBigIntegerNumber10(b);

        a = clearOpenZeroS(a);
        b = clearOpenZeroS(b);

        //determine end sign
        if (eqInt10(a, b) && !eq(asign, bsign)) {
            return '0';
        }
        else if (ltInt10(a, b)) {//a > b ,indeed
            var tmp = a;//data swap
            a = b;
            b = tmp;
            tmp = bsign;//sign swap
            bsign = asign;
            asign = tmp;
        }
        var finalSign = asign;

        var radix = 10;
        var nums = EMPTY_VALUES.ARRAY;
        var le = pmax(a, b);
        nums.length = le + 1;
        initZero(nums);
        var i = len(a) - 1;
        var j = len(b) - 1;
        var k = 0;
        //core 1
        while (i >= 0 && j >= 0) {
            if (eq(asign, bsign)) {//for +
                nums[k++] = parseInt10(a[i--]) + parseInt10(b[j--]);
            } else {//for -
                nums[k++] = parseInt10(a[i--]) - parseInt10(b[j--]);
            }
        }
        while (i >= 0) {
            nums[k++] = parseInt10(a[i--]);
        }
        // while (j >= 0) {//this is error,max num rest!!!Do you understand?!!!
        //     nums[k++] = parseInt10(b[j--]);
        // }

        // core 2
        for (var n = 0; n < len(nums); n++) {
            if (eq(asign, bsign)) {//+ handler
                if (nums[n] >= radix) {
                    nums[n + 1] += parseInt10(nums[n] / radix);
                    nums[n] %= radix;
                }
            } else {//- handler
                if (nums[n] < 0) {//because of '-',don't have num >= radix;
                    nums[n + 1] -= 1;
                    nums[n] += radix;
                }
            }

        }
        nums.reverse();
        nums = clearOpenZeroI(nums);
        var s = list2StrWithJoint(nums, '');
        if (eq(finalSign, '-')) {
            s = '-' + s;
        }
        return s;
    }

    function multiplyInt10(a, b) {

        if (!(int10RegExp.test(a) && int10RegExp.test(b))) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }

        //calc sign
        var asign = whatSign(a);
        var bsign = whatSign(b);

        a = getRidOfSign(a);
        b = getRidOfSign(b);

        checkBigIntegerNumber10(a);
        checkBigIntegerNumber10(b);

        a = clearOpenZeroS(a);
        b = clearOpenZeroS(b);

        var finalSign = eq(asign, bsign) ? '+' : '-';

        var radix = 10;
        var nums = EMPTY_VALUES.ARRAY;
        var le = pmax(a, b);
        nums.length = le * 2 + 1;
        initZero(nums);
        //core 1
        var k = 0;
        for (var i = len(a) - 1; i >= 0; i--) {
            for (var j = len(b) - 1; j >= 0; j--) {
                nums[len(a) - 1 - i + k++] += parseInt10(a[i]) * parseInt10(b[j]);
                // console.log(len(a) - 1 - i + k - 1, nums[len(a) - 1 - i + k - 1], parseInt10(a[i]), parseInt10(b[j]));
            }
            k = 0;
        }
        //core 2
        for (var n = 0; n < len(nums); n++) {
            if (nums[n] >= radix) {
                nums[n + 1] += parseInt10(nums[n] / radix);
                nums[n] %= radix;
            }

        }
        nums.reverse();
        nums = clearOpenZeroI(nums);
        var s = list2StrWithJoint(nums, '');
        if (eq(finalSign, '-')) {
            s = '-' + s;
        }
        return s;

    }

    function addInt10One(s) {
        // checkBigIntegerNumber10(s);
        return addInt10(s, '1');
    }

    function compareInt10(a, b) {
        checkBigIntegerNumber10(a);
        checkBigIntegerNumber10(b);
        if (len(a) > len(b)) {
            return 1;
        } else if (len(a) < len(b)) {
            return -1;
        }
        var i = 0;
        while (eq(a[i], b[i]) && i < len(a)) {
            i++;
        }
        if (eq(i, len(a))) {
            return 0;
        }
        else if (a[i] > b[i]) {
            return 1;
        } else if (a[i] < b[i]) {
            return -1;
        }
        return 0;
    }

    function gtInt10(a, b) {
        return compareInt10(a, b) > 0;
    }
    function ltInt10(a, b) {
        return compareInt10(a, b) < 0;
    }
    function eqInt10(a, b) {
        return eq(compareInt10(a, b), 0);
    }


    function powerInt10(s, p) {
        if (!int10RegExp.test(s)) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }
        var finalSign = whatSign(s);
        s = getRidOfSign(s);
        checkBigIntegerNumber10(s);
        s = clearOpenZeroS(s);
        var num = '1';
        p = String(p);
        for (var i = '0'; ltInt10(i, p); i = addInt10One(i)) {
            num = multiplyInt10(num, s);
        }
        if (eq(finalSign, '-')) {
            num = '-' + num;
        }
        return num;
    }

    function substractInt10(a, b) {
        //check decimal format
        if (!(int10RegExp.test(a) && int10RegExp.test(b))) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }
        //calc sign
        // var asign = whatSign(a);
        var bsign = whatSign(b);

        // a = getRidOfSign(a);
        b = getRidOfSign(b);

        //exchange sign '+' and '-'
        b = eq(bsign, '-') ? b : '-' + b;

        return addInt10(a, b);

    }

    function divideInt10(a, b) {
        //check decimal format
        if (!(int10RegExp.test(a) && int10RegExp.test(b))) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }
        //calc sign
        var asign = whatSign(a);
        var bsign = whatSign(b);

        a = getRidOfSign(a);
        b = getRidOfSign(b);


        checkBigIntegerNumber10(a);
        checkBigIntegerNumber10(b);

        a = clearOpenZeroS(a);
        b = clearOpenZeroS(b);

        if (eq(b, '0')) {
            throw new Error("divisor cannot be zero or 0");
        }

        var finalSign = eq(asign, bsign) ? '+' : '-';

        if (eq(a, '0')) {
            return eq(finalSign, '-') ? '-0' : '0';
        }

        //core
        var radix = '10';
        var quotient = '0';
        while (!(ltInt10(a, b))) {
            var rest = String(len(a) - len(b));
            var rest10 = powerInt10(radix, rest);
            var qn = multiplyInt10(b, rest10);
            if (gtInt10(qn, a)) {
                rest = substractInt10(rest, '1');
                rest10 = powerInt10(radix, rest);
            }
            qn = multiplyInt10(b, rest10);
            a = substractInt10(a, qn);
            quotient = addInt10(quotient, rest10);
        }


        if (eq(finalSign, '-')) {
            quotient = '-' + quotient;
        }
        return quotient;

    }

    function modInt10(a, b) {
        //check decimal format
        if (!(int10RegExp.test(a) && int10RegExp.test(b))) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }
        //calc sign
        var asign = whatSign(a);
        var bsign = whatSign(b);

        a = getRidOfSign(a);
        b = getRidOfSign(b);


        checkBigIntegerNumber10(a);
        checkBigIntegerNumber10(b);

        a = clearOpenZeroS(a);
        b = clearOpenZeroS(b);

        if (eq(b, '0')) {
            throw new Error("divisor cannot be zero or 0");
        }

        var finalSign = asign;

        if (eq(a, '0')) {
            return eq(finalSign, '-') ? '-0' : '0';
        }

        //core
        var radix = '10';
        // var quotient = '0';
        while (!(ltInt10(a, b))) {
            var rest = String(len(a) - len(b));
            var rest10 = powerInt10(radix, rest);
            var qn = multiplyInt10(b, rest10);
            if (gtInt10(qn, a)) {
                rest = substractInt10(rest, '1');
                rest10 = powerInt10(radix, rest);
            }
            qn = multiplyInt10(b, rest10);
            a = substractInt10(a, qn);
            // quotient = addInt10(quotient, rest10);
        }


        if (eq(finalSign, '-')) {
            a = '-' + a;
        }
        return a;

    }


    function BigInteger(s, radix = 10) {
        ntfs(this, BigInteger);
        var r = checkRadixAndNumber(s, radix);
        this.s = r[0];
        this.data = str2ListBySeparator(this.s, '');
        this.radix = r[1];
        this.sign = r[2];
    }

    var BigInteger_impl = {
        bigint10: function () {//new bigint obj
            return new BigInteger(this.int10Value());
        },
        unsignedInt10Value: function () {//string
            var data = EMPTY_VALUES.ARRAY;
            var s = '0';
            var radix = String(this.radix);
            for (var i = len(this.s) - 1; i >= 0; i--) {
                s = addInt10(s,
                    multiplyInt10(
                        String(digitsMap.get(this.s[i])),
                        powerInt10(radix, len(this.s) - i - 1)
                    )
                );//have to multiply n*radix^N
            }
            return s;
        },
        int10Value: function () {
            var sign = this.sign;
            if (eq(sign, '+')) {
                sign = '';
            }
            return sign + this.unsignedInt10Value()
        },
        add: function (a) {
            notInstanceof(a, BigInteger, "param must be BigInteger object!");
            var aData = a.int10Value();
            var oData = this.int10Value();
            return new BigInteger(addInt10(aData, oData));
        },
        multiply: function (a) {
            notInstanceof(a, BigInteger, "param must be BigInteger object!");
            var aData = a.int10Value();
            var oData = this.int10Value();
            return new BigInteger(multiplyInt10(aData, oData));
        },
        substract: function (a) {
            notInstanceof(a, BigInteger, "param must be BigInteger object!");
            var aData = a.int10Value();
            var oData = this.int10Value();
            return new BigInteger(substractInt10(aData, oData));
        },
        divide: function (a) {
            notInstanceof(a, BigInteger, "param must be BigInteger object!");
            var aData = a.int10Value();
            var oData = this.int10Value();
            return new BigInteger(divideInt10(oData, aData));
        },
        mod: function (a) {
            notInstanceof(a, BigInteger, "param must be BigInteger object!");
            var aData = a.int10Value();
            var oData = this.int10Value();
            return new BigInteger(modInt10(oData, aData));
        },
        power: function (n) {
            //One:
            // var sum = BigInteger.ONE;
            // n = String(n);
            // for (var i = '0'; ltInt10(i, n); i = addInt10One(i)) {
            //     sum = sum.multiply(this);
            // }
            // return sum;
            //Two:
            return new BigInteger(powerInt10(this.int10Value(), String(n)));
        },
        negate: function () {
            return new BigInteger(
                eq(this.sign, '-')
                    ?
                    '+' + this.unsignedInt10Value()
                    :
                    '-' + this.unsignedInt10Value());
        },
        addOne: function () {
            return this.add(BigInteger.ONE);
        },
        toString: function () {
            return this.s;
        }

    };

    impl(BigInteger, BigInteger_impl);

    var BigInteger_static_impl = {
        ZERO: new BigInteger('0'),
        ONE: new BigInteger('1'),
    };
    static_impl(BigInteger, BigInteger_static_impl);

BigInteger 类

a = new xy.BigInteger('123')
BigInteger {s: "123", data: Array(3), radix: 10, sign: "+"}
b  = new xy.BigInteger('-111')
BigInteger {s: "111", data: Array(3), radix: 10, sign: "-"}
a.divide(b).int10Value()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值