does modulo the largest +1 yield wrong results in a cast to 64 bit unsigned integer like size_t

ByronWien 6 Reputation points
2020-11-27T22:20:38.453+00:00
// the following code works as expected
std::cout << std::numeric_limits<unsigned int>::max() << std::endl; // yields 4294967295, the largest
std::cout << std::pow(2, 8 * sizeof(unsigned int)) << std::endl; // yields 4294967296
std::cout << static_cast<unsigned int>(std::pow(2, 8 * sizeof(unsigned int))) << std::endl; // yields 0, because of modulo the largest + 1
std::cout << static_cast<unsigned int>(std::pow(2, 8 * sizeof(unsigned int))*3 + 1) << std::endl; // yields 1, because of modulo the largest + 1

// working on 64bit windows with VS2019, C++  
std::cout << std::numeric_limits<size_t>::max() << std::endl; // yields 18446744073709551615, the largest, fine
std::cout << std::pow(2, 8 * sizeof(size_t)) << std::endl; // yields 18446744073709551616, fine
// now the unexpected happens. My question is why?
std::cout << static_cast<size_t>(std::pow(2, 8 * sizeof(size_t))) << std::endl; // yields 9223372036854775808 but should yield 0, because of modulo the largest + 1
std::cout << static_cast<size_t>(std::pow(2, 8 * sizeof(size_t))*3 + 1) << std::endl; // yields 9223372036854775808 but should yield 1, because of modulo the largest + 1
// whereby maybe worth to mention 9223372036854775808 is exactly half of 18446744073709551616.
// and by the way, clang produced 0 for both answers.
Developer technologies | C++
0 comments No comments
{count} vote

1 answer

Sort by: Most helpful
  1. Igor Tandetnik 1,116 Reputation points
    2020-11-27T23:26:27.05+00:00

    This code exhibits undefined behavior. The key observation is that the return type of std::pow is double, even when arguments are integral. So casts to unsigned int or size_t are floating-integral conversions. The C++ standard has this to say:

    [conv.fpint]/1 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.

    Emphasis mine.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.