我需要将一组5U11数字除以6.02,并且我更喜欢这样做,而不是在float和back之间进行强制转换。
5U11表示16位无符号数,其中11个最低有效位表示小数部分。
我应该如何表示6.02,以及单次计算误差的上限是多少?
发布于 2014-02-25 23:49:58
简单地缩放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指出我有一个反向的解决方案。
发布于 2014-02-25 23:53:35
解决这个问题的最直接的方法是计算6.02的倒数作为16位数;即计算舍入(2^16/ 6.02) = 0x2a86。请注意,顶部位未设置,因此我们可以选择更高的被除数并重新计算以获得更好的精度;在本例中,四舍五入(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处
0xfa19 * 0xaa1a + 0x20000 = 0xa62e008a >> 18 = 0x298c实际的答案应该是
31.2622 / 6.02 = 5.193058而我们得到的答案是
0x298c * 2^-11 = 5.193359这种情况下的误差是0.000302,或者说是LSB的0.62。
改进这些结果
可以选择一个更具体的舍入常数来最小化误差范围;本质上,这可以让我们弥补乘法逆(这里是0xaa1a)不精确的事实。在这个特定的例子中,最好的值似乎在0x1c200附近,它产生的误差界是0.56。
https://stackoverflow.com/questions/22018953
复制相似问题