【问题标题】:How to fix Precision problems [duplicate]如何解决精度问题[重复]
【发布时间】:2014-10-03 19:07:14
【问题描述】:

我有几个类遵循相同的基本概念来处理单位。

这是一个在单元测试中使用的简单示例:

    [Test()]
    public void Angle_MathOperatorTest()
    {
        Angle a1 = new Angle(AngleType.Degree, 360);
        Angle a2 = new Angle(AngleType.Radian, Math.PI * 2);

        Angle addedAngle = a1 + a2;
        addedAngle.Degrees.ShouldBeEquivalentTo(720);

        Angle subtractedAngle = a1 - a2;
        subtractedAngle.Radians.ShouldBeEquivalentTo(0);
    }

我已经制作了几个这样的类演示角度类,涵盖其他基本单位类型。

向我揭示我遇到精度问题的特定类是使用处理长度单位的类:Dimension

我帮助构建了一个基本的几何库,使用这个 Dimension 类作为它的基本单元类型。例如,这里是 Point 类:

public class Point
{

    public Dimension X;

    public Dimension Y;

    public Dimension Z;
}

线条和其他形状具有长度等属性,由使用此点类构建的维度和端点表示。

当我试图判断这些线是否都平行时,问题变得很明显。在这个函数中:

    /// <summary>
    /// checks to see whether every line is parallel
    /// </summary>
    /// <param name="passedLines">passed List of Lines</param>
    /// <returns></returns>
    public static bool AreAllParallel(this List<Line> passedLines)
    {

        for (int i = 0; i < passedLines.Count - 1; i++)
        {
            if (!passedLines[i].IsParallelTo(passedLines[i + 1]))
            {
                return false;
            }
        }

        return true;
    }

它通常会返回 false,因为它检查的精度太高。在使用点和线进行旋转和平移之后,舍入加起来刚好足以使该函数在我希望它返回 true 时返回 false。

所以:

以下哪一组是正确/更好的选择?

  • 只需检查 IsParallelTo 之类的函数,以了解相对接近的数字(例如 0.0001 英寸以内)

If(Math.Abs​​(thing.x - thing2.x)

  • 使用从配置文件中提取的可变常数改进了先前的想法,因此允许用户选择所需的可接受偏差

If(Math.Abs​​(thing.x - thing2.x)

  • 或在维度类的根级别减少问题:

我可以使用相同的策略

//inside Dimension Equals
public override bool Equals(object obj)
{
    return (Math.Abs(this.Inches - ((Dimension)(obj)).Inches)) < Constants.AcceptedEqualityDeviationConstant;
}

看起来确实像这样,但上面的更容易理解

return (Math.Abs​​(this.GetValue(this.InternalUnitType) - ((Dimension)(obj)).GetValue(this.InternalUnitType)))

或者最后,我的最后一个想法是将我的单元类中的所有内容替换为Decimal 的基本单位,而不是Double(尺寸、角度等)到十进制,并且以某种方式(在研究之后)数字看看有没有帮助。


我应该如何以及在哪里提高我的类相等运算的精度一致性?

附言这些库是开源的,可以找到(Units here 和 Geometry here)

【问题讨论】:

  • 您观察到的所有问题都是由浮点运算引起的。
  • 这可以通过实现众所周知的模式来优雅地处理:XXXXX 请参阅here for more details.?
  • 如果您不需要那么精确,我建议您不要使用小数。
  • @jth41 如果我有答案,我会提交答案,而不是评论。 :)
  • 我会让调用者决定所需的精度级别。在 IsParallelTo 和 AreAllParallel 方法中,包含一个公差参数,该参数给出允许的最大角度。

标签: c# decimal precision unit-class-library geometry-class-library


【解决方案1】:

如果e1 是第一行的方向,e2 是第二行的方向,那么要检查它们是否在 θ(弧度)的斜率容差内平行,请执行以下操作(伪代码):

bool is_parallel = |Cross(e1,e2)| <= |e1|*|e2|*Cos(θ)

其中|v| 是矢量幅度,Cross() 是矢量叉积。

【讨论】:

    猜你喜欢
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多