【问题标题】:Efficient computation of the high order bits of a 32 bit integer multiplication高效计算 32 位整数乘法的高位
【发布时间】:2009-09-08 23:54:36
【问题描述】:

许多 CPU 具有用于返回 32 位整数乘法的 位的单一汇编操作码。通常将两个 32 位整数相乘会产生 64 位结果,但如果将其存储在 32 位整数中,则会将其截断为低 32 位。

例如,在 PowerPC 上,mulhw 操作码在一个时钟内返回 32x32 位乘法的 64 位结果的高 32 位。这正是我正在寻找的,但更便携。 NVidia CUDA 中有一个类似的操作码 umulhi()。

在 C/C++ 中,有没有一种有效的方法来返回 32x32 乘法的高位? 目前我通过转换为 64 位来计算它,例如:

unsigned int umulhi32(unsigned int x, unsigned int y)
{
  unsigned long long xx=x;
  xx*=y;
  return (unsigned int)(xx>>32);
}

但这比常规的 32 x 32 乘法要慢 11 倍以上,因为即使是乘法,我也使用过大的 64 位数学运算。

有没有更快的方法来计算高位?

这显然不是最好用 BigInteger 库来解决(这太过分了,而且会产生巨大的开销)。

SSE 似乎有 PMULHUW,这是一个 16x16 -> 前 16 位版本,但没有我正在寻找的 32x32 -> 前 32 位版本。

【问题讨论】:

    标签: c++ c optimization


    【解决方案1】:

    gcc 4.3.2,具有 -O1 优化或更高版本,将您的函数完全按照您向 IA32 程序集展示的方式转换,如下所示:

    umulhi32:
            pushl   %ebp
            movl    %esp, %ebp
            movl    12(%ebp), %eax
            mull    8(%ebp)
            movl    %edx, %eax
            popl    %ebp
            ret
    

    这只是做一个 32 位 mull 并将结果的高 32 位(来自 %edx)放入返回值。

    这就是你想要的,对吧?听起来您只需要对编译器进行优化;)您可以通过消除中间变量将编译器推向正确的方向:

    unsigned int umulhi32(unsigned int x, unsigned int y)
    {
      return (unsigned int)(((unsigned long long)x * y)>>32);
    }
    

    【讨论】:

    • 是的,我使用过的几乎所有编译器都会在 -O2 处执行此操作,如果不是在 -O1 处。
    【解决方案2】:

    我认为在标准 C/C++ 中没有比现有方法更好的方法了。我要做的是编写一个简单的程序集包装器,它返回您想要的结果。

    不是你问的是 Windows,而是作为一个例子,即使 Windows 有一个 API 听起来像你想要的(在获得完整 64 位结果的同时进行 32 乘 32 位乘法),它实现了乘法作为一个做你正在做的事情的宏:

    #define UInt32x32To64( a, b ) (ULONGLONG)((ULONGLONG)(DWORD)(a) * (DWORD)(b))
    

    【讨论】:

      【解决方案3】:

      在 32 位 intel 上,乘法会影响输出的两个寄存器。也就是说,无论您是否愿意,64 位都是完全可用的。它只是编译器是否足够聪明以利用它的功能。

      现代编译器做了很多令人惊奇的事情,所以我的建议是多尝试一些优化标志,至少在英特尔上是这样。您可能会认为优化器可能知道处理器从 32 到 32 位生成 64 位值。

      也就是说,在某些时候,我试图让编译器在除法结果上使用模数和除数,但 1998 年的旧 Microsoft 编译器不够聪明,无法实现相同的指令产生两种结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-06
        • 2021-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多