与Math.Round()不一致

时间:2011-09-01 14:08:09

标签: c# rounding trigonometry

我有两个函数用于包含(-180,180)和(-π,π)之间的角度。目的是给定从-inf到+ inf的任何角度,它将在指定的间隔内保持等效角度。例如,1550°的角度为110°。

public double WrapBetween180(double angle)
{
    return angle - 360d * Math.Round(angle / 360d, MidpointRounding.AwayFromZero);
}
public double WrapBetweenPI(double angle)
{
    const double twopi = 2d * Math.PI;
    return angle - twopi * Math.Round(angle / twopi, MidpointRounding.AwayFromZero);
}

产生以下结果

WrapBetween180(-180) = -180
WrapBetween180( 180) =  180

WrapBetweenPI(-Math.PI) =  Math.PI
WrapBetweenPI( Math.PI) = -Math.PI

这些都不是我想要的。我想要的是:

WrapBetween180(-180) =  180
WrapBetween180( 180) =  180

WrapBetweenPI(-Math.PI) =  Math.PI
WrapBetweenPI( Math.PI) =  Math.PI

我尝试使用舍入方法,但仍然无法获得所需的结果。这个问题很明显,因为有时我处理的角度只是接近-π或π而且我的结果是不连续的。

关于如何最好地实现角度包装功能的任何建议都具有非包容性的下限和包容性上限?

3 个答案:

答案 0 :(得分:2)

对于以度为单位的角度,如果x介于-180和180之间,则180 - x介于0和360之间。您想要的等同于要求180 - x介于0之间(包括)和360(独家)。因此,只要180 - x达到360,我们就想在角度上添加360。这给了我们:

return angle + 360d * Math.Floor((180d - angle) / 360d);

弧度角度相同:

return angle + twopi * Math.Floor((Math.PI - angle) / twopi);

答案 1 :(得分:0)

它没有解决舍入问题,但这是我想要做的事情:

private static double ConvertAngle(double angle)
{
    bool isNegative = angle < 0;
    if (isNegative)
        angle *= -1;

    angle = angle % 360;
    if (isNegative)
        angle = -1 * angle + 360;

    if (angle > 180)
        angle = (angle - 360);

    return angle;
}

注意:这种方式假设你想要“后面”是180度,而不是-180度。

答案 2 :(得分:0)

这不是模数运算的情况吗?

private double Wrap180(double value)
{
    // exact rounding of corner values
    if (value == 180) return 180.0;
    if (value == -180) return 180.0;

    // "shift" by 180 and use module, then shift back.
    double wrapped = ((Math.Abs(value) + 180.0) % 360.0) - 180.0;

    // handle negative values correctly
    if (value < 0) return -wrapped;
    return wrapped;
}

它通过了这个测试

    Assert.AreEqual(170.0, wrap(-190.0));
    Assert.AreEqual(180.0, wrap(-180.0));
    Assert.AreEqual(-170.0, wrap(-170.0));
    Assert.AreEqual(0.0, wrap(0.0));
    Assert.AreEqual(10.0, wrap(10.0));
    Assert.AreEqual(170.0, wrap(170.0));
    Assert.AreEqual(180.0, wrap(180.0));
    Assert.AreEqual(-170.0, wrap(190.0));