我需要一个函数来将正双精度数四舍五入为最接近的整数。潜伏的我发现了一种非常优雅的方式
int x = floor(y + 0.5);我写了一个简单的测试程序:
double a = 10.0;
for (int i = 0; i < 10; i++) {
cout << a << "\t" << a + 0.5 << "\t" << floor(a + 0.5) << endl;
a += 0.1;
}但是我收到了一些奇怪的输出
10 10.5 10
10.1 10.6 10
10.2 10.7 10
10.3 10.8 10
10.4 10.9 10
10.5 11 10 <--- should be 11!
10.6 11.1 11
10.7 11.2 11
10.8 11.3 11
10.9 11.4 11那是什么?
向卢卡致谢
发布于 2013-03-13 17:35:31
下面是使用printf的输出:
printf("%.15f\t%.15f\t%.15f\n", a, a + 0.5, floor(a + 0.5));
现在不精确度很明显了:
10.000000000000000 10.500000000000000 10.000000000000000
10.100000000000000 10.600000000000000 10.000000000000000
10.199999999999999 10.699999999999999 10.000000000000000
10.299999999999999 10.799999999999999 10.000000000000000
10.399999999999999 10.899999999999999 10.000000000000000
10.499999999999998 10.999999999999998 10.000000000000000
10.599999999999998 11.099999999999998 11.000000000000000
10.699999999999998 11.199999999999998 11.000000000000000
10.799999999999997 11.299999999999997 11.000000000000000
10.899999999999997 11.399999999999997 11.000000000000000发布于 2013-03-13 17:25:59
通过添加0.1,您确实添加了一个略低于0.1的值。
所以加0.1 5次并不等同于加0.5一次;你不会精确地达到那个值。通过再次添加.5,您不会超过11,这会产生您观察到的行为。
一个C程序,比如
#include <stdio.h>
#include <math.h>
int main()
{
double a = 10.0;
int i;
for (i = 0; i < 11; i++) {
printf("%4.19f\t%4.19f\t%4.19f\n", a, a+.5, floor(a + 0.5));
a += 0.1;
}
printf("\n");
for (i = 0; i < 11; i++) {
a = 10.0 + i/10.0;
printf("%4.19f\t%4.19f\t%4.19f\n", a, a+.5, floor(a + 0.5));
}
}在其输出上显示
10.0000000000000000000 10.5000000000000000000 10.0000000000000000000
10.0999999999999996447 10.5999999999999996447 10.0000000000000000000
10.1999999999999992895 10.6999999999999992895 10.0000000000000000000
10.2999999999999989342 10.7999999999999989342 10.0000000000000000000
10.3999999999999985789 10.8999999999999985789 10.0000000000000000000
10.4999999999999982236 10.9999999999999982236 10.0000000000000000000
10.5999999999999978684 11.0999999999999978684 11.0000000000000000000
10.6999999999999975131 11.1999999999999975131 11.0000000000000000000
10.7999999999999971578 11.2999999999999971578 11.0000000000000000000
10.8999999999999968026 11.3999999999999968026 11.0000000000000000000
10.9999999999999964473 11.4999999999999964473 11.0000000000000000000
10.0000000000000000000 10.5000000000000000000 10.0000000000000000000
10.0999999999999996447 10.5999999999999996447 10.0000000000000000000
10.1999999999999992895 10.6999999999999992895 10.0000000000000000000
10.3000000000000007105 10.8000000000000007105 10.0000000000000000000
10.4000000000000003553 10.9000000000000003553 10.0000000000000000000
10.5000000000000000000 11.0000000000000000000 11.0000000000000000000
10.5999999999999996447 11.0999999999999996447 11.0000000000000000000
10.6999999999999992895 11.1999999999999992895 11.0000000000000000000
10.8000000000000007105 11.3000000000000007105 11.0000000000000000000
10.9000000000000003553 11.4000000000000003553 11.0000000000000000000
11.0000000000000000000 11.5000000000000000000 11.0000000000000000000不同之处:第一次是你的方法,累积误差和步长为0.0999999999999996447,而第二次重新计算a尽可能接近,使其有可能准确地达到10.5%和11.0%。
发布于 2013-03-13 17:31:06
该问题是由于舍入误差累积造成的。浮点数在内部表示为非整数,它们的值大多是近似值。因此,每次执行a += .1和a + .5操作时,您都会累积舍入误差,结果就是您得到的结果。
您可以尝试使用以下表达式,而不是增量修改(通常在大规模情况下会获得更好的结果):
a = 10. + .1 * i;https://stackoverflow.com/questions/15381119
复制相似问题