为什么这个浮点类型的值以这种方式输出
Why does this float type value output in this way?
我最近一直在关注一些在线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
。更改a
和b
之间的数字比例会降低可用的精度和范围。作为练习,我建议使用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个有意义的数字。
您还可以观察到,最接近的可表示值之间的间隔不是固定的(因此是浮点)。它们根据数字的相对值进行缩放。
- 并发/多线程:是否可以以这种方式生成相同的输出?
- 在数组中输入 n 个整数的列表,并以类似于钟摆来回移动的方式排列它们. 输入-1 3 2 5 4,输出5 3 1 2 4
- 从排序数组中删除重复项,具有不同代码方式的相同解决方案具有不同的输出
- 为什么两种不同的对象初始化方式给出不同的输出
- 用于了解输入和输出流缓冲区实际工作方式的程序
- 在 Windows 命令行中运行.exe在使用 2 种相同方式执行时会产生不同的输出
- 意外输出..函数绑定在虚拟表中的发生方式
- 更改输出文件外观(C )的方式 - 需要先阅读,然后以不同的格式写入
- 为什么这个浮点类型的值以这种方式输出
- 以编程方式清除Visual Studio输出窗口
- 重载输入/输出运算符,为什么它以这种方式工作而不是以另一种方式工作
- std::cout,是二进制的,是一种更快的写输出的方式
- 用于循环的C++没有以其他方式输出
- 使 c++ 程序以交互方式将输入输出传递给 windows 命令 prommpt
- 输出输入c++的最短方式
- C++ 字符串比较运算符>根据两个字符串的比较方式生成不同的输出
- 当使用spirit以其他方式解析结构时,会导致输出混乱
- c++ ||添加两个矩阵的方式更容易输出
- Can运算符<<用于设计我们自己的输出显示方式
- 为什么这在 C# 和 C++ 中的输出方式不同