I'd consider looking at the sign bit cheating, as it's basically the same thing the processor does for <.
–
starblueJan 23 '11 at 9:08

4

For C++ at least, from 5.8.3, discussing E1 >> E2: "If E1 has a signed type and a negative value, the resulting value is implementation-defined.", so "c >> 31" may or may not shift a sign bit from the most- to least-significant bit....
–
Tony DJan 23 '11 at 16:15

15 Answers
15

Let's dissect this. This first line is straightforward - it stores the difference of a and b. This value is negative if a < b and is nonnegative otherwise.

In the next line:

int k = (c >> 31) & 0x1;

the idea is to check if the value of c is negative. In virtually all modern computers, numbers are stored in a format called two's complement in which the highest bit of the number is 0 if the number is positive and 1 if the number is negative. Moreover, most ints are 32 bits. (c >> 31) shifts the number down 31 bits, leaving the highest bit of the number in the spot for the lowest bit. The next step of taking this number and ANDing it with 1 (whose binary representation is 0 everywhere except the last bit) erases all the higher bits and just gives you the lowest bit. Since the lowest bit of c >> 31 is the highest bit of c, this reads the highest bit of c as either 0 or 1. Since the highest bit is 1 iff c is 1, this is a way of checking whether c is negative (1) or positive (0). Combining this reasoning with the above, k is 1 if a < b and is 0 otherwise.

The final step is to do this:

int max = a - k * c;

If a < b, then k == 1 and k * c = c = a - b, and so

a - k * c = a - (a - b) = a - a + b = b

Which is the correct max, since a < b. Otherwise, if a >= b, then k == 0 and

@templatetypedef, suppose a = 0x80000000 (the min value of an int) and b = 1. What is c?
–
Peter TaylorJan 23 '11 at 7:52

3

@Peter Taylor- That's a good point. Note that I didn't come up with this answer; I was just explaining the OP's code. :-) But you are correct that this will break if the numbers are too far apart.
–
templatetypedefJan 23 '11 at 7:53

1

@templatetypedef, I know: I was partway through writing a very similar answer when you posted yours. I was just pointing it out for the benefit of OP.
–
Peter TaylorJan 23 '11 at 7:58

3

@Ani, the top bit is shifted into every position it passes through. The alternative would be max = a + (c >> 31) * c
–
Peter TaylorJan 23 '11 at 8:00

@mike.did: Can you do |a - b| without any conditionals?
–
templatetypedefJan 23 '11 at 7:52

5

It's kind of a stretch to assume that absolute value is an operator which can be used for this problem. It's a good answer, mathematically, but I doubt it would be accepted.
–
Keith IrwinJan 23 '11 at 7:56

This is based on the same technique as mikedld's solution above, but it is less "obvious" here what I am doing. An "abs" operation looks like you are comparing the sign of something but I here am taking advantage of the fact that sqrt() will always return you the positive square root so I am squaring (a-b) writing it out in full then square-rooting it again, adding a+b and dividing by 2.

You will see it always works: eg the user's example of 10 and 5 you get sqrt(100 + 25 - 100) = 5 then add 10 and 5 gives you 20 and divide by 2 gives you 10.

Here's how I think I'd do the job. It's not as readable as you might like, but when you start with "how do I do X without using the obvious way of doing X, you have to kind of expect that.
In theory, this gives up some portability too, but you'd have to find a pretty unusual system to see a problem.

This does have some advantages over the one shown in the question. First of all, it calculates the correct size of shift, instead of being hard-coded for 32-bit ints. Second, with most compilers we can expect all the multiplication to happen at compile time, so all that's left at run time is trivial bit manipulation (subtract and shift) followed by a load and return. In short, this is almost certain to be pretty fast, even on the smallest microcontroller, where the original used multiplication that had to happen at run-time, so while it's probably pretty fast on a desktop machine, it'll often be quite a bit slower on a small microcontroller.

k is 32nd bit of c which is the sign bit of c (assuming 32 bit integers. If done on a platform with 64 bit integers, this code will not work). It's shifted 31 bits to the right to remove the rightmost 31 bits leaving the sign bit in the right most place and then anding it with 1 to remove all the bits to the left (which will be filled with 1s if c is negative). So k will be 1 if c is negative and 0 if c is positive.

Then max = a - k * c. If c is 0, this means a>=b, so max is a - 0 * c = a. If c is 1, this means that a<b and then a - 1 * c = a - (a - b) = a - a + b = b.

In the overall, it's just using the sign bit of the difference to avoid using greater than or less than operations. It's honestly a little silly to say that this code doesn't use a comparison. c is the result of comparing a and b. The code just doesn't use a comparison operator. You could do a similar thing in many assembly codes by just subtracting the numbers and then jumping based on the values set in the status register.

I should also add that all of these solutions are assuming that the two numbers are integers. If they are floats, doubles, or something more complicated (BigInts, Rational numbers, etc.) then you really have to use a comparison operator. Bit-tricks will not generally do for those.

If b > a then (a-b) will be negative, sign will return -1, by adding 1 we get index 0 which is b, if b=a then a-b will be 0, +1 will give 1 index so it does not matter if we are returning a or b, when a > b then a-b will be positive and sign will return 1, adding 1 we get index 2 where a is stored.

The logic described in a problem can be explained as if 1st number is smaller then 0 will be subtracted else difference will be subtracted from 1st number to get 2nd number.
I found one more mathematical solution which I think is bit simpler to understand this concept.

Considering a and b as given numbers

c=|a/b|+1;
d=(c-1)/b;
smallest number= a - d*(a-b);

Again,The idea is to find k which is wither 0 or 1 and multiply it with difference of two numbers.And finally this number should be subtracted from 1st number to yield the smaller of the two numbers.
P.S. this solution will fail in case 2nd number is zero