6
for (unsigned int i = 1; i <= 100; i++) {
    if (i & 0x00000001) {
        std::cout << i<<",";
    }
}

why does (and how): if( i & 0x00000001 ) figure out the odd number?

sbi
  • 219,715
  • 46
  • 258
  • 445
Tom
  • 217
  • 1
  • 5
  • 10
  • Usually it's written `i & 0x00000001`, with a space between bitwise and (`&`) and the operand. – xtofl Sep 22 '09 at 18:45
  • 16
    you know, i & 1 does the trick too.. – ypnos Sep 22 '09 at 18:53
  • does it make a difference? whether there's a space or not? (just asking) – Tom Sep 22 '09 at 18:55
  • It doesn't make a difference, no. – Dan Olson Sep 22 '09 at 18:58
  • Is there any reason this would be 'better' than doing "if (! i%2)"? – nilamo Sep 22 '09 at 19:21
  • @nilamo - Unless the compiler automatically changes !i%2 to the bitwise operation, I imagine the bitwise compare uses less machine instructions. – ericp Sep 22 '09 at 19:41
  • 4
    But then if you were to optimize it changing `i++` to `i+=2` and removing condition would do much better ;-) – Michael Krelin - hacker Sep 22 '09 at 20:40
  • I guess you would need !(i%2) – erikkallen Sep 22 '09 at 21:09
  • @nilamo: not really. In general, the `%` operator tends to be slower than the `&` operator, so you'd use `&` in cases where either is fine. For this case, though, a C or C++ compiler which didn't replace `% 2` with `& 1` under the hood needs taking out and shooting. Might be worth knowing that cpython does *not* perform such optimisations, though, and obviously fully-interpreted languages don't either. – Steve Jessop Sep 23 '09 at 00:54

9 Answers9

23

0x00000001 is 1 in binary, although it's written in hexadecimal (base-16) notation. That's the 0x part.

& is the bit-wise 'AND' operator, which is used to do binary digit (bit) manipulations.

i & 1 converts all of the binary digits of i to zero, except for the last one.

It's straightforward to convert the resulting 1-bit number to a boolean, for evaluation by the if statement.

The following chart shows the last 16 binary digits of i, and what happens to them.

i:   i in binary:        i & 1 in binary:    convert to boolean
---- ------------------- ------------------- ---------------------
1    0000000000000001    0000000000000001    true
2    0000000000000010    0000000000000000    false
3    0000000000000011    0000000000000001    true
4    0000000000000100    0000000000000000    false
5    0000000000000101    0000000000000001    true
6    0000000000000110    0000000000000000    false
7    0000000000000111    0000000000000001    true
8    0000000000001000    0000000000000000    false
...  ...                 ...                 ...
99   0000000001100011    0000000000000001    true
100  0000000001100100    0000000000000000    false
Fred Larson
  • 60,987
  • 18
  • 112
  • 174
system PAUSE
  • 37,082
  • 20
  • 62
  • 59
  • is this working only for integers, or does this work for floats too? it got me thinking, because floats are stored differently in memory, but using the modulo operator they are casted to ints, with bitwise `and` there is no cast. – knittl Sep 22 '09 at 21:46
  • You can't apply bitwise operators to floating-point numbers as they are represented in a platform-specific format and the most commonly-used format does not lend itself well to bitwise operations. – coppro Sep 22 '09 at 21:56
  • you can’t? so this will result in an compiler error? or just in unspecified behavior? – knittl Sep 23 '09 at 07:39
  • It will be unspecified behaviour. Feel free to post another question about finding odd numbers for floating-point types. :) – system PAUSE Sep 23 '09 at 14:56
  • @Fred, thanks for the fix. It was a copy-paste bug, and I didn't have any unit tests to verify it. :( – system PAUSE Sep 23 '09 at 14:57
  • Not sure I'd call the LSBit "the last one" – Asteroids With Wings Jan 28 '21 at 19:14
  • @AsteroidsWithWings, I can see your perspective: "least significant bit" would certainly be more precise in this context. However, it's a mouthful, and might unnecessarily prompt another question. I try in some answers to find a balance between using plain, common vocabulary vs. domain-specific vocabulary, based on the phrasing of the question, to deliver an answer most efficiently. In this case, common language wins, since "the last one" in a natural left-to-right reading of the digits is accurate enough to get the point across. – system PAUSE Feb 07 '21 at 00:23
21

It's using a bitwise "and" operator to mask off all but the last bit. If the last bit is a 1, the number is odd. Is that enough explanation?

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
  • 4
    +1, I personally would also love to hear some explanation for using sesquipedalian notation instead of `1` ;-) – Michael Krelin - hacker Sep 22 '09 at 18:44
  • 6
    (To original poster) If you don't understand this Answer, which is correct, try changing 5 even numbers and 5 odd numbers to binary. Observe what happens on the last bit and how that relates to the number you transformed. (More specifically, look at what happens when the number is even and when the number is odd). Read up on bitwise AND as well – Malaxeur Sep 22 '09 at 18:45
  • @hacker: "Sesquipedalian" = "one who uses long words". Is that what you meant? – Michael Myers Sep 22 '09 at 18:46
  • so 0x00000001 is 8 bits, and int is 4 bytes which is 32 bits..so it still works..I can see if works, I was just not sure.. – Tom Sep 22 '09 at 18:48
  • No...it's a hexidecimal number, in other words, base-16. So each value represents four bits (and can be 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F). 0x00000001 is eight hex digits, which means 32 bits, which means 4 bytes, which is the size of an int (usually). You could have also used (i & 1) or (i & 0x1), but when you're doing bit manipulation it's usually better to write out the full set of bits (i.e. 0x00000001 or 0xFFFF0000 or the like) in order to make it clearer what you are doing. – jprete Sep 22 '09 at 18:54
  • mmyers, sesquipedalian means foot and a half long, the word Horace used to refer to *long words themselves* — *sesquipedalia verba*. Incidentally, I also referred to notation which is approximately foot and a half long. – Michael Krelin - hacker Sep 22 '09 at 19:06
  • 1
    Malaxeur, nice scientific approach. Next step would to prove that all odd numbers are prime numbers as well. Just check it for 3, 5 and 7 ;-) – Michael Krelin - hacker Sep 22 '09 at 19:08
13

When we look at numbers in base 10, it's easy to tell if a number is divisible by 10: it has a 0 in the last position. The code above looks at the digit in the last position as well, but in base 2. If it's non-zero, the number is not divisible by 2.

rlbond
  • 65,341
  • 56
  • 178
  • 228
10

It masks off the last bit. If you look at each place in the binary representation of a number (..., 256, 128, 64, 32, 16, 8, 4, 2, and 1), you'll notice that only the one's place is odd. All the rest of the places have an even value whether the bits are set or cleared (zero being even). And adding even numbers will always give an even number. Only that last one's place determines the parity of the number. The i & &0x00000001 part just isolates that last one's place.

Boojum
  • 6,592
  • 1
  • 30
  • 34
3

You are doing bitwise comparison. The if bit0 AND bit0 are both 1, then the answer's bit0 = 1.

Seeing that &0x00000001 is 1, any numbers with this bit are odd.

0x00000001 = 1
0x00000010 = 2
0x00000011 = 3
etc.

So, if you do a bitwise AND

00000001 AND 
00000001 = 
00000001 (same as true)

00000010 AND 
00000001 = 
00000000 (same as false)

00000011 AND 
00000001 = 
00000001 (same as true)

etc
ericp
  • 611
  • 2
  • 11
  • 17
3

Odd numbers are all numbers of the form (2*n+1) where n is any integer (-2,-1,0,1....). So to find an odd number you have to see if the integer you're working with has that '+1' on it. When stored as an unsigned integer, a number can be expressed as the sum of powers of 2: 2^0 + 2^1 +2^2 + 2^4, etc. The binary version of the unsigned integer looks like a truth map of sorts: for every place there's a '1' in the binary number, add that power of two to the number. So, if you start at the right most digit in the binary representation of the unsigned integer and move left, each digit represents a power of two. If the digit is 1 then you add that power of two to the running sum and when you reach the end of the binary number.

Thus: 10001110b can be converted into an integer by summing the powers of two:

Rightmost: 2^1 + 2^2 + 2^3 + 2^7 :Leftmost = 141

The trick is that the rightmost digit represents 2^0. This is always 1. All the other digits represent even numbers. So, in terms of odd numbers you have to find the '+1'. That corresponds to the rightmost digit. All the other digits represent numbers of the form '2*n'. Therefore, to determine if a number of this format (unsigned integer) is odd you need only see if the right most bit is '1'.

The operation performed on the unsigned integer is a logical AND operation. Anything AND'd with 0 is 0, and 1 AND'd with 1 is 1. So the operation will cause all binary digits in the unsigned integer representation to be 0 except for the binary digit representing 2^0 (which is 1). So the unsigned integer binary representation will boil down to 0x00000001 if it's odd and 0x00000000 if it's even.

Note: When I write 0x00000000, the '0x' means that it's hexadecimal format. Each '0' represents four bits. So 0x00 is hexadecimal for 00000000b Written out in binary, the resulting possible unsigned integer binary representations after AND'ing the unsigned integer are:

00000000000000000000000000000000b == 0 and 00000000000000000000000000000001b == 1

Stephen Friederichs
  • 1,029
  • 6
  • 12
2

Before I say the following, I'll first say that I pretty much always use the bit test to determine whether an int is odd or even.

But, strictly speaking, you should use (i % 2) or ((i % 2) != 0) to determine is i is odd. This will work regardless of the represenation of negative numbers, while on a one's complement machine (-3 & 0x01) will return zero (a false result) even though clearly it's odd.

I realize that machiens that use something other than two's complement to represent negative number are very,very rare nowadays, but it's also true that compilers nowadays will universally compile (i % 2) to a bit test anyway. And remember, I usually don't follow my own advice here, so that's might be an indication of the true value of this suggestion.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

The bitwise AND operator follows this truth table for every bit:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

Since computers work with numbers in base 2 and each bit represents a power of two value (1,2,4,8,16 ..),
the least significant bit represents the only odd number, regardless how big or small the value is, and regardless whether it is signed or unsigned. Since the resulting bit is only set if both operands have that bit set, the result is true if and only if the number is odd.

Example: 0b11101011 =
(1 * 2^0) + (1 * 2^1) + (0 * 2^2) + (1 * 2^3) +
(0 * 2^4) + (1 * 2^5) + (1 * 2^6) + (1 * 2^7) =
1 + 2 + 0 + 8 + 0 + 32 + 64 + 128 = 235
Without the least significant bit set, the value would be 234 and hence an even number.

0

For Example how we make a Binary Equivalent

8 4 2 1

0 0 0 0 = 0

0 0 0 1 = 1

0 0 1 0 = 2

0 0 1 1 = 3

So you can see for any odd no. LSB is always set , Same you check :)

I hope my answer is clear

Satbir
  • 6,358
  • 6
  • 37
  • 52