【问题标题】:Sum exceeding permissible value in looping floats循环浮点数中的总和超过允许值
【发布时间】:2015-07-03 13:50:24
【问题描述】:

我最近创建了这个简单的程序来计算平均速度。

平均速度 = Δx / Δt

我选择 x 作为 t 的函数 x = t^2

因此v = 2t

另外,avg v = (x2 - x1) / (t2 - t1)

我选择的区间是 t = 1s to 4s。暗示 x 来自 1 to 16

因此 avg v = (16 - 1) / (4 - 1) = 5

现在的程序:

#include <iostream>

using namespace std;
int main() {
    float t = 1, v = 0, sum = 0, n = 0;  // t = time, v = velocity, sum = Sigma v, n = Sigma 1
    float avgv = 0;

    while( t <= 4 ) {
        v = 2*t;
        sum += v;
        t += 0.0001;
        n++;
    }
    avgv = sum/n;
    cout << "\n---->  " << avgv << "  <----\n";
    return 0;
}

我使用非常小的时间增量来计算很多时刻的速度。现在,如果 t 的增量为 0.001,则计算出的 avg v 为 4.99998。
现在,如果我将 t 的增量设为 0.0001,则 avg v 变为 5.00007

进一步减少增量到 0.00001 得到 avg v = 5.00001

为什么会这样?

谢谢。

【问题讨论】:

  • 请参阅stackoverflow.com/questions/588004/… 以了解为什么不能期望浮点数学产生精确结果。
  • 从 float 更改为 double 并看到平均值正好是 5。这里的问题是 float 缺乏精度。见stackoverflow.com/questions/2100490/…
  • 计算机以二进制而非十进制工作。舍入错误和错误传播是您在使用浮点时应该(至少)注意的主题。这是您使用循环的代码,该循环将运行必要的次数:ideone.com/KTzKaP 请注意循环所需次数后的最终值。这是将 0.0001 添加到浮点数 30,0001 次时发生的错误传播。由于0.0001 不能以二进制形式精确表示,因此您会遇到问题。

标签: c++ optimization error-correction


【解决方案1】:

在基数中,2 0.00010.001 是周期数,因此它们没有精确的表示。其中一个被四舍五入,另一个被四舍五入,所以当你把很多它们相加时,你会得到不同的值。

这与十进制表示中发生的情况相同,如果您选择相应的数字求和(假设每个变量可以包含 3 个十进制数字)。 比较:

a = 1 / 3; // a becomes 0.333
b = a * 6; // b becomes 1.998

与:

a = 2 / 3; // a becomes 0.667
b = a * 3; // b becomes 2.001

两者都应该(理论上)导致2,但由于舍入误差,它们给出不同的结果

在十进制系统中,由于10 被分解为素数25,只有分母只能被25 整除的分数才能用有限个十进制数字表示(所有其他分数是周期性的),在以 2 为底的分数中,只有分母为 2 的幂的分数才能精确表示。尝试使用 1.0/512.01.0/1024.0 作为循环中的步骤。另外,要小心,因为如果您选择的步长太小,您可能没有足够的数字来表示 float 数据类型(即使用 doubles)

【讨论】:

  • 是否有任何方法可以仅使用浮点数来改进此循环,即仅使用浮点数来提高准确性?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-20
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多