【问题标题】:division as multiply and LUT ? / fast float division reciprocal除法为乘法和LUT? / 快速浮点除法倒数
【发布时间】:2012-09-01 10:53:15
【问题描述】:

是否可以在形式上做浮点除法的倒数 查找表(例如 1/f -> 1*inv[f] )?怎么可能做到? 我认为应该使用一些和掩码和移位来浮动 它是一种索引形式吗?具体会怎么样?

【问题讨论】:

  • 您是否意识到这会损失很多的准确性,或者会导致一个非常糟糕的巨大查找表?有很多浮点数,即使您将自己限制在[0.0, 1.0) 这样的范围内。
  • @up 我只需要倒数 - 比如说 10 位精度(查找表中的 1024 个浮点数) - 如果它更快或更慢,我会徘徊
  • @H2CO3 不,我需要它来除法而不是倒平方根
  • @grungefightr (facepalm truncated) 我知道,我的意思是你想使用位级操作实现 快速 除法,还是特别想使用查找表?

标签: c++ c optimization fpu


【解决方案1】:

你可以像这样猜测一个近似的逆:

int x = bit_cast<int>(f);
x = 0x7EEEEEEE - x;
float inv = bit_cast<float>(x);

在我的测试中,0x7EF19D07 稍好一些(测试时包含 2 次 Newton-Raphson 改进的效果)。

然后您可以使用 Newton-Raphson 进行改进:

inv = inv * (2 - inv * f);

根据需要多次迭代。 2 或 3 次迭代会产生不错的结果。

更好的初始近似值

为了最小化相对误差:

  • 0x7EF311C2(未优化)
  • 0x7EF311C3(1 次改进)
  • 0x7EF312AC(2 次改进)
  • 0x7EEEEBB3(3 项改进)

为了最小化 1 到 2 之间输入的绝对误差(它们在该范围之外工作得很好,但它们可能不是最好的):

  • 0x7EF504F3(未优化)
  • 0x7EF40D2F(1 次细化)
  • 0x7EF39252(2 次改进)

对于三个细化步骤,初始近似几乎不会影响最大相对误差。 0x7EEEEEEE 效果很好,我找不到更好的了。

【讨论】:

  • @grungefightr 在我的电脑上工作;)但是,更严重的是,它通过否定指数来工作,以及它对尾数(或显着)所做的事情我不太明白.. 但它不知何故,效果还不错。
  • 嗯,它有效。很有趣,@ 987654321@
  • 能否附上该演员表的完整工作示例?您不应该使用带有 reinterpret_cast 的指针吗?
  • @user2485710 *reinterpret_cast&lt;int*&gt;(&amp;f) 那么呢?
  • @harold 是的,我知道,我对您的单个具体示例感兴趣,您能否进一步扩展提供一个工作示例?
【解决方案2】:

一种方法是:

  1. 从输入中提取符号、指数和尾数
  2. 使用一些最重要的尾数位在表中查找其倒数
  3. 对指数取反,并根据尾数比例的变化进行调整
  4. 重新组合符号、指数和尾数以形成输出

在第 2 步中,您需要选择要使用的位数,在准确性和表格大小之间进行权衡。您可以通过使用不太重要的位在表条目之间进行插值来获得更高的准确性。

在步骤 3 中,由于输入尾数在 (0.5, 1.0] 范围内,因此它的倒数在 [1.0, 2.0) 范围内,因此需要进行调整,这需要重新归一化以给出输出尾数。

我不会尝试为此编写代码,因为我可能会错过一些稍微复杂的边缘情况。

您还应该研究涉及数值计算的方法,如果内存访问速度较慢,这些方法可能会产生更好的结果;在现代 PC 架构上,缓存未命中可能与数十次算术运算一样昂贵。 Wikipedia 看起来是一个很好的起点。当然,无论你做什么,都要对其进行测量,以确保它实际上比 FPU 除法运算要快。

【讨论】:

  • 你知道我认为我只需要映射浮点数的一些二进制部分(包含最高有效位)并使用这些位(比如十位)将其用作查找表中的索引 - 不需要有序索引,转换和计算 - 我知道我应该在浮点格式规范中查找:>
  • @grungefightr:是的,这就是第 2 阶段所做的,但您还需要计算新的指数。
  • 该死的指数,它需要比特,你 - 忘记了:(
  • 将重新考虑它(并接受 l8er 的答案,然后如果没有人同时提供一些有用的代码示例):/ 至少我可以尝试在我知道范围的特定除法案例中使用它我细分的花车...:/会尝试一下
【解决方案3】:

如果您的最小步长类似于 0.01,那么您可以支持表格中的 inverse-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

【讨论】:

  • 这有点帮助,但我不想将浮点数转换为整数我需要一个查找表,该表由稍微移位和屏蔽的浮点数索引
  • 你是对的,移位可能比乘法更快。但是你不能使用浮点数来索引基元
猜你喜欢
  • 2011-12-04
  • 2011-05-06
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 2016-12-30
相关资源
最近更新 更多