How does one get the width of an general int

Pages: 12

My goal is to set only the high bit of a general int. I would like to use it as a constant for speed considerations. I can calculate the high bit and it is dependent on whether it is signed or not? I doubt that to be the case, the way I got it to work is the following code. I set a constant value for HIGH_BIT in the template function and the only way that I currently know how to set only the high bit is the following,

const TypeOfInt HIGH_BIT = std::numeric_limits< TypeOfInt >::is_signed ?
std::numeric_limits< TypeOfInt >::min() : ~( TypeOfInt(~0) >> 1 );

Is there someplace where the high bit is defined as a constant in a header file? There has to be a better way to set only the high bit of a general integer.

Thank you so much!
Emily
For clarification, what do you want the high bit of an 8-bit signed integer to be? 7? or 6?
And for an unsigned 8-bit integer, you want this method to return 7?
There has to be a better way to set only the high bit of a general integer.

Bit math on signed integers is fairly suspicious. Regardless, consider using a variable template.
1
2
template <std::integral T> 
  T constexpr high_bit = T{1} << (sizeof(T) * 8 - 1);

Last edited on
you can boolean it..
high bit is simply x&128 (8 bit example).
so
high_bit = (x&128 != 0);
128 is from 2^(n-1) where n is number of bits in the integer type. 2^7 here.
setting it works similar.
x = x|(128)
or for a conditional assignment
x = x|( (something == other)*128);
the bool conditon becomes 1 or 0. if its true, it ors with 128, setting the bit.
if its zero, it ors with 0 which does nothing at all.
to clear it
you and it with a constant... the constant you get when all the other bits are set, and you can do a similar conditional statement to clear it conditionally as above. Interestingly, the number you want is 1 less than you were using... 128-1 = 127. (because 1000 -1 is 0111 in binary..)

if the type is signed, cast to unsigned to fiddle with bits.
Last edited on
Oooh, OP is asking for the number (e.g.) 0b1000'0000. I thought she was asking for the bit index.
Thank you everyone for your input.

mbozzi - left shift on a 64 bit signed integer causes warnings and does not seem to work. I did use something like meta template programing to come up with the implementation shown. It does work for both signed and unsigned types as it is. Just strange that there isn't something like,

std::numeric_limits< T >::bit_width and std::numeric_limits< T >::high_bit

and I would like to see,

HIGH_BIT = 1 << std::numeric_limits< T >::bit_width;

or simply use the constant high_bit

jonnin - see above mbozzi.

Gando - thanks, yes thank you, it is confusing. I searched before I posted and there seems no simple way to do what I have shown above in this post.
> Just strange that there isn't something like, std::numeric_limits< T >::bit_width

We do have std::numeric_limits<N>::digits
https://en.cppreference.com/w/cpp/types/numeric_limits/digits

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <concepts>
#include <limits>
#include <bitset>
#include <type_traits>

template < std::unsigned_integral N > N set_high_bit( N number )
{
    constexpr std::size_t NBITS = std::numeric_limits<N>::digits ;
    std::bitset<NBITS> bitset(number) ;
    bitset[NBITS-1] = true ; // set the most significant bit
    return N( bitset.to_ullong() ) ;
}

template < std::signed_integral N > N set_high_bit( N number )
{
    return set_high_bit( std::make_unsigned_t<N>( number ) ) ;
}

does not seem to work

I can't reproduce the problem.

What diagnostic message did you get? What output did you get? What output did you expect?


JLBorges - here is a test that hopefully shows the crux of the situation,

std::cout << std::numeric_limits< unsigned long long >::digits << " " << std::numeric_limits< long long >::digits << std::endl;

Produces "64 63", which is close to what I want if I want to use the left shift operator. This is what I got earlier. The high bit depends on whether it is signed or not. Then the left shift operator complains if I try to shift into the high bit of a signed number. I naively though that std::numeric_limits< T >::digits would work and I tried some to get it to work yet it is not so elegant.

mbozzi - ibid

What I have now works for all int types both signed and unsigned.
Last edited on
> The high bit depends on whether it is signed or not.

std::numeric_limits<N>::digits gives the number of bits excluding the sign bit (if any) and padding bits (if any). For instance, in a hypothetical implementation where the object representation of unsigned long long has 64 bits, but its value representation has only 56 bits, std::numeric_limits<unsigned long long>::digits would yield 56 and std::numeric_limits<long long>::digits would yield 55.

JLBorges - yes, I read the standard and was nonplussed. Let me reiterate the original question, is there a way to get the width of all the digits regardless of signedness? Instead of relying CHAR_BITS and sizeof to get the width, I was hoping for a typesafe way to get the total width including the signbit. What I want is not what 'digits' offer.
> is there a way to get the width of all the digits regardless of signedness?

1
2
3
4
5
6
7
8
#include <concepts>
#include <limits>

// bit_width including the sign-bit
template < std::integral N > constexpr std::size_t bit_width( N = {}  ) noexcept
{
    return std::numeric_limits< std::make_unsigned_t<N> >::digits ;
}


Usage: bit_width<int>() or bit_width(1234LL)
I would like to use it as a constant for speed considerations.


Would you like to explain this a bit more? There may be a better, cleaner way to achieve your goal, but we don't really know what that goal is.

This "single bit in the highest value bit" idea seems a bit of a hack, but without knowing what you are intending, I can't offer alternatives.
Last edited on
it could be useful... its the order of magnitude of the number, in binary.
log based 2 would get you there, but I can't see that being faster that bitwise magic, the log circuits are moderately sluggish. There may be hardware specific tricks, but general c++... not seeing anything better.
You could do metaprogramming to compute all the log-base 2 stuff at compile time.
yea but no faster even so. Its still going to come down to a wonky function with a constant poked into it. At best, same speed as his macro? Or do you see something I don't on the performance side?

From everyone's suggestions I settled (for now) the following:

constexpr TypeOfInt HIGH_BIT = ~( std::make_unsigned_t<TypeOfInt> (~0) >> 1);

Which perfectly sets the high bit (MSB) of any int type signed or unsigned.
jonnin,
I'm actually not sure what the goal here is. I don't understand why the answer isn't just sizeof(T) * CHAR_BITS, because an exact example has not been given yet. As far as performance, yeah at best it would be the same speed as any other function that returns a constant number (and with optimizations enabled, there wouldn't even be a function call).

Edit: I guess em's latest post removes any ambiguity if that's what works, and the thread is solved.
Last edited on
> I don't understand why the answer isn't just sizeof(T) * CHAR_BITS

Theory:

sizeof(T) * CHAR_BITS would yield the number of bits in the object representation.
What is required here is the number of bits in the value representation.

For narrow character types, each possible bit pattern of the object representation represents a distinct value. (Note: This requirement does not hold for other types.)
https://eel.is/c++draft/basic.fundamental#7


In theory, there is no difference between practice and theory. In practice, there is.
-- attributed to Yogi Berra



> with optimizations enabled, there wouldn't even be a function call

Yes, bit_width can be an immediate function (consteval) and set_msb can be constexpr
https://gcc.godbolt.org/z/nbsEPcYK8

Of course! Poifect example! It is somewhat comforting that someone out in the world can understand my jibberish and give an on point example. What a resource!

In theory, there is no difference between practice and theory. In practice, there is.
-- attributed to Yogi Berra

ROTFLMFGO!

Thank you so much JLBorges!

Sincerely,
Emily C137


Pages: 12