无论如何,避免浮点操作的最大在线点问题
Anyway to avoid floating point operation for Max Points on Line problem
我正在尝试解决Leet代码上的"在线最大点数"问题。我不可避免地需要进行浮点运算来计算每条线的 Y 截距和斜率。由于我过去的糟糕经历,我试图尽可能避免浮点运算。你有什么建议我怎么能在这里做到这一点吗?
我正在使用LeetCode框架进行开发,并且几乎只能访问标准C++库。 尝试使用双精度或长双精度,但其中一个测试用例已经将数字推到了这些数据类型准确性的极限。
//P1[0] is X coordinate for point P1 and P1[1] is Y coordinate
long double slopeCalc( vector<int> &p1, vector<int> &p2 )
{
if( p1[0] == p2[0] && p1[1] == p2[1] )
{
return DBL_MIN;
}
if( p1[0] == p2[0] && p1[1] != p2[1] )
{
return DBL_MAX;
}
return ( (long double)p2[1] - (long double)p1[1] ) / ((long double)p2[0] - (long double)p1[0]);
}
long double yIntersectionCalc( vector<int> &p1, vector<int> &p2 )
{
if( p1[0] == p2[0] && p1[1] == p2[1] )
{
return DBL_MIN;
}
if( p1[0] == p2[0] && p1[1] != p2[1] )
{
return DBL_MAX;
}
return ((long double)p1[1]*(long double)p2[0] - (long double)p2[1]*(long double)p1[0]) / (long double)(p2[0] - p1[0]);
}
如果两个点是 (0, 0) 和 (94911150, 94911151),则斜率计算为 1,这是不准确的。如果可能的话,我试图避免浮点划分。
注意:线上的最大点数问题将在 2D 空间中给定点(在本例中为整数坐标),并找到一条线上的最大点数。例如,如果点是 (0,0)、(2,2)、(4,3)、(1,1),则答案是 3,即点 (0,0)、(1,1) 和 (2,2)
在整数坐标中,三点的对齐测试可以写为表达式
(Xb - Xa) (Yc - Ya) - (Yb - Ya) (Xc - Xa) = 0
假设坐标范围需要N
位,则增量的计算需要N+1
位,表达式的精确计算需要2N+2
位。对此,你几乎无能为力。
在您的情况下,64 位整数就足够了。
一条建议:避免使用斜率/截距表示。
如果要避免使用浮点数,可以确定点 z 是否与其他两个点 x 和 y 共线的方法是计算矩阵的行列式
{{1,z1,z2},{1,x1,x2},{1,y1,y2}}
如果行列式为 0,则它们是共线的。由于使用排列定义计算行列式仅涉及乘法和加/减法,因此所有计算都将保留为整数。它为 0 的原因是行列式是三角形面积的两倍,以 x,y,z 为顶点,当且仅当三角形退化时为零。
另一种方法是使用 Fraction 对象,特别是由两个整数定义的线的斜率和截距被标识为 Fraction("有理数"),并且简化的分数由其分子和分母标识,因此您可以使用分数对(斜率、截距)作为标识符,并且由于您从不使用浮点运算,因此您无需处理舍入误差。有关分数的示例实现,请参阅 https://martin-thoma.com/fractions-in-cpp/,重要的部分是您可以使用算术运算符和规范化。
编辑:boost有一个有理数库,如果你想使用它 https://www.boost.org/doc/libs/1_68_0/libs/rational/
给定点a,b,c
,查看b,c
到一个共同点的斜率,a
:
ba.x = b.x - a.x
ba.y = b.y - a.y
ba.s = ba.y / ba.x
ca.x = c.x - a.x
ca.y = c.y - a.y
ca.s = ca.y / ca.x
a,b,c
点与AB
线的点是共线的,BC
具有共同的斜率,即:
ba.s == ca.s
替换和重新排列以消除分隔:
ba.y / ba.x == ca.y / ca.x
ba.y * ca.x / ba.x == ca.y
ba.y * ca.x == ca.y * ba.x
在原始公式中替换这些,然后a,b,c
是共线的 iff:
(b.y - a.y) * (c.x - a.x) == (c.y - a.y) * (b.x - a.x)
请注意,决定性答案也可以重新排列成这种形式,这证明了这种方法。但是这种形式只有 2 次乘法,而不是 12 次用于朴素行列式实现。
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 亚马逊在线评估编码问题,以找到第n个几何级数
- 我已经通过了该问题的所有测试用例,甚至是Udebugg上的所有测试用例,并且仍然在UVA在线法官上获得了WA裁决
- 无论如何,避免浮点操作的最大在线点问题
- 是否存在线程间共享变量的编译器优化问题
- 在线编译c/c++[安全问题]
- 在线组装;浮点数上的按位运算;这里出了什么问题?