是否有可能使浮子分裂的倒数在查找表的形式(例如象的1 / f - > 1个* INV并[f])? 如何才能做到? 我觉得有些掩码和移位,应appled浮动,使其索引的一种形式? 如何将它exectly?
Answer 1:
你能猜到这样的一个近似逆:
int x = reinterpret_cast<int>(f);
x = 0x7EEEEEEE - x;
float inv = reinterpret_cast<float>(x);
在我的测试中,0x7EF19D07稍好(与2牛顿迭代改进包括影响进行测试)。
然后你就可以用牛顿迭代改进:
inv = inv * (2 - inv * f);
往往你想迭代。 2或3次迭代得到好的结果。
更好的初始逼近
为了尽量减少相对误差:
- 0x7EF311C2(没有细化)
- 0x7EF311C3(1个细化)
- 0x7EF312AC(2个精炼)
- 0x7EEEEBB3(3个精炼)
为了尽量减少对1和2之间输入的绝对误差(它们工作不够好该范围之外,但是它们可能不是最好的):
- 0x7EF504F3(没有细化)
- 0x7EF40D2F(1个细化)
- 0x7EF39252(2个精炼)
三个细化步骤,初始近似勉强影响最大相对误差。 0x7EEEEEEE的伟大工程,我不能找到更好的东西。
Answer 2:
一种方法是:
- 提取输入符号,指数和尾数
- 使用一些最显著尾数位的查找它的倒数表
- 否定指数,并调整为尾数的规模变化
- 重组的迹象,指数和尾数形成输出
在步骤2中,你需要选择的位数来使用,准确性和表大小之间的交易。 你可以通过使用更少的显著位表项之间进行插值获得更高的精度。
在步骤3中,调整是必要的,因为输入尾数是在范围(0.5,1.0],因此它的倒数是在范围[1.0,2.0),这需要renormalising,得到输出尾数。
我不会尝试写这个代码,因为有可能是一些稍微繁琐的边缘情况下,我会想念。
你也应该调查涉及的数值计算,这可能提供更好的结果,如果内存访问速度慢的方法; 在现代PC架构,缓存缺失可能是几十个算术运算的昂贵。 维基百科看起来像一个良好的起点。 当然,不管你做什么,衡量它,以确保它实际上是比FPU除法运算速度更快。
Answer 3:
如果您的最低步骤是类似0.01,那么你可以支持从表逆-F。 每个指数乘以100,这样你就可以有
table[1]----->1.0/0.01
table[3]----->1.0/0.03
table[105]--->1.0/1.05
...
table[10000]->1.0/100.0
10000 elements for a range of (0.00,100.00)
如果你想要更好的精确度,则需要更多的内存。
另一个例子:
range................: 0.000 - 1000.000
minimum increments ..: 0.001
total element number.: 1 million
something like this: table[2343]=1.0/2.343
另一个例子:
range................: 0.000000 - 1.000000
minimum increments ..: 0.000001
total element number.: 1 million
something like this: table[999999]=1.0/0.999999
文章来源: division as multiply and LUT ? / fast float division reciprocal