Bug 20674

Summary: unexpected result from floating compare
Product: gcc Reporter: Jeff Piaget <piaget>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: gcc-bugs
Priority: P2 Keywords: wrong-code
Version: 3.4.3   
Target Milestone: ---   
Host: i586-mandrake-linux-gnu Target: i586-mandrake-linux-gnu
Build: Known to work:
Known to fail: Last reconfirmed:
Attachments: output of g++ -v -save-temps
preprocess output from g++ -v -save-temps

Description Jeff Piaget 2005-03-28 21:51:00 UTC
Small .C program shows a problem where a value of 1.0 is calculated, but that 
value falls through 2 if-checks ... one checks for "if (val <= 1.0)" , the next 
checks for "if (val > 1.0)" ... one of these if checks must be true but neither 
true leg is taken.

problem surfaces at optimization level -O1 (also tested -O2 and -O3 ... same 
problem)
problem goes away with -ffloat-store , although I feel this is a logic problem 
and not a precision problem.
problem goes away if compiled as .c (with pass-by-reference removed)

g++ -v -save-temps -O1 -o tmp1 tmp1.C

This is my first bug ... I am going to committ ... may add attachments later if 
not given the opportunity now
Comment 1 Andrew Pinski 2005-03-28 21:53:52 UTC

*** This bug has been marked as a duplicate of 323 ***
Comment 2 Jeff Piaget 2005-03-28 22:02:17 UTC
Created attachment 8473 [details]
output of g++ -v -save-temps
Comment 3 Jeff Piaget 2005-03-28 22:03:00 UTC
Created attachment 8474 [details]
preprocess output from g++ -v -save-temps
Comment 4 Jeff Piaget 2005-03-28 22:09:02 UTC
I do not think this is a precision problem. Although -ffloat-store resolves the 
problem, I feel this has changed the behavior of the program sufficiently to 
avoid the problem ... I should not have mentioned that -ffloat-store resolved 
the problem in my earlier note

// following is pseudocode ... run actual testcase to see problem
float i=1.0; // actually, a bunch of math that = 1.0
if ( i <= 1.0 ) return 0;
if ( ( i > 1.0 ) && ( i < 1.0001 ) ) return 0;
return 1;

I should never get a 1 for a return code. Change 1.0001 in my testcase to 1.1, 
you still see the problem.
Comment 5 Andrew Pinski 2005-03-28 22:34:52 UTC
If you write the function like so:
enum myRC doSomeMath
(
 int i1,
 float *f1,
 float* f2,
 float* f3,
 float* f4
)
{
  int i;
  float f5=0.0;
  float f6=0.0;
  float f7=0.0;

  for(i=0; i<i1global; i++){
    f5+=f1[i]*f1[i];
    f6+=f2global[i1][i]*f2global[i1][i];
    f7+=f1[i]*f2global[i1][i];
  }
  *f2=sqrt(f5);
  *f3=sqrt(f6);
  *f4=f7/(*f2* *f3);

  if((*f4>=-1.0)&&(*f4<=1.0))return(mySuccess);
  if((*f4>1.0)&&(*f4<1.000001)){
    *f4=1.0;
    return(mySuccess);
  }
  if((*f4<-1.0)&&(*f4>-1.000001)){
    *f4=-1.0;
    return(mySuccess);
  }
  if ( chkWithEqual == 1 ) {
    if((*f4>=1.0)&&(*f4<1.000001)){
      *f4=1.0;
      return(mySuccess);
    }
    if((*f4<=-1.0)&&(*f4>-1.000001)){
      *f4=-1.0;
      return(mySuccess);
    }
  }
  printf("%f is out of range -1.0 to 1.0\n",*f4);
  return(myFailure);
}

You still get the fail even with the C front-end in 3.4.0.

Note this does not fail in 4.0.0 and above (though there might be a way get a simlar failure if you have 
time to fiind one.  But I think this is still a precission problem.
Comment 6 Jeff Piaget 2005-03-28 22:44:17 UTC
I tried this on a 64-bit system, and noticed I needed to compile -m32 to get 
the error (this was on an older gcc level, though. 3.2.3)

I don't understand how this can be a precision problem. How can both if checks 
be true?
val <= 1.0
and
val > 1.0

Comment 7 Jeff Piaget 2005-03-28 22:46:21 UTC
my mistake in the previous post

how can both if-checks be false?
val <= 1.0
and
val > 1.0
Comment 8 Andrew Pinski 2005-03-28 22:49:55 UTC
(In reply to comment #6)
> I tried this on a 64-bit system, and noticed I needed to compile -m32 to get 
> the error (this was on an older gcc level, though. 3.2.3)

Well considering x86_64 uses the sse register math by default and not x87, I really doubt that it would 
be effect that.  I would try it on a sane target first like say PPC where you have no excusive precission.

Oh the reason is because one checks before the precission is truncated and the next one is after. Look 
at the example of 323 to give you an idea where this can happen.
Comment 9 Jeff Piaget 2005-03-28 23:05:35 UTC
323 compares 2 values across a function call ... somthing a programmer can 
reasonably consider. My problem occurs with 2 successive lines of code 
admittedly with 2 compares per line). I don't have a problem that the value of 
the variable changes after precision truncation ... but it seems like a bug 
that the compiler uses a full precision value for the 1st test and a truncated 
value for the 2nd test (the 2nd test being the next line of C++ code).
Comment 10 Daniel Berlin 2005-03-29 04:58:57 UTC
Subject: Re:  unexpected result from floating compare

On Mon, 2005-03-28 at 23:05 +0000, piaget at us dot ibm dot com wrote:
> ------- Additional Comments From piaget at us dot ibm dot com  2005-03-28 23:05 -------
> 323 compares 2 values across a function call ... somthing a programmer can 
> reasonably consider. My problem occurs with 2 successive lines of code 
> admittedly with 2 compares per line). I don't have a problem that the value of 
> the variable changes after precision truncation ... but it seems like a bug 
> that the compiler uses a full precision value for the 1st test and a truncated 
> value for the 2nd test (the 2nd test being the next line of C++ code).

Except, the value could have been spilled and reloaded from registers
between those two source lines, which on x86, is where the problem comes
from.
The problem is no different simply because the *source* lines happen to
be right next to each other.


Comment 11 Jeff Piaget 2005-03-29 13:42:15 UTC
(In reply to comment #10)

> Except, the value could have been spilled and reloaded from registers
> between those two source lines, which on x86, is where the problem comes
> from.
> The problem is no different simply because the *source* lines happen to
> be right next to each other.

I would have expected a compiler to identify these situations and produce code 
that logically matches the code being compiled. If this is not the case, then 
maybe -ffloat-store should be the default behavior with appropriate warnings 
about turning -ffloat-store off.

Comment 12 Andrew Pinski 2005-03-29 14:17:02 UTC

*** This bug has been marked as a duplicate of 323 ***