acosf()返回NaN

时间:2013-10-17 17:59:04

标签: objective-c c trigonometry cos

我有一个用Objective C编写的iPhone应用程序,我收集用户在屏幕上绘制的触摸点以创建路径。

我希望能够细化这些数据。我通过检查点的角度是否超过某个阈值来实现此目的的方法之一。例如,如果我在a,b,c这一行上取任意三个相邻点,如果角度ABC在180度的5度范围内,那么我可以移除点b而不会过多地影响线。

我试图通过将三角形ABC分成两个直角三角形来实现这一目标。然后我使用acosf()来找到(BAC)处的角度和c处的角度(BCA)。然后,我可以从180减去这两个角度,找到ABC的角度。

我的问题是acosf()经常返回NaN。当它返回一个数字时,我在计算器上检查它并且值是正确的。我已经尝试过返回NaN的价值观,他们也不会在计算器上工作。我知道这是因为它们超出了acosf()的范围。我怎么能避免这个?

以下是我使用的代码:

float prevToNextDist = ccpDistance(prevPoint.location, nextPoint.location);
    //work out the next point angle
    float pointToNextDistance = ccpDistance(point.location, nextPoint.location);
    float nextPointAngle = acosf((prevToNextDist/2)/pointToNextDistance);
    nextPointAngle = CC_RADIANS_TO_DEGREES(nextPointAngle);

    //work out the previous point angle
    float prevToPointDistance = ccpDistance(prevPoint.location, point.location);
    float prevPointAngle = acosf((prevToNextDist/2)/prevToPointDistance);
    prevPointAngle = CC_RADIANS_TO_DEGREES(prevPointAngle);

    //work out the point angle
    float pointAngle = 180 - nextPointAngle - prevPointAngle;

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

acos(x)acosf(x)的典型问题是确保参数在范围内。

由于各种FP问题,有时计算出的x 超出范围-1< = x< = 1。数学x可能在范围内,但舍入/精度有时会出现1.0000001之类的值。当x是NaN时,acosf(x)(到 8 小数步幅)的价值是多少?

if (x > 1.0) {
  x = 1.0;
}
else if (x < -1.0) {
  x = -1.0;
}
angle = acos(x);

此外:acosf()仅提供180度[0到pi]的范围。对于您的任务,您可能希望使用atan2f()。它提供了一个完整的“圈子”答案。

答案 1 :(得分:1)

1 / float不是默认的浮点类型,它是double。 float可能足以存储,即使这样你也应该用double进行计算。

2 /没有cppDistance的代码,很难确定,但我不认为它会像你想象的那样计算三角形的一面(我认为没有3点就不可能作为参数)。

3 /如果您的点是(xa,ya),(0,0)和(xb,yb)并且您正在寻找(0,0)处的角度(如果不是这样,只需更改坐标是这样的,你正在寻找的角度是

acos((xa*xb+ya*yb)/sqrt((xa*xa+ya*ya)*(xb*xb+yb*yb)))

答案 2 :(得分:0)

好的,我已经解决了这个问题,因此我发布的解决方案适用于任何可能偶然发现并发现它有用的人。虽然,我正在使用我自己的解决方案,chux和AProgrammers的建议都是合理的,并帮助我提出了解决方案,所以我对它们进行了投票。

正如chux所说,atan2()是更好的功能,而不是acosf()。这是基于角度精简点数据的代码:

#define kAngleTolerance 3

    double prevPointAngle = atan2(point.location.y - prevPoint.location.y, point.location.x - prevPoint.location.x) * 180.0f / M_PI;
    prevPointAngle = fabs(prevPointAngle);

    double nextPointAngle = atan2(nextPoint.location.y - point.location.y, nextPoint.location.x - point.location.x) * 180.0f / M_PI;
    nextPointAngle = fabs(nextPointAngle);

    double pointAngle = 180 - fabs(nextPointAngle - prevPointAngle);

    if (pointAngle < 180 + kAngleTolerance && pointAngle > 180 - kAngleTolerance ) {
        point.remove = YES;
        [pointsToRemove addObject:point];
    }