Mawtin
Mawtin

Reputation: 15

C++ Optimizer : division

Lets say I have 2 if statements:

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

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

I'd imagine the two to function the exact same, yet I'm guessing the first statement with the multiplication is more efficient than the division.

Would a C++ compiler optimize this? Or is this something I should take into account when designing my code

Upvotes: 0

Views: 137

Answers (3)

Mikhail
Mikhail

Reputation: 8028

If they are floats built with -O3, GCC will generate the same assembly (for better or for worse).

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

So, really, its ends up the same code :-)

Upvotes: 0

rustyx
rustyx

Reputation: 85452

Yes and no.

  1. The code is not identical:
  • due to rounding, there can be differences in results (e.g. frequency1_mhz=1001 and frequency2_hz=1)
  • the first version might overflow sooner than the second one. e.g. a frequency2_hz of 1000000000 would overflow an int (and cause UB)
  1. It's still possible to perform division using multiplication.

When unsure, just look at the generated assembly.

Here's the generated assembly for both versions. The second one is longer, but still contains no division.

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

Upvotes: 4

Quimby
Quimby

Reputation: 19213

No, these are not equivalent statemets because division is not a precise inverse of multiplication for floats nor integers.

  • Integer divison rounds down positive fractionns
int f1=999;
int f2=0;

static_assert(f1>f2*1000);

static_assert(f1/1000==f2);
  • Reciprocals are not precise:
static_assert(10.0!=10*(1.0/10));

Upvotes: 2

Related Questions