我正在研究一个将项目细分为象限的数据结构,我发现的一个瓶颈是我选择点的象限的方法。不可否认,它相当简单,但它被召唤了很多次,它加起来。我想有一种有效的方法可以把它变成我想要的东西,但我想不出来。
private int Quadrant(Point p)
{
if (p.X >= Center.X)
return p.Y >= Center.Y ? 0 : 3;
return p.Y >= Center.Y ? 1 : 2;
}
Center
的类型为Point
,坐标为ints
。是的,我运行了代码配置文件,不,这不是过早的优化。
因为这只是在内部使用,我认为我的象限 不在Cartesian order,只要它们的范围是0-3。
答案 0 :(得分:3)
C / C ++中最快的方式是
(((unsigned int)x >> 30) & 2) | ((unsigned int)y >> 31)
(30/31或62/63,取决于int的大小)。 这将使象限为0,2,3,1。
编辑LBushkin:
(((unsigned int)(x - center.x) >> 30) & 2) | ((unsigned int)(y-center.y) >> 31)
答案 1 :(得分:1)
我不知道你可以在C#中大大加快这段代码的速度。但是,你可以做什么,看看你是如何处理点的,看看你是否可以避免对这种方法进行不必要的调用。也许你可以创建一个QuadPoint
结构来存储一个点所在的象限(在你计算一次之后),这样你就不必再这样做了。
但是,诚然,这取决于您的算法正在做什么,以及是否可以存储/记忆象限信息。如果每一点都是完全独特的,这显然无济于事。
答案 2 :(得分:1)
我刚刚被告知正确排序产生0,1,2,3象限结果的解决方案:
#define LONG_LONG_SIGN (sizeof(long long) * 8 - 1)
double dx = point.x - center.x;
double dy = point.y - center.y;
long long *pdx = (void *)&dx;
long long *pdy = (void *)&dy;
int quadrant = ((*pdy >> LONG_LONG_SIGN) & 3) ^ ((*pdx >> LONG_LONG_SIGN) & 1);
此解决方案适用于double类型的x,y坐标。
我已经对这个方法进行了一些性能测试,并且在原始问题中进行了分支方法:我的结果是分支方法总是快一点(目前我有稳定的160/180关系)< / strong>,所以我更喜欢使用按位运算的方法的分支方法。
<强>更新强>
如果有人感兴趣,所有三种算法都合并为EKAlgorithms C/Objective-C repository作为“笛卡尔象限选择”算法:
所有算法都经过优化,可以处理双类型点。
性能测试向我们展示了一般来说,Mac OS X上的第一个分支算法是胜利者,但在Linux机器上我们确实看到第二个算法的执行速度比分支算法快一点。
因此,一般的结论是坚持使用分支算法,因为按位版本不会带来任何性能提升。
答案 3 :(得分:0)
我的第一次尝试是摆脱嵌套的条件。
int xi = p.X >= Center.X ? 1 : 0;
int yi = p.Y >= Center.Y ? 2 : 0;
int quadrants[4] = { ... };
return quadrants[xi+yi];
如果象限被允许重新编号,则象限中的数组查找是可选的。我的代码仍需要两次比较,但它们可以并行完成。
我提前为任何C#错误道歉,因为我通常编写C ++代码。
当两个无符号31位坐标存储在64位无符号长变量中时,也许更有效率。
// The following two lines are unnecessary
// if you store your coordinated in unsigned longs right away
unsigned long Pxy = (((unsigned long)P.x) << 32) + P.y;
unsigned long Centerxy = (((unsigned long)Center.x) << 32) + Center.y;
// This is the actual calculation, only 1 subtraction is needed.
// The or-ing with ones hast only to be done once for a repeated use of Centerxy.
unsigned long diff = (Centerxy|(1<<63)|(1<<31))-Pxy;
int quadrant = ((diff >> 62)&2) | ((diff >> 31)&1);
退一步,可以采用不同的解决方案。不要将您的数据结构立即分成象限,而是在两个方向上交替排列。这也是在相关的Kd-tree
中完成的