不使用除法运算符优化未知分母的划分

时间:2013-06-12 14:02:51

标签: integer-division

我正在尝试编写一个在运行时执行以下计算的C函数:

分子/分母

其中:

分子是先前的计算结果,总是正数,并且大于分母

分母是这样的(1 <= Denominator&lt; = 64)。

运行时计算必须快速,即最少的周期,因此除法运算符是不可能的。我已经看过递归减法和按位长除法,但我试图找到另一种解决方案。

任何帮助?

2 个答案:

答案 0 :(得分:1)

这是一个想法,它使用一个乘法和一个移位,因此它在大多数系统上比分割更快。由于你的分子在768,000,000~ = 30位时最高,我们在32位字中没有多少空间,所以我们必须使用64位乘法。

主要想法是利用以下事实:

x / y == (x * k) / (y * k)

除以2的幂是一个简单,快速的位移。

所以,为了选择一个特定的例子,假设x = 700,000,000y = 47(所以正确的商是14,893,617)。为了避免舍入误差,我们的偏移需要大约是我们最大可能分子的大小--30位。找到k的值,该值最接近y * k = 2^30,在这种情况下为k = 22845571。然后是x * k = 0x38D08C4CE6F500。将此值移位30位得出0xE34231 = 14,893,617,即我们的预期商。对于某些分子/分母组合,您可能需要再添加1-2位以进行舍入,除非在您的商中被1除掉是可以接受的。

然后,练习将创建一个查找表,其中包含每个可能分母的正确乘数。

编辑:正如下面的评论所指出的,选择k = (2^30 + y - 1) / y应该提供比k = round(2^30 / y)更好,更一致的结果。

答案 1 :(得分:0)

Big @ss表适用于小数字:

unsigned int divTable[kMaxNumerator][64] = {...}

你把每个可能的鸿沟的价值放在那里。在某些尺寸之上不太实用,但它确实适用于包含的情况,并且是当天的纹理映射的常见解决方案:)然后我读了你的评论,看到你在768,000,000范围内,这是因为完全不切实际,除非你可以处理相当多的精确损失。