2016-05-31 20 views
-1

バイナリ・パワー・オン機能に問題があります。乗算の実行中に結果を含む変数がオーバーフローし、誤った結果が返されます。ソース値が4,312,952,827より大きい場合に発生します。だから私はこの問題をどのように解決するのですか?ここに私の機能のコードがあります。私に間違った結果を与えるバイナリ・パワー化

unsigned long long binpow(unsigned long long a, unsigned long long n, unsigned long long m) 
{ 
    unsigned long long res; 
    res=1; 
    while (n) 
    { 
     if (n & 1) 
     { 
      res=(res*a)%m; 
      n--; 
     } 
     a=(a*a)%m; 
     n >>= 1; 
    } 
    return res; 
} 
+0

コーナーケース: 'binpow(positive_a、0、1)'は間違った答え '1'を生成します。そのようなケースをキャッチするために 'unsigned long long res = 1LLU%m'で始めることができました。 – chux

答えて

0

あなたの残基及び弾性率の両方が(mだけシフト)unsigned long longの幅を超えています。

unsigned __int128のようなコンパイラ拡張タイプを使用すると問題が解決され、4,312,952,827に対して正しい結果が得られます。

unsigned __int128 binpow(unsigned __int128 a, unsigned __int128 n, unsigned __int128 m) 
{ 
    unsigned __int128 res; 
    res = 1; 
    while (n) 
     { 
      if (n & 1) 
       { 
        res = (res*a)%m; 
        n--; 
       } 
      a = (a*a) % m; 
      n >>= 1; 
     } 
    return res; 
} 

また、あなたは安全な方法で大量に仕事をしたい場合は、gmplib

+0

ありがとう、私の友人、あなたの答えは非常に有用です。実際には、この関数をnumberがプ​​ライムかどうかを定義するアルゴリズムの一部として使用しています。ここでの計算のスピードは非常に重要です。その図書館の計算が遅くなることを聞かせてもらえますか? –

1

のような汎用BIGNUMライブラリがある表現a*aは元のサイズの2倍である部屋が必要です。あなたのシナリオでは4,312,952,827 > 2^32-1、従ってあなたはunsigned long longの範囲外です。

モジュラ指数のバイナリラダーを実装するための経験則は、引数のデータ型の少なくとも2倍の範囲で算術演算を実行できるため、場合によっては128ビットです。

関連する問題