如何解决精度问题

时间:2014-10-03 19:07:15

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

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

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

    [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 Class,涵盖了其他基本单元类型。

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

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

public class Point
{

    public Dimension X;

    public Dimension Y;

    public Dimension Z;
}

线条和其他形状具有像Dimensions这样的属性,以及使用此Point Class构建的端点。

当我试图判断这些线是否全部平行时,问题变得明显。就像在这个函数中一样:

    /// <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,因为它检查的精度太高。在使用Points和line进行Rotations和Translations之后,当我希望它返回true时,舍入加起来足以使该函数返回false。

所以:

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

  • 只需检查IsParallelTo等函数,查看相对较近的数字(例如在.0001英寸范围内)
  

如果(Math.Abs​​(thing.x - thing2.x)&lt; .0001)

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

if(Math.Abs​​(thing.x - thing2.x)&lt; Properties.AcceptedDeviationConstant)

  • 或在Dimension Class中根据级别减少问题:

我可以使用相同的策略

//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)))&lt; Constants.AcceptedEqualityDeviationConstant;

或者最后,我的最后一个想法是将我的单元类中的所有内容替换为Decimal的基本单位而不是Double(Dimension,Angle等)到Decimal以及某种方式(在研究之后)在它上面)弄清楚这是否会有所帮助。


我应该如何以及在哪里提高班级平等操作的精确性?

P.S。这些库是开源的,可以找到(单位here和几何here

1 个答案:

答案 0 :(得分:0)

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

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

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