7

I'm getting a massive speedup from using this option when compiling my code. From the man page it says that this option:

Do not set "errno" after calling math functions that are executed with a single instruction, e.g., "sqrt"

Its not clear to me what the 'errno' is, and how it is used elsewhere (is this the same as the exit code of a program?) Furthermore, the man page says:

A program that relies on IEEE exceptions for math error handling may want to use this flag for speed while maintaining IEEE arithmetic compatibility.

Its not clear to me what this means, are the IEEE exceptions standard for c++ or common libraries of c++ (e.g. Eigen, Boost, etc.)

Essentially, I'm trying to determine if this is a 'safe' option to use in my code, or what side-effects I should be aware of from its use. A previous answer says this may affect 'thread local variables' but I have no clue what that means.

EDIT: My code is a simple one-off procedural code to handle a scientific problem. It is not going to be part of a deeply embeded system that requires complex error-handling. However, the code must not fail in subtle, silent ways.

Daniel Marchand
  • 584
  • 8
  • 26
  • 1
    Many standard math functions set `errno` on errors. Disabling that allows for simpler more optimized code paths, at the cost of making error detection harder. – Shawn Jun 11 '19 at 19:23
  • 1
    @Shawn Looks like a decent answer – Lightness Races in Orbit Jun 11 '19 at 19:24
  • 2
    Possible duplicate of [How to know what the 'errno' means?](https://stackoverflow.com/q/503878/608639) – jww Jun 11 '19 at 19:38
  • 1
    With `-fno-math-errno` mathematical functions becomes equivalent to function declared with the `[[gnu::const]]` [function attribute](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes). That improves drastically optimization. – Oliv Jun 11 '19 at 19:48
  • @Oliv I don't see how those things are the same? `-fno-math-errno` is about the function's behaviour; `[[gnu::const]]` is about the behaviour's repeatability. – Lightness Races in Orbit Jun 11 '19 at 20:08
  • 1
    @LightnessRacesinOrbit Maybe you overestimate optimizer: [demo](https://godbolt.org/z/xx51O2). – Oliv Jun 11 '19 at 20:56
  • @Oliv What I'm saying is that they fundamentally mean different things. Though without the `errno` setting it's probably easier for the optimiser to reach the same conclusion that you promise with `[[gnu::const]]`. That's not the same as saying it's "equivalent" though; not at all. – Lightness Races in Orbit Jun 11 '19 at 21:11
  • Caveat: there are also [undocumented side effects not only on math functions](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88576). – FrankHB Nov 23 '21 at 19:34

2 Answers2

9

C introduced the concept of a single errno or "error number" that could be used to determine the precise cause of the failure of some standard functions, including mathematical functions, to perform their duties. POSIX extended errno, and C++11 picked up some of those extensions too.

When one of these functions fails, the global integer errno is set to a value that tells you why. Obviously that incurs a performance penalty.

GCC is saying that this flag disables this behaviour for certain mathematical functions, speeding up your program at the cost of diagnostic utility and standard-compliance.

If you're already not observing errno when any of the affected functions fails, and you're probably not because you'd never heard of it, then you won't lose any functionality. This may be the case if you're writing a really time-constrained program, or when the particular reason for a failure doesn't dictate what your code does next. (However I advise looking into error checking more broadly to ensure that your code is as robust as it ought to be.)


However, it is possible for you to accidentally observe side-effects if you have a bug. Imagine if you were doing something like the following:

std::some_maths_function(42);
if (errno == ERANGE)
   exit(-1);

Oops! We are checking errno even when some_maths_function(42) succeeded. Let's say that above this code is a call to std::some_other_maths_function(999) which usually fails and results in errno being set to EDOM. That masked the bug in the code above.

Now turn on the compiler flag. If some_other_maths_function is one of the functions that no longer sets errno, your bug will be unmasked, and it may take you a few moments to realise that you ought to have written something more like:

if (std::some_maths_function(42) == -1)
{
   if (errno == RANGE)
      exit(-1);
}

Of course it's hardly GCC's fault that you had a bug, but this does show how the behaviour of your program can differ after enabling this "optimisation" flag. Indeed, the documentation says:

This option is not turned on by any -O option since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.

In other words, this flag sends you off-book. But it may be worth it.


The variable errno must be thread-local (that is, there is actually one of them for each thread in your program) otherwise it'd be useless in a multi-threaded program. You can research the term "thread-local" for more information on this subject.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • If I'm reading https://en.cppreference.com/w/cpp/numeric/math/math_errhandling correctly, as long as your libc plays nicely with the option by setting `math_errhandling` to the appropriate value (2), using it can still be compliant. – Shawn Jun 11 '19 at 19:33
  • @Shawn Only if floating-point exceptions are used! I'm only guessing but I'd imagine this flag not to affect the value of `math_errhandling` and instead render the implementation non-compliant if its value has `MATH_ERRNO` masked into it. – Lightness Races in Orbit Jun 11 '19 at 19:36
  • @Shawn In fact the docs do say: _"This option is not turned on by any -O option since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications."_ In other words, this flag sends you off-book. – Lightness Races in Orbit Jun 11 '19 at 19:37
  • Unless you're on some funky hardware, you should hopefully have fp exceptions because they're required for IEEE floating point. – Shawn Jun 11 '19 at 19:38
  • glibc, at least, looks like it defines `math_errhandling` correctly. The number of programs that check it before assuming that math functions set errno, now... That's probably a very small number. And pre C99/C++11 doesn't have that feature in the standards at all; it *would* break old code too. – Shawn Jun 11 '19 at 19:42
  • @Shawn Not every maths operation that sets `errno` relates to floating-point. Although I admit I don't know how many of those are single-instruction. But, yes, you can rely on FP exceptions instead of `errno` if you like. – Lightness Races in Orbit Jun 11 '19 at 19:43
2

Beware that GCC might also disable errno for non-math functions such as malloc when -fno-math-errno is used. [0]

[0] -fno-math-errno causes GCC to consider that malloc does not set errno

Steve Ward
  • 486
  • 4
  • 11