19

JS の modulo 関数で計算しようとしましたが、正しい結果が得られません (1 になるはずです)。これはハードコードされたコードです。

var checkSum = 210501700012345678131468;
alert(checkSum % 97);

Result: 66

ここで何が問題なのですか?

よろしく、 ベネディクト

4

6 に答える 6

14

IBAN 計算フォームの通常の銀行口座番号の場合、文字列データ型に含まれる非常に大きな数値になります。この大きな数から、97 で割ったときの残りを見つけなければなりません -> 大きな数 % 97.

データ型を整数に変換するとすぐにオーバーフローが発生し、負の整数になり、最終的に残りの値が間違ってしまいます。いくつかの冗長なコード (これも間違った結果をもたらした) を見たので、私は自分自身を共有することに抵抗できませんでした。クレジットは、正規数で非常に大きな数のモジュラスを見つけるに行きます

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

注意: ここでは 10 桁を使用します。これは、JavaScript の最大整数の 15 桁 (および一部) よりも小さいため、97 よりも大きな数値になり、適切な丸め数です。最初の 2 つの引数が重要です。

于 2013-04-15T15:51:16.530 に答える
12

Benedikt のバージョンに対する一連の改善: "cRest += '' + cDivident;" バグ修正です。parseInt(divisor) を使用すると、両方の引数を文字列として渡すことができます。最後に空の文字列をチェックすると、常に数値が返されます。グローバル変数を使用しないように var ステートメントを追加しました。foreach を古いスタイルの for に変換したため、古い Javascript を使用するブラウザーで動作します。cRest == 0; を修正しました。バグ(@Dan.StackOverflowに感謝)。

function modulo (除数、除数) {
    var cDivident = '';
    var cRest = '';

    for (被除数の変数 i ) {
        var cChar = 被除数[i];
        var cOperator = cRest + '' + cDivident + '' + cChar;

        if (cOperator < parseInt(divisor) ) {
                cDivident += '' + cChar;
        } そうしないと {
                cRest = cOperator % 除数;
                もし ( cRest == 0 ) {
                    cRest = '';
                }
                cDivident = '';
        }

    }
    cRest += '' + cDivident;
    もし (cRest == '') {
        cRest = 0;
    }
    cRestを返します。
}
于 2010-05-05T10:35:51.700 に答える
5

あなたはこれの犠牲になっているように見えます:数値が精度を失うことなく行くことができるJavaScriptの最大の整数値は何ですか?

他のスレッドの内容を繰り返すだけです。

これらは64ビット浮動小数点値であり、最大の正確な整数値は2^53です。ただし、仕様セクション[8.5:数値タイプ]から:

一部のECMAScript演算子は、-2^31から2^31-1までの範囲、または0から2^32-1までの範囲の整数のみを処理します。これらの演算子はNumber型の任意の値を受け入れますが、最初にそのような各値を2^32整数値の1つに変換します。それぞれセクション0および0のToInt32およびToUint32演算子の説明を参照してください。

しかし、クレジットが必要な場合はクレジットします。ジミーは、レッグワーク(まあ、グーグル)をしたことで、あちらで受け入れられた答えを得ました。

于 2009-05-30T15:23:55.007 に答える
5

IBAN を確認するために ES6 で動作する (機能する) ソリューションをコピー&ペーストするだけの場合:

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

ワンライナーで書くこともできます。

モジュロ演算は、実際の数値を格納する整数の配列に対して実行されます (dividentは、文字列として関数に適用されます)。

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

これが機能するのは、Modulo が加算、減算、乗算に対して分配的であるためです。

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

ES5 にトランスパイルされた IBAN 関数は次のようになります。

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;
};
于 2017-07-19T11:42:53.620 に答える
4

最後に、私の解決策:

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;
}
于 2009-06-17T22:29:44.450 に答える
3

Silent Matt はBig Integers 用の Javascriptライブラリを開発しました。この問題も解決できます。

于 2010-12-14T21:14:48.460 に答える