gpt4 book ai didi

c - 为什么将一个小 float 添加到一个大 float 中只会删除小 float ?

转载 作者:行者123 更新时间:2023-11-30 16:40:28 26 4
gpt4 key购买 nike

假设我有:

float a = 3            // (gdb) p/f a   = 3
float b = 299792458 // (gdb) p/f b = 299792448

然后

float sum = a + b      // (gdb) p/f sum = 299792448

我认为这与尾数的移动有关。有人可以准确解释发生了什么事吗? 32位

最佳答案

32-bit floats只有 24 位精度。因此, float 无法准确地容纳 b - 它通过设置一些指数和尾数使其尽可能接近1来尽其所能。 (与源中常量最接近的可表示浮点;默认 FP 舍入模式为“最近”。)

然后,当您考虑 ba 的浮点表示形式并尝试将它们相加时,加法运算将移动小数 a 的尾数向下,因为它试图匹配 b 的指数,直到值 (3) 从末尾掉下来,只剩下 0。因此,加法运算符结束将浮点零添加到b。 (这是一种过度简化;如果尾数部分重叠,低位仍然会影响舍入。)

一般来说,无限精度加法结果必须按照当前 FP 舍入模式舍入到最接近的 float,而这恰好等于 b

另请参阅Why adding big to small in floating point introduce more error?对于数字发生一些变化但舍入误差较大的情况,例如使用十进制有效数字作为帮助理解二进制浮点舍入的方式。

<小时/>

脚注 1:对于这么大的数字,最近的两个 float 相距 32。现代铿锵连warns关于将源中的 int 舍入为表示不同值的 float 。除非您已经将其写为浮点或 double 常量(例如 299792458.0f),在这种情况下,舍入会在没有警告的情况下发生。

这就是为什么最小的 a 值会将 sum 向上舍入到 299792480.0f,而不是向下舍入到 299792448.0f > 的 b 值约为 16.000001,四舍五入为 299792448.0f。可运行示例 on the Godbolt compiler explorer .

默认的 FP 舍入模式舍入到最接近的偶数尾数作为平局。 16.0 恰好是一半,因此舍入为位模式 0x4d8ef3c2,而不是 0x4d8ef3c3。 https://www.h-schmidt.net/FloatConverter/IEEE754.html 。任何略大于 16 的值都会向上舍入,因为舍入关心的是无限精度结果。它实际上并没有在添加之前移出位,这是一种过度简化。最接近 16.000001 的 float 仅在尾数中设置了低位,位模式 0x41800001。它实际上约为 1.0000001192092896 x 24,或 16.0000019...小得多,它会四舍五入到正好 16.0f,并且 <= 1 ULP(最后一位的单位)b,这不会改变 b,因为 b 的尾数已经是偶数。

<小时/>

如果您通过使用 double a,b 避免提前舍入,则可以添加的最小值将向上舍入 299792480.0f,而不是向下舍入到 299792448.0f 当你执行 float sum = a+b 时,大约是 a=6.0000001;,这是有道理的,因为整数值 ...58 保持为 。 ..58.0 而不是向下舍入到 ...48.0f,即 float b = ...58 中的舍入误差为 -10,因此 a 可以小得多。

不过,这次有两个舍入步骤,a+b 舍入到最接近的 double 如果该加法不精确,则该 double 四舍五入为 float 。 (或者,如果 FLT_EVAL_METHOD == 2,就像 C 在 32 位 x86 上编译 80 位 x87 浮点一样,+ 结果将舍入为 80 位 long double,然后 float 。)

关于c - 为什么将一个小 float 添加到一个大 float 中只会删除小 float ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46623752/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com