JavaScript BigInteger 加减乘除幂运算,进制转换

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

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

    function checkRadixAndNumber(s, radix) {
        if (!numRegExp.test(s)) {
            throw new Error("Input first param must be a number string and and sign only one +/-!.");
        }
        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')) {
            var radixI = 8;
            s = s.substring(1);
            if (eq(s.charAt(0), 'o')) {
                // radix = 8;
                s = s.substring(1);
            }
            else if (eq(s.charAt(0), 'x')) {
                radixI = 16;
                s = s.substring(1);
            } else if (eq(s.charAt(0), 'b')) {
                radixI = 2;
                s = s.substring(1);
            } else if (eq(len(s), 0)) {
                radixI = radix;
            }
            radix = radixI;
        }

        if (!radix || lt(radix, 2) || gt(radix, 36)) {
            throw new Error("Radix between 2 and 36.");
        }

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

    /**
     * 
     * @param {String} a 
     * @param {String} b 
     */
    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;
        nums.length = len(a) + len(b);
        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);
    }

    /**
     * 
     * @param {String} s 
     * @param {String} p 
     */
    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;
    }
    /**
     * 
     * @param {String} a 
     * @param {String} b 
     */
    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);

    }

    /**
     * 
     * @param {String} a 
     * @param {STring} 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;

    }

    /**
     * 
     * @param {String} a 
     * @param {String} b 
     */
    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;

    }

    /**
     * 
     * @param {String} a 
     * @param {String} b 
     */
    function divideAndRemainderInt10(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', '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, a];

    }

    /**
     * 
     * @param {String} s 
     * @param {Number} radix 
     */
    function radixToInt10(s, radix) {

        var result = checkRadixAndNumber(s, radix);
        s = clearOpenZeroS(result[0]);
        radix = result[1];
        var sign = result[2];
        //core

        if (isNumber(radix) && !eq(radix, 10)) {
            var os = '0';
            radix = String(radix);
            for (var i = len(s) - 1; i >= 0; i--) {
                os = addInt10(os,
                    multiplyInt10(
                        String(digitsMap.get(s[i])),
                        powerInt10(radix, len(s) - i - 1)
                    )
                );//have to multiply n*radix^N
            }
            s = os;
        }


        if (eq(sign, '-')) {
            s = '-' + s;
        }

        return s;
    }

    /**
     * 
     * @param {String} s 
     * @param {Number} radix 
     */
    function int10ToRadix(s, radix) {
        if (!int10RegExp.test(s)) {
            throw new Error("params must be decimal number and sign only one +/-!");
        }

        var sign = whatSign(s);

        s = getRidOfSign(s);

        checkBigIntegerNumber10(s);

        s = clearOpenZeroS(s);
        //core
        if (isNumber(radix) && !eq(radix, 10)) {
            radix = String(radix);
            var radixNum = EMPTY_VALUES.ARRAY;
            var result = divideAndRemainderInt10(s, radix);
            radixNum.push(digits[result[1]]);
            while (!eq(result[0], '0')) {
                result = divideAndRemainderInt10(result[0], radix);
                radixNum.push(digits[result[1]]);
            }
            radixNum.reverse();
            s = list2StrWithJoint(radixNum, '');
        }

        if (eq(sign, '-')) {
            s = '-' + s;
        }

        return s;

    }


    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 = {
        int10: function () {//new bigint obj
            return new BigInteger(this.int10Value());
        },
        intRadix: function (r) {
            return new BigInteger(this.intRadixValue(r));
        },
        intRadixValue: function (r) {
            return int10ToRadix(this.int10Value(), r);
        },
        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;

            return radixToInt10(this.s, this.radix);
        },
        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 (r) {
            if (isNumber(r) && !eq(this.radix, r)) {
                return this.intRadixValue(r);
            }
            return this.s;
        },
        // toJSON: function (r) {//JSON.stringify()!
        //     return this.toString(r);
        // }
    };

    impl(BigInteger, BigInteger_impl);

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

a = new xy.BigInteger('123')
a.toString(26) //"4j"

BigInteger

你可能感兴趣的:(JavaScript,Algorithm)