6

I have been creating a short program for implementing Sieve of Eratosthenes. In he program, I have used int startingPoint which held the value of the current prime number, which had it's multiplications being marked non-prime, starting from its square. I used the pow() function to calculate the square of the starting point in the current loop. While doing so, I came across a weird phenomenon. When startingPoint was equal to 5, then after int i = pow(startingPoint,2) the value of i was 24, instead of 25. This phenomenon occurred only when startingPoint was equal to 5. Afterwards, I ran a few tests, that leaded to the following code snippet:

#include <iostream>
#include <math.h>

int main()
{
    int p=5;

    int num1 = pow(5,2);
    int num2 = pow(p,2);
    float num3 = pow(p,2);
    int num4 = floor(pow(p,2));

    std::cout.precision(10);

    std::cout<<num1<<std::endl; //25
    std::cout<<num2<<std::endl; //24
    std::cout<<std::fixed<<num3<<std::endl; //25.0000000000
    std::cout<<num4<<std::endl; //25            
}

As it can be seen, if I call pow with int literals, the result will be the actual square of the number. However, if I call it using int p=5, then what pow returns is actually one lower than the expected result. If I pass the result into a float variable, it also recieves the correct result.

Now, I know the way pow calculates powers is via approximation, and thus, errors such as this when converting to integer may occur. I might just let it be like that. But what REALLY made me stop and think is what happens with num4. pow(p,2) casted to int returns 24. But floor(pow(p,2)) casted to int returns 25. So the floor function, which, by standard rounds a number down, somehow makes the returned value cast into a higher integer value.

My question in short: Just how does that happen? (I was using gcc 5.3.0 through MinGW)

Edit: As I already stated in the question, I can accept the reason behind pow return value being casted into a lower integer value, but what I really can't comprehend (and I haven't seen this being brought up anywhere else either) is how floor fixes that. How can floor make the return value of pow actually cast into a higher integer value? Now THAT is the real question.

MrLumie
  • 247
  • 2
  • 10
  • Why is it tagged [C] and [C++] a the same time? In C++ math functions are overloaded (and can be even in ``), which means that you might end up calling completely different functions in these two languages. Your code is C++. Did you try this in C as well? Or did you add [C] tag just because you think these are chiefly C library functions? – AnT stands with Russia Nov 06 '16 at 18:41
  • 1
    @AnT BTW, I've removed the C tag because `#include ` and `std::cout` aren't valid C. – melpomene Nov 06 '16 at 18:43
  • 3
    `pow` works on floating points, so rounding problems when converting to `int` make sense; but it does not make sense that the result would be different for `int` variable and `int` constant parameter (`num1` and `num2`). [I cannot reproduce](http://ideone.com/v82iWO). – Karsten Koop Nov 06 '16 at 18:46
  • 3
    [Already asked and answered here](http://stackoverflow.com/questions/25678481/why-does-pown-2-return-24-when-n-5-with-my-compiler-and-os). It can't be reproduced unless you're using specific versions of specific compilers, compiled with specific options. – PaulMcKenzie Nov 06 '16 at 18:47
  • 1
    To calculate `num1` the compiler might have cheated using some optimisation. So in fact it created different code as for calculating `num2`. – alk Nov 06 '16 at 18:50
  • 1
    Can anyone explain the different result for `num2 ` and `num4`? OP: can you post the command line used to compile the example? – Michael Burr Nov 06 '16 at 18:56
  • I was more than sure that it's a compiler specific occurence, turned out I only get 24 as a result if I compile with -O0, any higher optimization level leads to showing the correct values. – MrLumie Nov 06 '16 at 19:14
  • As a "workaround", `pow(p,2)` can also be written as `p*p`. – Bo Persson Nov 06 '16 at 19:25
  • @SinanÜnür This isn't rounding for printing. I don't even see how an integer value could be rounded for printing anyway. But this `pow` function was actually used to initialize a loop variable, and it lead to the loop variable accessing an array on wrong indexes, because of the wrong conversion after pow. With all due respect, I wasn't asking for tips about not using `pow` for integer multiplication, I was asking about the reason behind this occurence, out of sheer curiosity. And although I could understand `pov` returning with a lower `int` value, I can't understand how `floor` fixes that. – MrLumie Nov 06 '16 at 19:27
  • @BoPersson Thank you, but the topic of the question is why this phenomenon occurs, not how to fix it. – MrLumie Nov 06 '16 at 19:28
  • @SinanÜnür `pow` does not, but the returned value is implicitly converted to `int`. And since I'm not printing out the returned value of `pow`, but the `int` variable, we can't possibly be talking about rounding for printing. – MrLumie Nov 06 '16 at 21:27
  • @MrLumie The reason for all of this will be in the generated assembly language. More than likely (and another comment alluded to this), just because you wrote explicitly `pow(p,2)` in two separate places in your code does **not** guarantee they result in the same assembly code or same set of assembly instructions. One deals with a temporary that is sent to `floor` the other does not. – PaulMcKenzie Nov 06 '16 at 21:28
  • Dupe didn't explain num4 - voted to reopen. – Bathsheba Nov 06 '16 at 21:55
  • @MrLumie Are you remembering to link with the math library? – Sinan Ünür Nov 06 '16 at 22:14
  • @Bathsheba I feel that it would benefit from a separate question. / Besides that can be explained [here](https://stackoverflow.com/questions/7517588). – user202729 May 16 '18 at 03:37
  • Possible duplicate of [Strange behaviour of the pow function](https://stackoverflow.com/questions/18155883/strange-behaviour-of-the-pow-function) – Jean-François Fabre Nov 21 '18 at 12:45

0 Answers0