在C或c++中,是否有比x >= start && x <= end更快的方法来测试一个整数是否在两个整数之间?
更新:我的具体平台是iOS。这是框模糊函数的一部分,它将像素限制在给定正方形中的圆形。
更新:在尝试接受的答案后,我在一行代码上得到了一个数量级的加速,而不是正常的x >=开始&& x <=结束方式。
更新:下面是XCode汇编器的前后代码:
新方法
// diff = (end - start) + 1
#define POINT_IN_RANGE_AND_INCREMENT(p, range) ((p++ - range.start) < range.diff)
Ltmp1313:
ldr r0, [sp, #176] @ 4-byte Reload
ldr r1, [sp, #164] @ 4-byte Reload
ldr r0, [r0]
ldr r1, [r1]
sub.w r0, r9, r0
cmp r0, r1
blo LBB44_30
老方法
#define POINT_IN_RANGE_AND_INCREMENT(p, range) (p <= range.end && p++ >= range.start)
Ltmp1301:
ldr r1, [sp, #172] @ 4-byte Reload
ldr r1, [r1]
cmp r0, r1
bls LBB44_32
mov r6, r0
b LBB44_33
LBB44_32:
ldr r1, [sp, #188] @ 4-byte Reload
adds r6, r0, #1
Ltmp1302:
ldr r1, [r1]
cmp r0, r1
bhs LBB44_36
令人惊讶的是,减少或消除分支能够提供如此惊人的速度。
只有一个比较/分支时,有一个老技巧可以做到这一点。它是否真的能提高速度还有待商榷,即使它真的能提高速度,可能也太小了,不值得注意或关心,但当你只从两次比较开始时,巨大提高的机会是相当渺茫的。代码如下:
// use a < for an inclusive lower bound and exclusive upper bound
// use <= for an inclusive lower bound and inclusive upper bound
// alternatively, if the upper bound is inclusive and you can pre-calculate
// upper-lower, simply add + 1 to upper-lower and use the < operator.
if ((unsigned)(number-lower) <= (upper-lower))
in_range(number);
对于典型的现代计算机(即任何使用双补码的计算机),转换到unsigned实际上是一个nop——只是改变了相同位的看待方式。
注意,在典型情况下,您可以在(假定的)循环之外预先计算上下,因此这通常不会占用大量时间。除了减少分支指令的数量,这也(通常)改善了分支预测。在这种情况下,无论该数字低于范围的底端还是高于范围的顶端,都采用相同的分支。
至于这是如何工作的,基本思想很简单:一个负数,当被视为无符号数时,将比任何开始是正数的数都大。
在实践中,该方法将number和区间转换到原点,并检查number是否在区间[0,D]中,其中D = upper - lower。如果数字低于下界:为负数,如果高于上界:大于D。
只有一个比较/分支时,有一个老技巧可以做到这一点。它是否真的能提高速度还有待商榷,即使它真的能提高速度,可能也太小了,不值得注意或关心,但当你只从两次比较开始时,巨大提高的机会是相当渺茫的。代码如下:
// use a < for an inclusive lower bound and exclusive upper bound
// use <= for an inclusive lower bound and inclusive upper bound
// alternatively, if the upper bound is inclusive and you can pre-calculate
// upper-lower, simply add + 1 to upper-lower and use the < operator.
if ((unsigned)(number-lower) <= (upper-lower))
in_range(number);
对于典型的现代计算机(即任何使用双补码的计算机),转换到unsigned实际上是一个nop——只是改变了相同位的看待方式。
注意,在典型情况下,您可以在(假定的)循环之外预先计算上下,因此这通常不会占用大量时间。除了减少分支指令的数量,这也(通常)改善了分支预测。在这种情况下,无论该数字低于范围的底端还是高于范围的顶端,都采用相同的分支。
至于这是如何工作的,基本思想很简单:一个负数,当被视为无符号数时,将比任何开始是正数的数都大。
在实践中,该方法将number和区间转换到原点,并检查number是否在区间[0,D]中,其中D = upper - lower。如果数字低于下界:为负数,如果高于上界:大于D。