这种使用移位运算的除法近似是如何工作的?
How does this approximation of division using bit shift operations work?
在java.util.DualPivotQuicksort
中出现如下代码行:
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
变量 length
是一个大于或等于 47 的 int
。
我熟悉有符号右移运算符的工作原理。但是我不知道为什么这些特定的操作会导致除以 7 的近似值。有人可以解释一下吗?
>>
是位移位。你右移的每一位,实际上除以 2 的数。
因此,(length >> 3)
是length/8
(四舍五入),(length >> 6)
是length/64
。
取(length/8)+(length/64)
约length*(1/8+1/64)
=length*0.140625
(约)
1/7 = 0.142857...
末尾的+1
可以拆分为每个term的+0.5
,这样length/8
四舍五入到最接近的(而不是向下),而length/64
也四舍五入到最接近的值。
一般来说,您可以很容易地近似 1/y
,其中 y = 2^n+-1
使用类似的位移近似。
无限几何级数为:
1 + x + x^2 + x^3 + ... = 1 / (1 - x)
乘以 x:
x + x^2 + x^3 + ... = x/(1 - x)
并代入 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)
这大约是 y = 2^n - 1
。
要近似 y = 2^n + 1
,请替换为 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)
然后将无限级数截断到所需的精度。
要为 ronalchn 的回答添加数学背景:
因为7=8-1=8*(1-1/8),按几何级数除以7等同于乘以
1/7 = 1/8·(1+1/8+1/8²+1/8³+…) = 1/8+1/8²+1/8³+…
要对除以 5 做同样的事情,可以使用 3·5=16-1,因此
1/5 = 3/16·(1+1/16+1/16²+…)
这会邀请像
这样的公式
(3*n)<<4 + (3*n) << 8 + 1
在众所周知的等式
中设置x = 1/8
1 + x + x^2 + x^3 + ... = 1 / (1 - x)
并简化,得到
1/8 + 1/64 + 1/512 + ... = 1/7
在您的示例中,将此两边乘以 length
,得到
length / 7 = length / 8 + length / 64 + length / 512 + ...
请注意,这是 "exact" 除法,而不是整数除法 - 我在写数学,而不是 Java 代码。
然后近似假设第三项和后续项太小而无关紧要,并且 length / 8
和 length / 64
中的一项平均可能需要向上舍入,而不是向下舍入.所以,现在使用整数除法,length / 7 = length / 8 + length / 64 + 1
是一个非常好的近似值。
你给出的表达式,使用按位运算符,只是另一种写法,前提是 length
是正数。
正在计算
的所有值
n/8 + n/64 - n/7
误差呈线性增长,同时保持负值。
下面的列表显示给定错误的第一次出现
n = 7 e = -1
n = 63 e = -2
n = 511 e = -3
n = 959 e = -4
n = 1407 e = -5
n = 1855 e = -6
n = 2303 e = -7
n = 2751 e = -8
n = 3199 e = -9
n = 3647 e = -10
n = 4095 e = -11
n = 4543 e = -12
n = 4991 e = -13
n = 5439 e = -14
n = 5887 e = -15
n = 6335 e = -16
n = 6783 e = -17
n = 7231 e = -18
n = 7679 e = -19
n = 8127 e = -20
n = 8575 e = -21
n = 9023 e = -22
n = 9471 e = -23
n = 9919 e = -24
...
比例明显趋向于1/448 = 1/8 + 1/64 - 1/7
。
在java.util.DualPivotQuicksort
中出现如下代码行:
// Inexpensive approximation of length / 7
int seventh = (length >> 3) + (length >> 6) + 1;
变量 length
是一个大于或等于 47 的 int
。
我熟悉有符号右移运算符的工作原理。但是我不知道为什么这些特定的操作会导致除以 7 的近似值。有人可以解释一下吗?
>>
是位移位。你右移的每一位,实际上除以 2 的数。
因此,(length >> 3)
是length/8
(四舍五入),(length >> 6)
是length/64
。
取(length/8)+(length/64)
约length*(1/8+1/64)
=length*0.140625
(约)
1/7 = 0.142857...
末尾的+1
可以拆分为每个term的+0.5
,这样length/8
四舍五入到最接近的(而不是向下),而length/64
也四舍五入到最接近的值。
一般来说,您可以很容易地近似 1/y
,其中 y = 2^n+-1
使用类似的位移近似。
无限几何级数为:
1 + x + x^2 + x^3 + ... = 1 / (1 - x)
乘以 x:
x + x^2 + x^3 + ... = x/(1 - x)
并代入 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)
这大约是 y = 2^n - 1
。
要近似 y = 2^n + 1
,请替换为 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)
然后将无限级数截断到所需的精度。
要为 ronalchn 的回答添加数学背景:
因为7=8-1=8*(1-1/8),按几何级数除以7等同于乘以
1/7 = 1/8·(1+1/8+1/8²+1/8³+…) = 1/8+1/8²+1/8³+…
要对除以 5 做同样的事情,可以使用 3·5=16-1,因此
1/5 = 3/16·(1+1/16+1/16²+…)
这会邀请像
这样的公式(3*n)<<4 + (3*n) << 8 + 1
在众所周知的等式
中设置x = 1/8
1 + x + x^2 + x^3 + ... = 1 / (1 - x)
并简化,得到
1/8 + 1/64 + 1/512 + ... = 1/7
在您的示例中,将此两边乘以 length
,得到
length / 7 = length / 8 + length / 64 + length / 512 + ...
请注意,这是 "exact" 除法,而不是整数除法 - 我在写数学,而不是 Java 代码。
然后近似假设第三项和后续项太小而无关紧要,并且 length / 8
和 length / 64
中的一项平均可能需要向上舍入,而不是向下舍入.所以,现在使用整数除法,length / 7 = length / 8 + length / 64 + 1
是一个非常好的近似值。
你给出的表达式,使用按位运算符,只是另一种写法,前提是 length
是正数。
正在计算
的所有值n/8 + n/64 - n/7
误差呈线性增长,同时保持负值。
下面的列表显示给定错误的第一次出现
n = 7 e = -1
n = 63 e = -2
n = 511 e = -3
n = 959 e = -4
n = 1407 e = -5
n = 1855 e = -6
n = 2303 e = -7
n = 2751 e = -8
n = 3199 e = -9
n = 3647 e = -10
n = 4095 e = -11
n = 4543 e = -12
n = 4991 e = -13
n = 5439 e = -14
n = 5887 e = -15
n = 6335 e = -16
n = 6783 e = -17
n = 7231 e = -18
n = 7679 e = -19
n = 8127 e = -20
n = 8575 e = -21
n = 9023 e = -22
n = 9471 e = -23
n = 9919 e = -24
...
比例明显趋向于1/448 = 1/8 + 1/64 - 1/7
。