测试计算几何中双精度数相等性的一般策略

时间:2014-10-29 19:18:19

标签: java algorithm double computational-geometry floating-point-precision

所以这对我来说似乎是一个反复出现的问题 - 我正试图在de Berg等人的 Computational Geometry 中实现线段交叉和双重连接的边缘列表叠加算法。现在,我正在使用以下函数来测试两个值的相等性:

private static final double absTol = 1e-14;
private static final double relTol = 1e-10;        
public static final boolean areClose(double i, double j) {
    return (Math.abs(i-j) <= absTol) || 
           (Math.abs(i-j) <= relTol*Math.max(Math.abs(i), Math.abs(j)));
}

我遇到的主要问题是我偶尔会遇到一个错误。例如,今天我意识到我的一个函数失败了,因为我最初将absTol设置为1e-16,当我的一个函数应该识别出0.0和{时,上述函数失败了{1}}是平等的。我通过将1.535e-15调整为absTol来解决问题。所以我的问题是,有没有更好的方法来解决这个问题,然后磨练公差?或者,您是否应该修改算法以便它们只输出错误的值而不是崩溃?不确定如何从这里开始。

我注意到的一点是,在线段交叉算法中,概述了here,计算交叉点需要两个单独的函数。基本上,第一次计算交叉点相关事件点时,计算两个段的交集;我使用以下算法:

1e-14

但是,当确定状态中的行相等时,我一直在使用:

public static Point2D findIntersection(Line2D line1, Line2D line2) {
    double s1X = line1.getX2()-line1.getX1();     
    double s1Y = line1.getY2()-line1.getY1();
    double s2X = line2.getX2()-line2.getX1();     
    double s2Y = line2.getY2()-line2.getY1();

    double s = (-s1Y*(line1.getX1()-line2.getX1())+s1X*(line1.getY1()-line2.getY1()))/(-s2X*s1Y+s1X*s2Y);
    double t = ( s2X*(line1.getY1()-line2.getY1())-s2Y*(line1.getX1()-line2.getX1()))/(-s2X*s1Y+s1X*s2Y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
        return new Point2D.Double(line1.getX1()+(t*s1X), line1.getY1()+(t*s1Y));
    } else {
        return null; 
    }
}

测试线与事件线相交的位置(当两条或更多条线具有相同的截距时,它们在同一位置与事件线相交)。基本上,使用两种不同的算法来找到交叉点,这意味着我得到的值略有不同。最后,我也开始意识到private double getIntercept(Line2D line) { if (MathUtilities.areClose(line.getY1(), line.getY2())) { // line is horizontal. Set intersection to x value return this.x; } else { return line.getX1() + (line.getX2()-line.getX1())*((this.y-line.getY1())/(line.getY2()-line.getY1())); } } 中使用的相等性测试不一定是可传递的,因此也会导致一些问题。

2 个答案:

答案 0 :(得分:3)

处理&#34;准确性&#34;计算几何中出现的问题比你想象的更频繁。除了定点运算(已经提出)之外,另一种方法是使用自适应精度算法 - 以高于双精度的方式评估运算,但仅在必要时保持正确性。

实现自适应精确操作是一项非常重要的任务,但是有一些库是可用的,即Shewchuck的robust predicates和/或MPFR library由CGAL几何库。

可以通过几次调用Shewchuk的orientation例程来稳健地检测两条线之间的交叉点。

答案 1 :(得分:2)

您存在一个基本问题,即您将坐标存储(可能)比对您有意义的精度更高。也就是说,如果两个值的差异小于absTol时总是被认为是相等的,那么存储或使用不是absTol的整数倍的值并执行计算是没有意义的。值会产生异常结果。

除绝对公差外,您还存在与使用相对公差相关的固有不一致性。例如,如果您向上或向下缩放模型,则其某些areClose()关系可能会发生变化。

您是否考虑使用定点算术?这样可以避免算术异常和一些缩放异常,加上它可以让你对评估平等的主题有所缓解。它不会解决所有你的问题,但可能值得一看。