Binary shift is "too big" but isn’t

I’m making a floating_point class and am trying to access the last bit in an unsigned long by masking it by (1 << 64), but when I compile and run it stops me saying that my value is too big, even though it’s exactly within the constraints! I checked the size of my unsigned long and it said 8 too so I don’t get it, mind helping me?
1
2
3
4
5
6
#include <iostream>

int main(){
  unsigned long mask = 1 << 64;
  std::cout << mask;
}


The warning I get is:

warning: shift count >= width of type [-Wshift-count-overflow]
unsigned long mask = 1 << 64;


And the output is:
0
Last edited on
1. unsigned long is a 32-bit integer even on some 64-bit platforms.
2. 2^64 cannot be held by a 64-bit integer. Did you mean to 2^63?
3. 1 is still of type int. You need to convert it to a suitably large type first in order to nor overflow with the shift.
 
auto mask = (std::uint64_t)1 << 63;
Last edited on
@helios oh. Right. First bit is 1 not 2. XD thanks yes I did in fact mean 2^63, that coupled with the cast worked:

1
2
3
4
5
6
#include <iostream>

int main(){
  unsigned long mask = (std::uint64_t)1 << 63;
  std::cout << mask;
}
If you insist on using unsigned long as your type you should know that there is a literal suffix ul that you can use to turn integer literals into that type.

 
unsigned long mask = 1ul << 63;

u = unsigned
l = long
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdint>

template<typename T> // T should be an unsigned type
constexpr T highest_power_of_2() { return (T)(-1) ^ ((T)(-1) >> 1); }

std::ostream& operator<<(std::ostream& os, __uint128_t u128) {
    std::string s;
    for ( ; u128; u128 /= 10) s += char('0' + u128 % 10);
    if (s.size() == 0) s = '0';
    os.width(os.width() - std::streamsize(s.size()) + 1);
    for (auto it = s.rbegin(); it != s.rend(); ++it) os << *it;
    return os;
}

int main() {
    using std::cout; using std::setw;
    auto  u32 = highest_power_of_2<std::uint32_t>();
    auto  u64 = highest_power_of_2<std::uint64_t>();
    auto u128 = highest_power_of_2<__uint128_t>(); // non-standard
    cout << " u32: " << setw(42) <<  u32 << '\n';
    cout << " u64: " << setw(42) <<  u64 << '\n';
    cout << "u128: " << setw(42) << u128 << '\n';
}

 u32:                                 2147483648
 u64:                        9223372036854775808
u128:    170141183460469231731687303715884105728

Another possibility: ~(~(T)0 >> 1)
I like your way better.
And I added handling hex and oct to operator<<.
I imagine that could be made better, too.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <iomanip>
#include <string>
#include <cstdint>

template<typename T> // T should be an unsigned type
constexpr T highest_power_of_2() { return ~(~(T)0 >> 1); }

std::ostream& operator<<(std::ostream& os, __uint128_t u128) {
    char BaseChar = os.flags() & os.uppercase ? 'A' : 'a';
    unsigned Base = os.flags() & os.oct ?  8 : os.flags() & os.dec ? 10 : 16;
    std::string s;
    for ( ; u128; u128 /= Base) {
        auto val = int(u128 % Base);
        s += char(val > 9 ? BaseChar - 10 + val : '0' + val);
    }
    if (os.flags() & os.showbase && !(os.flags() & os.dec)) {
        if (os.flags() & os.hex) s += char(BaseChar + ('X' - 'A'));
        s += '0';
    }
    if (s.size() == 0) s += '0';
    os.width(os.width() - std::streamsize(s.size()) + 1);
    for (auto it = s.rbegin(); it != s.rend(); ++it) os << *it;
    return os;
}

int main() {
    using std::cout; using std::setw;
    auto  u32 = highest_power_of_2<std::uint32_t>();
    auto  u64 = highest_power_of_2<std::uint64_t>();
    auto u128 = highest_power_of_2<__uint128_t>(); // non-standard
    cout << std::hex << std::showbase;
    cout << " u32: " << setw(42) <<  u32 << '\n';
    cout << " u64: " << setw(42) <<  u64 << '\n';
    cout << "u128: " << setw(42) << u128 << '\n';
}

 u32:                                 0x80000000
 u64:                         0x8000000000000000
u128:         0x80000000000000000000000000000000

Last edited on
Note that numeric_limits<>::digits is the number of non-sign bits in an integer type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <limits>

using namespace std;

int main()
{
    cout << "char has " << numeric_limits<char>::digits << " non-sign bits\n";
    cout << "unsigned char has " << numeric_limits<unsigned char>::digits << " non-sign bits\n";
    cout << "short has " << numeric_limits<short>::digits << " non-sign bits\n";
    cout << "unsigned short has " << numeric_limits<unsigned short>::digits << " non-sign bits\n";
    cout << "int has " << numeric_limits<int>::digits << " non-sign bits\n";
    cout << "unsigned int has " << numeric_limits<unsigned int>::digits << " non-sign bits\n";
    cout << "long has " << numeric_limits<long>::digits << " non-sign bits\n";
    cout << "unsigned long has " << numeric_limits<unsigned long>::digits << " non-sign bits\n";
}

char has 7 non-sign bits
unsigned char has 8 non-sign bits
short has 15 non-sign bits
unsigned short has 16 non-sign bits
int has 31 non-sign bits
unsigned int has 32 non-sign bits
long has 63 non-sign bits
unsigned long has 64 non-sign bits
Topic archived. No new replies allowed.