为什么这个浮点类型的值以这种方式输出

  • 本文关键字:方式 输出 类型 c++
  • 更新时间 :
  • 英文 :


我最近一直在关注一些在线C++教程,发现自己对其中一个代码示例中发生的事情感到不知所措。他们使用了变量float f = 3.33333333333333333333333333333333333333f;,然后输出它;将精度设置为等于16sf。我知道浮点变量不能精确到16sf,但我很好奇为什么输出的值是3.333333253860474。我推测第7个sf之后的每个数字可能只是存储在变量使用的内存位置中的垃圾。为了检查这一点,我复制了使用的代码,自己编译并运行,f得到了完全相同的输出。因此,我不认为它们是输出这些最后9位数字的原因,至少是随机的。有人能解释为什么std::cout << f;会给出这样的输出吗?

我想您应该看到3.333333000000000。

计算机上的数字不是以十进制(以10为基数)存储的,3.333333000000000也不能以二进制(以2为基数)精确表示。数字3.333333253860474是最接近的值1,它在可用的有效数字中具有所有三个。

想象一下,如果你有一个只有1.1增量的数字系统:

|-------|-------|-------|-------|
0      1.1     2.2     3.3     4.4

在这个系统中,如果你想要数字3,你就运气不好了,可能会得到3.3。如果你不知道1.1是该系统中最小的"增量",那么.3可能看起来是"随机的"。

有点像那样。

1我不知道这是最接近的值,还是最接近的向上值。不管怎样都不重要

记住,容纳一个数字的空间是有限的。所以必须对实数的连续空间进行采样。想象一下,您使用的是十进制而不是二进制。你有10个数字。你不能准确地表示1.0000000001。所以你必须绕过它。

此外,采样不必具有固定的精度。例如,你如何用10位数表示3000 000 000 000 000?很简单,你可以用指数表示法,它是3*10^12。只看到5位数字!这与浮点运算非常接近。假设你有10个数字,让我们把基数固定为10,这样我们就不会在这上面浪费数字了。留给我们的是a*10^b。更改ab之间的数字比例会降低可用的精度和范围。作为练习,我建议使用3/7和5/5,并尝试使用指数表示法表示几个数字。

如果你把基数改为2,你实际上已经达到了。"垃圾"来自于使用2的幂而不是10的幂。

c/c++中的float通常实现IEEE 754标准的单精度值,尽管NathanOlivier指出的是正确的,但这取决于实现。

为了检查有多少数字是相关的,c++提供了std::numeric_limits。对于表意系统,它是6。其余的不是垃圾,它来自于值的二进制表示。有适当的数学公式。

以下是IEEE 754标准的单精度浮点表示背后的数学解释。浮点数字通常四舍五入到最接近的可表示值。如果你对浮点表示感兴趣,我认为这是相关的,尽管从技术上讲,它不能保证遵循IEEE 754,但大多数编译器和语言的大多数实现都是这样做的

你玩下面的例子(现场):

#include <iostream>
#include <limits>
#include <cmath>
using namespace std;
int main() {
cout << std::numeric_limits<float>::digits10 << 'n';
cout << std::numeric_limits<float>::is_iec559 << 'n';
cout.precision(20);
cout << 3.333333333333333 << 'n';
for(int i = 0; i < 10; ++i) {
float f = i;
cout << "f: " << f << " next:" <<  nextafter(f, f+1.0) << " diff: " << f-nextafter(f, f+1.0) << 'n';
}
return 0;
}

正如您所看到的,float和相应的10进制字符串表示之间的来回转换只能保证6个有意义的数字。

您还可以观察到,最接近的可表示值之间的间隔不是固定的(因此是浮点)。它们根据数字的相对值进行缩放。

最新更新