Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right Shift to Perform Divide by 2 On -1

Tags:

java

algorithm

I know that I can perform divide by 2 using right shift.

For simplicity, take a 4 bit number system

-1 - 1111
-2 - 1110
-3 - 1101
-4 - 1100
-5 - 1011
-6 - 1010
-7 - 1001
-8 - 1000
7  - 0111
6  - 0110
5  - 0101
4  - 0100
3  - 0011
2  - 0010
1  - 0001
0  - 0000

If I try to perform

6 / 2 = 0110 >> 1 = 0011 = 3
-6/ 2 = 1010 >> 1 = 1101 = -3

Is valid for both +ve and -ve number

However, when come to 1

1 / 2 = 0001 >> 1 = 0000 = 0
-1/ 2 = 1111 >> 1 = 1111 = -1

Seems like there is a special case in -1, as right shift then to move it to negative infinity.

Currently, I need to put a special if check for this, as I am expecting -1 / 2 = 0.

I was wondering how do you guy handle this exception in your code? You guy put an if check?

like image 663
Cheok Yan Cheng Avatar asked Jan 27 '10 00:01

Cheok Yan Cheng


People also ask

How do you divide by 2 on a shift?

When shifting right with a logical right shift, the least-significant bit is lost and a 0 is inserted on the other end. For positive numbers, a single logical right shift divides a number by 2, throwing out any remainders.

Does shift left divide by 2?

Right shifting binary numbers would divide a number by 2 and left shifting the numbers would multiply it by 2. This is because 10 is 2 in binary.

Is shift right multiply by 2?

Just as left shifts are equivalent to multiplying a number by 2, right shifts are equivalent to dividing a number by 2. However, when we shift bits to the right, a 1 in the sign bit can represent a larger positive number rather than a smaller negative number.


3 Answers

Any negative odd number won't work. However to answer your question, if you know you can have negative numbers, just divide by 2. This is turned into a shift with a fixup by the jit/compiler.

like image 88
ergosys Avatar answered Sep 19 '22 14:09

ergosys


@Anon is technically correct.

However, it is best practice to use the / operator for division, and leave micro-optimization to the JIT compiler. The JIT compiler is capable of optimizing divisions by constants as shift/add sequences ... when this is an optimal thing to do for the execution platform.

Doing this kind of thing is (probably) a premature optimization, and it may be an anti-optimization if your code needs to run fast on multiple Java platforms.

like image 33
Stephen C Avatar answered Sep 19 '22 14:09

Stephen C


I got bored one day and profiled divides vs shifts for power of 2 stuff; thought I'd post it here for anyone interested.

On HotSpot VM 1.6 on Windows, using j /= 4 across -100000000 to 100000000 ran in about 12 seconds while using j = (j >= 0) ? j >> 2 : ~(~j+1 >> 2) + 1; ran in just 2.5s.

OpenJDK VM 1.6 on Linux got 5.5s for divides and 1.5s for shifts.

This would suggest that the JIT compiler doesn't really do anything fancy for power of 2 division.

GCC managed to optimize the division so that it was faster than the flips and shifts.

~(~j+1 >> 2) + 1 uses twos complement to flip the number positive, shift and flip it back.

long j = 0;
for (long i = -100000000; i < 100000000; i++) {
    j = i;
    j /= 4;
}
System.out.println(j);`

vs

long j = 0;
for (long i = -100000000; i < 100000000; i++) {
    j = i;
    j = (j >= 0) ? j >> 2 : ~(~j+1 >> 2) + 1;
}
System.out.println(j);`
like image 43
nik3daz Avatar answered Sep 18 '22 14:09

nik3daz