Set last `n` bits in unsigned int
Solution 1
If you meant the least-significant n bits:
((uint32_t)1 << n) - 1
On most architectures, this won't work if n is 32, so you may have to make a special case for that:
n == 32 ? 0xffffffff : (1 << n) - 1
On a 64-bit architecture, a (probably) faster solution is to cast up then down:
(uint32_t)(((uint64_t)1 << n) - 1)
In fact, this might even be faster on a 32-bit architecture since it avoids branching.
Solution 2
Here's a method that doesn't require any arithmetic:
~(~0u << n)
Solution 3
The other answers don't handle the special case of n == 32
(shifting by greater than or equal to the type's width is UB), so here's a better answer:
(uint32_t)(((uint64_t)1 << n) - 1)
Alternatively:
(n == 32) ? 0xFFFFFFFF : (((uint32_t)1 << n) - 1)
Solution 4
const uint32_t masks[33] = {0x0, 0x1, 0x3, 0x7 ...
void setbits(uint32_t *x, int n)
{
*x |= masks[n];
}
Solution 5
If n is zero then no bits should be set based on the question.
const uint32_t masks[32] = {0x1, 0x3, 0x7, ..., 0xFFFFFFFF};
void setbits(uint32_t *x, int n)
{
if ( (n > 0) && (n <= 32) )
{
*x |= masks[--n];
}
}
Comments
-
Cartesius00 almost 2 years
How to set (in most elegant way) exactly
n
least significant bits ofuint32_t
? That is to write a functionvoid setbits(uint32_t *x, int n);
. Function should handle eachn
from0
to32
.Especially value
n==32
should be handled.-
Jim Rhodes over 12 yearsby last do you mean high order or low order?
-
phuclv almost 5 yearsthis question handles any values in the range [0, 64]: Creating a mask with N least significant bits set
-
-
TonyK over 12 yearsThe other answers handle it perfectly well. (1 << 32) - 1 is 0xFFFFFFFF.
-
Oliver Charlesworth over 12 years@Tony: No they don't. Shifting beyond the length of the type is undefined.
-
Oliver Charlesworth over 12 yearsUnnecessary amounts of coding, but at least it will give the right answer.
-
Oliver Charlesworth over 12 years@Tony: You're downvoting because I gave an answer containing portable code with well-defined behaviour?
-
Cartesius00 over 12 years@Marcelo: I guess it works even without u64 test, just the first version, doesn't it?
-
Alex S over 12 years@TonyK: No, it doesn't work, because shifting a 32-bit integer by 32-bits isn't supported on most architectures (certainly not on Intel).
-
James McNellis over 12 yearsRight: "The behavior is undefined if the right operand is...equal to the length in bits of the promoted left operand." [C++11 §5.8/1]
-
nos over 12 years@TonyK n == 32 shifts one past the width, which is undefined behavior.
-
Cartesius00 over 12 years@TJD: I guess unnecessary amount of memory access.
-
Alex S over 12 years@TonyK: This has as much to do with the CPU as the compiler, and it doesn't work my i686-apple-darwin11-llvm-gcc-4.2.
-
Cartesius00 over 12 years@Marcelo: Anyway, Marcelo, answer accepted. Good to know about 1<<32 issue.
-
Jens Gustedt over 12 yearsI don't think that this answer is correct.
1
is of typeint
and1 << n
could go wrong for much more cases than you assume. A first shot would be to use1U << n
but then the OP explicitly wanteduint32_t
. For that the correct thing would be to useUINT32_C(1) << n
. -
Alex S over 12 years@MichaelKrelin-hacker: Nice. Though I assume you meant
(uint32_t)((-1)>>(32-n))
-
Michael Krelin - hacker over 12 yearsoops. But no, I meant
(uint32_t)
, with signed it will stay with all bits set for all values of n. -
Michael Krelin - hacker over 12 yearsI see you edited your guess, still no, I want to cast before shifting.
-
Alex S over 12 years@JensGustedt: Other than 32, which has already been discussed, which other value(s) doesn't my answer handle correctly?
-
Alex S over 12 years@MichaelKrelin-hacker: Ah, sorry; I misunderstood what you were trying to do. Yes, that works, but it also has an edge-case: n == 0.
-
Jens Gustedt over 12 years@MarceloCantos, IRC left shift with
31
on an 32 bit integer leads to overflow => undefined behavior. And thenint
is only guaranteed to be 16 bit wide by the standard. In summary your version can fail for values from16
to31
. -
Jens Gustedt over 12 years@MarceloCantos, also in your faster version, what is the purpose of cast
n
touint64_t
? You should "cast" the1
this is what determines the type of the expression. -
Jens Gustedt over 12 years@OliCharlesworth, casting a constant? This should just be
UINT64_C(1)
. And then your alternative solution doesn't work on architectures with 16 bitint
, but doesn't work for 32 bitint
either, because for31
you have an overflow. -
David Rodríguez - dribeas over 12 yearsBranching would most probably not be an issue here... there are specific assembly instructions to handle the simpler
cond?a:b
cases like this. Try to compile into assembly and check the output. -
Alex S over 12 years@JensGustedt: Ah yes; good points; I've fixed it. When you said, "much more cases", I thought you meant something more calamitous.
-
Jens Gustedt over 12 years@MarceloCantos, at least the 31 is calamitous. Please fix it by just putting a
1U
instead of1
as a base of the shift. -
Jens Gustedt over 12 years@OliCharlesworth, why casting a constant where the language gives you the right tool to just specify the right one?
-
DarkDust about 11 years+1, no memory access, no branches and no special cases. I consider this to be the most elegant solution.
-
Eric about 11 years@DarkDust: Except this (sometimes) fails for n = 32, since shifting a
uint_32t
by32
is undefined behaviour. -
xuhdev over 9 yearsYou can just use
~0UUL
or~0UL
instead of0xsomanyf
. It'll be more platform independent as you don't need to know the exact size ofint
orlong
or whatever. -
Alex S over 9 years@xuhdev: The OP stipulated uint32_t.
-
wonder.mice over 8 yearsIf you can't shift all the way through, then shift half of that and then do the rest: (1 << n/2 << n - n/2) - 1 (sort of a joke)
-
underscore_d over 6 yearsYour case for
n >= 32
does not help, since the prior unchecked shift will still be done, and ifn >= sizeof(TheType) * CHAR_BIT
, that's UB, which isn't affected by whether you try to paper over it after the fact. -
paxdiablo over 6 yearsPerhaps "goals" should also include "readable/understandable code" :-)
-
Harvey over 6 years@paxdiablo Yeah, that's why I stated the goals: to indicate that readable code was NOT the goal. :)
-
Harvey over 6 years@underscore_d What's "UB" mean? It's ok if the first line is produces a bad value for
n>=32
because the next line corrects it. I've added a program to the answer that proves the algorithm. Honestly, it has been so long that I needed the program to prove it to myself. -
underscore_d over 6 years@Harvey Undefined behaviour poisons the entirety of a program as soon as you invoke it. You cannot "correct it" by overwriting it afterwards. And it means absolutely nothing if you find that the code happens to produce the correct results when tested, because the UB means that it's not required to and can break at any time (when ported to a different architecture, compiler, Standard revision, etc.). Code that invokes UB is bad and shouldn't be posted as a recommendation, and that's the end of it.
-
Harvey over 6 years@underscore_d I get your point, and I respectfully disagree. Example:
x = uint32_t(1) << 40; x = 7;
Even if the first statement is undefined behavior (for some values, e.g. 40), the second line is very much defined behavior and the result is ok. Unless "undefined behavior" includes crashing an app or memory corruption, it's good. -
Harvey over 6 years@underscore_d To be fair, I was surprised that
<<
doesn't mean shift for my current compiler. It clearly means shift with rotation which I wouldn't have expected (undefined behavior). -
underscore_d over 6 years@Harvey There's nothing to disagree about. The letter of the Standard is that once UB occurs, the behaviour of the entire program is undefined. It doesn't matter if you then do something that completely replaces the object; UB has occurred, and it can't be undone. Sure, practically, probably nothing will go wrong, as compilers don't make it their mission to ruin your life. But it's formally ill-formed code, so it's irresponsible to portray it as being fine.
-
Harvey over 6 years@underscore_d I agree with you in principle. In this case, I'm ok with this specific code because I think "undefined behavior" probably means "undefined, but sane". In other words, no compiler writer is going to guarantee that the value returned is what you expected, but they will probably guarantee not to modify anything other than that value producing no side effects. I'll add a comment with your warning.
-
phuclv almost 5 yearsthere are many ways to handle that case without a branch: Creating a mask with N least significant bits set
-
phuclv over 3 yearsThe
-1 ^
part is the same as a NOT operation, so just use~((1 << (32 - n)) - 1)