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?
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.
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.
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.
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.
>>
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With