如何解决浮动浮动
float a = 1.0 + ((float) (1 << 25))
float b = 1.0 + ((float) (1 << 26))
float c = 1.0 + ((float) (1 << 27))
运行这段代码后,a、b、c 的浮点值是多少?解释为什么 a、b 和 c 的位布局会导致每个值都是原来的样子。
解决方法
运行这段代码后,a、b 和 c 的浮点值是多少?
当 int
为 32 位时,以下整数移位定义明确且准确。代码不会移动 float
@EOF。
// OK with 32-bit int
1 << 25
1 << 26
1 << 27
转换为 float
,上述 2 的幂值也定义明确,没有精度损失。
// OK and exact
(float) (1 << 25)
(float) (1 << 26)
(float) (1 << 27)
将这些添加到 double
1.0 是定义明确的精确和。典型的 double
有 53 位有效数,可以准确地表示 0x8000001.0p0
。例如:DBL_MANT_DIG == 53
// Let us use hexadecimal FP notation
1.0 + ((float) (1 << 25)) // 0x2000001.0p0 or 0x1.0000008p+25
1.0 + ((float) (1 << 26)) // 0x4000001.0p0 or 0x1.0000004p+26
1.0 + ((float) (1 << 27)) // 0x8000001.0p0 or 0x1.0000002p+27
最终代码尝试将 double
值分配给 float
,而在典型的 float
编码范围内,无法准确表示这些值。
typical float
有一个 24 位有效数。例如:FLT_MANT_DIG == 24
如果要转换的值在可以表示但不能准确表示的值范围内,则结果是最接近的较高或最接近的较低可表示值,以实现定义的方式选择。 C17dr § 6.3.1.4 2.
典型的实现定义方式四舍五入到最近,与偶数相关。
float s = 0x0800001.0p0; printf("%a\n",s);
float t = 0x1000001.0p0; printf("%a\n",t);// 0x1000001.0p0 1/2 way between two floats
float a = 0x2000001.0p0; printf("%a\n",a);
float b = 0x4000001.0p0; printf("%a\n",b);
float c = 0x8000001.0p0; printf("%a\n",c);
输出
0x1.000002p+23 // exact conversion double to float
0x1p+24
0x1p+25
0x1p+26
0x1p+27
解释为什么 a、b 和 c 的位布局会导致每个值都是原来的样子。
位布局不是问题。它是带有 float
的 FLT_MANT_DIG == 24
的属性,它是一个 24 位有效数和实现定义的行为,导致 double
值四舍五入为附近的 float
一个。任何带有 float
的 FLT_MANT_DIG == 24
布局都会有类似的结果。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。