2

Question

I was impressed by tricks like the xor-swap algorithm and similar. So I asked myself, is it possible to assign a variable a value, but only if the value is positive - without using any sort of if or hidden conditionals; just pure math.

Alternative

Basically, this but without the if:

int a = ...
int b = ...

if (b >= 0) {
    a = b;
}

Examples

Here are some example input/output setups to illustrate the desired logic:

a = 1, b = 10 -> a = 10 // b is positive
a = 1, b = 0 -> a = 0   // b is 0, also positive
a = 1, b = -10 -> a = 1 // b is negative
Zabuzard
  • 25,064
  • 8
  • 58
  • 82

1 Answers1

4

tl;dr

int a = ...
int b = ...

int isNegative = b >>> 31;       // 1 if negative, 0 if positive
int isPositive = 1 - isNegative; // 0 if negative, 1 if positive
a = isPositive * b + isNegative * a;

Signum


An easy way to achieve the task is to try to aquire some sort of signum, or more specifically a way to get a factor of

  • either 0, if b is positive
  • or 1 if b is negative, or vice-versa.

Now, if you take a look at how int is represented internally with its 32-bits (this is called Two's complement):

// 1234
00000000 00000000 00000100 11010010
// -1234
11111111 11111111 11111011 00101110

You see that it has the so called sign-bit on the very left, the most-significant-bit. Turns out, you can easily extract that bit with a simple bit-shift that just moves the whole bit-pattern 31 times to the right, only leaving the 32-th bit, i.e. the sign-bit:

int isNegative = b >>> 31; // 1 if negative, 0 if positive

Now, to get the opposite direction, you simply negate it and add 1 on top of it:

int isPositive = 1 - isNegative; // 0 if negative, 1 if positive

Annihilator and Identity

Once you have that, you can easily construct your desired value by exploiting the fact that

  • multiplication with 0 basically erases the argument (0 is an annihilator of *)
  • and addition with 0 does not change the value (0 is an identity element of +).

So, coming back to the logic we want to achieve in the first place:

  • we want b if b is positive
  • and we want a if b is negative

Hence, we just do b * isPositive and a * isNegative and add them together:

a = isPositive * b + isNegative * a;

Now, if b is positive, you will get:

a = 1 * b + 0 * a
  = b + 0
  = b

and if it is negative, you will get:

a = 0 * b + 1 * a
  = 0 + a
  = a

Other datatypes

The same approach can also be applied to any other signed data type, such as byte, short, long, float and double.

For example, here is a version for double:

double a = ...
double b = ...

long isNegative = Double.doubleToLongBits(b) >>> 63;
long isPositive = 1 - isNegative;
a = isPositive * b + isNegative * a;

Unfortunately, in Java you can not use >>> directly on double (since it usually also makes no sense to mess up the exponent and mantissa), but therefore you have the helper Double#doubleToLongBits which basically reinterprets the double as long.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82