师乘法和LUT? /快速浮除法倒数(division as multiply and LUT ?

2019-09-22 01:46发布

是否有可能使浮子分裂的倒数在查找表的形式(例如象的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:

一种方法是:

  1. 提取输入符号,指数和尾数
  2. 使用一些最显著尾数位的查找它的倒数表
  3. 否定指数,并调整为尾数的规模变化
  4. 重组的迹象,指数和尾数形成输出

在步骤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