I am trying to calculate a motor position from an encoder, however that does not really matter. I just checked godbolt.org to see if my inline function compiled into a single multiplication and was pretty disappointed that it didn’t. I used -O3 for maximum optimization.

Does somebody know why it does not compile into a single function, or what I had to change to achieve that? You can find my code here: https://godbolt.org/z/qT9srfPT1 .

I know that it does not really matter, but I am curious.

  • FizzyOrange
    link
    fedilink
    arrow-up
    13
    ·
    12 days ago

    Use -ffast-math… if you dare. Or just use

    inline double position_from_steps(int steps) {
      return (2.0 * PI / 4096.0) * steps;
    };
    

    The reason it doesn’t optimise it into one multiplication is because that isn’t actually the same calculation. Floating point numbers aren’t real numbers, so it isn’t true that (a * b) / c == (a / c) * b. Since the “optimisation” would actually change the semantics, compilers don’t do it by default.

    -ffast-math says “hey I don’t care about reliable semantics; just do whatever to make it fast”. But it also does a load of stuff that you may find surprising. so you really shouldn’t use it. Much better just to reorganise your code.

    You can also use -funsafe-math-optimizations which is the more specific subset of -ffast-math that does this particular optimisation. See https://gcc.gnu.org/wiki/FloatingPointMath

    Also I would question if it matters. This micro-optimisation will make zero difference on x86. On a microcontroller (I assume what you’re actually using if you’re encoding motor positions) it might matter a bit more but double check your microcontroller even has an FPU. Lots don’t. Even if it does, doing it in integer space will probably be faster (though not necessarily).

  • Speiser0@feddit.org
    link
    fedilink
    arrow-up
    2
    ·
    12 days ago

    The compiler can’t replace every floating point division with a multiplication with the reciprocal. And it can’t assume associativity. See also -ffast-math.

    You can do this: return (double)steps * (2.0 * PI / 4096.0);