1

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

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,我不知道是什么原因造成的。

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

在这一点上,无论如何我都会切换到矩阵,但这种奇怪的情况让我很好奇,有人知道发生了什么吗?

4

3 回答 3

2

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

您正在减去两个大小相似的数字(r0+PI2第一个,a1-PI2第二个),因此正在经历重要性的损失- 结果的几个最重要的位为零,因此剩下的位更少来表示差异。这就是为什么答案只匹配到小数点后 6 位。

如果您需要更高的精度,则 adouble或 32 位或更大的定点表示可能比float. 还有可用的任意精度库,例如GMP,它可以以您需要的所有精度表示数字,尽管算术将比内置类型慢得多。

于 2012-09-14T10:54:08.423 回答
-1

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

于 2012-09-14T09:47:00.907 回答
-1

浮点数的行为不像数学实数。每个 2 的总和都可能导致“错误”。所以我不会仅仅因为一个例子就称第一个正确和第二个不正确。如果你想保持误差很小,你需要小心你对浮点数所做的每一个动作。

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

例如10000000.0 + 0.1 - 10000000.0几乎没有0.1

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

于 2012-09-14T09:55:22.020 回答