-2

please can somebody explain this to me

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

using namespace std;

int main()
{
    int sum = 0;

    for(int j = 0; j < 3; j++) {

        sum += 24 * pow(10, 3 - j - 1);

    }

    cout << sum << endl;


    return 0;
}

This is my little program and it is printing out wrong answer (2663 instead of 2664), but when I write 1 * pow(...) instead of 24 everything is good. I am so confuse

filo
  • 67
  • 1
  • 5
  • 2
    Very simple: `pow` operates on `double`, not `int`. Hence, some values cannot be represented exactly. When converting to the result back to `int`, it may round down or up. – stefan Apr 10 '16 at 20:24

2 Answers2

0

If you need exact results, never rely on data types that cannot store the the results in an exact way. In your case, the expression 24 * pow(10, 3 - j - 1) has type double, as the return type of pow is double and the multiplication of an int and a double results in a double.

The correct way of writing this piece of code is to use a power function that operates on integers:

int pow(int base, int exponent)
{
    assert(exponent >= 0); // Design decision, you may want to support negative exponents as well
    int result = 1;
    for (int i = 0; i < exponent; ++i)
    {
        result *= base;
    }
    return result;
}

For finding instances of such mistakes, enable warnings (e.g. in gcc it's -Wconversion).

stefan
  • 10,215
  • 4
  • 49
  • 90
  • `int pow(int base, int exponent) { assert(exponent >= 0); int result = 1, exp = 1, mask = 1; for (int i = 0; i < sizeof(int) * 8 - 1; ++i) { exp *= base; if(exponent && mask) result *= exp; mask <<= 1; } return result; }` – bipll Apr 10 '16 at 20:45
  • @bipll Care to elaborate what you're trying to say with your comment? – stefan Apr 10 '16 at 20:47
  • Turning O(N) exponentiation into O(logN). – bipll Apr 10 '16 at 20:48
  • 1
    @bipll Well the runtime of this algorithm isn't what the question is about, it's just a quick sample implementation. And actually, I think it's fairly pointless to care about performance of this algorithms for `int`, as the maximum valid exponent for all except three cases is less than 64 anyway. By the way, it should be `exponent & mask`. – stefan Apr 10 '16 at 20:51
  • Yeah, thanks, mistyped. BTW, in case base is 1 or zero, any exponent will fit into 32bit. – bipll Apr 10 '16 at 20:54
  • 1
    @bipll Exactly, for -1, 0 and 1, any exponent is fine. But for all bases with magnitude >= 2, (assuming a 64bit integer), the exponent can only be <= 64, as any value above will result in overflow (which is undefined behavior for signed integers). – stefan Apr 10 '16 at 20:58
-1

There is no implementation of pow() that returns an int, so apparently the implementation that returns a float is being selected by the compiler as the default one.

The problem with float is that it cannot represent all numbers, it works with approximations. Which means that some of the results of this pow() may be not exact integer numbers as you would expect.

When you implicitly convert the result of pow() to int when trying to store it in the variable sum, that is of type int, the decimals are truncated, causing loss of information.

To prevent this loss of information, use double instead of int. When operating with doubles, the implementation of pow() that returns a double will be used, and it shouldn't have problems to give you the correct answer, nothing will be truncated and information won't be lost.

Havenard
  • 27,022
  • 5
  • 36
  • 62
  • `double` has the exact same problem as `float`. There are integers that don't have an exact representation as `double`. If the result as an integer has to be exact, it is a very bad idea to convert to any floating point number type at any time. – stefan Apr 10 '16 at 20:57
  • @stefan He doesn't have a choice, he is using `pow()`, and it will always truncate down to the closest integer when converting to `int`. The cleanest solution in this case is just accept that the library uses `double` and use it too. Alternatively, you can do the old ugly hack of doing `(int)(x + 0.5)` to make sure the number is truncated to the value you expect, but personally I'd avoid putting that on my code. Also, `double` guarantees a number of digits of precision, usually 15, which is way more than you can tell for `float`. – Havenard Apr 10 '16 at 21:06