13

Sometimes I need to be sure that some integer is even. As such I could use the following code:

int number = /* magic initialization here */;

// make sure the number is even
if ( number % 2 != 0 ) {
    number--;
}

but that does not seem to be very efficient the most efficient way to do it, so I could do the following:

int number = /* magic initialization here */;

// make sure the number is even
number &= ~1;

but (besides not being readable) I am not sure that solution is completely portable.

  • Which solution do you think is best?
  • Is the second solution completely portable?
  • Is the second solution considerably faster that the first?
  • What other solutions do you know for this problem?
  • What if I do this inside an inline method? It should (theoretically) be as fast as these solutions and readability should no longer be an issue, does that make the second solution more viable?

note: This code is supposed to only work with positive integers but having a solution that also works with negative numbers would be a plus.

NotMe
  • 87,343
  • 27
  • 171
  • 245
João Portela
  • 6,338
  • 7
  • 38
  • 51
  • 2
    Relevant discussion here: [Would you use num%2 or num&1 to check if a number is even?](http://stackoverflow.com/questions/1949271/would-you-use-num2-or-num1-to-check-if-a-number-is-even/1949293#1949293) – jason Jan 19 '11 at 18:57
  • I don't see why it wouldn't be portable... you're just setting the least significant bit to 0. I would just have a constant defined for ~1 , e.g. `EVEN_MASK = ~1`, and then use what you have. Like you said, an inline method would enhance the readability. – I82Much Jan 19 '11 at 18:58
  • @Jason: No. This question is "how do you *make* a number even" (not "how do you *check whether* a number is even". @OP: Don't you think it won't make any difference performance-wise? –  Jan 19 '11 at 18:58
  • @delnan: You're right. My mistake. – jason Jan 19 '11 at 19:01
  • 8
    number = 2. Any other requirements? – patros Jan 19 '11 at 19:05
  • 3
    How does it not seem "efficient"? That code is never going to be your bottleneck. Just use the `%` and `--`, and move on. – Lightness Races in Orbit Jan 19 '11 at 19:12
  • @patros - It would be nice if the number would not differ more than 1 from the original number ;) – João Portela Jan 19 '11 at 19:24
  • Doing some comparisons between the two approaches using the `time` linux utility I was not able to conclude that the first approach is faster than the second. Anyone else has data on this? – João Portela Jan 19 '11 at 19:43
  • @Tomalak - if this function was call from a loop that executed several million times the divide, test, and decrement will take considerable longer than the AND. – semaj Jan 19 '11 at 21:30
  • Joao: If your profiler can't even measure how efficient `%` is, you can be sure it's efficient enough. – John Dibling Jan 19 '11 at 21:56
  • @semaj: Compilers these days have clever things called optimisations! – Lightness Races in Orbit Jan 19 '11 at 22:32
  • @Tomalak - Thank you for your reminding me about optimizers. How do we know what compiler the OP is using? I've looked over the question and apparently missed it. Are all compilers required to make this optimization? Would an optimizer actually make this optimization or is that just an assumption? – semaj Jan 20 '11 at 00:33
  • 1
    @semaj: I think that @Tomalak's point was that this is a micro optimization and that is the job of the compiler. Even if it does not do it now it will probably do so in the near future (and even if it does not do we really care); and the more important thing is that the code is clear and easy to understand. – Martin York Jan 20 '11 at 00:43
  • @semaj: My point is, let the compiler care. If the compiler doesn't optimise it, then oh well never mind. Just write the code concisely and clearly to do what you want to do, and move on. – Lightness Races in Orbit Jan 20 '11 at 11:45
  • 1
    Efficiency seems to be one of the main concerns of the OP. Not worrying about it or assuming the compiler does it or may or may not do it sometime in the future does not seem very helpful to the OP. – semaj Jan 20 '11 at 16:29

9 Answers9

32

Personally, I'd go with an inline helper function.

inline int make_even(int n)
{
    return n - n % 2;
}

// ....

int m = make_even(n);
suszterpatt
  • 8,187
  • 39
  • 60
  • 3
    +1 for clarity. This code will probably be compiled to `m = n & ~1` or similar anyway. – Fred Foo Jan 19 '11 at 19:16
  • Can't get any better than this. – Michael Smith Jan 19 '11 at 20:19
  • 9
    return n - (n % 2); Never rely on operator precedence. – Mike Sherrill 'Cat Recall' Jan 19 '11 at 22:40
  • 1
    @Catcall: You can rely on operator precedence just fine! But I agree, for legibility and peace of mind, there's really no reason to omit the parentheses here. Include them! ("Never" is a little strong.) – Lightness Races in Orbit Jan 19 '11 at 23:37
  • 5
    @suszterpatt: Because better programmers than me say it's a bad idea, and my experience says they're right. "Unless reader and compiler both understand the writer, the program is not communicating properly." /The Elements of Programming Style/, Kernighan and Plauger, p15. "Don't just be right--be obviously right so that nobody has to look it up." /Writing Solid Code/, Maguire, p 139. You'll find the same idea in McConnell's /Code Complete/, Eckel's /Thinking in Java/, etc. And I don't think "never" is too strong; bad habits with short expressions lead to bad habits with long expressions. – Mike Sherrill 'Cat Recall' Jan 20 '11 at 01:51
  • 5
    @Catcall: sure, I understand that sentiment, but then I also think that the precedence of basic arithmetic operators is already obvious without the parentheses and nobody would have to look them up. Still, point well made. – suszterpatt Jan 20 '11 at 09:12
7

Before accepting an answer I will make my own that tries to summarize and complete some of the information found here:

Four possible methods where described (and some small variations of these).

  1. if (number % 2 != 0) { number--; }
  2. number&= ~1
  3. number = number - (number % 2);
  4. number = (number / 2) * 2;

Before proceeding any further let me clarify something: The expected gain for using any of these methods is minimal, even if we could prove that one method is 200% faster than the others the worst one is so fast that the only way to have visible gain in speed would be if this method was called many times in a CPU bound application. As such this is more of an exercise for fun than a real optimization.

Analysis

Readability

As far as readability goes I would rank method 1 as the most readable, method 4 as the second best and method 2 as the worse. People are free to disagree but I ranked them like this because:

  1. In method 1 it is as explicit as possible that if the number is odd you want to subtract from it making it even.
  2. Method 4 is also very much explicit but I ranked it second because at first glance you might think it is doing nothing, and only a fraction of a second latter you're like "Oh... Integer division.".
  3. Method 2 and 3 are almost equivalent in terms of readability, but many people are not used to bitwise operations and as such I ranked method 2 as the worse.

With that in mind I would add that it is generally accepted that the best way to implement this is using an inline function, and none of the options is that unreadable, readability is not really an issue (direct uses in the code are explicit and clear and reading the method will never be that hard).

If you don't want to use an inline method I would recommend that you only use method 1 or method 4.

Compatibility issues

Underflow

It has been mentioned that method 1 may underflow, depending on the way the processor represents integers. Just to be sure you can add the following STATIC_ASSERT when using method 1.

STATIC_ASSERT(INT_MIN % 2 == 0, make_even_may_underflow);

As for method 3, even when INT_MIN is not even it may not underflow depending on whether the result has the same sign of the divisor or the dividend. Having the same sign of the divisor never underflows because INT_MIN - (-1) is closer to 0. Add the following STATIC_ASSERT just to be sure:

STATIC_ASSERT(INT_MIN % 2 == 0 || -1 % 2 < 0, make_even_may_underflow);

Of course you can still use these methods when the STATIC_ASSERT fails since it would only be a problem when you pass INT_MIN to your make_even method, but I would STRONGLY advice against it.

(Un)supported bit representations

When using method 2 you should make sure your compiler bit representation behaves as expected:

STATIC_ASSERT( (1 & ~1) == 0, unsupported_bit_representation);

// two's complement OR sign-and-magnitude.
STATIC_ASSERT( (-3 & ~1) == -4 || (-3 & ~1) == -2 , unsupported_bit_representation); 

Speed

I also did some naive speed tests using the Unix time utility. I ran every different method (and its variations) 4 times and recorded the results, since the results didn't vary much I didn't find necessary to run more tests.

The obtained results show method 4 and method 2 as the fastest of them all.

Conclusion

According to the provided information, I would recommend using method 4. Its readable, I am not aware of any compatibility issues and performs great.

I hope you enjoy this answer and use the information contained here to make your own informed choice. :)


The source code is available if you want to check my results. Please note that the tests where compiled using g++ and run in Mac OS X. Different platforms and compilers may give different results.

João Portela
  • 6,338
  • 7
  • 38
  • 51
6

I would use the second solution. In any binary representation, regardless of the number of bits, big-endian vs. little-endian, or other architecture differences, that operation will have the effect of setting the lowest bit to zero. It's fast and completely portable. The intent of the code can be explained via comments, if you meet any poor C programmers who can't figure out what it means.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
  • I agree. This is a far more elegant option and is equally as portable as the other option. –  Jan 19 '11 at 19:32
  • 6
    When you say, "completely portable", presumably you mean "to any implementation you're likely to use". It's not completely portable to any implementation permitted by the C and C++ standards, since a 1s' complement representation gives negative odd numbers a last bit of 0. – Steve Jessop Jan 19 '11 at 19:36
  • @Steve, 1's complement! I had forgotten that such a thing existed. Well played, sir. Well played. – JSBձոգչ Jan 22 '11 at 05:21
6
int even_number = (number / 2) * 2;

This should work regardless architecture as long as optimizer is not going in the way (it shouldn't but who knows).

Tomek
  • 4,554
  • 1
  • 19
  • 19
  • A compiler could (fairly) optimize this into `even_number = number`. – Steve M Jan 19 '11 at 19:04
  • 11
    @Tomek/@Steve There is no compiler that will do the optimization you describe! Integer division is *defined* to truncate the remainder. – Andrew Stein Jan 19 '11 at 19:10
  • 5
    Steve: a *broken* compiler could :-) – user52875 Jan 19 '11 at 19:15
  • 1
    a broken compiler could :-) - that's what I was afraid off. Properly optimizing compiler should turn (number / 2) * 2 to the instruction(s) which are more efficient on the target. This could as well be number & ~1 – Tomek Jan 19 '11 at 19:24
  • Many compilers will turn this into something like (number>>1)<<1, which is quite reasonable I think. – Suma Jan 20 '11 at 20:05
  • I gave my vote to n - n % 2 which has similar potential for optimization but is better in not optimized case (one subtraction and one modulus which is probably faster on all architectures then my division and multiplication). – Tomek Jan 20 '11 at 21:08
3

The &= solution looks best to me. If you want to make it more portable and more readable:

const int MakeEven = -2;

int number = /* magic initialization here */
// Make sure number is even
number &= MakeEven;

The second solution should be considerably faster than the first. Is it completely portable? Most likely, although there's probably some computer somewhere that does math differently.

This should work for positive and negative integers.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • 1
    This makes it *less* portable, not more. `~1` works with both sign-magitude and 2s complement representations, but `-2` only works with 2s complement. – caf Jan 19 '11 at 23:41
3

Use your second solution as inline function and put static assert into implementation of it to document and test that it works on platform that it is compiled on.

 BOOST_STATIC_ASSERT( (1 & ~1) == 0 );

 BOOST_STATIC_ASSERT( (-1 & ~1) == -2 );
Öö Tiib
  • 10,809
  • 25
  • 44
2

Your second solution only works if your sign representation is "two's complement" or "sign and magnitude". To do it in place I'd go with suszterpatt's variant, which should (almost) always work

number -= (number % 2);

You don't know for sure in which direction this will "round" for negative values, so in extreme cases you might have an underflow.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • It seems to me that it would always round down. Which means it could *underflow*. (note: integers in two's complement would never underflow because the largest negative number is always even). – João Portela Jan 20 '11 at 10:40
  • @João, AFAIR, modulo of a negative integer may be positive or negative. For your remark on the minimum value, no unfortunately the value with sign bit 1 and otherwise zeros must not be necessarily be chosen by the compiler implementor as the smallest negative number. It may be a so-called trap representation. But you are right for the underflow versus overflow. I'll correct my answer accordingly. – Jens Gustedt Jan 20 '11 at 12:08
  • I stand corrected, I was not aware that the result of the modulo operation was implementation dependent. Can you provide an example of when the smallest integer represented in 2 complement would not be even? - seems like I only got 1 out of 3 right :p – João Portela Jan 20 '11 at 14:42
  • No, I don't know of any compiler platform implementation that has this, this is probably only a theoretical possibility. But the standard explicitly allows that, so I guess at least historically there must have been one :) – Jens Gustedt Jan 20 '11 at 15:00
-1
even_integer = (any_integer >> 1) << 1;

This solution achieves the goal in the most performant way compared to the other suggested solutions. In general, bitwise shift is the cheapest possible operation. Some compilers generate the same assembly for "number = (number / 2) * 2" as well but that is not guaranteed on all target platforms and programming languages.

MFA
  • 1
  • 2
  • 2
    Please add an explanation why this is better than the existing answers – Michael Kotzjan May 19 '21 at 12:19
  • Because of the performance! Bitwise shift costs almost nothing compared to division and multiplication. – MFA May 20 '21 at 14:00
  • I just used `gcc -O3 -S` to compare your answer to the accepted one. They both resulted in the same assembler code. Since this is an answer to an old question with an already accepted answer you should always add some more explanations to your answer for future readers to understand why your answer might be better :) – Michael Kotzjan May 21 '21 at 04:39
  • In the main question, no programming language or platform is mentioned. In genral, bitwise shift is the cheapest possible operation. If your compiler generates the same assembly for both, for the language and target platform you used, doesn't mean that's the case for all languages and platforms (JavaScript for example) – MFA May 21 '21 at 17:35
  • And that is exactly what you should add to your answer to make it a truly great answer :) – Michael Kotzjan May 23 '21 at 14:28
-4

The following approach is simple and requires no multiplication or division.

number = number & ~1;

or

number = (number + 1) & ~1;
Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 1
    So increment it if it's not. I thought that part was obvious! – Jonathan Wood Jan 19 '11 at 19:00
  • 1
    You still missed the question. OP has a way to check for evenness (and indeed increments in that case) but ask how this compares to bitwise and-trickery. –  Jan 19 '11 at 19:04