amillerp
amillerp

Reputation: 11

int256_t using C++ boost library capable of showing 2^{256} - 1

I'm using the cpp_int header file from boost/multiprecision and for some reason when I cast -1 to a uint256_t then cast it back to an int256_t, it keeps the same value (~1.15e77). When I increment this variable, it wraps back to 0. What gives. Why is my int256_t acting like a uint256_t?

Apologies for bad formatting, I'm not used to using stack overflow.

I tried printing the int256_t and it printed the same value as the uint26_t, which it shouldn't be able to do. I also tried printing int256_t(-1) and it printed -1 fine. If I compare the int256_t to -1 it equates to false, but if I increment them both and then compare it it equates to true as they're both now 0.

Why is this the case? The max uint256_t should be 0xfff....fff, and a signed 2s complement version of -1 in int256_t is 0xfff....fff as well. Is the boost implementation of integers not 2s complement?

Upvotes: 0

Views: 345

Answers (1)

Andrey Semashev
Andrey Semashev

Reputation: 10624

int256_t uses signed magnitude format for number representation, meaning that it separately stores the information about sign and magnitude of the number:

The type uses a sign-magnitude representation internally, so type int128_t has 128-bits of precision plus an extra sign bit. In this respect the behaviour of these types differs from fundamental (built-in) 2's complement types.

When you cast int256_t to uint256_t, you strip information about the sign and get the number that is equal to "0 + the signed number". For negatives, this causes a wrap, so for -1 you get numeric_limits<uint256_t>::max(). When you cast back, the sign is assumed positive, since by definition unsigned numbers are always positive. The magnitude part of int256_t is capable of holding the same number of bits as uint256_t, so the conversion is without loss.

Demonstrating:

Live On Compiler Explorer

#include <iostream>
#include <boost/multiprecision/cpp_int.hpp>

namespace mp = boost::multiprecision;

int main()
{
    mp::int256_t si1{-1};
    mp::uint256_t ui1{si1};
    mp::int256_t si2{ui1};

    std::cout << si1 << "\n" << ui1 << "\n" << si2 << std::endl;
}

Prints

-1
115792089237316195423570985008687907853269984665640564039457584007913129639935
115792089237316195423570985008687907853269984665640564039457584007913129639935

Upvotes: 3

Related Questions