类似浮点函数的结果不同

时间:2012-09-14 09:18:12

标签: c++ floating-accuracy

所以我有两个应该做同样事情的功能

float ver1(float a0, float a1) {
    float r0 = a0 - a1;
    if (abs(r0) > PI) {
        if (r0 > 0) {
            r0 -= PI2;
        } else {
            r0 += PI2;
            }
    }
    return r0;
}

float ver2(float a0, float a1) {
    float a2 = a1 - PI2;

    float r0 = a0 - a1;
    float r1 = a0 - a2;

    if (abs(r0) < abs(r1)) {
        return r0;
    }
    if (abs(r0) > abs(r1)) {
        return r1;
    }

    return 0;
}

注意:PI和PI2是pi的浮点常数和2 * pi

奇怪的是,有时它们会产生不同的结果,例如,如果你喂它们0.28605145和5.9433694,那么第一个导致0.62586737,第二个导致0.62586755,我无法弄清楚是什么造成这种情况。

如果您手动计算结果应该是什么,您会发现第二个答案是正确的。我在2d物理模拟中使用这个功能,真正奇怪的是第一个答案(错误的答案)在那里工作,而第二个答案(正确的一个)使它起到各种疯狂的作用。与未知来源如此微小的差异和如此深远的影响:|

此时我还是转向了矩阵,但这种奇怪的情况让我很好奇,有谁知道发生了什么?

3 个答案:

答案 0 :(得分:2)

float通常具有大约24位的精度,或大约7位小数。

您正在减去两个相似幅度的数字(第一个r0+PI2,第二个a1-PI2),因此正在经历重要性损失 - 其中几个结果的有效位为零,因此剩余的位数较少以表示差异。这就是为什么答案只匹配大约6位小数。

如果您需要更高的精度,那么double或32位或更大的定点表示可能比float更合适。还有一些任意精度库,例如GMP,可以用你需要的所有精度来表示数字,尽管算术会比内置类型慢得多。

答案 1 :(得分:-1)

您应该使用fabs()函数而不是abs(),因为abs()仅适用于整数。使用带有浮点的abs()时,您会得到奇怪和错误的结果。

答案 2 :(得分:-1)

浮点数不像数学实数。每个总和2可能导致“错误”。因此,我不会因为一个例子而将第一个正确和第二个错误称为错误。如果你想让误差保持较小,你需要注意你对浮点数所做的每一个动作。

如果数字的abs在相同范围内,则误差通常较小。 如果范围不同,误差往往会更大。

例如,10000000.0 + 0.1 - 10000000.0几乎不是0.1

如果你知道输入的范围,你可以调整代码以减少错误。