When I directly output std::pow(10,2)
, I get 100 while doing (long)(pow(10,2))
gives 99. Can someone explained this please ?
cout<<pow(10,2)<<endl;
cout<<(long)(pow(10,2))<<endl;
The code is basically this in the main function.
The compiler is mingw32-g++.exe -std=c++11 using CodeBlocks Windows 8.1 if that helps
Floating point numbers are approximations. Occasionally you get a number that can be exactly represented, but don't count on it. 100 should be representable, but in this case it isn't. Something injected an approximation and ruined it for everybody.
When converting from a floating point type to an integer, the integer cannot hold any fractional values so they are unceremoniously dropped. There is no implicit rounding off, the fraction is discarded. 99.9 converts to 99. 99 with a million 9s after it is 99.
So before converting from a floating point type to an integer, round the number, then convert. Unless discarding the fraction is what you want to do.
cout
, and most output routines, politely and silently round floating point values before printing, so if there is a bit of an approximation the user isn't bothered with it.
This inexactness is also why you shouldn't directly compare floating point values. X probably isn't exactly pi, but it might be close enough for your computations, so you perform the comparison with an epsilon, a fudge factor, to tell if you are close enough.
What I find amusing, and burned a lot of time trying to sort out, is would not have even seen this problem if not for using namespace std;
.
(long)pow(10,2)
provides the expected result of 100. (long)std::pow(10,2)
does not. Some difference in the path from 10,2 to 100 taken by pow
and std::pow
results in slightly different results. By pulling the entire std
namespace into their file, OP accidentally shot themselves in the foot.
Why is that?
Up at the top of the file we have using namespace std;
this means the compiler is not just considering double pow(double, double)
when looking for pow
overloads, it can also call std::pow
and std::pow
is a nifty little template making sure that when called with datatypes other than float and double the right conversions are taking place and everything is the same type.
(long)(pow(10,2))
Does not match
double pow(double, double)
as well as it matches a template instantiation of
double std::pow(int, int)
Which, near as I can tell resolves down to
return pow(double(10), double(2));
after some template voodoo.
What the difference between
pow(double(10), double(2))
and
pow(10, 2)
with an implied conversion from int
to double
on the call to pow
is, I do not know. Call in the language lawyers because it's something subtle.
If this is purely a rounding issue then
auto tempa = std::pow(10, 2);
should be vulnerable because tempa should be exactly what std::pow
returns
cout << tempa << endl;
cout << (long) tempa << endl;
and the output should be
100
99
I get
100
100
So immediately casting the return of std::pow(10, 2)
into a long
is different from storing and then casting. Weird. auto tempa
is not exactly what std::pow
returns or there is something else going on that is too deep for me.