什么时候附加 'f' 会在分配给 `float` 时更改浮动常量的值?
When does appending an 'f' change the value of a floating constant when assigned to a `float`?
将 f
应用于浮点常量似乎与将常量分配给 float
时没有区别。
int main(void) {
float f;
// 1 2345678901234567
f = 3.1415926535897932;
printf("%.6a %.8f pi 3.1415926535897932\n", f, f);
f = 3.1415926535897932f; // v
printf("%.6a %.8f pi 3.1415926535897932f\n", f, f);
}
有无f
,数值相同
// value value code
0x1.921fb6p+1 3.14159274 pi 3.1415926535897932
0x1.921fb6p+1 3.14159274 pi 3.1415926535897932f
为什么要使用 f
?
这是根据 Answer Your Own Question 的自我回答。
追加一个 f
使常量成为 float
而 有时 会产生不同的值。
类型
类型差异:double
到 float
。
当 f
也被省略时,启用良好的编译器可能会发出警告。
float f = 3.1415926535897932; // May generate a warning
warning: conversion from 'double' to 'float' changes value from '3.1415926535897931e+0' to '3.14159274e+0f' [-Wfloat-conversion]
值
要产生 价值 差异,请注意潜在的 double rounding 问题。
第一次舍入是由于代码的文本被转换为浮点类型。
the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an implementation-defined manner. C17dr § 6.4.4.2 3
鉴于这两个选择,非常常见 实现定义的方式是将源代码文本转换为最接近的 double
(没有 f
) 或最接近的带有 f
后缀的 float
。质量较低的实施有时会成为第二接近的选择。
将 double
FP 常量分配给 float
会导致另一次舍入。
If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. C17dr § 6.3.1.4 2
一种非常常见实现定义的方式是将double
转换为最接近的float
——关系为偶数。 (注意:编译时舍入可能会受到各种编译器设置的影响。)
双舍入值变化
考虑源代码使用的值 非常接近 到 2 float
值的一半。
如果没有 f
,将代码四舍五入为 double
可能会导致值恰好介于 2 float
之间。 double
到 float
的转换可能不同于“使用 f
”。
对于 f
,转换结果最接近 float
。
示例:
#include <math.h>
#include <stdio.h>
int main(void) {
float f;
f = 10000000.0f;
printf("%.6a %.3f 10 million\n", f, f);
f = nextafterf(f, f + f);
printf("%.6a %.3f 10 million - next float\n", f, f);
puts("");
f = 10000000.5000000001;
printf("%.6a %.3f 10000000.5000000001\n", f, f);
f = 10000000.5000000001f;
printf("%.6a %.3f 10000000.5000000001f\n", f, f);
puts("");
f = 10000001.4999999999;
printf("%.6a %.3f 10000001.4999999999\n", f, f);
f = 10000001.4999999999f;
printf("%.6a %.3f 10000001.4999999999f\n", 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四舍五入的问题在向上、向下或接近零的舍入模式下不太可能发生。当第二次舍入使中途情况的方向复杂化时,就会出现问题。
发生率
当代码不准确地转换为非常接近 2 float
值中间的 double
时会出现问题 - 这种情况相对罕见。即使代码常量是十进制或十六进制形式,问题也适用。使用随机常数:大约 1 in 230.
推荐
很少是主要问题,但 f
后缀更适合获得 float
的最佳值并消除警告。
1 double这里指的是做某事两次,而不是double
.
这种类型
chux's answer 的一个小附录是一个可能令人困惑的例子:我们给浮点数赋值,然后立即将浮点数与值进行比较,发现它们不相等!
#include <stdio.h>
#define DCN 0.7
#define FCN 0.7f
int main(void)
{
float f = DCN;
const char* cf = (f == DCN) ? "equal" : (f > DCN) ? "greater" : (f < DCN) ? "less" : "???" ;
printf("DCN\t%s\n", cf);
float g = FCN;
const char* cg = (g == FCN) ? "equal" : (g > FCN) ? "greater" : (g < FCN) ? "less" : "???" ;
printf("FCN\t%s\n", cg);
}
当我 运行 我得到:
DCN less
FCN equal
另一方面,如果常量被替换为 0.1
和 0.1f
我得到:
DCN more
FCN equal
将 f
应用于浮点常量似乎与将常量分配给 float
时没有区别。
int main(void) {
float f;
// 1 2345678901234567
f = 3.1415926535897932;
printf("%.6a %.8f pi 3.1415926535897932\n", f, f);
f = 3.1415926535897932f; // v
printf("%.6a %.8f pi 3.1415926535897932f\n", f, f);
}
有无f
,数值相同
// value value code
0x1.921fb6p+1 3.14159274 pi 3.1415926535897932
0x1.921fb6p+1 3.14159274 pi 3.1415926535897932f
为什么要使用 f
?
这是根据 Answer Your Own Question 的自我回答。
追加一个 f
使常量成为 float
而 有时 会产生不同的值。
类型
类型差异:double
到 float
。
当 f
也被省略时,启用良好的编译器可能会发出警告。
float f = 3.1415926535897932; // May generate a warning
warning: conversion from 'double' to 'float' changes value from '3.1415926535897931e+0' to '3.14159274e+0f' [-Wfloat-conversion]
值
要产生 价值 差异,请注意潜在的 double rounding 问题。
第一次舍入是由于代码的文本被转换为浮点类型。
the result is either the nearest representable value, or the larger or smaller representable value immediately adjacent to the nearest representable value, chosen in an implementation-defined manner. C17dr § 6.4.4.2 3
鉴于这两个选择,非常常见 实现定义的方式是将源代码文本转换为最接近的 double
(没有 f
) 或最接近的带有 f
后缀的 float
。质量较低的实施有时会成为第二接近的选择。
将 double
FP 常量分配给 float
会导致另一次舍入。
If the value being converted is in the range of values that can be represented but cannot be represented exactly, the result is either the nearest higher or nearest lower representable value, chosen in an implementation-defined manner. C17dr § 6.3.1.4 2
一种非常常见实现定义的方式是将double
转换为最接近的float
——关系为偶数。 (注意:编译时舍入可能会受到各种编译器设置的影响。)
双舍入值变化
考虑源代码使用的值 非常接近 到 2 float
值的一半。
如果没有 f
,将代码四舍五入为 double
可能会导致值恰好介于 2 float
之间。 double
到 float
的转换可能不同于“使用 f
”。
对于 f
,转换结果最接近 float
。
示例:
#include <math.h>
#include <stdio.h>
int main(void) {
float f;
f = 10000000.0f;
printf("%.6a %.3f 10 million\n", f, f);
f = nextafterf(f, f + f);
printf("%.6a %.3f 10 million - next float\n", f, f);
puts("");
f = 10000000.5000000001;
printf("%.6a %.3f 10000000.5000000001\n", f, f);
f = 10000000.5000000001f;
printf("%.6a %.3f 10000000.5000000001f\n", f, f);
puts("");
f = 10000001.4999999999;
printf("%.6a %.3f 10000001.4999999999\n", f, f);
f = 10000001.4999999999f;
printf("%.6a %.3f 10000001.4999999999f\n", 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四舍五入的问题在向上、向下或接近零的舍入模式下不太可能发生。当第二次舍入使中途情况的方向复杂化时,就会出现问题。
发生率
当代码不准确地转换为非常接近 2 float
值中间的 double
时会出现问题 - 这种情况相对罕见。即使代码常量是十进制或十六进制形式,问题也适用。使用随机常数:大约 1 in 230.
推荐
很少是主要问题,但 f
后缀更适合获得 float
的最佳值并消除警告。
1 double这里指的是做某事两次,而不是double
.
chux's answer 的一个小附录是一个可能令人困惑的例子:我们给浮点数赋值,然后立即将浮点数与值进行比较,发现它们不相等!
#include <stdio.h>
#define DCN 0.7
#define FCN 0.7f
int main(void)
{
float f = DCN;
const char* cf = (f == DCN) ? "equal" : (f > DCN) ? "greater" : (f < DCN) ? "less" : "???" ;
printf("DCN\t%s\n", cf);
float g = FCN;
const char* cg = (g == FCN) ? "equal" : (g > FCN) ? "greater" : (g < FCN) ? "less" : "???" ;
printf("FCN\t%s\n", cg);
}
当我 运行 我得到:
DCN less
FCN equal
另一方面,如果常量被替换为 0.1
和 0.1f
我得到:
DCN more
FCN equal