看到一种快速计算整数除255的整数除法算法
#define div_255_fast(x) (((x) + (((x) + 257) >> 8)) >> 8)
在[0,65536]的范围内误差为零。
这个算法在网上能搜到的最早记录是 @韦易笑 在csdn上的创作
【原创】快速除以255的方法_Skywind Inside-CSDN博客blog.csdn.net我来尝试给一个证明和推广。
问题的实数原型:求证:当0<=x<=65536时,
引理1:
对于y的整数解包含
。
这并不难证明,条件等价于:256y<=x+y<256(y+1)
这又等价于y<=x/255<y+1+1/255,当y是整数时,这表示
或者
。后者仅当x%255==0 。
所以这是一个不动点,仅在x是255倍数的时候可能有吸收。
令
, 我们把估计值y=a 不断地迭带入,
,
.....
注意到
小于或等于
, a初值我们就给点补偿取
。
然而实际发现这样那个吸收奇异点很影响我们,在很小的数值范围内就会发生吸收,仅仅在初值进行补偿是无法打破吸引的。。仔细观察了一下,因为本来x%255==0的地方,
就即将会发生很大变化,一吸收就完全动不了(可能还没收敛到结果)。
引理2:
对于y的整数解 包含
。
这并不难证明,条件等价于:256y<=x+1+y<256(y+1)
这又等价于y-1/255<=x/255<y+1,当y是整数时,这表示
或
。
后者仅当x%255==254 。
令
, 我们把估计值y=a 不断地迭带入,
,
.....
注意到
小于或等于
, a初值我们就给点补偿取
。
2次迭代,正确的区间为[0, 65536+253],此时就是
也就是@韦易笑 的#define div_255_fast(x) (((x) + (((x) + 257) >> 8)) >> 8) 的结果。证明完毕。
3次迭代,正确的区间为[0, 2^24+253] ,此时就是
可以写成(( x+(((x) + (((x) + 256*256+257) >> 8)) >> 8))>>8) 的结果
4 次迭代,正确的区间为[0, 0xff000000-1]。
注意254这个值会影响迭代的有效性,边界区间都最先在余数为254的值那里有问题。
原本以为很简单就能证明,没想到一开始陷入了错误的思路耽误了不少。。具体推广到别的数值就下次再聊吧。