分配给“float”时,附加“f”何时会更改浮动常量的值?
f
在将常量分配给 a 时,将an应用于浮点常量似乎没有什么区别float
。
int main(void) {
float f;
// 1 2345678901234567
f = 3.1415926535897932;
printf("%.6a %.8f pi 3.1415926535897932n", f, f);
f = 3.1415926535897932f; // v
printf("%.6a %.8f pi 3.1415926535897932fn", f, f);
}
有或没有f
,值是一样的
// value value code
0x1.921fb6p+1 3.14159274 pi 3.1415926535897932
0x1.921fb6p+1 3.14159274 pi 3.1415926535897932f
为什么要使用f
?
回答
这是每个回答你自己的问题的自我回答。
附加 af
很少有区别,但在某些情况下确实如此。当f
也被省略时,启用良好的编译器可能会发出警告。
float f = 3.1415926535897932; // May generate a warning
警告:从“double”到“float”的转换会将值从“3.1415926535897931e+0”更改为“3.14159274e+0f”[-Wfloat-conversion]
要产生价值差异,请注意潜在的双舍入问题。
第一次舍入是由于代码的文本被转换为浮点类型。
结果要么是最近的可表示值,要么是与最近的可表示值紧邻的较大或较小的可表示值,以实现定义的方式选择。C17dr § 6.4.4.2 3
一种非常常见的实现定义方式是将源代码文本转换为最接近的double
(没有f
)或最接近float
的f
后缀。质量较差的实现有时是第二个最佳选择。
将double
FP 常数分配给 afloat
会导致另一次舍入。
如果要转换的值在可以表示但不能精确表示的值范围内,则结果是最接近的较高或最接近的较低可表示值,以实现定义的方式选择。C17dr § 6.3.1.4 2
一种非常常见的实现定义方式是将 the 转换double
为最接近的float
- ties to even。(编译时间舍入可能受各种编译器设置的影响。)
双舍入值变化
考虑源代码使用的值非常接近2 个float
值之间的中间值的情况。
如果没有f
,则将代码四舍五入到 adouble
可能会导致值恰好介于 2float
秒之间。double
到float
then的转换可能不同于“with an f
”。
使用f
,转换结果最接近float
。
#include <math.h>
#include <stdio.h>
int main(void) {
float f;
f = 10000000.0f;
printf("%.6a %.3f 10 millionn", f, f);
f = nextafterf(f, f + f);
printf("%.6a %.3f 10 million - next floatn", f, f);
puts("");
f = 10000000.5000000001;
printf("%.6a %.3f 10000000.5000000001n", f, f);
f = 10000000.5000000001f;
printf("%.6a %.3f 10000000.5000000001fn", f, f);
puts("");
f = 10000001.4999999999;
printf("%.6a %.3f 10000001.4999999999n", f, f);
f = 10000001.4999999999f;
printf("%.6a %.3f 10000001.4999999999fn", f, f);
}
输出
0x1.312d00p+23 10000000.000 10 million
0x1.312d02p+23 10000001.000 10 million - next float
// value value source code
0x1.312d00p+23 10000000.000 10000000.5000000001
0x1.312d02p+23 10000001.000 10000000.5000000001f // Different, and better
0x1.312d04p+23 10000002.000 10000001.4999999999
0x1.312d02p+23 10000001.000 10000001.4999999999f // Different, and better
舍入模式
当舍入模式为向上、向下或趋向于零时,关于双1舍入的问题不太可能出现。当第二次四舍五入在中途情况下复合方向时,就会出现这种情况。
出现率
当代码不精确地转换double
为非常接近 2 个float
值之间的中间值时会出现问题 - 因此相对罕见。即使代码常量是十进制或十六进制形式,问题也适用。使用随机常数:大约 2 30中的 1个。
推荐
很少有主要问题,但f
后缀更好地获得最佳值float
并安静警告。
1 double在这里是指做某事两次,而不是 type double
。