2

Say I write an expression in c, for example

a = (((b+c) / d) / f) + ((3.14 * e) ) / f) ;

Here a,b,c,d,e,f are all double precision variables. When I compile my code using, for example, the gcc compiler with some optimization setting, does the compiler respect the particular form of the expression as I wrote it, or does it modify the expression to make the code run faster? For example, would/could gcc with -O2 optimization setting compile the above expression to

a = ((b+c + 3.14* d * e) / (d*f))

Or would it keep the expression as is? I am concerned about the compiler changing the forms of my equations, which may affect the numerical stability of my expressions.

physics_researcher
  • 638
  • 2
  • 9
  • 22
  • What? It does respect the *semantics* of your program and is guaranteed to produce the result fully identical to these semantics as long as you are not violating any rules defined in the C standard. But *how* it is doing it - it is mostly up to the compiler. – Eugene Sh. Mar 07 '18 at 21:42
  • Possible duplicate of [What does gcc's ffast-math actually do?](https://stackoverflow.com/questions/7420665/what-does-gccs-ffast-math-actually-do) – anatolyg Mar 07 '18 at 21:45
  • 1
    Just dont add -Ofast -funsafe-math-optimizations or -ffast-math if that is what you want. Normal optimizations like -O1, -Os, -O2 or -O3 _shouldnt_. – technosaurus Mar 07 '18 at 21:56
  • 1
    @technosaurus it is very probable that the optimisation level may change the order of the evaluation - and the results may vary. – 0___________ Mar 07 '18 at 23:59
  • @PeterJ_01 then your compiler is not standards compliant or you have "unsafe" optimizations enabled that you didn't realize. Older compilers did do this a long time ago (~2 decades) ... so unless your compiler is really old or you allow a broken build system to dictate your optimization options - very improbable. – technosaurus Mar 08 '18 at 02:07
  • Ok. Maybe I remember it from the far past. Anyway IMO it is better to be sure than to relay on the correctness of the compiler and self esteem. 90% of silly difficult to debug errors come from the wrong assumptions and are easy to prevent. I prefer to be safe by adding couple of parentheses to my code than sorry. – 0___________ Mar 08 '18 at 10:38

1 Answers1

2

The compiler is guaranteed to produce an expression that yields an equivalent result to evaluating your formula as it is written. This includes all type conversions, side effects, and exceptions the expressions may produce.

In particular, your way to optimize the expression would not pass the equivalency test, because ((b+c) / d) in the original expression would be evaluated in terms of the types of b, c, and d, which could be int or float; your second (optimized) formula, on the other hand, forces the double type on the entire expression because of addition of 3.14. It also multiplies e by d in the numerator to compensate for d*f in the denominator, which may produce an overflow that did not exist in the original formula.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • It is not 100% the truth. There is no particular order of the expression evaluation, with respect of the operator precedence and parentheses. The result of the float operations can be different as the result of the float operations can be different if the order of evaluation is changed. To avoid such problems use the parentheses – 0___________ Mar 07 '18 at 22:54
  • 1
    @PeterJ_01 I am not talking about the order of evaluation, it is implementation defined. It is true that picking a particular order of evaluation may influence the value of the expression. However, if the original expression is supposed to evaluate something that yields an exception, call some function with side effects twice, etc., the compiler cannot rewrite the expression to produce the side effect only once, or to avoid an exception. For example, compilers cannot rewrite `float x = ..., a = 1, b = a / x * x;` as `b = a`, because that would eliminate a possible division by zero. – Sergey Kalinichenko Mar 07 '18 at 23:11
  • Yes but the question IMO is about something else. He has asked if he can be 100% sure the he will get the same result in the different compilation environments. But there is no such a guarantee, The results may vary, – 0___________ Mar 07 '18 at 23:52
  • 1
    @PeterJ_01 No. Refer to http://port70.net/~nsz/c/c11/n1570.html#5.1.2.3p6 - the output produced has to be identical to the abstract machine output. So if rearranging of operations will lead to a different output - it should not occur. – Eugene Sh. Mar 08 '18 at 00:20
  • From my experience compilers do rearrange.IMO oo be 100% sure is safer to use more parentheses than necessary if the order of the evaluation is critical. – 0___________ Mar 08 '18 at 00:30
  • I've edited my question; I've specified that all the variables are declared as double. – physics_researcher Mar 08 '18 at 01:59
  • Order of evaluation isn't implementation-defined. If there are no sequencing relations involved then it's unspecified. – M.M Mar 08 '18 at 03:08
  • @Justin Even with all `double`s your conversion would be invalid, because the product of large `d` and `e` in the numerator may overflow `double`. The compiler cannot change your formula to introduce an overflow in the intermediate result; it is also not allowed to rearrange the formula make an overflow in the intermediate result disappear. – Sergey Kalinichenko Mar 08 '18 at 03:26