c++ – How many numbers can this type represent?

Question:

How to find out how many numbers a given type can represent, except for std::pow(2., sizeof(type)*8) ?

Answer:

For integer types, the number of different variants can be obtained by subtracting the minimum possible value from the maximum possible value and adding one, i.e .:

std::numeric_limits<T>::max() - std::numeric_limits<T>::min() + 1;

But here it is worth considering the moment that for types with rank >= int we will get an overflow and the result as zero. To prevent this from happening, you need to cast the first argument to some maximum possible integer type. BigInt call it BigInt for BigInt .

static_cast<BigInt>(std::numeric_limits<T>::max()) - std::numeric_limits<T>::min() + 1;

This approach will increase the number of types for which the code can be called, but overflow will still occur for situations where sizeof(T) == sizeof(BigInt) . And this cannot be avoided, because any type will have a representation for zero, and therefore the number of possible options will be at least one more than the maximum number represented by this type.

For demonstration, I chose the non-standard __int128_t type as BigInt , but available in various compilers:

template <class T>
auto range() {
    return static_cast<__int128_t>(std::numeric_limits<T>::max()) - std::numeric_limits<T>::min() + 1;
}

Check (the code for outputting a value of the __int128_t type __int128_t borrowed from James Kanze 's answer , since no ready-made solutions are provided by compilers):

#include <cstdint>
#include <limits>
#include <iostream>

std::ostream&
operator<<( std::ostream& dest, __int128_t value )
{
    std::ostream::sentry s( dest );
    if ( s ) {
        __uint128_t tmp = value < 0 ? -value : value;
        char buffer[ 128 ];
        char* d = std::end( buffer );
        do
        {
            -- d;
            *d = "0123456789"[ tmp % 10 ];
            tmp /= 10;
        } while ( tmp != 0 );
        if ( value < 0 ) {
            -- d;
            *d = '-';
        }
        int len = std::end( buffer ) - d;
        if ( dest.rdbuf()->sputn( d, len ) != len ) {
            dest.setstate( std::ios_base::badbit );
        }
    }
    return dest;
}

template <class T>
auto range() {
    return static_cast<__int128_t>(std::numeric_limits<T>::max()) - std::numeric_limits<T>::min() + 1;
}

int main() {
    std::cout << range<int>() << "\n"
    << range<unsigned>() << "\n"
    << range<long>() << "\n"
    << range<char>() << "\n"
    << range<short>() << "\n"
    << range<unsigned long long>() << "\n"
    << range<bool>() << "\n";
}

Possible conclusion:

4294967296  
4294967296  
18446744073709551616  
256  
65536  
18446744073709551616  
2  

The std::make_unsigned suggested in the other answer will not work for the bool type, since it has no way to be signed or unsigned.

Scroll to Top