6

I'm having some strange issues with pow(). If i do

return 44330*(1 - pow((float) pressure / PRESSURE0, 1/5.255F));

where pressure is an int32_t and PRESSURE0is a constant, I get an error saying undefined reference to `pow'. However, if I do

return 44330*(1 - pow((float) pressure / PRESSURE0, 1.0F));

it's fine. Am I doing something wrong?

Thanks

Kar
  • 6,063
  • 7
  • 53
  • 82
  • Please try -lm in your compiler options. – user411313 May 20 '15 at 05:25
  • 2
    This is most likely caused by a compiler optimization: in the second case, since the exponent is `1.0`, there is no need to call the `pow()` function. To fix the first variant, try linking with `-lm`. See also http://stackoverflow.com/questions/9920789/literal-constant-vs-variable-in-math-library and http://stackoverflow.com/questions/2049412/do-math-functions-of-constant-expressions-get-pre-calculated-at-compile-time – Andreas Fester May 20 '15 at 05:25
  • I don't think this -lm will solve this - his second example works and I assume it compiles the same. @Kate - are you using a c++ compiler? Can you provide your make file and headers you use for pow? – Ishay Peled May 20 '15 at 05:33
  • 1
    @IshayPeled Reproduce it. You will see exactly the issue OP has. See my answer below. – Andreas Fester May 20 '15 at 05:40

1 Answers1

7

Generally, in order to use math functions like sqrt(), pow() etc. you need to link with the math library, libm (on gcc, use the -lm option).

However, the compiler is free to apply optimizations, especially when the arguments to the functions are constants. Consider the following two simplified functions:

double f1(int pressure) {
   return pow((float) pressure / PRESSURE0, 1/5.255F);
}

double f2(int pressure) {
   return pow((float) pressure / PRESSURE0, 1.0F);
}

This gets compiled into i386 code as follows (unnecessary assembler directives removed):

f1:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp

; (float) pressure / PRESSURE0
        fildl   8(%ebp)
        fldl    .LC0
        fdivrp  %st, %st(1)

; pow()
        fldl    .LC1
        fstpl   8(%esp)
        fstpl   (%esp)
        call    pow

        leave
        ret
f2:
        pushl   %ebp
        movl    %esp, %ebp

; (float) pressure / PRESSURE0
        fildl   8(%ebp)
        fldl    .LC0
        fdivrp  %st, %st(1)

; NO call to pow(x, 1.0), since it would not change the value of x

        popl    %ebp
        ret

In f2(), since the exponent to pow() is 1.0, there is no need to call the pow() function - the compiler detects this and removes the function call. Hence, if there are no other calls to any math functions in your code, it is not necessary to link against libm in that particular case.

See also

Community
  • 1
  • 1
Andreas Fester
  • 36,091
  • 7
  • 95
  • 123
  • 2
    Side note: this is why undefined reference to function is treated by the standard as *undefined behaviour, no diagnostic required*: so that compilers can optimize without having to keep a paper trail of what they optimized out – M.M May 20 '15 at 05:45