您似乎将舍入(和精度损失)的两个来源与浮点数混淆了。
浮点表示
第一个是由于浮点数在内存中表示的方式,正如您刚才指出的那样,它使用二进制数作为尾数和指数。经典的例子是:
const float a = 0.1f;
const float b = 0.2f;
const float c = a+b;
printf("%.8f + %.8f = %.8f\n",a,b,c);
将打印出来
0.10000000 + 0.20000000 = 0.30000001
在那里,数学上正确的结果是 0.3,但 0.3 用二进制表示无法表示。相反,您会得到可以表示的最接近的数字。
保存为文本
另一个是max_digits10 发挥作用的地方,用于浮点数的文本表示,例如,当您执行printf 或写入文件时。 p>
当您使用%f 格式说明符执行此操作时,您会得到十进制打印出来的数字。
当您以十进制打印数字时,您可以决定打印多少位数。在某些情况下,您可能无法准确打印出实际数字。
例如,考虑
const float x = 10.0000095f;
const float y = 10.0000105f;
printf("x = %f ; y = %f\n", x,y);
这将打印出来
x = 10.000010 ; y = 10.000010
另一方面,使用 %.8f 将 printf 的精度提高到 8 位会给你。
x = 10.00000954 ; y = 10.00001049
因此,如果您想使用 fprintf 或 ofstream 将这两个浮点值作为文本保存到文件中,并使用默认位数,您可能已经将相同的值保存了两次,而原来的 @ 有两个不同的值987654335@和y。
max_digits10 是“我需要写多少个十进制数字才能避免所有可能值出现这种情况?”这个问题的答案。换句话说,如果您用max_digits10 数字(恰好是浮点数为 9)编写浮点数并将其加载回来,则保证得到与开始时相同的值。
请注意,写入的十进制值可能与浮点数的实际值不同(由于表示不同。但仍然保证比您将十进制数的文本读取 float 你会得到相同的值。
编辑:一个例子
查看那里的代码不足:https://ideone.com/pRTMZM
假设你有之前的两个floats,
const float x = 10.0000095f;
const float y = 10.0000105f;
并且您希望将它们保存为文本(典型的用例是保存为 XML 或 JSON 等人类可读的格式,甚至使用打印来调试)。在我的示例中,我将使用 stringstream 写入字符串。
让我们先尝试一下默认精度:
stringstream def_prec;
def_prec << x <<" "<<y;
// What was written ?
cout <<def_prec.str()<<endl;
这种情况下的默认行为是在编写文本时将我们的每个数字四舍五入为10。所以现在如果我们使用该字符串读回另外两个浮点数,它们将不包含原始值:
float x2, y2;
def_prec>>x2 >>y2;
// Check
printf("%.8f vs %.8f\n", x, x2);
printf("%.8f vs %.8f\n", y, y2);
这将打印出来
10 10
10.00000954 vs 10.00000000
10.00001049 vs 10.00000000
这个往返从浮动到文本再返回已经删除了很多数字,这可能很重要。显然,我们需要比这更精确地将我们的值保存到文本中。文档保证使用max_digits10 不会在往返过程中丢失数据。让我们尝试使用setprecision:
const int digits_max = numeric_limits<float>::max_digits10;
stringstream max_prec;
max_prec << setprecision(digits_max) << x <<" "<<y;
cout <<max_prec.str()<<endl;
现在将打印出来
10.0000095 10.0000105
所以这次我们的值保存了更多的数字。让我们试着回读:
float x2, y2;
max_prec>>x2 >>y2;
printf("%.8f vs %.8f\n", x, x2);
printf("%.8f vs %.8f\n", y, y2);
打印出来的
10.00000954 vs 10.00000954
10.00001049 vs 10.00001049
啊哈!我们找回了我们的价值观!
最后,让我们看看如果我们使用 比max_digits10 少一位数会发生什么。
stringstream some_prec;
some_prec << setprecision(digits_max-1) << x <<" "<<y;
cout <<some_prec.str()<<endl;
这是我们保存为文本的内容
10.00001 10.00001
我们回读:
10.00000954 vs 10.00000954
10.00001049 vs 10.00000954
所以在这里,精度足以保持x 的值,但不是向下舍入的y 的值。这意味着我们需要使用max_digits10,如果我们想确保不同的浮动可以使文本往返并保持不同。