どうすればいいの...
2 つの 64 ビット数の乗算
2 つの 16 桁の 16 進数の乗算
...アセンブリ言語を使用。
レジスタ %eax、%ebx、%ecx、%edx、およびスタックのみを使用できます。
編集: ああ、x86 で ATT 構文を使用しています EDIT2:
アセンブリに逆コンパイルすることはできません...
どうすればいいの...
2 つの 64 ビット数の乗算
2 つの 16 桁の 16 進数の乗算
...アセンブリ言語を使用。
レジスタ %eax、%ebx、%ecx、%edx、およびスタックのみを使用できます。
編集: ああ、x86 で ATT 構文を使用しています EDIT2:
アセンブリに逆コンパイルすることはできません...
ランドール・ハイドの「The Art of Assembly Language」というコースの教科書と思われるものを使用してください。
4.2.4 - 拡張精度乗算を参照してください。
通常は 8x8、16x16、または 32x32 の乗算で十分ですが、より大きな値を乗算したい場合もあります。拡張精度乗算には、x86 シングル オペランド MUL および IMUL 命令を使用します。
拡張精度の乗算を実行する際に覚えておくべきおそらく最も重要なことは、多倍精度の加算も同時に実行する必要があるということです。すべての部分積を合計するには、結果を生成するいくつかの追加が必要です。次のリストは、32 ビット プロセッサで 2 つの 64 ビット値を乗算する適切な方法を示しています。
(完全なアセンブリ リストと図については、リンクを参照してください。)
これが 64x86 の場合、
function(x, y, *lower, *higher)
movq %rx,%rax #Store x into %rax
mulq %y #multiplies %y to %rax
#mulq stores high and low values into rax and rdx.
movq %rax,(%r8) #Move low into &lower
movq %rdx,(%r9) #Move high answer into &higher
このコードは、(x64 コードではなく) x86 が必要であり、おそらく 64 ビット製品のみが必要であり、オーバーフローや符号付きの数値は気にしないことを前提としています。(署名されたバージョンも同様です)。
MUL64_MEMORY:
mov edi, val1high
mov esi, val1low
mov ecx, val2high
mov ebx, val2low
MUL64_EDIESI_ECXEBX:
mov eax, edi
mul ebx
xch eax, ebx ; partial product top 32 bits
mul esi
xch esi, eax ; partial product lower 32 bits
add ebx, edx
mul ecx
add ebx, eax ; final upper 32 bits
; answer here in EBX:ESI
これは、OP の正確なレジスタ制約を尊重しませんが、結果は x86 によって提供されるレジスタに完全に適合します。(このコードはテストされていませんが、正しいと思います)。
[注:ここにある他の「回答」はどれも質問に直接回答していないため、閉じられた別の質問からこの回答を(私の)転送しました]。
x86 を使用しているため、4 つの mull 命令が必要です。64 ビット量を 2 つの 32 ビット ワードに分割し、下位ワードを結果の最下位ワードと 2 番目に下位ワードに乗算し、次に、異なる数値から下位ワードと上位ワードの両方のペアを乗算します (結果の 2 番目と 3 番目に下位ワードに移動します)。最後に、両方の上位ワードを結果の上位 2 ワードに変換します。キャリーを処理することを忘れずに、それらをすべて一緒に追加します。入力と出力のメモリ レイアウトを指定していないため、サンプル コードを記述することはできません。
使用している言語によって異なります。MIPS アセンブリの学習で覚えていることから、Move From High コマンドと Move From Lo コマンド、または mflo と mfhi があります。mfhi は上位 64 ビットを格納し、mflo は合計数の下位 64 ビットを格納します。
各「桁」が実際には 32 ビットの整数であることを除いて、2 桁の数値のペアを掛けるように、通常の long 乗算を実行します。アドレス X と Y で 2 つの数値を乗算し、結果を Z に格納する場合、(疑似コードで) 実行したいことは次のとおりです。
Z[0..3] = X[0..3] * Y[0..3] Z[4..7] = X[0..3] * Y[4..7] + X[4..7] * Y[0..3]
結果の上位 64 ビットを破棄していることに注意してください (64 ビット数 x 64 ビット数は 128 ビット数であるため)。また、これはリトルエンディアンを想定していることにも注意してください。また、符号付きと符号なしの乗算にも注意してください。
64 ビットをサポートする C コンパイラ (GCC は IIRC を実行します) を見つけて、それを行うプログラムをコンパイルし、逆アセンブリを取得します。GCC は独自に吐き出すことができ、適切なツールを使用してオブジェクト ファイルから取得できます。
OTOHはx86で32bX32b = 64b opです
a:b * c:d = e:f
// goes to
e:f = b*d;
x:y = a*d; e += x;
x:y = b*c; e += x;
他のすべてがオーバーフローします
(未テスト)
署名なしのみを編集
ああ、アセンブリ、私がそれを使用してからしばらく経ちました。ここでの本当の問題は、あなたが取り組んでいるマイクロコントローラ(とにかくアセンブリでコードを書いていたもの)に64ビットレジスタがないことだと思いますか?その場合は、作業している数字を分割して、ピースで複数の乗算を実行する必要があります。
これはあなたの言い方からすると宿題のように聞こえるので、これ以上詳しく説明するつもりはありません :P
私はあなたが学生であるに違いないので、これがうまくいくかどうか見てみましょう: 単語ごとに実行し、ビットシフトを使用してください。最も効率的な解決策を考えてください。符号ビットに注意してください。
128モードが必要な場合は、これを試してください...
__uint128_t AES::XMULTX(__uint128_t TA,__uint128_t TB)
{
union
{
__uint128_t WHOLE;
struct
{
unsigned long long int LWORDS[2];
} SPLIT;
} KEY;
register unsigned long long int __XRBX,__XRCX,__XRSI,__XRDI;
__uint128_t RESULT;
KEY.WHOLE=TA;
__XRSI=KEY.SPLIT.LWORDS[0];
__XRDI=KEY.SPLIT.LWORDS[1];
KEY.WHOLE=TB;
__XRBX=KEY.SPLIT.LWORDS[0];
__XRCX=KEY.SPLIT.LWORDS[1];
__asm__ __volatile__(
"movq %0, %%rsi \n\t"
"movq %1, %%rdi \n\t"
"movq %2, %%rbx \n\t"
"movq %3, %%rcx \n\t"
"movq %%rdi, %%rax \n\t"
"mulq %%rbx \n\t"
"xchgq %%rbx, %%rax \n\t"
"mulq %%rsi \n\t"
"xchgq %%rax, %%rsi \n\t"
"addq %%rdx, %%rbx \n\t"
"mulq %%rcx \n\t"
"addq %%rax, %%rbx \n\t"
"movq %%rsi, %0 \n\t"
"movq %%rbx, %1 \n\t"
: "=m" (__XRSI), "=m" (__XRBX)
: "m" (__XRSI), "m" (__XRDI), "m" (__XRBX), "m" (__XRCX)
: "rax","rbx","rcx","rdx","rsi","rdi"
);
KEY.SPLIT.LWORDS[0]=__XRSI;
KEY.SPLIT.LWORDS[1]=__XRBX;
RESULT=KEY.WHOLE;
return RESULT;
}