#include <iostream> // ostream #include <limits> // numeric_limits<T>::max using namespace std; // ------------------------------------------------------------------- template<class T> // T = double or float static T factorial(T value) { T fact = 1.0; while (value > 1.0) fact *= value--; return fact; } // ------------------------------------------------------------------- template<class T> // T = double or float static void test(T) { cout << "representation max = " << numeric_limits<T>::max() << "\n\n"; cout << "factorial(34) = "<< factorial(T(34)) << endl; cout << "factorial(35) = " << factorial(T(35)) << endl; cout << "factorial(170) = " << factorial(T(170)) << endl; cout << "factorial(171) = " << factorial(T(171)) << "\n\n"; } // ------------------------------------------------------------------- int main() { cout << "factorial limits for floats:\n"; test((float)0); cout << "factorial limits for doubles:\n"; test((double)0); return 0; } Release: gcc version 3.2.3 (also 3.2.1 and 3.2) Environment: Red Hat Linux 7.2, kernel 2.4.18, on Pentium IV How-To-Repeat: The code explores the range of the factorial function for floats vs doubles. When run without optimization: g++-3.2 factorial.cpp -o test the code correctly outputs "inf" for arguments > 34 for float instantiation, and "inf" for arguments > 170 for double. When any optimization level is used, say: g++-3.2 -O3 factorial.cpp -o test the double output remains the same, but factorial(float 35) and factorial(float 170) now give incorrect results. Specifically, the float instantiation returns values 1.03331e+40 for 35! and 7.25742e+306 for 170! which are more than the max float = 2.95233e+38.
Fix: If I add code to factorial such as: T fact = 1.0; ostringstream ist; ist << fact; the program produces correct answers even with optimization turned on. However, this slows down the processing time for the factorial routine (and shouldn't be necessary).
From: "Timothy C Prince" <tprince@myrealbox.com> To: bird@bainet.com Cc: gcc-gnats@gcc.gnu.org Subject: Re: optimization/10644: float calculation exceeds representation max, only when optimizer is turned on Date: Tue, 06 May 2003 18:09:19 +0000 -----Original Message----- From: bird@bainet.com To: gcc-gnats@gcc.gnu.org Date: 6 May 2003 16:38:32 -0000 Subject: optimization/10644: float calculation exceeds representation max, = only when optimizer is turned on=20 >Number: 10644 >Category: optimization >Synopsis: float calculation exceeds representation max, only when op= timizer is turned on >Confidential: no >Severity: non-critical >Priority: medium >Responsible: unassigned >State: open >Class: wrong-code >Submitter-Id: net >Arrival-Date: Tue May 06 16:46:00 UTC 2003 >Closed-Date: >Last-Modified: >Originator: Rebecca Bird >Release: gcc version 3.2.3 (also 3.2.1 and 3.2) >Organization: >Environment: Red Hat Linux 7.2, kernel 2.4.18, on Pentium IV >Description: #include <iostream>=09=09=09// ostream #include <limits>=09=09 =09// numeric_limits<T>::max using namespace std;=20 // ------------------------------------------------------------------- template<class T>=09=09=09 // T =3D double or float static T factorial(T value) { T fact =3D 1.0; while (value > 1.0)=20 fact *=3D value--;=09 return fact; } // ------------------------------------------------------------------- template<class T>=09=09=09// T =3D double or float static void test(T) { cout << "representation max =3D " << numeric_limits<T>::max() << "\n\n"= ; cout << "factorial(34) =3D "<< factorial(T(34)) << endl;=09 cout << "factorial(35) =3D " << factorial(T(35)) << endl;=09 cout << "factorial(170) =3D " << factorial(T(170)) << endl;=09 cout << "factorial(171) =3D " << factorial(T(171)) << "\n\n";=09 } // ------------------------------------------------------------------- int main() { cout << "factorial limits for floats:\n"; test((float)0); cout << "factorial limits for doubles:\n"; test((double)0); return 0; } >How-To-Repeat: The code explores the range of the factorial function for floats vs doubles= . When run without optimization: g++-3.2 factorial.cpp -o test the code correctly outputs "inf" for arguments > 34 for float instantiation= , and "inf" for arguments > 170 for double. When any optimization level is used, say: g++-3.2 -O3 factorial.cpp -o test the double output remains the same, but factorial(float 35) and factorial(f= loat 170) now give incorrect results. Specifically, the float instantiat= ion returns values 1.03331e+40 for 35! and 7.25742e+306 for 170! which ar= e more than the max float =3D 2.95233e+38. >Fix: If I add code to factorial such as: T fact =3D 1.0; ostringstream ist;=09=09 ist << fact;=09 the program produces correct answers even with optimization turned on. How= ever, this slows down the processing time for the factorial routine (and = shouldn't be necessary). >Release-Note: >Audit-Trail: >Unformatted: ----gnatsweb-attachment---- Content-Type: text/plain; name=3D"factorial.cpp" Content-Disposition: inline; filename=3D"factorial.cpp" // Show limits of factorial routine for floats vs doubles #include <iostream>=09=09=09// ostream #include <limits>=09=09=09// numeric_limits<T>::max using namespace std;=20 // ------------------------------------------------------------------- template<class T>=09=09=09// T =3D double or float static T factorial(T value) { =09T fact =3D 1.0; =09while (value > 1.0)=20 =09=09fact *=3D value--;=09 =09return fact; } // ------------------------------------------------------------------- template<class T>=09=09=09// T =3D double or float static void test(T) { =09cout << "representation max =3D " << numeric_limits<T>::max() << "\n\n"; =09cout << "factorial(34) =3D "<< factorial(T(34)) << endl;=09 =09cout << "factorial(35) =3D " << factorial(T(35)) << endl;=09 =09cout << "factorial(170) =3D " << factorial(T(170)) << endl;=09 =09cout << "factorial(171) =3D " << factorial(T(171)) << "\n\n";=09 } // ------------------------------------------------------------------- int main() { =09cout << "factorial limits for floats:\n"; =09test((float)0); =09cout << "factorial limits for doubles:\n"; =09test((double)0); =09return 0; } The results with -march=3Dpentium4 -mfpmath=3Dsse might be more to your lik= ing. Tim Prince
State-Changed-From-To: open->closed State-Changed-Why: Not a Bug. If you want exact floating point behaviour use -ffloat-store which fixes your problem. If you don't do this gcc will happily do your calculations at higher precision if that helps optimization.
Reopening bug so I can mark it as a dup of ....
bug 323, which is the master bug for excessive precision. *** This bug has been marked as a duplicate of 323 ***