如何解决精度问题

本文关键字:精度 问题 解决 何解决 | 更新日期: 2023-09-27 18:25:33

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

以下是单元测试中使用的一个简单示例:

    [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);
    }

我已经制作了几个类,比如这个演示的Angle类,涵盖了其他基本的单元类型。

向我透露我有精度问题的特定类是使用处理长度单位的类: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。

因此:

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

  • 只是对相对接近的数字(例如0.0001英寸以内)执行IsParallelTo之类的函数检查

如果(Math.Abs(thing.x-thing2.x)<0001)

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

如果(Math.Abs(thing.x-thing2.x)<属性.AcceptedDeviationConstant)

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

我可以使用相同的策略

//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.InteralUnitType))<常数AcceptedEqualityDeviationConstant;

或者最后,我的最后一个想法是将我的单元类中的所有内容都替换为Decimal的基本单元,而不是Double(维度、角度等)的Decimal,并以某种方式(在研究了它之后)弄清楚这是否有帮助。


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

p.s.这些库是开源的,可以在中找到(此处为Units,此处为Geometry)

如何解决精度问题

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

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

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