在浏览一个帖子C 语言有什么奇技淫巧?时,无意看到一个整数除255快速算法,其算法如下:
#define div_255_fast(x) (((x) + (((x) + 257) >> 8)) >> 8)
对此算法已有人给出证明255快除算法的证明和推广,但对于我的数学水平而言,这个证明似乎比这个算法本身更难以理解。在此,仅列出自己的理解过程,且是完全不严谨的。
算法展开式如下:
x
255
=
x
2
8
+
x
255
∗
2
8
=
x
2
8
+
x
2
16
+
x
255
∗
2
16
=
x
2
8
+
x
2
16
+
x
2
24
+
x
2
32
+
x
255
∗
2
32
\frac{x}{255}=\frac{x}{2^8}+\frac{x}{255*2^8}=\frac{x}{2^8}+\frac{x}{2^{16}}+\frac{x}{255*2^{16}}=\frac{x}{2^8}+\frac{x}{2^{16}}+\frac{x}{2^{24}}+\frac{x}{2^{32}}+\frac{x}{255*2^{32}}
255x=28x+255∗28x=28x+216x+255∗216x=28x+216x+224x+232x+255∗232x
将
x
2
24
+
x
2
32
+
x
255
∗
2
32
\frac{x}{2^{24}}+\frac{x}{2^{32}}+\frac{x}{255*2^{32}}
224x+232x+255∗232x视为
x
255
−
(
x
2
8
+
x
2
16
)
\frac{x}{255}-(\frac{x}{2^8}+\frac{x}{2^{16}})
255x−(28x+216x)的误差部分,在[0,65536]的范围内,误差部分在x=65536时有最大值,该最大值为
1
2
8
+
1
2
16
+
1
255
∗
2
16
\frac{1}{2^{8}}+\frac{1}{2^{16}}+\frac{1}{255*2^{16}}
281+2161+255∗2161,不妨舍弃
1
255
∗
2
16
\frac{1}{255*2^{16}}
255∗2161取最大值为
1
2
8
+
1
2
16
\frac{1}{2^{8}}+\frac{1}{2^{16}}
281+2161,此时有:
x
255
≈
x
2
8
+
x
2
16
+
1
2
8
+
1
2
16
=
x
+
1
+
x
+
1
2
8
2
8
\frac{x}{255}\approx\frac{x}{2^8}+\frac{x}{2^{16}}+\frac{1}{2^{8}}+\frac{1}{2^{16}}=\frac{x+1+\frac{x+1}{2^8}}{2^8}
255x≈28x+216x+281+2161=28x+1+28x+1
原式得证。
我的理解是,所谓的整数除255快速算法实质上是对整数除256的误差进行找补,且找补的部分为常数。为满足[0,65536]的范围内算法成立,故应取展开式误差部分的最大值。
另外,尝试误差部分仅取
1
2
8
\frac{1}{2^{8}}
281,则算法如下:
#define div_255_fast(x) (((x) + (((x) + 256) >> 8)) >> 8)
此时,该算法在[0,65534]的范围内成立。