0

我正在翻译一些与 PMP 相关的 C++ 代码,用于姿态控制和部分代码使用FLT_EPSILON.

该代码执行以下操作:

while (angle > ((float)M_PI+FLT_EPSILON))

M_PI很简单,但我不知道该怎么做FLT_EPSILON。谷歌告诉我:

这是 1 与大于 1 的 float 类型的最小浮点数之间的差异。它应该不大于 1E-5。

然而,其他来源状态值,如1.192092896e-07F.

我不是 100% 清楚为什么要使用它。我怀疑这与浮动的粒度有关。因此,如果有人可以澄清它试图在 C++ 中做什么,并且如果这是 javascript 的一个问题,那么这将非常有帮助。

我不确定javascript如何在内部处理像这些值这样的东西,所以我们将不胜感激。

作为一个仅供参考,我正在翻译的代码如下(来自 QGroundControl,它是开源的):

float limitAngleToPMPIf(float angle) {
    if (angle > -20*M_PI && angle < 20 * M_PI) {
        while (angle > ((float)M_PI + FLT_EPSILON)) {
            angle -= 2.0f * (float)M_PI;
        }

        while (angle <= -((float)M_PI + FLT_EPSILON)) {
            angle += 2.0f * (float)M_PI;
        }
    } else {
        // Approximate
        angle = fmodf(angle, (float)M_PI);
    }

    return angle;
}

- - 编辑 - -

刚刚意识到 fmodf 没有定义。显然它是一个 lib 函数并执行以下操作:

fmod() 函数计算 x 除以 y 的浮点余数。返回值为 x - n * y,其中 n 是 x / y 的商,向零舍入为整数。

4

1 回答 1

1

This code is attempting to keep angle within an interval around zero.

However, managing angles in this way is troublesome and requires considerable care. If it is not accompanied by documentation explaining what is being done, why, and the various errors and specifications that are involved, then it was done improperly.

It is impossible for this sort of angle reduction to keep accumulated changes accurately over a long sequence of changes, because M_PI is only an approximation to π. Therefore, this sort of reduction is generally only useful for aesthetic or interface effect. E.g., as some angle changes, reducing it can keep it from growing to a point where there may be large jumps in calculation results due to floating-point quantization or other calculation errors that would be annoying to a viewer. Thus, keeping the angle within an interval around zero makes the display look good, even though it diverges from what real physics would do over the long term.

The choice of FLT_EPSILON appears to be arbitrary. FLT_EPSILON is important for its representation of the fineness of the float format. However, at the magnitude of M_PI, the ULP (finest change) of a float is actually 2*FLT_EPSILON. Additionally, JavaScript performs the addition with double-precision arithmetic, and FLT_EPSILON is of no particular significance in this double format. I suspect the author simply chose FLT_EPSILON because it was a convenient “small” number. I expect the code would work just as well as if angle > M_PI had been written, without the embellishment, and (float) M_PI were changed to M_PI everywhere it appears. (The addition of FLT_EPSILON may have been intended to add some hysteresis to the system, so that it did not frequently toggle between values near π and values near –π. However, the criterion I suggest, angle > M_PI, also includes some of the same effect, albeit a smaller amount. That might not be apparent to somebody inexperienced with floating-point arithmetic.)

Also, it looks like angle = fmodf(angle, (float) M_PI); may be a bug, since this is reducing modulo M_PI rather than 2*M_PI, so it will add 180º to some angles, producing a completely incorrect result.

It is possible that replacing the entire function body with return fmod(angle, 2*M_PI); would work satisfactorily.

于 2013-06-08T02:17:57.167 回答