C++程序奇怪输出的原因
Reason of strange output of a c++ program
这是一个简单的 C++ 程序的代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
double x = 3;
double y = .15;
while(x>0) {
printf("%.15f ",x);
cout<<x<<endl;
x-=y;
}
return 0;
}
输出:
> 3.000000000000000 3
> 2.850000000000000 2.85
> 2.700000000000000 2.7
> 2.550000000000000 2.55
> 2.400000000000000 2.4
> 2.250000000000000 2.25
> 2.100000000000001 2.1
> 1.950000000000001 1.95
> 1.800000000000001 1.8
> 1.650000000000001 1.65
> 1.500000000000001 1.5
> 1.350000000000001 1.35
> 1.200000000000001 1.2
> 1.050000000000001 1.05
> 0.900000000000001 0.9
> 0.750000000000001 0.75
> 0.600000000000001 0.6
> 0.450000000000001 0.45
> 0.300000000000001 0.3
> 0.150000000000001 0.15
> 0.000000000000001 1.05471e-15
现在看第 7 行。这不奇怪吗?由于某种原因,这里 2.25 - .15 是 2.100000000000001。我知道这可以通过使用 float 来避免。但我想知道为什么会这样。
如 dww 所述,您的问题说明了浮点错误。
因为计算机是二进制的,所以如果它们有超过一定数量的数字,它们就不能准确地存储浮点数。
为了说明,整数以二进制非常精确地存储。 8 位,0000 0000,可以表示 2^8 个值,即 0-256。 16 位,0000 0000 0000 0000,可以表示 2^16 个值,即 0-65536。负值使用 2 的补码存储,因此存储与正数一样精确。
请注意 none 个整数如何需要 "floating-point" 来表示。
浮点表示起来比较棘手,因为点的位置决定了确切的值,而且它可能显示在不同的地方。如果有 16 个数字位置,0000000000000000,则浮点数可以是沿线的任何位置。 16.00027562809373 可以表示为 756352.8363578476 或 0.000000000000001.
但是浮点数的可用值是有限的,就像整数一样。在您的输出中,看起来任何超出范围的数字 0.000000000000001 < x < 999999999999999.9 都无法准确表示,有效数 > 2^52(浮点数)也不能存储在 64 位内存中。
因为您的尾数字段是 16 位长,我猜这就是您输出的字段宽度。 (我无法猜测你是什么系统运行,因为这也决定了你计算机的浮点精度。这意味着 64 位系统比 32 位系统具有更高的精度。)
在64位系统中,一个浮点数在内存中会有这样的结构:
0 | 000 0000 00000 | 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
^----------------^---------------------------- ------------------------------^---------------- ----------------------------
+/-_____exponent_____________________________significand___________________
有效数字是存储数字,指数决定浮点数的位置,符号决定它是正数还是负数。
末尾的“1”表示计算机认为存在小于 0.000000000000001 的某个值,但它正在四舍五入。最后,数字非常小且接近于零,表示为 0.000000000000001 1.05471e-15;等于 0.00000000000000105471 并且仍然是正值。
这是一个简单的 C++ 程序的代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
double x = 3;
double y = .15;
while(x>0) {
printf("%.15f ",x);
cout<<x<<endl;
x-=y;
}
return 0;
}
输出:
> 3.000000000000000 3
> 2.850000000000000 2.85
> 2.700000000000000 2.7
> 2.550000000000000 2.55
> 2.400000000000000 2.4
> 2.250000000000000 2.25
> 2.100000000000001 2.1
> 1.950000000000001 1.95
> 1.800000000000001 1.8
> 1.650000000000001 1.65
> 1.500000000000001 1.5
> 1.350000000000001 1.35
> 1.200000000000001 1.2
> 1.050000000000001 1.05
> 0.900000000000001 0.9
> 0.750000000000001 0.75
> 0.600000000000001 0.6
> 0.450000000000001 0.45
> 0.300000000000001 0.3
> 0.150000000000001 0.15
> 0.000000000000001 1.05471e-15
现在看第 7 行。这不奇怪吗?由于某种原因,这里 2.25 - .15 是 2.100000000000001。我知道这可以通过使用 float 来避免。但我想知道为什么会这样。
如 dww 所述,您的问题说明了浮点错误。
因为计算机是二进制的,所以如果它们有超过一定数量的数字,它们就不能准确地存储浮点数。
为了说明,整数以二进制非常精确地存储。 8 位,0000 0000,可以表示 2^8 个值,即 0-256。 16 位,0000 0000 0000 0000,可以表示 2^16 个值,即 0-65536。负值使用 2 的补码存储,因此存储与正数一样精确。
请注意 none 个整数如何需要 "floating-point" 来表示。
浮点表示起来比较棘手,因为点的位置决定了确切的值,而且它可能显示在不同的地方。如果有 16 个数字位置,0000000000000000,则浮点数可以是沿线的任何位置。 16.00027562809373 可以表示为 756352.8363578476 或 0.000000000000001.
但是浮点数的可用值是有限的,就像整数一样。在您的输出中,看起来任何超出范围的数字 0.000000000000001 < x < 999999999999999.9 都无法准确表示,有效数 > 2^52(浮点数)也不能存储在 64 位内存中。
因为您的尾数字段是 16 位长,我猜这就是您输出的字段宽度。 (我无法猜测你是什么系统运行,因为这也决定了你计算机的浮点精度。这意味着 64 位系统比 32 位系统具有更高的精度。)
在64位系统中,一个浮点数在内存中会有这样的结构:
0 | 000 0000 00000 | 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
^----------------^---------------------------- ------------------------------^---------------- ----------------------------
+/-_____exponent_____________________________significand___________________
有效数字是存储数字,指数决定浮点数的位置,符号决定它是正数还是负数。
末尾的“1”表示计算机认为存在小于 0.000000000000001 的某个值,但它正在四舍五入。最后,数字非常小且接近于零,表示为 0.000000000000001 1.05471e-15;等于 0.00000000000000105471 并且仍然是正值。