我正在为具有快速整数运算的微处理器编写代码,并且没有那么快浮点运算。我需要将整数除以1到9之间的数字,并将结果转换回整数。
我制作了一个浮点数组,其成员包括0,1,0.5,0.3333等。 但我认为除了(1/3)之外的数字还有MAGIC常量(如0x55555556)。
这是什么数字?
答案 0 :(得分:4)
如果微控制器上的除法指令足够快,请使用它。如果你需要结果的小数部分,你可以使用余数;在大多数体系结构中,除法指令将商置于一个寄存器中,将余数置于另一个寄存器中。
如果你的除法指令不够快但是乘法指令是,你可以使用以下技术(听起来好像这是你所追求的技术)。在大多数体系结构中,将32位数乘以另一个32位数会产生64位结果;更重要的一半存储在一个寄存器中,而较不重要的一半存储在另一个寄存器中。您可以通过实现通过数字n的除法与乘以(2 ^ 32)/ n相同,然后获取结果的更重要的32位来利用这一点。换句话说,如果你想除以3,你可以乘以0x100000000 / 3 = 0x55555555,然后取结果的更重要的32位。
你在这里做的实际上是一种定点运算。有关详细信息,请查看Wikipedia article。
答案 1 :(得分:1)
我假设,基于微控制器标签,您没有快速整数除法。我的答案也是无符号值 - 它适用于有符号值,你只需要限制下面棘手位中使用的数字。
一个好的开始是除以2,4和8.这些可以分别通过1,2和3位的右移来完成,假设你的CPU有一个逻辑右移指令。
其次,除以1只是按原样保持数字。刚离开,3,5,6,7和9。
Tricky位从这里开始:
对于其他数字,您可以使用以下事实:可以用乘法和移位替换除法。
假设你有一个16位处理器。要除以N,则乘以256 / N并向右移8位:
N = 3, multiply by 85
N = 5, multiply by 51
N = 6, multiply by 43
N = 7, multiply by 37
N = 9, multiply by 28
以72/5的随机示例为例。乘以72乘51得到3672然后向右移8位得到14。
为了使其正常工作,您使用的数字不得溢出16位。由于你的最坏情况是乘以85,你可以处理最多771的数字。
这是有效的原因是因为8位的右移与除以256相同,并且:
m * (256 / n) / 256
= m / (n / 256) / 256
= m / n * 256 / 256
= m / n * (256 / 256)
= m / n
如果你有一个32位处理器,值和范围会有所改变,因为它是65536 / N:
N = 3, multiply by 21,846, right shift 16 bits, max value roughly 196,600.
N = 5, multiply by 13,108.
N = 6, multiply by 10,923.
N = 7, multiply by 9,363.
N = 9, multiply by 7,282.
再次,让我们选择随机20,000 / 7:20,000乘以9,363是187,260,000,当你右移16位时,你得到2,857 - 实际结果是2,857。
C中的以下测试程序显示给定值的准确度数字。它使用有符号值,因此最高可达98,000,但您可以看到最大误差为1,它出现在13,110的低点(仅有0.008%误差)。
#include <stdio.h>
int res[5] = {0};
int low[5] = {-1,-1,-1,-1,-1};
int da[] = {3,5,6,7,9};
int ma[] = {21846,13108,10923,9363,7282};
int main (void) {
int n, i;
for (n = 0; n < 98000; n++) {
for (i = 0; i < sizeof(da)/sizeof(da[0]); i++) {
int r1 = n / da[i];
int r2 = (n * ma[i])>>16;
int dif = abs (r1-r2);
if (dif >= 5) {
printf ("%d / %d gives %d and %d\n", n, da[i], r1, r2);
return 1;
}
res[dif]++;
if (low[dif] == -1) {
low[dif] = n;
}
}
}
for (i = 0; i < sizeof(res)/sizeof(res[0]); i++) {
printf ("Difference of %d: %6d, lowest value was %6d\n", i, res[i], low[i]);
}
return 0;
}
输出:
Difference of 0: 335874, lowest value was 0
Difference of 1: 154126, lowest value was 13110
Difference of 2: 0, lowest value was -1
Difference of 3: 0, lowest value was -1
Difference of 4: 0, lowest value was -1
答案 2 :(得分:1)
整数常数除以整数常数可以用移位和乘法的组合代替。有关详细信息,请参阅this optimization guide。对于cource来说,如果它在感兴趣的芯片上更快地运行,那么它是有用的。