1

I have a C program which includes math.h and makes use of the sqrt function from that header. Very strangely, when I do not pass the -Ofast flag, my code does not compile.

If I use the following to compile my code:

gcc -std=c99 foo.c

Either by itself, or add any of -O1, -O2 or -Os (those are uppercase O's) to that command, I get the following error:

/tmp/ccAcT2Bz.o: In function `sum_of_divisors':
foo.c:(.text+0xb): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

-O3 gives a similar, but more elaborate error (note that I don't call sqrt within main):

/tmp/ccBKvvFS.o: In function `sum_of_divisors':
foo.c:(.text+0x5c): undefined reference to `sqrt'
/tmp/ccBKvvFS.o: In function `main':
foo.c:(.text.startup+0xe5): undefined reference to `sqrt'
foo.c:(.text.startup+0xf3): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

However, -Ofast compiles without error and the program runs perfectly. So,

  • Why does this happen? Why must a certain optimization level be enabled for it to compile? Is it a GCC bug?
  • How can I fix it, if I choose not to use -Ofast?
rvighne
  • 20,755
  • 11
  • 51
  • 73

2 Answers2

3

I'll try to phrase this as an answer based on the comments I've provided.

Essentially -ffast-math allows for mathematical 'optimizations' that do not conform to the IEEE-754 standard. Some examples includes allowing floating-point operations to obey the laws of associativity, e.g., they behave like 'real' numbers: (a + b) + c == a + (b + c) - and this is not a correct assumption with floating-point numbers. You can look at the man page for gcc to see the options that -ffast-math enables.

The option also allows for other code generation options that depart from the IEEE-754 standard. Operations that should raise exceptions, signalling NaNs, etc., may not be honoured. The example in the comments was sqrt; if we pass a negative value to sqrt, the results may not conform to the IEEE-754 standard. Trying to find the source of these inconsistencies far outweighs any benefit on modern processors. Modern CPUs have massive floating point resources, and correctness is far more important than any misplaced sense of efficiency.

There are very real examples of where honouring the associative property of real numbers when dealing with floating-point numbers leads to incorrect results. One example is Kahan summation. It relies on the non-associative property of floating-point arithmetic. There are other examples where careful analysis of numeric algorithms rely on IEEE-754 properties. Another example is Heron's formula for the area of a triangle.

Numerical analysis is a broad field, and the IEEE-754 standards represent a very careful and well-researched effort to standardize the idiosyncratic behaviour of floating-point operations, and their deviation from the naive ideal of 'real' numbers. It represents a massive effort over decades of research and experience (not to mention frustration) in numerically intensive computation.

There are people who frequently answer floating-point questions on this site with a much broader knowledge of the topic than I have. I just hope to convince you that -ffast-math is simply ill-advised in many cases (often an algorithm with better numerical conditioning is a better first step), and introduce sources of error that are extremely difficult to find, with results that are often impossible to reproduce on other platforms. Avoid it like the plague.

Brett Hale
  • 21,653
  • 2
  • 61
  • 90
1

The math library must be linked in when building the executable

so you need to compile with -lm option.

Jayesh Bhoi
  • 24,694
  • 15
  • 58
  • 73
  • Thank you for your reply. But **why** does this happen? Why does `-Ofast` change GCC's behavior in this way? – rvighne Aug 22 '14 at 04:56
  • [-Ofast](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html) Disregard strict standards compliance. -Ofast enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on **-ffast-math** and the Fortran-specific -fno-protect-parens and -fstack-arrays. – phuclv Aug 22 '14 at 05:01
  • @LưuVĩnhPhúc Really help full new for me. – Jayesh Bhoi Aug 22 '14 at 05:04
  • @LưuVĩnhPhúc: Ah, so `-Ofast` (and thus `-ffast-math`) implies `-lm` in some indirect way, is that right? – rvighne Aug 22 '14 at 05:05
  • @rvighne - think about what would happen if you passed a negative number to `sqrt`. `-ffast-math` might not handle this in a way that strictly conforms to IEEE-754, on the assumption that someone using `-ffast-math` is confident they would never do anything so silly - until they inevitably do. – Brett Hale Aug 22 '14 at 05:26
  • @BrettHale: Should I then completely avoid `-Ofast` for that reason (and also the issue I have) and use `-O3 -lm` instead? – rvighne Aug 22 '14 at 05:27
  • @rvighne - definitely. Or `-O2 -lm`. The other issue is that `-ffast-math` isn't the performance win it once was. Modern CPUs (desktop / laptop class) have massive scalar floating point resources, and handle many more 'edge cases' in silicon, rather than slower microcode. It's just not worth the hassle these days. – Brett Hale Aug 22 '14 at 05:34
  • Could any of the commenters here make a complete answer please? – rvighne Aug 22 '14 at 05:37
  • @BrettHale You can answer this.I will delete my soon. – Jayesh Bhoi Aug 22 '14 at 05:51
  • @Jayesh: Don't delete it, these comments are valuable! – rvighne Aug 22 '14 at 05:58
  • @rvighne Don't worry after answer given by anyone in this comment list i will delete it. – Jayesh Bhoi Aug 22 '14 at 06:08