Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 地板()行为异常_C++_Integer_Rounding_Floor - Fatal编程技术网

C++ 地板()行为异常

C++ 地板()行为异常,c++,integer,rounding,floor,C++,Integer,Rounding,Floor,我需要一个函数将一个正的double取整为最接近的整数。我发现这是一种非常优雅的方式 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; }

我需要一个函数将一个正的double取整为最接近的整数。我发现这是一种非常优雅的方式

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;
}
双a=10.0;
对于(int i=0;i<10;i++){

cout通过添加0.1,确实可以添加略低于0.1的值

因此,将0.1乘以5与将0.5乘以一次并不相同;你不能精确地达到该值。再次将0.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));
    }
}

区别:第一次运行的方法是累积误差和步长为0.099999999996447的方法,而第二次运行的方法是重新计算尽可能接近的a,使其能够精确地达到10.5和11.0。

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

您可以尝试不看增量修改,而是看如何使用以下表达式(通常它在大规模上提供更好的结果):


以下是使用
printf
的输出:

printf(“%.15f\t%.15f\t%.15f\n”,a,a+0.5,楼层(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

问题是,正如其他人所指出的,你从来没有 实际上有
10.5
;你只有非常接近的东西 至
10.5
(但略小)

一般来说,对于这类事情,你不应该 向浮点值添加增量。您应该 仅使用整数增量,并每次将其缩放到 浮点值:

for ( int i = 0; i != 10; ++ i ) {
    double aa = a + ( i / 10. );
    std::cout << aa << '\t' << aa + 0.5 << '\t' << floor( aa + 0.5 ) << std::endl;
}
for(int i=0;i!=10;++i){
双aa=a+(i/10.);

std::cout double和float(存储在浮点标准中的变量)只是近似值。精度不受精确小数的限制。关于浮点计算的很多细节:--网上也有不错的PDF版本。但GLGL的答案已经说明了这一点。
10.5
实际上是
10.499999999
左右。
cout
打印得很漂亮,但floor知道
10.999999999
不是
11
10.5
10.5
。机器浮点能够准确地表示它。问题是他从来没有
10.5
。如果OP添加
0.125
,他们会更好,因为
1/8
可以准确地表示th。@PeterWood如果OP添加
0.125
,那就更好了很可能他没有意识到可能有问题。@JamesKanze抱歉,是的,OP需要理解有问题。我想帮助他们思考为什么有些数字比其他数字更好。这是朝着正确方向迈出的一步,但这里的问题是,
0.1
无法准确表示。使用
10.+(i/10.
应给出正确的结果,但是:所有涉及的数字都可以准确表示,当
i
5
时,结果也可以准确表示。(当
i
1
时,结果仍不完全是
10.1
。但对于舍入,我们只关心结果是否接近
某个值。5
)需要注意的是,这里的舍入误差是在将
.1
转换为浮点值时产生的。一个粗略的类比是
int i=0;i+=3/2;i+=3/2;
i
的结果值是2,而不是3。没有必要将问题与
printf
混淆。只需将精度设置为
std::cout
@JamesKanze-这个问题之前已经用C标记了。不过现在应该还是很清楚发生了什么。
a = 10. + .1 * i;
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
for ( int i = 0; i != 10; ++ i ) {
    double aa = a + ( i / 10. );
    std::cout << aa << '\t' << aa + 0.5 << '\t' << floor( aa + 0.5 ) << std::endl;
}