我需要将一组5U11数字除以6.02
,并希望在不进行浮点数转换的情况下完成此操作。
5U11表示一个16位无符号数字,其中11个最低有效位表示小数部分。
我该如何表示6.02
,单次计算的误差上限是多少?
我需要将一组5U11数字除以6.02
,并希望在不进行浮点数转换的情况下完成此操作。
5U11表示一个16位无符号数字,其中11个最低有效位表示小数部分。
我该如何表示6.02
,单次计算的误差上限是多少?
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添加到被除数中(因此在上面的示例中,被除数为2^18,因此舍入值为2^17或0x20000
。
考虑到小域,最简单的方法是进行详尽搜索以确定最大误差。使用上面的示例并使用四舍五入,通过添加0x20000
,最大误差出现在x=0xfa19
处:
0xfa19 * 0xaa1a + 0x20000 = 0xa62e008a >> 18 = 0x298c
31.2622 / 6.02 = 5.193058
虽然我们已经有了答案,但是
0x298c * 2^-11 = 5.193359
0xaa1a
)不精确的事实。在这种特定情况下,最佳值似乎在0x1c200
左右,这将产生0.56个LSB的误差界限。x += 0x20000;
,而不是x += 0x2000
。 - al45tairuns16_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指出我有一个反转的解决方案。
(2^18 / 6.02)
相乘,然后移位(带或不带四舍五入因子)并不总是提供最佳答案。在OP的5U11中尝试3.0或0x1800。 我的答案是0x03FD(0.49853...)。你的方法提供了0x3FC(0.49804...)和3/6.02为0.49833... - chux - Reinstate Monica
float
/double
类型的浮点数? - Ingo Leonhardt