Move integer to nearest divisible by 4 in C ++

I would like to move the integer to the nearest number "divisible by 4" in C ++, but not if the number is currently divisible by 4. Here is my best attempt, but I'm sure this is suboptimal:

offset = (offset & 3) ? (offset | 3) +1 : offset; 

Should there be, of course, a quick way to do this without including the tertiary IF statement?

Note: In this case, the offset is a 32-bit int.

+5
source share
4 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, for example size_t& . Thanks @BaummitAugen.

It also works when offset wider than int , even without cast, offset = (offset + 3) & ~3; but I'm not sure if it matches the language standard.


This algorithm can be described in English as "add 3, then round."

The rounding part is done by setting the two least significant bits to zero using binary arithmetic. The bits are reset by applying binary AND with the inverse bit pattern, in other words, we make the bit pattern of all bits whose value we want to keep unchanged and use it as a mask.

Binary representation 3 : 00000011

We get the inverse bitmask with ~ (bitwise NOT, so as not to be confused with the operator ! Logical NOT): ~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 in ~ expand so that the bitmask matches. That's why we impose literal 3 on the same type as offset .

+7
source

You can do it:

 number = 4 * ((number + 3) / 4) 

Whether it will be more effective depends on your profile - the profile and sees.

+3
source
 offset = ((offset +3 ) >> 2) << 2; 

However, I prefer the decision of Magnus Hoff.

Bias

Ideally should be unsigned. If you make this a built-in function, you can use the unsigned parameter. In this case, you can also parameterize the power, i.e., T. E. 2. In this case, the number you add will 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, not two shit

 template< typename U > U roundUpPower2( U num, size_t nBits ) { U mask = (static_cast<U>(1) << nBits) - 1; return (num + mask) & ~mask; } 

Note that the purpose of casting 1 is that if you use 64-bit arithmetic, your nBits can be any value from 1 to 63, and plain 1 is of type int, signed and probably 32 bits, in which case the arithmetic will be incorrect if nBits is 32 or higher if you did not pronounce it.

+3
source

Here is an alternative approach:

 offset += -offset & 3; 

Depending on the quiescent separation (0, 1, 2 or 3), it adds the appropriate amount for rounding (0, 3, 2 or 1).

+1
source

Source: https://habr.com/ru/post/1200576/


All Articles