-->

Why does cmath pow give inaccurate answers?

2019-05-11 01:09发布

问题:

In C++11:

pow(1061,6);   // = 1426567426713180416

Check the last 3 digits. I know for sure that result is wrong, because 1061^6 = 1426567426713180361.

But this other method does it right:

long a =1;    
for(int i=0; i<6 ; i++){ a*=1061; }
cout << a;  // = 1426567426713180361

pow is included from cmath.

If anyone knows, I'd like to know why both results aren't equal.

回答1:

std::pow will return double for the integral case and this answer here explains the first integral where double can not longer exactly represent every integral starts at 9007199254740993 after this we may have integers that can not be exactly repsented exactly as a double.

We can see this more easily using the fact that narrowing conversions are ill-formed using uniform initialization. Using the results you desire we see that:

double d2{1426567426713180361};

is a narrowing conversion (live godbolt)

error: constant expression evaluates to 9007199254740993 which cannot be narrowed to type 'double' [-Wc++11-narrowing]
double d1{9007199254740993} ;
        ^~~~~~~~~~~~~~~~

since it can not be exactly represented. We can also see the number from earlier is also a narrowing conversion:

double d1{9007199254740993} ;

while:

double d3{1426567426713180416};

is not.



回答2:

pow uses double for its output, which has approximately 16 decimal digits of accuracy. A 64bit long however has 19.



回答3:

std::pow works on doubles. It does not keep the precision of the resultant number for such large integral values as well as integer arithmetic does.



标签: c++ c++11 cmath