如何用一个小浮点数除以一个定点数?

时间:2014-02-25 15:36:20

标签: c math fixed-point

我需要将一组5U11数字除以6.02,并且更愿意这样做而不会强制转换为浮动和返回。

5U11表示16位无符号数,11个最低有效位代表小数部分。

我应该如何表示6.02以及单次计算误差的上限?

2 个答案:

答案 0 :(得分:2)

简单缩放100就足够了。

uns16_t x_5U11;
uns32_t acc;
acc = x_5U11;
acc *= 100;
acc += 301; // for round to nearest rather than truncation.
acc /= 602;

错误界限:x_5U11中的1/2 LSbit。

-

如果速度是最重要的,那么除了执行倍数并按照@alastai的建议划分(通过移动)是要走的路。通过适当的舍入,答案应该在+/- 1 LSBit之内。

如果准确度最重要,则此方法提供+/- 1/2 LSbit(最佳答案)。

[编辑]感谢@Ingo Leonhardt指出我有一个倒置的解决方案。

答案 1 :(得分:2)

这个问题最直接的方法是将6.02的倒数计算为16位数;即计算轮(2 ^ 16 / 6.02)= 0x2a86。请注意,顶部位未设置,因此我们可以选择更高的红利并重新计算以获得更高的准确性;在这种情况下,round(2 ^ 18 / 6.02)= 0xaa1a。

现在,取5U11的数字并进行16x16到32位的加宽乘法,然后向右移(在本例中)为18位,得到你的结果,为5U11值。

例如:

14.3562 * (2^18 / 6.02) = 625148.122 / 2^18 = 2.384
0x72d9  * 0xaa1a        = 0x4c4fc40a >> 18  = 0x1313

你确实会以这种方式做一些准确的事情,并且可以稍微改进这种天真的方法(请参阅Henry S. Warren的书 Hacker's Delight ,关于这个主题的更多内容和其他有用的东西)。

显然,如果你的机器能够进行更广泛的乘法运算,你可以将分红的大小增加到2 ^ 18以上,这将提高你的准确度。


更新

舍入

如果你想要舍入到最近,你应该添加 d / 2,其中 d 是你的红利(所以在上面的例子中,红利是2 ^ 18,因此舍入值为2 ^ 17或0x20000

错误分析

鉴于域名较小,最简单的方法是进行详尽的搜索以确定最大错误。使用上面的示例并通过添加0x20000 使用舍入到最近,最大错误结果为 x = 0xfa19:< / p>

0xfa19 * 0xaa1a + 0x20000 = 0xa62e008a >> 18 = 0x298c

实际答案应为

31.2622 / 6.02 = 5.193058

虽然我们的答案是

0x298c * 2^-11 = 5.193359

此实例中的错误为0.000302,或LSB的0.62。

改善这些结果

可以选择更具体的舍入常量来最小化误差界限;基本上这可以让我们补偿我们的乘法逆(这里0xaa1a)不精确的事实。在这个特定的例子中,最佳值似乎在0x1c200附近,这产生了LSB的0.56的误差范围。