我试图了解 NumPy 如何实现四舍五入到最接近的数,即使在转换为较低精度格式时也是如此,在本例中为 Float32 到 Float16,具体来说,当数字在 Float32 中是正常的,但在 Float16 中四舍五入为低于正常值时。
我的理解如下,
在 float32 中,数字有位
31 | 三十 | 二十九 | 二十八 | 二十七 | 二十六 | 二十五 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 十三 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
s | e0 | e1 | e2 | e3 | e4 | e5 | e6 | e7 | m0 | 米1 | 平方米 | 米3 | 米4 | m5 | 米6 | m7 | M8 | m9 | m10 | m11 | m12 | m13 | m14 | m15 | m16 | m17 | m18 | m19 | m20 | m21 | m22 |
/*
* If the last bit in the half significand is 0 (already even), and
* the remaining bit pattern is 1000...0, then we do not add one
* to the bit after the half significand. However, the (113 - f_exp)
* shift can lose up to 11 bits, so the || checks them in the original.
* In all other cases, we can just add one.
*/
if (((f_sig&0x00003fffu) != 0x00001000u) || (f&0x000007ffu)) {m
f_sig += 0x00001000u;
}
上述代码用于打破最接近偶数的平局。我不明白为什么在逻辑或的第二部分,我们对0x0000'07ffu
(位 m12-m22) 进行按位与,而不是0x0000'ffffu
(m11-m22) 进行按位与。
一旦我们将尾数位对齐为 float16 的亚正规格式(这是此段代码之前的位移所做的),在上面的 float32 数字表示中,我们就可以m10
决定m22
要舍入的方向。
我的理解是,OR 的第二部分检查数字是否大于中间点,如果是,则将半有效数字位加一。但对于原始数字,它不是只检查中间点以上的数字子集吗?在 float16 数字中,m9 将是最后一个要保留的精度。因此,如果满足以下条件,我们将向上舍入:
m9 为 1,m10 为 1,m11-m22 均为 0(或的第一部分)
m10 为 1,m11-m22 中至少有一个为 1(将数字置于中间点以上)
如果 m11-m22 中任何一个为 1,则可以通过将 1 添加到 m10 来简化。如果 m10 已经为 1,则添加将影响到 m9,否则将不受影响。但是,在 NumPy 代码的情况下,检查的位是 m12-m22。
我不确定我遗漏了什么。这是一个特殊情况吗?
我期望位 m11-m22 能够决定是否加 1 以及是否加 m12-m22。