This is the mail archive of the gcc-prs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: optimization/9736: same fp comparison can lead to different results


The following reply was made to PR optimization/9736; it has been noted by GNATS.

From: Richard Addison-Wood <richard at wetafx dot co dot nz>
To: richard at wetafx dot co dot nz, gcc-gnats at gcc dot gnu dot org, gcc-bugs at gcc dot gnu dot org,
   nobody at gcc dot gnu dot org, gcc-prs at gcc dot gnu dot org
Cc:  
Subject: Re: optimization/9736: same fp comparison can lead to different results
Date: Thu, 27 Feb 2003 20:37:25 +1300

 http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=9736
 
 From various parts of the ISO/IEC C++ standard:
 
   5 Expressions
 
   ...
 
   Many binary operators that expect operands of
   arithmetic or enumeration type cause conversions
   and yield result types in a similar way. The
   purpose is to yield a common type, which is also
   the type of the result. This pattern is called
   the usual arithmetic conversions, which are
   defined as follows:
 
     If either operand is of type long double, the
     other shall be converted to long double.
 
     Otherwise, if either operand is double, the
     other shall be converted to double.
 
     Otherwise, if either operand is float, the
     other shall be converted to float.
 
     ...
 
   The values of the floating operands and 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.  55)
 
   ...
 
   55) The cast and assignment operators must still
   perform their specific conversions as described
   in 5.4, 5.2.9 and 5.17.
 
 ...
 
   5.17 Assignment operators
 
   There are several assignment operators, all of
   which group right-to-left. All require a
   modifiable lvalue as their left operand, and the
   type of an assignment expression is that of its
   left operand. The result of the assignment
   operation is the value stored in the left
   operand after the assignment has taken place;
   the result is an lvalue.
 
   ...
 
   In simple assignment (=), the value of the
   expression replaces that of the object referred
   to by the left operand.
 
 ...
 
   4 Standard conversions
 
   ... A standard conversion sequence will be
   applied to an expression if necessary to convert
   it to a required destination type.
 
   [Note: expressions with a given type will be
   implicitly converted to other types in several
   contexts:
 
   -- When used as operands of operators. The
   operator's requirements for its operands dictate
   the destination type (clause 5).
 
   ...
 
   -- When used as the source expression for an
   initialization (which includes use as an
   argument in a function call and use as the
   expression in a return statement). The type of
   the entity being initialized is (generally) the
   destination type. See 8.5, 8.5.3.
 
   -- end note]
 
 ...
 
   4.8 Floating point conversions
 
   An rvalue of floating point type can be
   converted to an rvalue of another floating point
   type. If the source value can be exactly
   represented in the destination type, the result
   of the conversion is that exact
   representation. If the source value is between
   two adjacent destination values, the result of
   the conversion is an implementation-defined
   choice of either of those values. Otherwise, the
   behavior is undefined.
 
 
 
 
 Consider this small test program:
 
 // original.cc:
 int f(float x, float y, float z, float w)
 {
   float v = x*x+y*y+z*z+w;
   int test1 = v < 1.0f ? 1 : 2;
   return test1;
 }
 int main(void)
 {
   return f(0.5f, 0.5f, 0.5f, 0.25f-1.0f/67108864.0f);
 }
 
 The standard allows the intermediate calculations
 for v to be at greater precision than float,
 although the types are still considered to be
 float.  However, when v itself is initialized,
 there is an implicit standard conversion to float.
 Thus, we are allowed rewrite the small test
 program as this (where the types represent the
 actual precision):
 
 // transformed.cc:
 int f(float x, float y, float z, float w)
 {
   const long double temp_x = x;
   const long double temp_y = y;
   const long double temp_z = z;
   const long double temp_w = w;
   const long double temp_xx = temp_x*temp_x;
   const long double temp_yy = temp_y*temp_y;
   const long double temp_xxpyy = temp_xx+temp_yy;
   const long double temp_zz = temp_z*temp_z;
   const long double temp_xxpyypzz = temp_xxpyy+temp_zz;
   const long double temp_xxpyypzzpw = temp_xxpyypzz+temp_w;
   float v = temp_xxpyypzzpw;
   int test1 = v < 1.0f ? 1 : 2;
   return test1;
 }
 int main(void)
 {
   return f(0.5f, 0.5f, 0.5f, 0.25f-1.0f/67108864.0f);
 }
 
 I expect both programs to initialize v to 1.0f
 (and return 2 from f() and main()).  However, with
 -O1, original.cc is not compiled according to the
 standard.
 
 [Paradoxically, transformed.cc is compiled
 correctly with -O1.  The generated code is
 essentially the same except for transformed.cc
 that the proper conversion to float is generated
 for initializing v.]


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]