std::cout不能按预期打印浮点数

4
为什么 std::cout << 1.00000001; 打印出的是 1? 当使用 1.0001时,它可以正常工作,但只有在超过某个精度之后,它停止正确打印。
这些数字是硬编码的,所以这个问题不是重复的。在那个问题中,因为两个浮点数相加产生了一个无理数,这意味着无法正确存储这些数字,但在我的情况下,数字是硬编码的,那么不能显式初始化为1.00000001的 float 无法打印(或存储)的原因是什么? 是因为 cout 无法打印该值还是真的是一个 int
考虑下面的程序:
int main()
{
    float num = 1.0000001f;
    float num2 = num * 2;
    std::cout << num;
    std::cout << num2;
}
num2打印2,但编译器在line 2没有警告将float转换为int,因此我认为num必须是float。这是否意味着这只是与cout有关的问题?我可以安全地假设在内部,num实际上是1.0000001f,即使它在控制台上打印1,也是这样吗?
我的编译器是Visual Studio 2019的内置编译器。

2
这实际上是完全相同的问题。1.00000001f严格等于1.f。 - spectras
@spectras,结尾的1只是丢失了吗? - user14859499
4
好的。浮点数有限精度。试着用这个转换器玩一下:https://www.h-schmidt.net/FloatConverter/IEEE754.html,了解它是如何工作的。 - spectras
@ spectras 好的,谢谢。我尝试将它从float转换为long double,现在似乎可以正确处理高精度数字了。但是我会认为,float只会丢失它无法存储的精度。当超过其限制时,为什么会丢失所有精度呢? - user14859499
1
1.0000001f1.0f是相同的值(更准确地说:实现定义了符号1.0000001f是否会给您浮点数1.0或1.00000011920928955078125。这两个都是编译器的有效选择,因为它们是最接近1.0000001的2个浮点数)。 - spectras
我必须同意 @spectras 的观点,这正是在重复问题中所描述和回答的问题。无论数字是计算还是硬编码的,都可以尝试构建二进制分数的串行总和(1 + 1/2 + 1/2^2 + ... + 1/2^n),这将为1.0000001给出一个精确的结果。简单的数学解释了为什么不可能将这个数字表示为二进制分数的总和。 - πάντα ῥεῖ
2个回答

4

总结我的评论:

  • 数字1.0000001不能被浮点数表示。
  • 编译器会选择一个浮点数值。
  • 它可以按任何方式舍入(向上,向下或最接近),这是实现定义的。

因此,如果您使用此转换器进行一些尝试,您会发现在1之后的下一个浮点值为:

  • 1
  • 1.00000011920928955078125
  • 1.0000002384185791015625
  • 1.00000035762786865234375
  • 1.000000476837158203125
  • ...

1.0000001位于前两个之间,所以您的编译器可以选择任何一个。在您的情况下,似乎您的编译器选择了1。

(对于打印操作,cout操作将截断定义精度后的数字,因此它不会显示上面完整的数字-该精度默认为6位小数)。


3
我认为默认精度为6位数字,但它们全是零,因此不会输出。
#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::setprecision(10);

    // this is what you had
    float f1 = 1.0000001f;
    float f2 = f1 * 2;
    std::cout << f1 << std::endl;
    std::cout << f2 << std::endl;

    // any more zeroes and it would have been idistinguishable from 1.0
    f1 = 1.00000001f;
    f2 = f1 * 2;
    std::cout << f1 << std::endl;
    std::cout << f2 << std::endl;
}

1.000000119
2.000000238
1
2


你的编译器仍然可以自由地给你输出1 2 1 2,这是实现定义的。点赞提到了渲染精度 :) - spectras

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接