c - 分配给 'f' 时,附加 `float` 何时会更改 float 常量的值?

标签 c floating-point

在将常量分配给 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使常数 a float有时会产生值(value)差异。

类型差异:doublefloat .
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]



要产生值(value)差异,请注意潜在风险 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 )或最接近的 floatf后缀。质量较差的实现有时是第二个最佳选择。
分配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 之间s。 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
舍入模式
当舍入模式向上、向下或趋向于零时,关于 double1 舍入的问题不太可能出现。当第二次四舍五入在中途情况下复合方向时,就会出现这种情况。
出现率
当代码不准确地转换为 double 时会出现问题非常接近 2 float 的中途值 - 所以相对少见。即使代码常量是十进制或十六进制形式,问题也适用。使用随机常数:大约 230 分之一。
推荐
很少是主要问题,但 f后缀更好地获得 float 的最佳值并安静警告。

1 double 这里指的是做两次某事,而不是类型 double .

关于c - 分配给 'f' 时,附加 `float` 何时会更改 float 常量的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66631288/

相关文章:

c - 如何在 C 中两个索引之间的链表中的 "extract"节点?

c - 寻找一种工具来告诉我 C 中的计算需要哪些整数宽度才不会溢出

c++ - 将 bitset 与 float 类型一起使用

floating-point - 32 位 float (以十进制和二进制表示)可表示的最小奇数是多少?

c# - 查找满足某些条件的所有集合( vector )

创建 Windows API 以从命令行添加、修改、查询、删除注册表项

c - char 类型数组使用什么操作数?

c++ - 比较两个包含 double 的文件

c - IEEE754 浮点值的可移植序列化

c++ - float C++,如何在数组的每个元素末尾添加 "f"