2

I have the following C program:

#include <stdio.h>
#include <math.h>

#define LOG2(x) ((int)( log((double)(x)) / log(2) ))

int main() {

    int num = 64;
    int val1 = LOG2(num);
    int val2 = LOG2(64);

    printf("val1: %d, val2 %d\n", val1, val2);

    return 0;
}

Which outputs:

val1: 5, val2: 6

Why does this macro produce a different (and wrong) answer when I use it with a variable, but works correctly when I just type 64 directly?

Regardless of whether or not this is actually a good way to get the log base 2, what is causing this behavior? Is there any way I can get this macro to work properly with variables? (all my inputs will be exact powers of 2)

SuperPig
  • 70
  • 7
  • For me, both shows `5`: _http://ideone.com/QSVioZ_ – Washington Guedes Apr 20 '16 at 03:33
  • 1
    For me, both are 6. Could you please tell which machine and compiler you are using? –  Apr 20 '16 at 03:39
  • The issue appears to be your cast to `(int)` in the macro. Removing the cast allows `LOG2` to return the same with the values declared as `double`. – David C. Rankin Apr 20 '16 at 03:49
  • which compiler are you using – phuclv Apr 20 '16 at 03:54
  • http://stackoverflow.com/questions/588004/is-floating-point-math-broken – M.M Apr 20 '16 at 03:55
  • There is also a rare case when int loses its precision when casted to double.. I have even managed to ask a question here based on this. See [this](http://stackoverflow.com/questions/36734284/casting-int-to-double) – sjsam Apr 20 '16 at 05:26
  • Just don't use casts, the compiler pretends that you know what you are doing. Here, already the cast to `double` is superfluous, because the value would be converted to `double` anyhow. Then, casting a double to `int` is looking for trouble, too. In any case what you observe here is probably that in one case your compiler is somehow to determine the correct *log₂* at compile time (for the constant) and for the other it does a call to the `log` function. – Jens Gustedt Apr 20 '16 at 06:26

1 Answers1

2

This is, mathematically, a fine way of computing base-2 logs, but since log(val) and log(2) are both going to be long, messy fractions, it's not unlikely that the result of the division will end up being 5.999, which will truncate down to 5. I recommend rounding, especially if you know the inputs will always be powers of 2.

(But why did you get different answers for constant vs. variable? That's a good question, and I'm not sure of the answer. Usually the answer is that when there are constants involved the compiler is able to perform some/all of the calculation at compile time, but often the compiler ends up using subtly or significantly different floating-point arithmetic than the run-time environment. But I wouldn't have thought the compiler would be interpreting functions like log() while doing compile-time constant folding.)


Also, some C libraries have a log2() function which should give you perfect answers, but I don't know how standard that function is.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103