先看下面的代码以及输出:
int main()
{
double a = 80.845;
float b = 80.845;
printf("%.2lf %.2f\n", a, b);
double c = 2.005;
float d = 2.005;
printf("%.2lf %.2f\n", c, d);
double e = 2.05;
float f = 2.05;
printf("%.1lf %.1f\n", e, f);
return 0;
}
Output:
80.84 80.85
2.00 2.01
2.0 2.0
众所周知,
double
和
float
都是浮点数,他们的输入输出格式分别对应
%lf
和
%f
由于计算机内部都是用
0
0
0
和
1
1
1
存储数据,所以存储整数的时候不会存在精度问题,但是存储小数就会有问题了,因为
2
−
1
=
0.5
2^{-1}=0.5
2
−
1
=
0
.
5
、
2
−
2
=
0.25……
2^{-2}=0.25 … …
2
−
2
=
0
.
2
5
.
.
.
.
.
.
,如果我们要存储的数为
0.7
0.7
0
.
7
,我们是无法准确的对其进行存储的。
另外,
double
的精度比
float
高,再加上输出会默认四舍五入,结合上面的输出,我们可以猜想:2.005以
double
的形式存储的时候真实值小于2.005,以
float
的形式存的时候,其真实值略大
实际上,用代码也可以很直观的看出来:
int main()
{
double a = 2.005;
float b = 2.005;
printf("%.20lf\n%.20f\n", a, b);
return 0;
}
Output:
2.00499999999999989342
2.00500011444091796875
考虑到精度问题,接下来是围绕精度问题的一个问题:
四舍五入
在以
%f
或者
%lf
输出的时候,程序会默认四舍五入,但是遇到了像上面的情况怎么办呢?
很简单,在后面加上一个略小的数即可,但是这个数也不是随便加的。我觉得,如果要保留n位小数,那么加上0.000…001(小数点后面
n+2/3/4个0的位置
)比较合适。这个值绝对不能太大,不然本来不进位的进位了,也不能十分小,不然没效果。
另外一种是模拟进位,使用
int
强转,舍弃小数部分的原理
两种方法:
int main()
{
double a = 1.00000005; //保留七位小数
printf("%.7f\n", a); //不处理精度会出错
printf("%.7f\n", a + 0.0000000001); //方法一
printf("%.7f\n", int(a * 10000000 + 0.5) / 10000000.0); //方法二
return 0;
}
Output:
1.0000000
1.0000001
1.0000001