12

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
Michael Chen
  • 121
  • 1
  • 4
  • 2
    `pow(26,2)` as in 26*26 = 676? – Alexei Levenkov Dec 08 '12 at 06:01
  • 1
    yea, pow as in the standard power function. – Michael Chen Dec 08 '12 at 06:02
  • Can you post your code? I'm not sure how you'd get these values either. – Maurice Reeves Dec 08 '12 at 06:03
  • You have a typo in the result as above. My guess is that with optimization on it replaces the call with a literal at compile time which is the difference, but not sure why it would happen and what the underlying problem is. – PeterJ Dec 08 '12 at 06:03
  • #include #include using namespace std; int main() { cout< – Michael Chen Dec 08 '12 at 06:04
  • I didn't change any other compiler/linker/options. I use codeblocks. – Michael Chen Dec 08 '12 at 06:07
  • Using a different compiler I get a warning that it can't find an overload, what happens if you change 26 to 26.0? – PeterJ Dec 08 '12 at 06:12
  • Have you tried compiling it outside of CodeBlocks to see if you get the same result? – Maurice Reeves Dec 08 '12 at 06:13
  • No i haven't tried another IDE, maybe tomorrow. Results with doubles are weird. double a=26; double b=2; cout< – Michael Chen Dec 08 '12 at 06:25
  • So I just built the same program in both Cygwin (gcc 4.5.3) and Mingw (gcc 4.7.2) and I was able to get it to recreate the behavior (returning 675 for the downcasted value) in Mingw, but not in Cygwin. I did try a few different optimization hints, and standard hints as well, and 4.5.3 on Cygwin didn't ever return 675. I should mention that this was done on Win7 64bit. So, the real question is if this is a bug, or by design in the newer version? – Maurice Reeves Dec 08 '12 at 06:26
  • I guess the other thing that puzzles me is why you keep saying 625, 626, etc, when that middle number should be a 7. Is this just an encoding error, or is your code really losing that extra 50 in value somewhere? – Maurice Reeves Dec 08 '12 at 06:29
  • lol. Getting tired. Not encoding error, human copy error. – Michael Chen Dec 08 '12 at 06:33
  • Same error was not observed through through a slightly older version of codeblocks with a slightly older version of mingw + gcc (main difference is old one is 7.4 gdb and new one was 7.5 gdb) – Michael Chen Dec 08 '12 at 06:39
  • 1
    Please recheck and fix the code to the correct incorrect numbers. – cxxl Dec 08 '12 at 07:14
  • 1
    Possible duplicate of [C: i got different results with pow(10,2) and pow(10,j), j=2;](https://stackoverflow.com/questions/19126809/c-i-got-different-results-with-pow10-2-and-pow10-j-j-2) – phuclv Apr 09 '19 at 08:24
  • 1
    [Why does gcc compiler output pow(10,2) as 99 not 100?](https://stackoverflow.com/q/25474351/995714), [Why pow(10,5) = 9,999 in C++](https://stackoverflow.com/q/9704195/995714) – phuclv Apr 09 '19 at 08:25
  • These were all bugs in gcc pow() used by default, not even pow() from libm as that requires you to use -fno-builtin. All fixed nowadays. – Валерий Заподовников Mar 11 '23 at 23:01

1 Answers1

12

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:

template<typename T>
T square(T 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.

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Lindydancer
  • 25,428
  • 4
  • 49
  • 68
  • 1
    Any particular reason you're recommending to use a macro and not a function? – NPE Dec 08 '12 at 08:42
  • 1
    Also, I would replace *is known* with *is a known small integer*. It's not much use if it is known by is either large or fractional. – NPE Dec 08 '12 at 08:43
  • @NPE, I picked a macro as it is type-neutral, and it was easy to type :). Of course, if you know the type you can define a function, alternatively a set of overloaded functions, or even a template function. – Lindydancer Dec 08 '12 at 08:57
  • I would have upvoted the answer, but I strongly dislike the idea of using a macro for this, especially in C++. – NPE Dec 08 '12 at 08:59
  • @NPE, OK, you convinced me, a function it is! – Lindydancer Dec 08 '12 at 09:14
  • 2
    how about a template. Best of both worlds. – rubenvb Dec 08 '12 at 10:03
  • well this error isn't just for exponent 2, pow(26,3) and pow(26,4) etc also has this error. Also so is the suggestion for pow next time to use int x= int(pow(b,e)+0.4) stuff like this instead? – Michael Chen Dec 08 '12 at 16:51
  • @MichaelChen, correct, the `pow` function has this problem for ALL values, which is the reason why I strongly advice against using it. The *example*, however, which I provided was for the specific case were the second parameter was the constant two. – Lindydancer Dec 08 '12 at 17:13
  • It seems that pow is also inaccurate for floating point values in Gcc and Clang. The pow function in MS Visual Studio is apparently more accurate. However, I am missing a reliable function to compare with before I can give a definite answer. – A Fog May 24 '19 at 12:47