Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does this approximation of division using bit shift operations work?

In java.util.DualPivotQuicksort, the following line of code appears:

// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1; 

The variable length is an int greater than or equal to 47.

I am familiar with how the signed right shift operator works. But I do not know why these particular operations result in an approximation of division by 7. Could someone explain please?

like image 958
RCB Avatar asked Oct 11 '15 09:10

RCB


People also ask

How do you use bit shifts to divide?

Division. To divide a number, a binary shift moves all the digits in the binary number along to the right and fills the gaps after the shift with 0: to divide by two, all digits shift one place to the right. to divide by four, all digits shift two places to the right.

How does bitwise shift operator work?

The bitwise shift operators are the right-shift operator ( >> ), which moves the bits of an integer or enumeration type expression to the right, and the left-shift operator ( << ), which moves the bits to the left.

Is bit shifting the same as dividing?

Bitshifting shifts the binary representation of each pixel to the left or to the right by a pre-defined number of positions. Shifting a binary number by one bit is equivalent to multiplying (when shifting to the left) or dividing (when shifting to the right) the number by 2.

How does bitwise left shift operator work?

The bitwise shift operators move the bit values of a binary object. The left operand specifies the value to be shifted. The right operand specifies the number of positions that the bits in the value are to be shifted.


2 Answers

>> is bitshift. Every bit you shift right, in effect divides the number of 2.

Therefore, (length >> 3) is length/8 (rounded down), and (length >> 6) is length/64.

Take (length/8)+(length/64) is approximately length*(1/8+1/64) = length*0.140625 (approximately)

1/7 = 0.142857...

The +1 at the end can be split into +0.5 for each term, so that length/8 is rounded to nearest (instead of down), and length/64 is also rounded to nearest.


In general, you can easily approximate 1/y, where y = 2^n+-1 with a similar bit-shift approximation.

The infinite geometric series is:

1 + x + x^2 + x^3 + ... = 1 / (1 - x)

Multiplying by x:

x + x^2 + x^3 + ... = x/(1 - x)

And substituting x = 1/2^n

1/2^n + 1/2^2n + 1/2^3n + ... = (1/2^n) / (1 - 1/2^n)
1/2^n + 1/2^2n + 1/2^3n + ... = (1/2^n) / ((2^n - 1)/2^n)

1/2^n + 1/2^2n + 1/2^3n + ... = 1 / (2^n - 1)

This approximates y = 2^n - 1.

To approximate y = 2^n + 1, substitute x = -1/2^n instead.

- 1/2^n + 1/2^2n - 1/2^3n + ... = (-1/2^n) / (1 + 1/2^n)
1/2^n - 1/2^2n + 1/2^3n - ... = (1/2^n) / ((2^n + 1)/2^n)

1/2^n - 1/2^2n + 1/2^3n - ... = 1 / (2^n + 1)

Then just truncate the infinite series to the desired accuracy.

like image 130
ronalchn Avatar answered Oct 27 '22 01:10

ronalchn


Set x = 1/8 in the well-known equality

1 + x + x^2 + x^3 + ... = 1 / (1 - x)

and simplify, to give

1/8 + 1/64 + 1/512 + ...  = 1/7

Multiply both sides of this by length in your example, to give

length / 7 = length / 8 + length / 64 + length / 512 + ...

Note that this is "exact" division, not integer division - I'm writing mathematics, not Java code.

Then the approximation assumes that the third and subsequent terms will be too small to matter, and that on average one of length / 8 and length / 64 is likely to need rounding up, rather than rounding down. So, now using integer division, length / 7 = length / 8 + length / 64 + 1 is a very good approximation.

The expression you gave, using bitwise operators, is just an alternative way of writing this, provided length is positive.

like image 25
Dawood ibn Kareem Avatar answered Oct 27 '22 01:10

Dawood ibn Kareem