モジュラー乗算


7

私はウィキペディアのモジュラー乗算のページを読んでいました...を計算アルゴリズムを理解できませんでした。ab(modm)

uint64_t mul_mod(uint64_t a, uint64_t b, uint64_t m)
{
  long double x;
  uint64_t c;
  int64_t r;
  if (a >= m) a %= m;
  if (b >= m) b %= m;
  x = a;
  c = x * b / m;
  r = (int64_t)(a * b - c * m) % (int64_t)m;
  return r < 0 ? r + m : r;
}

私はそれを得ます:

ab(modm)((amodm)(bmodm))modm

私が得ていないステップはc=x*b/m後でr = (int64_t)(a * b - c * m) % (int64_t)m;それのために何をしているのですか?

記事は言う:

ハードウェアによって、浮動小数点乗算は積の最上位ビットが保持されるというトリックを使用する一方で、整数乗算は最下位ビットが保持される

これがどのように関連しているかはわかりません!!!

回答:


7

何が起こっているのかについて、よりコンパクトで数学的な説明を次に示します。ましょうと入力されると、既に低減モジュロである、そうと。(コード的には、これは行の後を意味します。)を計算する必要があります。つまり、設定して、一部のに対してとなるようなを見つけます。abma<mb<mb %= mabmodmx=abrxx=qxm+rxqx

あふれないケース

オーバーフローしないケースでは、モジュラスを計算してそれで完了できます。代わりに、コードは次を計算します: Nowます。ここで私は懸念を回避しました。が浮動小数点変数の仮数に収まらない可能性があります。ただし、適合する限り、これは問題にはなりません。最終的にここで、は、大きさがより小さいです。前と同じように続行します。

y=xm=qx+rxm=qx+rxm=qx
xym=qxm+rxqxm=rxxmx=ab<m2x=x+eem
y=xm=qx+rx+em=qx+rx+em
この場合、およびであるので、削除できません。ある場合であってもよいまたは、それは確かに間(厳密に)であろうが、及び、そうはまたはいずれかです。ここでrx+emrx<me<mrx+e>mrx+e<0m2mrx+em0±1
xym=qxm+rxqxmrx+emm=rxrx+emm
ここでモジュラス演算を実行すると、余分な項が取り除かれますが、Cが選択する規則により(-1)%m = -1ます。常に正の数を返す規則を取得するには、負の場合、結果にを追加します。m

あふれる事件

我々は整数演算MODやっていると仮定しましょう例えば、、とのは、仮定しよう手段。これで乗算がラップされます。整数場合、と記述します。つまり、計算により数値が得られます。浮動小数点の計算は、以前と同様に、が仮数に収まることを前提としています(が大きい場合は、80ビットの拡張精度浮動小数点数が必要になる場合があります)。係数については、および定義します。、N264ab>Nm2>N>mx=ab=z+kNk<ma*bzmmz=qzm+rzkN=qNm+rNx=qzm+qNm+rz+rN。前と同様に、を浮動小数点変数として格納すると、丸め誤差が発生する可能性がありますなので、ここでもです。以前と同じ計算を行うと、次のようになります。 ここでウサギを帽子から取り出しました。ここでは、加算mod、およびmodため、です。前と同じように、 mod を取得します。x|e|<mx=x+e

zxmm=qzm+rzqzmqNmrz+rN+emm=rzqNmrz+rN+emm=rz+rNrz+rN+emm
NN qNm+rN=kN=0qNm=rNmrz+rN=xmodm、そして以前のように、Cの慣例はこれが負になる可能性があり、修正する必要があります。

残っている潜在的な問題が1つあります。はます。でない限り、これは問題を引き起こしません。この場合、間違った答えが返されます。以下のためのこの手段は。(余談ですが、場合、になるので問題はありません。)になるように浮動小数点ハードウェアを切り捨てて構成すると、このケースは発生しません。(仮数がを保持できるという私の制限を忘れないでください!)。rz+rN+em22m>NN=264m>2632m=N0e0m

これを最上位/最下位ビットに接続する

引用した部分に具体的に対処するために、「base」のように、ベースとして考える2より大きい整数を考えます。通常の場合、はとして表されます。浮動小数点表現では、これをと記述します。ここで、2つの(正の)1 桁の桁の数値を乗算したいとしましょう。結果には最大で2桁が必要になります。たとえば、([標準]の桁の表現で必要な場合)および。1つのベースのみを保存できるように制限されている場合、B10B=102121=2B+12.1×B1BcB+dB0c<B0d<BB結果の桁。2つの明らかな選択肢、またはます。cd

選択することは、modをとして機能させることと同じです。これは、整数演算で発生するものです。(ちなみに、アセンブリレベルでは、整数の乗算でこれらの両方の数字が生成されることがよくあります。)dBcB+d=dmodB

一方、浮動小数点演算はを選択することに実質的に対応しますが、指数をインクリメントすることで補正します。実際には、結果をとして表しますが、格納できるのは1 桁の桁のみなので、これはちょうどます。(実際には、我々は大きなベースに、小型基地(すなわち2)ではなく、1桁または2桁の数字を複数桁番号などの数字を検討します。これは、私たちは、より高い数字の一部保存することができますの場合を彼らは、店舗には必要ありませんされていないが、すべての最悪のシナリオには失われている。のいずれもcc.d×B1Bc×B1dcdc指数の部屋がなくなるまで失われます。上記のコードの場合、これは問題ではありません。)

を浮動小数点形式で忠実に表現できる限り、式は、base-でその上位桁を抽出したものと見なすことができます。上記のコードと数学は、数値の進数表現と進数表現の間の相互作用として見ることができます。mabmmNm

実用性

このドラフトのセクション5.2.4.2.2に基づくと、C11標準でlong doubleは仮数部の長さがおよそ33ビットである必要があるようです。(特に、それが唯一の最小数を指定する表示小数点忠実に表現することができる桁。)実際には、汎用のCPU、特にのx86ファミリーのCPUを対象とする場合、ほとんどのCコンパイラは、IEEE754型を使用します。この場合double、仮数は53ビットになります。x86ファミリのCPUは、事実上64ビットの仮数で80ビット形式をサポートします。すべてではないがいくつかのコンパイラはlong double、x86をターゲットとする場合にそれを示します。コードの有効範囲は、これらの実装の詳細によって異なります。


卓越した答え!まだ頭をている1つのケース:がなるほど負であるとします。その後の値はなり、ひいては範囲内。この値がます。次に、(符号付きの型)にキャストすると、負の数に折り返されます。この場合、なぜコードは正しいことをするのですか?特に、なるに変換した後(それがあった場合)、次いで-andメーク陽性動作が得られるはずではなくerx+e<0a*b - c*mrx+mm..2m1263int64_trx+mrx+m264int64_t263%mrx264modmrx。(続き)
DW

この動作をトリガーするテストケースはまだ見つかりません。特に、私はのための任意の値を見つけることができないabmここの値は、ここで、すなわち、と。このケースは起こりますか?可能であれば、このコードがその状況で正しい結果をもたらすのはなぜですか?rx+e<0a*b - c*m263rx+e<0rx+m263
DW

10億個のランダムな値を試した後、それらの条件を満たすテストケースを見つけることができません。それで、おそらくこのケースは不可能ですか?しかし、なぜ?
DW

また、エッジで何が起こるかわかりません。この場合、、およびの範囲にあるに以下です。以降これには問題生じない、、ケース。ただし、ないため、場合、問題がある可能性があります。たとえば、場合、です。私たちがあれば、私にはわからないだろう0rz<m0rN<m|e|<mrz+rN+em12m<N1012m<NmN/2m263N=264しかし問題があります。私はそう信じています。一方、丸めモードが切り捨てに設定されている場合は、なり、までは機能すると思います。e0m=N1
Derek Elkinsが

編集とコメントをありがとう。しかし、それが私が話しているケースにどのように対処するかはまだわかりません。私が心配しているケースは、がであり、(キャストが負を生成するように)数)。あなたのコメントはケースには問題がないと言っていますが、理由はわかりません。それがまさに私が心配しているケースです。私は丸めモードを検討しましたが、デフォルトの丸めモードは「丸め」ではなく「丸めから偶数」であることがわかり、問題が解決されていないようです。rz+rN+em1rz+rN+m263int64_t1
DW
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.