Python 测试两条线段相交时的算术精度问题

Python 测试两条线段相交时的算术精度问题,python,floating-point,precision,Python,Floating Point,Precision,我编写了一个测试平面中两条线段相交的代码。我不会为所有的细节打扰你 代码采用两条线段,每条线段由两个端点描述,然后通过在y=a*x+b中拟合a和b将每条线段拟合到一条直线上。然后通过x=b2-b1/a2-a1找到两条线的交点。最后,它测试交点x是否包含在两条线段内 相关部分如下所示: # line parameterization by a = Delta y / Delta x, b = y - a*x a1 = (line1.edge2.y - line1.edge1.y) / (line1

我编写了一个测试平面中两条线段相交的代码。我不会为所有的细节打扰你

代码采用两条线段,每条线段由两个端点描述,然后通过在y=a*x+b中拟合a和b将每条线段拟合到一条直线上。然后通过x=b2-b1/a2-a1找到两条线的交点。最后,它测试交点x是否包含在两条线段内

相关部分如下所示:

# line parameterization by a = Delta y / Delta x, b = y - a*x
a1 = (line1.edge2.y - line1.edge1.y) / (line1.edge2.x - line1.edge1.x)
b1 = line1.edge1.y - a1 * line1.edge1.x
a2 = (line2.edge2.y - line2.edge1.y) / (line2.edge2.x - line2.edge1.x)
b2 = line2.edge1.y - a2 * line2.edge1.x
# The intersection's x
x = - (b2 - b1) / (a2 - a1)
# If the intersection x is within the interval of each segment
# then there is an intersection
if (isininterval(x, line1.edge1.x, line1.edge2.x) and
    isininterval(x, line2.edge1.x, line2.edge2.x)):
    return True
else:
    return False
为了简洁起见,我放弃了很多处理特定情况的测试,比如当边彼此平行时a1==a2,当它们在同一条线上时,当边的长度为0,当边沿垂直轴时,a变为无穷大等

函数isininterval非常简单

def isininterval(x0, x1, x2):
    """Tests if x0 is in the interval x1 to x2"""
    if x1 <= x0 <= x2 or x2 <= x0 <= x1:
        return True
    else:
        return False
现在的问题是:我发现由于舍入误差,当交点与线段边缘重合时,测试将给出错误的结果

例如,如果第1行介于0,0和3,5之间,第2行介于3,5和7,1之间,则生成的交点x为2.9999999996,这将给出错误答案。应该是3岁


你能提出一个解决方案吗?

这是浮点运算的一个问题/特点。通过以某种方式对指令进行排序,可以将错误降至最低,但最终,您将得到近似的答案,因为您可能用有限的位数来表示无限数

您需要定义您构建的任何函数,使它们能够容忍这些错误。看看您的示例,正确的值与您得到的值之间的差值为1e-16级-非常低


对于不等式,尤其是等式,放松精确/位匹配的约束是值得的。例如,如果您想测试x==3,您可以将其写成absx-3 您需要定义您构建的任何函数,使它们能够容忍这些错误。看看您的示例,正确的值与您得到的值之间的差值为1e-16级-非常低


对于不等式,尤其是等式,放松精确/位匹配的约束是值得的。例如,如果您想测试x==3,您可以将其写成absx-3你不接受实际上差异很大的值,同样,也不会遇到非常大的1E+32值的问题。是否有机器定义的ε?它对所有机器都通用吗?sys模块中有sys.float\u info.epsilon,但这可能有点低,因为它在技术上定义为1和大于1的最小数字(表示为浮点)之间的差值。因此[1,1+eps]之间没有任何浮动。然而,这是非常特定于应用程序的,您应该可以自由地进行实验。实际上,您可以通过编写一些非常仔细的代码来证明缓解这个问题/特性。我相信这项技术应该归功于乔纳森·舍丘克。请参阅。您可能希望使用“相对差异”,例如absx-target/maxabsx,absarget