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