3

Consider the following short C program:

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


#define K 20
// int K = 20;

int main() {
    printf("%f\n", sqrt(K));
}

This program, as given, compiles with gcc Foo.c, and produces correct output.

However, if we comment out the #define line, and comment in the int K = 20 line, then we get a compile-time error of undefined reference to sqrt', which can only be fixed by compiling with gcc Foo.c -lm.

I am on gcc 4.7.3 on Ubuntu 13.04.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
  • In the second case K is not a constant and its value upon entering `main()` is unknown. – n. m. could be an AI Feb 16 '14 at 07:01
  • may be this may help http://stackoverflow.com/questions/1033898/why-do-you-have-to-link-the-math-library-in-c – Aseem Goyal Feb 16 '14 at 07:02
  • @n.m., I realize that, as stated in the question, but my question is, if GCC contains the code to compute the square root of a constant at compile-time, why can't it just inject that same code to compute the square root of the variable at run-time? – merlin2011 Feb 16 '14 at 07:03
  • See what happens if you use `#define K (-20)` – Leeor Feb 16 '14 at 07:05
  • @Leeor, that's fascinating! It gives the same linker error. By the way, I assume you meant `#define K (-20)`. – merlin2011 Feb 16 '14 at 07:06
  • `why can't it just inject that same code` — perhaps it does, and that code consists of calling `sqrt` from `libm`. Or perhaps it doesn't inject the exact same code. Why would it have to? – n. m. could be an AI Feb 16 '14 at 07:07
  • Yeah, corrected that. I have no idea why that happens, just wanted to see if it worked :). I'm guessing gcc has a built in set of functions for "simple" cases – Leeor Feb 16 '14 at 07:08
  • Refer to [Constant folding](http://en.wikipedia.org/wiki/Constant_folding). – devnull Feb 16 '14 at 07:10
  • Also see [this](http://stackoverflow.com/questions/19486738/why-is-lm-not-necessary-in-some-cases-when-compiling-and-linking-c-code). – devnull Feb 16 '14 at 07:15
  • When GCC constant-folds floating point expressions at compile time it uses a very generic emulation library, based on [GNU MPFR](http://www.mpfr.org/), that can faithfully reproduce all of the different varieties of not-quite-IEEE floating point implemented by all the different CPUs GCC can generate code for. It's accurate, but it's not fast, and it's not designed to spit out inline code for elementary functions. You probably wouldn't want that anyway. The machine code for `sin()` on the computer I'm typing this on is over a kilobyte long. – zwol Feb 20 '14 at 03:44
  • (For clarity, that was `sin()` in the system libm, not the MPFR implementation of `sin()`, which I would expect to be rather *larger*; precise approximation of trigonometric functions is "nontrivial" in the mathematician's sense.) – zwol Feb 20 '14 at 03:49

2 Answers2

6

During compilation, the compiler determines that you are calling a function with a constant literal as the only argument. So it can optimise by substituting the result of the function call.

It calculates the sqrt at compile time. Note that it does not, a suggested in your comment, inject code to calculate it at run time.

Of course the compiler well only do this for certain functions.

After this optimisation there is no requirement to call sqrt at run time, so you don't get an error if you didn't link it.

harmic
  • 28,606
  • 5
  • 67
  • 91
  • After writing this I found this near identical answer http://stackoverflow.com/questions/2049412/do-math-functions-of-constant-expressions-get-pre-calculated-at-compile-time – harmic Feb 16 '14 at 07:24
3

I believe this is the library GCC uses for float constant folding:

nodakai
  • 7,773
  • 3
  • 30
  • 60