【问题标题】:Assembly: 64 bit multiplication with 32-bit registers汇编:64 位乘法与 32 位寄存器
【发布时间】:2013-10-26 01:33:47
【问题描述】:

我有一个关于在 x86 汇编中实现 64 位乘法的问题。据我所知,我已经发布了代码。我不知道其他人做了什么(我可能在我已经做过的事情上犯了错误)。任何方向将不胜感激。

dest at %ebp+8
x    at %ebp+12
y    at %ebp+16

movl        16(%ebp), %esi      //Move y into %esi
movl        12(%ebp), %eax      //Move x into %eax
movl        %eax, %edx          //Move x into %edx
sarl        $31, %edx            //Shift x right 31 bits (only sign bit remains)
movl        20(%ebp), %ecx      //Move the low order bits of y into %ecx
imull       %eax, %ecx          //Multiply the contents of %ecx (low order bits of y) by x
movl        %edx, %ebx          //Copy sign bit of x to ebx
imull       %esi, %ebx          //Multiply sign bit of x in ebx by high order bits of y
addl        %ebx, %ecx          //Add the signed upper order bits of y to the lower order bits (What happens when this overflows?)
mull        %esi                //Multiply the contents of eax (x) by y
leal        (%ecx,%edx), %edx           
movl        8(%ebp), %ecx
movl        %eax, (%ecx)
movl        %edx, 4(%ecx)

【问题讨论】:

  • 将 2 个 32 位值相乘并不能真正算作 64 位乘法。以及如何在 20(%ebp) 处移动 long 移动 y 的任何位,除非 y 是 64 位值,但结果没有 64 位位置(dest 只有 32 位),除非它应该覆盖 x...
  • 这会将一个有符号的 32 位整数与一个有符号的 64 位整数相乘,产生一个有符号的 64 位整数。以 2^32 为底,在纸上算出来。
  • 顺便说一句,unsigned 32x64 乘法只需要imul + mul 和2 加(godbolt.org/g/VC6i9T):32 位输入的上半部分为零,不是 0 或 -1,所以 x_h * y_h 术语消失了。 (顺便说一句,gcc 在这里可以做得更好,用 cmov / sub 而不是实际乘以 x 的上半部分。它可以用cdq 生成它。)实际的 64x64 乘法需要更少的指令(没有符号-延长上半部分)。

标签: assembly x86


【解决方案1】:

下面是64位乘法的算法:

x, y: 64-bit integer
x_h/x_l: higher/lower 32 bits of x
y_h/y_l: higher/lower 32 bits of y

x*y  = ((x_h*2^32 + x_l)*(y_h*2^32 + y_l)) mod 2^64
     = (x_h*y_h*2^64 + x_l*y_l + x_h*y_l*2^32 + x_l*y_h*2^32) mod 2^64
     = x_l*y_l + (x_h*y_l + x_l*y_h)*2^32

Now from the equation you can see that only 3(not 4) multiplication needed.

 movl 16(%ebp), %esi    ; get y_l
 movl 12(%ebp), %eax    ; get x_l
 movl %eax, %edx
 sarl $31, %edx         ; get x_h, (x >>a 31), higher 32 bits of sign-extension of x
 movl 20(%ebp), %ecx    ; get y_h
 imull %eax, %ecx       ; compute s: x_l*y_h
 movl %edx, %ebx
 imull %esi, %ebx       ; compute t: x_h*y_l
 addl %ebx, %ecx        ; compute s + t
 mull %esi              ; compute u: x_l*y_l
 leal (%ecx,%edx), %edx ; u_h += (s + t), result is u
 movl 8(%ebp), %ecx
 movl %eax, (%ecx)
 movl %edx, 4(%ecx)

你也可以查看implement 64-bit arithmetic on a 32-bit machine

【讨论】:

    【解决方案2】:

    这不是 64 位乘法(将一对 64 位数字相乘得到 128 位结果)。这是 32 位乘法(将一对 32 位数字相乘得到 64 位结果)。

    32 位 80x86 支持单条指令的 32 位乘法。基本上,MUL 指令将一对无符号 32 位数字相乘以在 EDX:EAX 中生成无符号 64 位结果;并且(“一个操作数”版本)IMUL 指令将一对带符号的 32 位数字相乘以在 EDX:EAX 中生成带符号的 64 位结果。

    注意:IMUL 的“单操作数”版本使用 EAX 中的值作为隐含的第二个操作数。

    基本上;您需要将其中一个值加载到 EAX 中,使用一次IMUL(其中操作数是第二个值),然后存储结果。

    【讨论】:

    • 这是 32x64,而不是 32x32。如果是 32x32,则只有一个乘法指令,但这个序列有三个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 2014-01-05
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2017-03-11
    相关资源
    最近更新 更多