3

I', trying this simple code. It shows the first 10 integers that can not be represented in float:

int main(){
  int i, cont=0;
  float f;
  double di, df;
  for(i=10000000, f=i; i<INT_MAX; i++, f=i, df=f, di=((float)i)){
    if(i!=f){
      printf("i=%d   f=%.2f   df=%.2lf   di=%.2lf\n", i, f, df, di);
      if(cont++==10) return 0;
    }
  }
  return 1;
}

di is a double variable, but I set it to (float)i, so it should be equal to df, but it is not.

For example, the number 16777217 is represented as 16777216 by f and df, but di is still 16777217, ignoring the (float) casting.

How is this possible?

**I am using this: gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3

salteador
  • 31
  • 4

2 Answers2

2

Relevant to your question is 6.3.1.8:2 in the C99 standard:

The values of floating operands and of the results of floating expressions may be represented in greater precision and range than that required by the type; the types are not changed thereby.

and in particular footnote 52:

The cast and assignment operators are still required to perform their specified conversions as described in 6.3.1.4 and 6.3.1.5.

Reading the footnote, I would say that you have identified a bug in your compiler.

You may have identified two bugs in your compiler: the i!=f comparison is done between floats (see promotion rules on the same page of the standard), so it should always be false. Although, in this latter case, I think that the compiler may be allowed to use a larger type for the comparison by 6.3.1.8:2, perhaps making the comparison equivalent to (double)i!=(double)f and thus sometimes true. Paragraph 6.3.1.8:2 is the paragraph in the standard I hate most, and I am still trying to understand strict aliasing.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • Thanks a lot.I think you are right and there is a bug (or feature?) in the compiler, as i!=f is compared between doubles instead of floats. – salteador Mar 26 '12 at 23:11
  • This is an extremely longstanding known bug in gcc that the developers have little will to fix because it moderately hurts performance for people who don't care about correctness. If you don't care about making your program incompatible with old cpus, you can fix the problem with `-msse` (use SSE instead of FPU for floating point). Note that on platforms other than x86 (and perhaps m68k?) the issue does not exist. – R.. GitHub STOP HELPING ICE Mar 27 '12 at 03:07
  • @R..: If they want to maximize performance without regard to correctness, why not simply have all floating-point computations return 42.0? Wouldn't that be faster than pretending to do math on them? It's good IMHO for a compiler to perform things like `f4 = f1+f2+f3;` using an 80-bit extended format rather than 32-bit format for the intermediate values, *provided it's consistent in its handling of such things*, but if comparisons and casts aren't done on the proper types they're meaningless and "speed" is irrelevant. – supercat Sep 23 '13 at 22:11
  • It was actually fixed in gcc 4.5.x. – R.. GitHub STOP HELPING ICE Sep 24 '13 at 00:02
2

This post explains what is going on:

http://www.exploringbinary.com/when-floats-dont-behave-like-floats/

Basically extra precision might be stored on the machine for different expression evaluations, making what would be equal floats not equal.

Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
  • The standard requires casts to throw away any extra precision. GCC is simply broken in this regard, and it's a known issue. The issue can be partly side-stepped with the `-ffloat-store` option, but that only fixes assignments, not casts. – R.. GitHub STOP HELPING ICE Mar 27 '12 at 03:05