c中的双精度比较失败

时间:2012-12-06 20:06:47

标签: c floating-point double precision

  

可能重复:
  Why “for( i = 0.1 ; i != 1.0 ; i += 0.1)” doesn’t break at i = 1.0?

我有一个数字(实际)区间[x,y]。我必须使用类似的东西来迭代它:

nr = 0;
for (i = x; i <= y; i += step) //step is a small double value
    nr++;

对于[-1,1],步长为0.001,很明显nr应该是2001(-1.000 ... 0.999 1.000),但它计算nr = 2000(我调查了它并且最后一次比较失败了:0.999 + 0.001 &gt; 1.000)

如何计算确切的nr值?

4 个答案:

答案 0 :(得分:3)

你需要使用整数来做这件事,或者对不精确感到满意,因为浮点数和双打本身就是不精确的*。您的代码完全符合C语言规范。浮动和双打在要求精确精确的情况下使用是不安全的。

除此之外,您需要在问题中提供有关您的要求的更多信息。如果nr是一个温度,那么计算你需要使用不存在或不存在的物理学的确切值(我不是物理学家,所以我不能告诉你)。如果step实际上是一个非理性值,那么您必须向上或向下舍入 - 您的调用以及哪个是正确的取决于您的业务逻辑要求。如果它是合理的并且不需要舍入,则需要乘以最小公分母并使用int s(或C中的分数类等)。

*每个注释浮点数/双精度数是准确的,当分数具有2的幂的分母时,如果你可以强制stepy符合这个,你的问题会很清楚,但是当然,如果step未均匀分配到y,您将需要执行与上述完全相同的业务逻辑处理。

答案 1 :(得分:0)

您遇到的问题是浮点数(floatdouble)没有完全存储,因此内存中的表示形式比不完全更准确。

所以你有两个选择 - 使用精确数字或在循环周围使用整数,然后计算值。

这可以按如下方式完成:

int numberOfIntervals = 2000;
double lowestValue = -1.0;
for (loop = 0; loop <= numberOfIntervals; ++loop)
{
    double v = (0.001 * loop ) + lowestValue;
}

答案 2 :(得分:0)

int nsteps = (int)((y-x)/step);
for(int i=0; nsteps; ++i){
   double v = x + (i*step);  // use v in your calculations
}

答案 3 :(得分:-1)

二进制浮点不精确是不正确的。真实的是,对于内容符合两个不同(正和/或负)幂的总和的数字,该值将是精确的。显然,十进制数字符合十的幂的总和,因此它们不准确。基础四,八和十六符合,因为它们是两的倍数。

我很久以前发布了this answer,它会给你一个关于浮点数有多精确的提示。您还可以通过将两个负幂相加来查看分数的组合方式。

至于如何解决问题,您可以获得所需的工具。如果算法不合适,你可以使它适合。