Reputation: 24708
I'd like to move an integer up to the nearest 'divisible by 4' number in C++, but not if the number is currently divisible by 4. Here's my best attempt, but I'm sure this is suboptimal:
offset = (offset & 3) ? (offset | 3) +1 : offset;
There must surely be a fast way of doing this that doesn't include the tertiary IF statement?
Additional note: In this case offset is a 32-bit int.
Upvotes: 9
Views: 1407
Reputation: 22089
offset = (offset + 3) & ~(decltype(offset))3;
Or
#include <type_traits>
// ...
offset = (offset + 3) &
~static_cast<std::remove_reference<decltype(offset)>::type>(3);
if you need to support the possibility that offset
is a reference type, such as size_t&
. Thanks @BaummitAugen.
It also seems to work when offset
is wider than int
even without the type cast, offset = (offset + 3) & ~3;
, but I am uncertain as to whether or not it is mandated by the language standard.
This algorithm can be described in English as "add 3 then round down".
The rounding down part is done by setting the two least significant bits to zero by binary arithmetics. Unsetting of bits is done by applying binary AND with the inverse bit pattern, in other words we make a bit pattern of all the bits whose value we want to keep unchanged and apply it as a mask.
Binary representation of 3
: 00000011
We get the inverse bit mask with the ~
(bitwise NOT, not to be confused with !
logical NOT) operator: ~3
For the ~
operator, the size of the operand determines the size of the result, so on my machine ~(unsigned char)3 == 252
(1111 1100
) and ~(unsigned int)3 == 4294967292
(1111 1111 1111 1111 1111 1111 1111 1100
). The default size for an integer literal is int
.
When offset
is a wider type (has more bits) than int
, we need the operand to ~
to be widened so the bitmask matches. This is why we cast the literal 3
to the same type as offset
.
Upvotes: 9
Reputation: 263250
Here is an alternative approach:
offset += -offset & 3;
Depending on the division rest (0, 1, 2, or 3), it adds the appropriate amount to round up (0, 3, 2 or 1).
Upvotes: 2
Reputation: 31445
offset = ((offset +3 ) >> 2) << 2;
However I prefer Magnus Hoff's solution.
offset should ideally be an unsigned type. If you make this an inline function you can use a parameter that is unsigned. You can also parameterise the power, of course, i.e. 2 in this case. In such a case the number you add would be (1<
So for a general solution:
template< typename U >
U roundUpPower2( U num, size_t nBits )
{
return (( num + (static_cast<U>(1) << nBits) - 1 ) >> nBits) << nBits;
}
Using a bitmask rather than two shits
template< typename U >
U roundUpPower2( U num, size_t nBits )
{
U mask = (static_cast<U>(1) << nBits) - 1;
return (num + mask) & ~mask;
}
Note the purpose of casting the 1 is that if you are using 64 bit arithmetic your nBits might be any value from 1 to 63 and plain 1
is of type int, signed and probably 32 bits, in which case the arithmetic would go wrong if nBits is 32 or higher if you don't cast it.
Upvotes: 4
Reputation: 171167
You can do this:
number = 4 * ((number + 3) / 4)
Whether it's more efficient depends on your setup - profile and see.
Upvotes: 3