GCC C++ pow accuracy

2019-01-27 17:55发布

问题:

So i was in a computing contest and i noticed a weird bug. pow(26,2) would always return 675, and sometimes 674? even though correct answer is 676. These sort of errors also occur with pow(26,3), pow(26,4) etc After some debugging after the contest i believe the answer has to do with the fact int rounds down. Interestingly this kind of error has never occured to me before. The computer i had was running mingw on windows 8. GCC version was fairly new, like 2-3 months old i believe. But what i found was that if i turned the o1/o2/o3 optimization flag on these sort of error would miraculously disappear. pow(26,2) would always get 676 aka correct answer Can anyone explain why?

#include <cmath> 
#include <iostream> 

using namespace std; 
int main() { 
    cout<<pow(26,2)<<endl; 
    cout<<int(pow(26,2))<<endl; 
}

Results with doubles are weird.

double a=26; 
double b=2; 
cout<<int(pow(a,b))<<endl; #outputs 675 
cout<<int(pow(26.0,2.0))<<endl; # outputs 676 
cout<<int(pow(26*1.00,2*1.00))<<endl; # outputs 676

回答1:

The function pow operates on two floating-point values, and can raise one to the other. This is done through approximating algorithm, as it is required to be able to handle values from the smallest to the largest.

As this is an approximating algorithm, it sometimes gets the value a little bit wrong. In most cases, this is OK. However, if you are interested in getting an exact result, don't use it.

I would strongly advice against using it for integers. And if the second operand is known (2, in this case) it is trivial to replace this with code that does this much faster and that return the correct value. For example:

int square(int x)
{
  return x * x;
}

To answer the actual question: Some compilers can replace calls to pow with other code, or eliminate it all together, when one or both arguments are known. This explains why you get different results.