-2

On the Internet I found the following problem:

int a = (int)pow(2, 32);
cout << a;

What does it print on the screen?

Firstly I thought about 0, but after I wrote code and executed it, i got -2147483648, but why?

Also I noticed that even (int)(pow(2, 32) - pow(2, 31)) equals -2147483648.

Can anyone explain why (int)pow(2, 32) equals -2147483648?

Joseph D.
  • 11,804
  • 3
  • 34
  • 67
eaniconer
  • 184
  • 2
  • 10
  • The body and the title don't agree.. anyway, consider https://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html and note the particular 'magic value'. – user2864740 Jul 12 '18 at 05:23
  • Glad the c# tag was removed. There is no pow there. – PepitoSh Jul 12 '18 at 05:32
  • Possible duplicate of [What is an integer overflow error?](https://stackoverflow.com/questions/2641285/what-is-an-integer-overflow-error) –  Jul 12 '18 at 05:39
  • For c# we have similar behaviour: int a = (int)Math.Pow(2, 32); – eaniconer Jul 12 '18 at 05:40

3 Answers3

6

Assuming int is 32 bits (or less) on your machine, this is undefined behavior.

From the standard, conv.fpint:

A prvalue of a floating-point type can be converted to a prvalue of an integer type. The conversion truncates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

Most commonly int is 32 bits, and it can represent values in the interval [-2^31, 2^31-1] which is [-2147483648, 2147483647]. The result of std::pow(2, 32) is a double that represents the exact value 2^32. Since 2^32 exceeds the range that can be represented by int, the conversion attempt is undefined behavior. This means that in the best case, the result can be anything.

The same goes for your second example: pow(2, 32) - pow(2, 31) is simply the double representation of 2^31, which (just barely) exceeds the range that can be represented by a 32-bit int.

The correct way to do this would be to convert to a large enough integral type, e.g. int64_t:

std::cout << static_cast<int64_t>(std::pow(2, 32)) << "\n"; // prints 4294967296
jcai
  • 3,448
  • 3
  • 21
  • 36
  • There is a proposal for the standard to make signed integer overflow well-behaved: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r0.html – Henri Menke Jul 12 '18 at 05:35
  • I heard about that, but that doesn't apply to this particular example since technically speaking this isn't an integer overflow. In fact, even if the target type were `uint32_t`, this would still be UB. – jcai Jul 12 '18 at 05:38
0

The behavior you are seeing relates to using Two's Complement to represent signed integers. For 3-bit numbers the range of values range from [-4, 3]. For 32-bit numbers it ranges from -(2^31) to (2^31)-1. (i.e. -2147483648 to 2147483647).

Phillip Ngan
  • 15,482
  • 8
  • 63
  • 79
0

this because the result of the operation overflow int data type because it exceeds its max value so don't cast to int cast it to long

#include <iostream>
#include <cmath>
#include <climits>
using namespace std;

int main() {
    cout << (int)pow(2, 32) << endl;
    // 2147483647
    cout << INT_MIN << endl;
    //-2147483648
    cout << INT_MAX << endl;
    //2147483647
    cout << (long)pow(2, 32) << endl;
    //4294967296
    cout << LONG_MIN << endl;
    // -9223372036854775808
    cout << LONG_MAX << endl;
    // 9223372036854775808
    return 0;
}

if you are not aware about int overflow you can check this link

Ahmed Yousif
  • 2,298
  • 1
  • 11
  • 17