Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move integer to the nearest divisible by 4 in C++

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.

like image 585
Matt Parkins Avatar asked Aug 18 '14 10:08

Matt Parkins


1 Answers

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.

like image 158
Magnus Hoff Avatar answered Sep 21 '22 12:09

Magnus Hoff