rembremading said:
> The following piece of code has (for me) completely unexpected
behaviour.
This is cross-posted to comp.std.c. See the final paragraph for a
standards question. This is the second posting attempt.
> (I compile it with gcc-Version 4.0.3)
> Something goes wrong with the integer to float conversion.
> Maybe somebody out there understands what happens.
> Essentially, when I subtract the (double) function value GRID_POINT(2) from
> a variable which has been assigned the same value before this gives a
> non-zero result and I really do not understand why.
>
> The program prints
> 5.000000000000000000e-01; -2.775557561562891351e-17;
> 0.000000000000000000e+00
>
> And the comparison
> if(temp1==GRID_POINT(2))
> has negative outcome.
>
> When I replace
> ((double)(i)) by 2.0
> everything behaves as expected. So the output is
> 5.000000000000000000e-01; 0.000000000000000000e+00; 0.000000000000000000e+00
>
> But: even if the integer to float conversion is inexact (which, I think,
> should not be the case) something like
> temp1 = GRID_POINT(2);
> temp3 = temp1-GRID_POINT(2);
> should still result in temp3==0.0, whatever function GRID_POINT does.
>
> What do You think?
>
> Thank you!
>
> ---------------------------------------------------
> #include <stdio.h>
>
> double GRID_POINT(int i);
>
> double GRID_POINT(int i)
> {
> return ( 0.1 + ( (80.1-0.1)/(400.0) )*((double)(i)) );
> }
>
> int main (void) {
>
> double temp1, temp2, temp3;
>
> temp1 = GRID_POINT(2);
> temp2 = GRID_POINT(2);
> temp3 = temp1-GRID_POINT(2);
>
> printf("%.18e; %.18e; %.18e\n", temp1, temp3, temp1-temp2 );
>
> if(temp1==GRID_POINT(2)){
> printf("these two are equal\n");
> }
>
> return 0;
> }
> ---------------------------------------------------
The original code temp3 may be non-zero because of extra precision:
5.2.4.2.2:
The value of operations with floating operands and values subject to the
usual arithmetic conversions and of floating constant are evaluated to a
format whose range and precision may be greater than required by the
type. The use of evaluation formats is characterized by the
implementation-defined value of FLT_EVAL_METHOD.
The standard requires that values be rounded to their specified
precision by storing into a variable of the type or cast to the type
(See 5.1.2.3 footnote 4). Neither of these requirements are in effect
for the use of GRID_POINT(2) within the statement computing temp3.
The compiler is probably passing the evaluated value back in a floating
point register with more precision than a double variable.
Regarding the effect of replacing (double)i by the constant 2, you
permit the compiler to evaluate the expression in GRID_POINT() at
compile time. The compiler probably is then propagating that constant
to the assignments in main. What is apparently different in the
compile-time evaluation is that the value computed in GRID_POINT() gets
rounded to double precision before it is used in main.
Is the compiler rounding of the constant value, compared with the
register passing with extra precision, conforming? 5.1.2.3 footnote 4
says "an implicit spilling of a register is not permitted to alter the
value." Is the compile time evaluation, vs. runtime evaluation, an
implicit spilling of a register? If not, what is an "implicit spilling
of a register"?