如何以标准/便携和高效的方式编写int64 = int32*int32?

use*_*438 2 c c++

相关: 这对int64_t的处理是GCC和Clang的错误吗?

我能想到的唯一解决方案是将其中一个操作数显式转换为int64,至少也要强制产品int64.

但是如果以这种方式完成,则由编译器的智能实际做到int64*int32,或者int64*int64,或者理想情况下,将其优化回来int32*int32.

如在相关问题讨论,分配的结果int32*int32,以int64不改变的事实int32*int32已经引起UB.

任何想法?

小智 9

您已经指出了如何以标准,便携和高效的方式执行此操作:

int64_t mul(int32_t x, int32_t y) {
    return (int64_t)x * y;
    // or static_cast<int64_t>(x) * y if you prefer not to use C-style casts
    // or static_cast<int64_t>(x) * static_cast<int64_t>(y) if you don't want
    // the integral promotion to remain implicit
}
Run Code Online (Sandbox Code Playgroud)

您的问题似乎是关于假设的体系结构,其具有与功能签名对应的汇编指令

int64_t intrinsic_mul(int32_t x, int32_t y);
int64_t intrinsic_mul(int64_t x, int64_t y);
int64_t intrinsic_mul(int64_t x, int32_t y); // and maybe this too
Run Code Online (Sandbox Code Playgroud)

并且,在这个假设的体系结构中,第一个具有相关优势,而且,在编译上述函数时,编译器无法使用此指令,并且最重要的是,它无法提供对上述内部函数的访问.

我希望这样的场景真的很少见,但是如果你真的发现自己处于这种情况,大多数编译器也允许你编写内联汇编,所以你可以编写一个直接调用这个特殊指令的函数,并且仍然提供足够的元数据优化器可以有效地使用它(例如使用符号输入和输出寄存器,因此优化器可以使用它想要的任何寄存器,而不是使寄存器选择硬编码).

  • @mfro:我必须抛出其中一个参数,否则产品将是`int32_t`,因此在转换为`int64_t`之前会失去精度并且容易溢出.(或者,我想,如果我心情好的话,我本可以直接提出`int64_t`这个论点) (3认同)

Ker*_* SB 5

内置算术表达式仅针对同类操作数类型退出.任何涉及混合类型的表达都意味着整体提升,并且算术操作本身只是为同类型定义并应用于同类型.

选择int32_t或者int64_t.

正如你可能正确地理解,对于整型算术运算的两个备选项(至少+,-*)易受UB通过溢出,但在两个操作时不能有任何溢出int64_t这既可以表示为s int32_t秒.例如,以下工作:

int64_t multiply(int32_t a, int32_t b)
{
    // guaranteed not to overflow, and the result value is equal
    // to the mathematical result of the operation
    return static_cast<int64_t>(a) * static_cast<int64_t>(b);
}
Run Code Online (Sandbox Code Playgroud)

例如,以下是GCC如何将其转换为Linux上的x86和x86_64(请注意不同的调用约定):

multiply(int, int):

// x86 (32-bit, "-m32 -march=i386")     x86-64 ("-m64 -march=x86-64")
// args are on the stack                args are in EDI, ESI
// return in EDX:EAX                    return in RAX

mov     eax, DWORD PTR [esp+8]          movsx   rax, edi
                                        movsx   rsi, esi
imul    DWORD PTR [esp+4]               imul    rax, rsi
ret                                     ret
Run Code Online (Sandbox Code Playgroud)

  • 通过范围分析(或者更可能在这种情况下,窥视孔优化),编译器应该知道操作数都是32位,并且32x32乘法操作就足够了. (2认同)