コンピューターは、オーバーフローエラーなしで指数演算をどのように計算できますか?


32

いくつかのRSA暗号化/復号化方法を研究して、この記事を見つけました:RSAアルゴリズムの例

このメッセージを解読するにはこれが必要です ここに画像の説明を入力してください

の合計結果ここに画像の説明を入力してくださいは非常に大きく、64ビット/ 32ビットマシンでは、1つのレジスタにこのような大きな値を保持できるとは思わない。コンピューターはオーバーフローせずにどのようにそれを行いますか?


この質問は今週のスーパーユーザー質問でした。詳細について
ブログエントリを読むか自分でブログに投稿してください


6
これがcs.stackexchange.comに移行された場合、より良い答えが得られるかどうか疑問に思います。これは、CS / Mathサイトに適しているように思われます。CS/ Mathサイトでは、低レベルの実際の詳細が非常に低いレベルでダウンしていることに焦点を当てています。
ゾレダチェ

1
これは、スーパーユーザーにとって十分に有効です。
ジェームズメルツ

回答:


40

整数モジュラス演算は、ℤ->ℤ/nℤからのリング準同型(Wikipedia)であるため、

(X * Y) mod N = (X mod N) * (Y mod N) mod N

少し簡単な代数でこれを自分で確認できます。(mod右側のファイナルは、モジュラーリングの乗算の定義により表示されることに注意してください。)

コンピューターはこのトリックを使用して、多数の桁を計算することなく、モジュラーリングの指数を計算します。

               / 1 I = 0、
               |
(X ^ I)mod N = <(X *(X ^(I-1)mod N))mod NI奇数、
               |
               \(X ^(I / 2)mod N)^ 2 mod NI even&I / = 0

アルゴリズム形式では、

-- compute X^I mod N
function expmod(X, I, N)
    if I is zero
        return 1
    elif I is odd
        return (expmod(X, I-1, N) * X) mod N
    else
        Y <- expmod(X, I/2, N)
        return (Y*Y) mod N
    end if
end function

(855^2753) mod 3233必要に応じて、これを使用して16ビットレジスタのみで計算できます。

ただし、RSAのXおよびNの値は非常に大きく、大きすぎてレジスタに収まりません。モジュラスは通常1024-4096ビット長です!したがって、手動で乗算を行うのと同じように、コンピューターに「長い」方法で乗算を実行させることができます。0-9の数字を使用する代わりに、コンピューターは0-2 16 -1などの「単語」を使用します。(16ビットのみを使用すると、アセンブリ言語に頼らずに2つの16ビット数を乗算し、32ビットの完全な結果を得ることができます。アセンブリ言語では、通常64ビットの完全な結果、または64ビットのコンピューター、完全な128ビットの結果。)

-- Multiply two bigints by each other
function mul(uint16 X[N], uint16 Y[N]):
    Z <- new array uint16[N*2]
    for I in 1..N
        -- C is the "carry"
        C <- 0
        -- Add Y[1..N] * X[I] to Z
        for J in 1..N
            T <- X[I] * Y[J] + C + Z[I + J - 1]
            Z[I + J - 1] <- T & 0xffff
            C <- T >> 16
        end
        -- Keep adding the "carry"
        for J in (I+N)..(N*2)
            T <- C + Z[J]
            Z[J] <- T & 0xffff
            C <- T >> 16
        end
    end
    return Z
end
-- footnote: I wrote this off the top of my head
-- so, who knows what kind of errors it might have

これは、Xの単語数にYの単語数を掛けた時間にほぼ等しい時間でXにYを掛けます。これはO(N 2)時間ます。上記のアルゴリズムを見て、それを分解すると、彼らが学校で教えるのと同じ「長い掛け算」です。10桁まで記憶されたタイムテーブルはありませんが、座ってそれを解決すれば、まだ1,926,348 x 8,192,004を掛けることができます。

長い乗算:

    1,234
  x 5,678
---------
    9,872
   86,38
  740,4
6,170
---------
7,006,652

実際には、Strassenの高速フーリエ法などの乗算用の高速アルゴリズム(Wikipedia)や、追加と減算を追加するが乗算は少ない単純なメソッドがあり、全体的に高速になります。GMPのような数値ライブラリは、数値の大きさに基づいて異なるアルゴリズムを選択できます。フーリエ変換は最大の数値に対してのみ最速であり、数値が小さいほど単純なアルゴリズムを使用します。


+1。ただしmod N、中国剰余定理の最後に余分なものがありません。((16 mod 5)等しくない(4 mod 5) * (4 mod 5):前者は1、後者は16)
-ruakh

@ruakh:修正されました。本当に言いたいのですが、R / kRはR / k1R x R / k2R x ... R / knRと同型です。ここで、k1..knはペアワイズ互いに素であり、その積はkで、Rは主要な理想領域です。私は長い間*をオーバーロードしてきたのでモジュラー以外のものとして見るのは難しいです。言い換えれば、私の通常の表記規則でmodは、これは不要です。
ディートリッヒエップ

1
@Synetech:しかし、私はこれらの4つの言葉が大好きです。「読者のための運動」。
ディートリッヒエップ

1
(X * Y) mod N = (X mod N) * (Y mod N) mod N本当ですが、中国の剰余定理とは何の関係もありません。
デニス

1
@Dennis:答えのコドメインの構造を明確にしました。(私が書いたので、それは決して曖昧ではありません...)
ディートリッヒエップ

9

簡単な答えは、彼ら自身ではなく、できないということです。確かに、x-bitマシンの概念を採用する場合、限られた数のビットで表すことができる限られた数の数字があります。 10進法。

そうは言っても、非常に大きな数のコンピューター表現は、暗号化の分野の大きな要素です。コンピュータで非常に大きな数を表す方法は多数あり、それぞれが次のように変化します。

これらの方法にはそれぞれ長所と短所があり、ここにすべての方法をリストすることはできません/できませんが、非常に簡単な方法を紹介します。

整数が0〜99の値のみを保持できるとします。どうすれば100を表すことができますか?これは最初は不可能に思えるかもしれませんが、それは単一の変数のみを考慮するためです。という整数unitsと1つの整数があればhundreds、100:を簡単に表すことができますhundreds = 1; units = 0;。9223:のように、もっと大きな数字を簡単に表すことができますhundreds = 92; units = 23

これは簡単な方法ですが、非常に非効率的であると言えます。コンピューターができることの限界を押し上げるほとんどのアルゴリズムと同様に、それは通常、力(多数を表す)と効率(高速検索/保存)の間の綱引きです。先ほど言ったように、コンピューターで多数を表現する方法はたくさんあります。メソッドを見つけて試してみてください!

これであなたの質問に答えてくれることを願っています!この

参考文献:記事とこれは、詳細については役に立つかもしれません。


3

これを実行する方法(繰り返しの2乗などを含むはるかに高速な方法があります)は、乗算することで、すべての乗算後にモジュラスを取得します。モジュラスの2乗が2 ^ 32(または2 ^ 64)未満である限り、オーバーフローは発生しません。


3

同じ方法で。

342 * 189が何であるかを知らないことを推測します。しかし、あなたは次の事実を知っています:

9 * 2 = 18
9 * 4 = 36
9 * 3 = 27
8 * 2 = 16
8 * 4 = 32
8 * 3 = 24
1 * 2 = 2
1 * 4 = 4
1 * 3 = 3

18 + 360 + 2700 + 160 + 3200 + 24000 + 200 + 4000 + 30000 = 64638

これらの単純な事実を知り、それらを操作する技術を学んだことで、そうでなければできなかった算術を行うことができます。

同様に、一度に64ビット以上の数学を処理できないコンピューターは、大きな問題を小さな断片に簡単に分割し、それらの小さな断片を実行し、それらを元に戻して、より大きな、以前の答えられない問題。


0

加算と減算に関する限り、多くのCPUには、算術演算がオーバーフローした場合に設定される「キャリービット」があります。そのため、結果の保存に8バイトが必要で、CPUが32ビット(4つの8ビットバイトに相当)の場合、2つの加算演算を実行できます。最初に「低ワード」で、次に「高ワード」でキャリービットがオーバーフローを処理します。最初にキャリービットをクリアする必要があります。これは、高ビットCPUがパフォーマンスを向上させる理由の1つです。これは、これをそれほど行う必要がないためです。

もちろん、これは8ビットCPUでのアセンブラーの経験が限られているためです。キャリービットが乗算および除算命令を備えた最新のCPUでどのように機能するかはわかりません。非Intel RISC CPUの動作も異なる場合があります。

浮動小数点演算についてはあまり知りませんが、基本的にバイトは特定の場所ではなく、固定数の場所を表します。それが「浮動」ポイントと呼ばれる理由です。したがって、たとえば、数値34459234は、3.4459234または3.4459234E + 20(3.4459234 x 10 ^ 20)とほぼ同じメモリ空間を消費します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.