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,
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.
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?
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.
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.
#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 ) ) ;
}
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.
> 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.
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.
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?
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.
> 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
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