首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >floor()的行为异常

floor()的行为异常
EN

Stack Overflow用户
提问于 2013-03-13 17:16:43
回答 4查看 178关注 0票数 3

我需要一个函数来将正双精度数四舍五入为最接近的整数。潜伏的我发现了一种非常优雅的方式

代码语言:javascript
复制
int x = floor(y + 0.5);

我写了一个简单的测试程序:

代码语言:javascript
复制
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;
}

但是我收到了一些奇怪的输出

代码语言:javascript
复制
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

那是什么?

向卢卡致谢

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-03-13 17:35:31

下面是使用printf的输出:

printf("%.15f\t%.15f\t%.15f\n", a, a + 0.5, floor(a + 0.5));

现在不精确度很明显了:

代码语言:javascript
复制
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
票数 2
EN

Stack Overflow用户

发布于 2013-03-13 17:25:59

通过添加0.1,您确实添加了一个略低于0.1的值。

所以加0.1 5次并不等同于加0.5一次;你不会精确地达到那个值。通过再次添加.5,您不会超过11,这会产生您观察到的行为。

一个C程序,比如

代码语言:javascript
复制
#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));
    }
}

在其输出上显示

代码语言:javascript
复制
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%。

票数 3
EN

Stack Overflow用户

发布于 2013-03-13 17:31:06

该问题是由于舍入误差累积造成的。浮点数在内部表示为非整数,它们的值大多是近似值。因此,每次执行a += .1a + .5操作时,您都会累积舍入误差,结果就是您得到的结果。

您可以尝试使用以下表达式,而不是增量修改(通常在大规模情况下会获得更好的结果):

代码语言:javascript
复制
a = 10. + .1 * i;
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15381119

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档