解决这个问题最直接的方法是将 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:
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 个 LSB。