We know that -2*4^31 + 1 = -9.223.372.036.854.775.807, the lowest value you can store in long long, as being said here: What range of values can integer types store in C++. So I have this operation:
#include <iostream>
unsigned long long pow(unsigned a, unsigned b) {
unsigned long long p = 1;
for (unsigned i = 0; i < b; i++)
p *= a;
return p;
}
int main()
{
long long nr = -pow(4, 31) + 5 -pow(4,31);
std::cout << nr << std::endl;
}
Why does it show -9.223.372.036.854.775.808 instead of -9.223.372.036.854.775.803? I'm using Visual Studio 2015.
Visual Studio has defined pow(double, int)
, which only requires a conversion of one argument, whereas your pow(unsigned, unsigned)
requires conversion of both arguments unless you use pow(4U, 31U)
. Overloading resolution in C++ is based on the inputs - not the result type.
This is a really nasty little problem which has three(!) causes.
Firstly there is a problem that floating point arithmetic is approximate. If the compiler picks a pow
function returning float or double, then 4**31 is so large that 5 is less than 1ULP (unit of least precision), so adding it will do nothing (in other words, 4.0**31+5 == 4.0**31). Multiplying by -2 can be done without loss, and the result can be stored in a long long
without loss as the wrong answer: -9.223.372.036.854.775.808.
Secondly, a standard header may include other standard headers, but is not required to. Evidently, Visual Studio's version of <iostream>
includes <math.h>
(which declares pow
in the global namespace), but Code::Blocks' version doesn't.
Thirdly, the OP's pow
function is not selected because he passes arguments 4
, and 31
, which are both of type int
, and the declared function has arguments of type unsigned
. Since C++11, there are lots of overloads (or a function template) of std::pow
. These all return float
or double
(unless one of the arguments is of type long double
- which doesn't apply here).
Thus an overload of std::pow
will be a better match ... with a double return values, and we get floating point rounding.
Moral of the story: Don't write functions with the same name as standard library functions, unless you really know what you are doing!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With