Modulo in JavaScript - large number

前端 未结 6 1845
情深已故
情深已故 2021-01-07 20:39

I try to calculate with JS\' modulo function, but don\'t get the right result (which should be 1). Here is a hardcoded piece of code.

var checkSum = 21050170         


        
相关标签:
6条回答
  • 2021-01-07 21:19

    Finally, my solution:

    function modulo (divident, divisor) {
        cDivident = '';
        cRest = '';
    
        for each ( var cChar in divident ) {
            cOperator = cRest + '' + cDivident + '' + cChar;
    
            if ( cOperator < divisor ) {
                cDivident += '' + cChar;
            } else {
                cRest = cOperator % divisor;
                if ( cRest == 0 ) cRest = '';
                cDivident = '';
            }
    
        }
    
        return cRest;
    }
    
    0 讨论(0)
  • 2021-01-07 21:22

    Silent Matt has developed a Javascript library for Big Integers. It could solve this issue too.

    0 讨论(0)
  • 2021-01-07 21:24

    looks like you've fallen victim to this: What is JavaScript's highest integer value that a Number can go to without losing precision?

    just to reiterate what's in the other thread:

    they are 64-bit floating point values, the largest exact integral value is 2^53. however, from the spec section [8.5: Number Type]:

    Some ECMAScript operators deal only with integers in the range −2^31 through 2^31−1, inclusive, or in the range 0 through 2^32−1, inclusive. These operators accept any value of the Number type but first convert each such value to one of 2^32 integer values. See the descriptions of the ToInt32 and ToUint32 operators in sections 0 and 0, respectively

    But credit where credit is due. Jimmy got the accepted answer over there for doing the legwork (well, googling).

    0 讨论(0)
  • 2021-01-07 21:26

    For those who simply want to copy&paste a working (functional) solution in ES6 to check IBANs:

    function isIBAN(s){
        const rearranged = s.substring(4,s.length) + s.substring(0,4);
        const numeric   = Array.from(rearranged).map(c =>(isNaN(parseInt(c)) ? (c.charCodeAt(0)-55).toString() : c)).join('');
        const remainder = Array.from(numeric).map(c => parseInt(c)).reduce((remainder, value) => (remainder * 10 + value) % 97,0);
    
        return  remainder === 1;}
    

    You could even write it as a one-liner.

    The modulo operation is performed on the array of integers storing the actual number (divident, applied as string to function):

    function modulo(divident, divisor){
       return Array.from(divident).map(c => parseInt(c)).reduce((remainder, value) => (remainder * 10 + value) % divisor,0);
    };
    

    This works because Modulo is distributive over addition, substraction and multiplication:

    • (a+b)%m = ((a%m)+(b%m))%m
    • (a-b)%m = ((a%m)-(b%m))%m
    • (ab)%m = ((a%m)(b%m))%m

    The IBAN function transpiled to ES5 looks like:

    function (s) {
        var rearranged = s.substring(4, s.length) + s.substring(0, 4);
        var numeric = Array.from(rearranged).map(function (c) { return (isNaN(parseInt(c)) ? (c.charCodeAt(0) - 55).toString() : c); }).join('');
        var remainder = Array.from(numeric).map(function (c) { return parseInt(c); }).reduce(function (remainder, value) { return (remainder * 10 + value) % 97; }, 0);
        return remainder === 1;
    };
    
    0 讨论(0)
  • 2021-01-07 21:28

    For an IBAN calculation form a normal bankaccount number I end up with a very large number contained in a string datatype. From this large number I have to find the rest when divided by 97 -> large number % 97.

    As soon as I convert the datatype to an integer I get an overflow resulting in a negative integer and eventually a wrong rest value. As I saw some verbose pieces of code (which also gave wrong outcome), I could not resist to share my own. Credits go to Finding Modulus of a Very Large Number with a Normal Number

    modulo: function(divident, divisor) {
        var partLength = 10;
    
        while (divident.length > partLength) {
            var part = divident.substring(0, partLength);
            divident = (part % divisor) +  divident.substring(partLength);          
        }
    
        return divident % divisor;
    }
    

    N.B. I use 10 positions here as this is smaller than the 15 (and some) positions of max integer in JavaScript, it results in a number bigger than 97 and it's a nice round number. The first two arguments matter.

    0 讨论(0)
  • 2021-01-07 21:36

    A bunch of improvements to Benedikt's version: "cRest += '' + cDivident;" is a bugfix; parseInt(divisor) makes it possible to pass both arguments as strings; check for empty string at the end makes it always return numerical values; added var statements so it's not using global variables; converted foreach to old-style for so it works in browsers with older Javascript; fixed the cRest == 0; bug (thanks @Dan.StackOverflow).

    function modulo (divident, divisor) {
        var cDivident = '';
        var cRest = '';
    
        for (var i in divident ) {
            var cChar = divident[i];
            var cOperator = cRest + '' + cDivident + '' + cChar;
    
            if ( cOperator < parseInt(divisor) ) {
                    cDivident += '' + cChar;
            } else {
                    cRest = cOperator % divisor;
                    if ( cRest == 0 ) {
                        cRest = '';
                    }
                    cDivident = '';
            }
    
        }
        cRest += '' + cDivident;
        if (cRest == '') {
            cRest = 0;
        }
        return cRest;
    }
    
    0 讨论(0)
提交回复
热议问题