0

enter image description hereWhen 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

random40154443
  • 1,100
  • 1
  • 10
  • 25
  • 1
    show the code you are using. Are you directly calling pow like that. It would be really really strange in that case. – knightrider Oct 17 '15 at 14:58
  • For me it is printing 100 100 (gcc4.9 and clang 3.6). Which compiler are you using? are you using standard math lib or are you using custom implementation? – knightrider Oct 17 '15 at 15:03
  • under visual studio 2015 its shows me 100 twice , what is your compiler ? – HDJEMAI Oct 17 '15 at 15:03
  • 4
    you've an answer here i think: http://stackoverflow.com/questions/9704195/why-pow10-5-9-999-in-c – HDJEMAI Oct 17 '15 at 15:16
  • @HocineDJEMAI right concept but missing something. I can duplicate (mingw, g++ 4.8.1), but if it was just simple rounding `auto temp = pow(10,2); cout<<(long)temp< – user4581301 Oct 17 '15 at 16:06
  • Oh, as does calling std::pow with doubles: `pow(10.0,2.0);` – user4581301 Oct 17 '15 at 16:07
  • Likely pow returning number just below 100 so cast to long is taking floor which gives 99. What does standard say about pow implantation. There are many ways to implement pow but there can be subtle floating point differences depending on method used. Often Taylor series is used, also using exp can be used which itself may use Taylor series. I'm not sure if standard guarantees pow results between all implementations. – steviekm3 Oct 17 '15 at 16:30
  • @steviekm3 's what I thought too until I looked at it. There are different `pow`s being called. – user4581301 Oct 17 '15 at 16:34
  • [Why does gcc compiler output pow(10,2) as 99 not 100?](https://stackoverflow.com/q/25474351/995714), [Why does pow(5,2) become 24?](https://stackoverflow.com/q/22264236/995714), [pow(a,b) returning 1 less than the actual value when b is more than 15? (duplicate)](https://stackoverflow.com/q/59705590/995714) – phuclv Sep 10 '20 at 09:46
  • Does this answer your question? [Why does gcc compiler output pow(10,2) as 99 not 100?](https://stackoverflow.com/questions/25474351/why-does-gcc-compiler-output-pow10-2-as-99-not-100) – phuclv Sep 10 '20 at 09:46

2 Answers2

3

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.

user4581301
  • 33,082
  • 7
  • 33
  • 54
0

These are the std::pow overloads:

float       pow( float base, float exp );

double      pow( double base, double exp );

long double pow( long double base, long double exp );

float       pow( float base, int iexp );//(until C++11)

double      pow( double base, int iexp );//(until C++11)

long double pow( long double base, int iexp ); //(until C++11)

Promoted    pow( Arithmetic1 base, Arithmetic2 exp ); //(since C++11)

But your strange behaviour is MINGW's weirdness about double storage and how the windows run-time doesnt like it. I'm assuming windows is seeing something like 99.9999 and when that is cast to an integral type it takes the floor.

int a = 3/2; // a is = 1

mingw uses the Microsoft C run-time libraries and their implementation of printf does not support the 'long double' type. As a work-around, you could cast to 'double' and pass that to printf instead. Therefore, you need double double:

On the x86 architecture, most C compilers implement long double as the 80-bit extended precision type supported by x86 hardware (sometimes stored as 12 or 16 bytes to maintain data structure alignment), as specified in the C99 / C11 standards (IEC 60559 floating-point arithmetic (Annex F)). An exception is Microsoft Visual C++ for x86, which makes long double a synonym for double.[2] The Intel C++ compiler on Microsoft Windows supports extended precision, but requires the /Qlong‑double switch for long double to correspond to the hardware's extended precision format.[3]

sbail95
  • 198
  • 8