Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If I want to round an unsigned integer to the closest smaller or equal even integer, can I divide by 2 then multiply by 2?

Tags:

c++

c

For example :

f(8)=8 f(9)=8 

Can I do x = x/2*2; ? Is there a risk that the compiler will optimize away such expression ?

like image 713
user2370139 Avatar asked Oct 18 '17 07:10

user2370139


People also ask

How do you represent unsigned integers?

The signed integer is represented in twos complement notation. The most significant byte is 0 and the least significant is 3. The unsigned integer is represented by an unsigned binary number whose most significant byte is 0; the least significant is 3. See the Signed Integer and Unsigned Integer figure (Figure 1).

Can you compare unsigned and signed int?

A 1-byte unsigned integer has a range of 0 to 255. Compare this to the 1-byte signed integer range of -128 to 127. Both can store 256 different values, but signed integers use half of their range for negative numbers, whereas unsigned integers can store positive numbers that are twice as large.

Are unsigned integers always positive?

Unsigned Integers (often called "uints") are just like integers (whole numbers) but have the property that they don't have a + or - sign associated with them. Thus they are always non-negative (zero or positive).

What happens when you subtract from an unsigned int?

Subtracting two unsigned values of the same size will result in an unsigned value. If the first operand is less than the second the result will be arithmetically in correct.


2 Answers

The compiler is allowed to make any optimisiations it likes so long as it does not introduce any side effects into the program. In your case it can't cancel the '2's as then the expression will have a different value for odd numbers.

x / 2 * 2 is evaluated strictly as (x / 2) * 2, and x / 2 is performed in integer arithmetic if x is an integral type.

This, in fact, is an idiomatic rounding technique.

like image 198
Bathsheba Avatar answered Sep 22 '22 08:09

Bathsheba


Since you specified the integers are unsigned, you can do it with a simple mask:

x & (~1u) 

Which will set the LSB to zero, thus producing the immediate even number that is no larger than x. That is, if x has a type that is no wider than an unsigned int.

You can of course force the 1 to be of the same type as a wider x, like this:

x & ~((x & 1u) | 1u) 

But at this point, you really ought to look at this approach as an exercise in obfuscation, and accept Bathsheba's answer.


I of course forgot about the standard library. If you include stdint.h (or cstdint, as you should in C++ code). You can let the implementation take care of the details:

uintmax_t const lsb = 1; x & ~lsb; 

or

x & ~UINTMAX_C(1) 
like image 38
StoryTeller - Unslander Monica Avatar answered Sep 22 '22 08:09

StoryTeller - Unslander Monica