C++ 优化器:除法

C++ Optimizer : division

假设我有 2 个 if 语句:

if (frequency1_mhz > frequency2_hz * 1000) {// some code}

if (frequency1_mhz / 1000 > frequency2_hz ) {// some code}

我想这两者的功能完全相同,但我猜第一个乘法语句比除法更有效。

C++ 编译器会对此进行优化吗?或者这是我在设计代码时应该考虑的事情

不,这些不是等效的状态机,因为除法不是浮点数或整数乘法的精确逆运算。

  • 整数除法向下舍入正分数
int f1=999;
int f2=0;

static_assert(f1>f2*1000);

static_assert(f1/1000==f2);
  • 倒数不精确:
static_assert(10.0!=10*(1.0/10));

是也不是。

  1. 代码不相同:
  • 由于四舍五入,结果可能存在差异(例如 frequency1_mhz=1001frequency2_hz=1
  • 第一个版本可能比第二个版本更快溢出。例如1000000000 的 frequency2_hz 会溢出 int(并导致 UB)
  1. 仍然可以使用乘法来执行除法。

不确定时,请查看生成的程序集。

Here's 为两个版本生成的程序集。第二个更长,但仍然没有分割。

version1(int, int):
        imul    esi, esi, 1000
        xor     eax, eax
        cmp     esi, edi
        setl    al
        ret
version2(int, int):
        movsx   rax, edi
        imul    rax, rax, 274877907     ; look ma, no idiv!
        sar     edi, 31
        sar     rax, 38
        sub     eax, edi
        cmp     eax, esi
        setg    al
        movzx   eax, al
        ret

如果它们是用 -O3 构建的浮点数,GCC 将生成相同的程序集(无论好坏)。

bool first(float frequency1_mhz,float frequency2_hz) {
    return frequency1_mhz > frequency2_hz * 1000;
}

bool second(float frequency1_mhz,float frequency2_hz) {
    return frequency1_mhz / 1000 > frequency2_hz;
}

The assembly

first(float, float):
        mulss   xmm1, DWORD PTR .LC0[rip]
        comiss  xmm0, xmm1
        seta    al
        ret
second(float, float):
        divss   xmm0, DWORD PTR .LC0[rip]
        comiss  xmm0, xmm1
        seta    al
        ret
.LC0:
        .long   1148846080

所以,实际上,它的代码相同:-)