我正在编写一个 Typescript 游戏,其中有绘制到画布上的顶点,以及来自它们的一些边。我想确定来自不同顶点的某些边是否相交。为此,我使用通用
doLinesIntersect
函数来确定两条边是否相交。
但是,问题是它显示所有线相交,因为如果两条边共享一个顶点,它们计算为始终相交,但我不希望这样。我可以通过手动检查它们是否共享一个顶点来使其“工作”,如下所示:
function doLinesTrulyIntersect(aX1: number, aY1: number, aX2: number, aY2: number, bX1: number, bY1: number, bX2: number, bY2: number): boolean {
const sharesVertexes = (aX1 === bX1 && aY1 === bY1) ||
(aX1 === bX2 && aY1 === bY2) ||
(aX2 === bX1 && aY2 === bY1) ||
(aX2 === bX2 && aY2 === bY2);
return !sharesVertexes && doLinesIntersect(
aX1, aY1, aX2, aY2,
bX1, bY1, bX2, bY2
);
}
基本上,如果两条边共享一个顶点,那么它们不会相交。
但是,这总是有效吗?逻辑是,既然如果两条边具有相同的顶点,那么(因为它们是同一个点),浮点相等测试应该起作用,对吗?毕竟,它们的底层是完全相同的。
但是,我知道通常测试两个浮点是否相等是不正确且不一致的,但这适用于这种情况吗?
如果一条边上的端点X和另一条边上的端点Y设置为等于同一点P,则X等于Y。浮点实体不是自发变化的神秘实体,相等性测试报告两个事物相等当且仅当它们相等时。
当您看到有关比较浮点数是否相等的警告时,实际问题是比较任何类型的近似值,而不是浮点算术所特有的任何内容。假设有一些理想数 N 并且我们有两个近似值 A 和 B 到 N。 A 和 B 相等吗?很可能不是,因为以不同的方式准备两个近似值通常会产生不同的结果。要估计美国蓝眼睛人口的百分比,您可能会出去对 1,000 人进行抽样,并得出一些百分比 A,另一个人可能会出去对其他 1,000 人进行抽样,并得出一些百分比 B 。尽管这两者都是 N 的近似值,但它们很可能不相等。
在浮点运算中出现这个问题的原因是,浮点主要是为“近似”实数运算而设计的,并且主要用于此目的。请注意,它是浮点算术,近似于实数算术。浮点数字是实际的实数(它们的子集)。这些数字没有任何近似或其他奇怪的地方:每个浮点数都是一个实数。当您将浮点变量设置为浮点数时,它会保留该数字。它不会改变或变得近似。 浮点数的计算过程会引入近似值和舍入误差:大多数浮点运算,包括加法和其他算术、科学函数,以及从十进制转换为浮点格式(包括源代码中的十进制数字)代码或程序输入)是可能对其结果进行四舍五入以适合浮点格式的操作。
请注意,上述内容实际上适用于
任何数字格式。当精确的数学结果不符合格式时,定点数的计算也会产生舍入结果。并且整数的计算也被调整以适应整数格式。整数算术中的 7/3
产生 2,误差大于 10 分之一,而“双精度”浮点中的
7./3.
误差小于千万亿分之一。因此,整数运算的舍入误差可能比浮点运算严重得多。人们之所以对浮点舍入而不是整数舍入持谨慎态度,是因为我们使用这些格式的主要方式,而不是因为它们固有的对错误的敏感性。此外,一旦您使用近似值,所有结果都是近似值。通过减去两个几乎相等的数字,您可以获得非常大的相对误差。人们对比较提出警告,因为这是新手可能误用的一种操作。但是,每当您使用任何格式的近似值时,您都应该了解可能发生的错误以及错误的大小。
以上所有内容都是为了给您提供背景信息,以确定您可以依赖哪些操作。如果您将两个端点设置为同一点并稍后比较它们,它们将比较为相等。
您描述的问题中可能出错的一些事情是:
您一开始就没有将两个端点设置为同一点。