为什么这种浮点型值以这种方式输出?

时间:2017-01-03 13:36:59

标签: c++

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

2 个答案:

答案 0 :(得分:7)

我认为你期待看到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 我不知道它是最接近的值,还是最接近的值。无论哪种方式都无关紧要。

答案 1 :(得分:1)

请记住,你有一个有限的空间来容纳一个数字。所以必须对实数的连续空间进行抽样。想象一下,您使用的是十进制系统而不是二进制系统。你有10位数。您不能完全代表1.000000000001。所以你必须围绕它。

此外,采样不必具有固定的精度。例如。你怎么能用10位数表示3 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 standard的单精度值,尽管NathanOlivier指出这是正确的,这是留给实现的。

要检查相关的位数,c ++会提供std::numeric_limits。对于ideone系统,它是6.其余的不是垃圾,它来自值的二进制表示。有适当的数学公式。

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

您可以使用以下示例(live):

#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个有意义的数字。

您还可以观察到最接近的可表示值之间的间隔不固定(因此浮点)。它们随着数字的相对值而缩放。