アセンブラーでは、MULコマンドを使用して64ビットの結果EAX:EDXを取得できますが、Cで同じことを行うにはどうすればよいですか?http://siyobik.info/index.php?module=x86&id=210
uint64_tを使用して結果をシフトする私のアプローチは機能しません^^
助けてくれてありがとう(=
自分
アセンブラーでは、MULコマンドを使用して64ビットの結果EAX:EDXを取得できますが、Cで同じことを行うにはどうすればよいですか?http://siyobik.info/index.php?module=x86&id=210
uint64_tを使用して結果をシフトする私のアプローチは機能しません^^
助けてくれてありがとう(=
自分
まともなコンパイラは、尋ねられたときにそれを実行します。
たとえば、VC ++ 2010を使用すると、次のコードが表示されます。
unsigned long long result ;
unsigned long a = 0x12345678 ;
unsigned long b = 0x87654321 ;
result = (unsigned long long)a * b ;
次のアセンブラを生成します。
mov eax,dword ptr [b]
mov ecx,dword ptr [a]
mul eax,ecx
mov dword ptr [result],eax
mov dword ptr [a],edx
いくつかのコードを投稿してください。これは私のために働きます:
#include <inttypes.h>
#include <stdio.h>
int main(void) {
uint32_t x, y;
uint64_t z;
x = 0x10203040;
y = 0x3000;
z = (uint64_t)x * y;
printf("%016" PRIX64 "\n", z);
return 0;
}
#含む
/* The name says it all. Multiply two 32 bit unsigned ints and get
* one 64 bit unsigned int.
*/
uint64_t mul_U32xU32_u64(uint32_t a, uint32_t x) {
return a * (uint64_t)b; /* Note about the cast below. */
}
これにより、次のものが生成されます。
mul_U32xU32_u64:
movl 8(%esp), %eax
mull 4(%esp)
popl %ebp
ret
コンパイルした場合:
gcc -m32 -O3 -fomit-frame-pointer -S mul.c
これは、mul
命令(mull
ここでは、x86のgnuアセンブラが好む方法であるmultiply longと呼ばれます)を希望する方法で使用します。
この場合、数値が関数に渡されたため、パラメーターの1つがレジスターに配置されるのではなく、スタックから直接プルされました(4(%esp)
つまり、スタックポインターの4バイト上にあり、スキップされる4バイトがリターンアドレスです)。スタックにプッシュされます(x86 ABI(アプリケーションバイナリインターフェイス)による)。
関数をインライン化するか、コードで数学を実行しただけmul
の場合、多くの場合、命令が使用される可能性がありますが、最適化コンパイラーは、関数が機能すると判断できる場合は、一部の乗算をより単純なコードに置き換えることもできます(たとえば、 1つ以上の引数がわかっている場合は、これをシフトまたは定数に変えることができます)。
Cコードでは、コンパイラが64ビットの結果を生成するように、引数の少なくとも1つを64ビット値にキャストする必要がありました。コンパイラが32ビット値を乗算するときに64ビットの結果を生成するコードを使用する必要があったとしても、C演算の規則によれば、通常は同じタイプの値になるため、その上半分は重要であるとは見なされなかった可能性があります。コンポーネントの中で最大の範囲を持つ値として(ただし、実際には正確に機能していないと主張できる場合を除きます)。
コンパイラに__emulまたは__emuluと同等のものを入手できるかどうかを確認してください(または、MSコンパイラを使用している場合はこれを使用してください)。ただし、制限やその他の面白い問題(_aulmulなど)の背後に座っていない限り、64ビット乗算は自動的に機能するはずです。
2つの32ビット量を乗算して64ビットの結果を取得することを意味しますか?
これは、C自体では予測されていません。たとえば、32ビットを2つ使用するuint32_t
と、結果は同じ幅になります。または、前にキャストしましuint64_t
たが、その特別な(そして高速な)乗算の利点を失います。
私が見る唯一の方法は、インラインアセンブラ拡張機能を使用することです。gccはこれで非常に優れており、非常に最適なコードを生成できます。しかし、これは異なるバージョンのコンパイラ間で移植可能ではありません。(ただし、多くのパブリックドメインコンパイラはgccを採用していると思います)
Cでそれを正確に行うことはできません。つまり、2つのNビット値を乗算して、結果として2Nビット値を取得することはできません。C乗算のセマンティクスは、マシン乗算のセマンティクスとは異なります。Cでは、乗算演算子は常に同じタイプの値に適用されT
(いわゆる通常の算術変換がそれを処理します)、同じタイプの結果を生成しT
ます。
乗算でオーバーフローが発生した場合は、オペランドに大きな型を使用する必要があります。より大きな型がない場合は、運が悪いです(つまり、大規模な乗算のライブラリレベルの実装を使用する以外に選択肢はありません)。
たとえば、プラットフォームの最大の整数型が64ビット型の場合、マシンのアセンブリレベルでmul
、正しい128ビットの結果を生成する操作にアクセスできます。言語レベルでは、そのような乗算にアクセスすることはできません。