【问题标题】:Will the two lines intersect in a Cartesian plane两条线会在笛卡尔平面上相交吗
【发布时间】:2012-11-05 13:52:51
【问题描述】:

我在“Crack the Coding Interview”一书中遇到了这个问题。

给定笛卡尔平面上的两条线,确定两条线是否相交。`

解决办法如下:

public class Line {

    static double epsilon = 0.000001;
    public double slope;
    public double yintercept;

    public Line(double s, double y) {
        slope = s;
        yintercept = y;
    }

    public boolean intersect(Line line2) {
        return Math.abs(slope - line2.slope) > epsilon ||
        Math.abs(yintercept - line2.yintercept) < epsilon;
    }
}

为什么没有简单的解决方案,如果斜率不同,那么它们将相交。为什么 epsilon 和 y 截取。

在建议中它说

不要假设斜率和 y 截距是整数。了解浮点表示的局限性。永远不要检查 == 是否相等。

【问题讨论】:

  • 你了解测试两个浮点数是否相等的问题吗?
  • @Beta 我也可以在那里使用一些帮助。谢谢
  • 这正是我在大多数情况下讨厌浮点数据类型的原因。如果我要阅读该问题,我会假设斜率和截距是实际数字,而不是浮点表示。 java中有一个BigDecimal类型,它没有浮点问题——我敢肯定它运行计算比double慢得多,但至少你不会有epsilon废话来处理。跨度>

标签: java math floating-point


【解决方案1】:

“解决方案”是错误的。

此“解决方案”中隐含的概念是,已传递的参数不准确,即在调用 intersect 之前,这些值已经过计算,可能会产生带有舍入错误的结果。因为值中存在错误,所以如果精确计算会相等的数字是不相等的。为了将它们识别为相等,此“解决方案”将某些实际上不相等的值视为相等。

这种推理的一个缺陷是intersect 例程不知道错误可能有多大,因此没有基础知道它应该使用epsilon 的值。理想值可能为零,也可能是一百万。鉴于所提供的信息,所使用的值 1e-5 在任何工程原理中都没有依据。不仅如此,没有使用绝对错误的基础,就像这段代码一样。根据具体情况,使用的适当容差可能是相对误差、以 ULP 命名的误差或其他一些技术。根本没有理由相信当传递的参数理想地表示相交线但以某种未知方式计算时,此代码将返回 true

另一个缺陷是例程错误地接受不相等的相等值。该例程将报告为不与许多相交的线相交。这段代码并没有解决例程返回错误答案的问题;它只是改变了返回错误答案的情况,而且很可能大大增加了错误答案的数量。

【讨论】:

  • @SamuelEdwinWard:你对垂直线有什么具体问题?
  • 假设的解决方案将如何处理它们?能否用这个接口有意义地表示它们,代码会给出正确的答案吗?
  • @SamuelEdwinWard:我的回答断言问题中的“解决方案”是错误的。对于垂直或接近垂直的线,这不会改变。 intersect 可以将两条相交的线报告为不相交,因为在将它们传递给 intersect 之前,错误已经使它们的计算斜率相等(并且计算的值可能都是无穷大)。同样,两条不相交的线可能会被报告为相交,因为它们在理想情况下相等的斜率已被计算为不相等,其量大于epsilon(特别是如果一条是无限的,一条是有限的)。
  • @SamuelEdwinWard:对于垂直或接近垂直的线消失的一种可能性是intercept 在传递的实际值不相等时接受它们的斜率相等。这是因为斜率将是无限的或非常大,因此它们的差异不会小于epsilon
【解决方案2】:

首先,如果坡度不同,它们将相交的简单解决方案并不完整。它们可以具有相同的斜率和截距,因此是相同的。

建议所说的 epsilon 是因为计算机中的数字表示不准确。根据IEEE-standard,一个双精度数大约有 15 个精确计算的数字,因此斜率和截距可能由于先前的计算而产生舍入误差,因此使用 == 进行简单检查可能会得出它们不相同,而它们只是舍入误差不同.

【讨论】:

    【解决方案3】:

    如果没有斜坡,为什么没有简单的解决方案 相同,那么它们将相交。为什么 epsilon 和 y 截距。

    该解决方案考虑了由floating-point 算术引起的近似误差。 由于浮点数并不代表所有可能的实数,而是一个相对较小的子集(在 [-1,+1] 区间中更密集),当您必须处理浮点算术时,通常使用阈值来执行相等检查。

    epsilon 值表示一个阈值,在该阈值下 2 个不同的浮点值将被视为相等。

    【讨论】:

    • 击败我们...作为一名学生 (@Kraken),您最终将了解浮点数与整数类型数的存储和操作方式之间的区别,但是要记住的主要事情是,例如,20.0 - 7.0 可能不等于(使用 ==)120.0 - 117.0。
    • @LJ2 我猜你的意思是,20.0-7.0 != 到 120.0 - 107.0?
    • 是的,数学,我不太擅长,尤其是在处理一到两位减法时:/ 谢谢
    • @LJ2: 20. - 7. 等于 120. - 107. 在每个常见的浮点实现中。浮点错误不只是随机发生的;行为是指定的,如果您了解规范,则可以依赖该行为。
    • @Eric:我的意思是我的例子是假设性的......我想我会修改我的评论以阅读 - '你希望得到精确到小数点后 15 位的答案的任意计算不是必须等于不同的任意计算,(编辑:预期)相同的答案精确到小数点后 15 位。很抱歉我的具体任意示例可能造成的任何混淆:)
    【解决方案4】:

    在这一切之下,数字在处理时都被转换为二进制。不可能将大多数浮点数表示为精确的二进制数(因为它们将是 1 和 0 的无限序列),因此通过截断二进制序列来进行近似。例如,浮点数 0.1(即:十分之一)不能表示为精确的二进制数,而是用看起来像 0.000110011 的近似值表示……截断这个二进制数会导致潜在的舍入错误,因此确切的相等“==”可能会导致错误的响应,而实际上正是这种舍入误差给出了假阴性。引入 epsilon 试图通过说“低于这个数字的任何东西我们认为是零”来避免这些错误。请参阅wikipedia 的“二进制分数”部分了解更多信息。

    【讨论】:

    • 像往常一样,这只会将问题转移到 epsilon 值的选择上,这并不容易确定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多