Why is there a difference in calculation results between literals and variables?

78 Views Asked by At

When debugging some C code, I encountered some weird inconsistencies in double calculations. I managed to isolate it to the following minimal example:

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

int main()
{
  float f = 268.6f;
  printf("Using variable float   %.1f: %d\n",   f,      (unsigned char)(round(f)));
  printf("Using literal  float   %.1f: %d\n",   268.6f, (unsigned char)(round(268.6f)));
  double d = 268.6;
  printf("Using variable double  %.1lf: %d\n",  d,      (unsigned char)(round(d)));
  printf("Using literal  double  %.1lf: %d\n",  268.6,  (unsigned char)(round(268.6)));
  long double ld = 268.6L;
  printf("Using variable ldouble %.1llf: %d\n", ld,     (unsigned char)(round(ld)));
  printf("Using literal  ldouble %.1llf: %d\n", 268.6L, (unsigned char)(round(268.6L)));
  return 0;
}

Which on my machine after gcc weirdlit.c -lm -oweirdlit; ./weirdlit using GCC version 11.2.0 produces following output:

Using variable float   268.6: 13
Using literal  float   268.6: 255
Using variable double  268.6: 13
Using literal  double  268.6: 255
Using variable ldouble 268.6: 13
Using literal  ldouble 268.6: 255

While the resulting values are obviously nonsensical (casting floating point values to unsigned char tends to do that), the values are not the point. The thing that baffled me is that the results are different when a literal value is used compared to when a variable with the exact same literal value assigned to it is used. Thinking it can be an optimization quirk, I tested it again with gcc weirdlit.c -lm -O2 -oweirdlit; ./weirdlit. Turned out I was right, optimization changed the output and this time the results were consistent.

Using variable float   268.6: 255
Using literal  float   268.6: 255
Using variable double  268.6: 255
Using literal  double  268.6: 255
Using variable ldouble 268.6: 255
Using literal  ldouble 268.6: 255

As we can see the result here (255) is the same as when the literals were used in the version without optimization. This shows us that GCC correctly detected that the variables don't change between assignment and being used and the literal values can be substituted in their place.

What I want to know is why this happens. Does GCC use some different versions of the math library functions to calculate the expression values during the optimization than the ones used later at runtime? Or is there some other explanation for this phenomenon?

0

There are 0 best solutions below