Python整数比较(不等于0)基准

Python integer comparison (not equal to 0) benchmarks

我在 python 中制作一个 2D 物理引擎是为了好玩。我使用物体的速度来确定是否应该 运行 对其进行碰撞检测。也就是说,如果它的速度会导致它在下一个周期内进入另一个物体,那么我 运行 对其进行碰撞检测。

注意:x 和 y 速度总是整数

所以我意识到我必须检查对象的 x 或 y 速度是否小于或大于(不是)0。

有很多方法可以做到这一点。我想出了 4 种不同的方法:

def cmp1 (a,b):
    return a > 0 or a < 0 or b > 0 or b < 0

def cmp2 (a, b):
    return a != 0 or b != 0

def cmp3 (a, b):
    return abs(a | b) > 0

def cmp4 (a, b):
    return a | b != 0

我喜欢第4种方法,因为它操作最少,英文也好读 a or b does not equal 0

但是在我使用的 4 种方法和基准测试方法中,它的平均时间倒数第二慢,这让我很吃惊。事实上,第一种方法是最快的(再次使用我使用的基准测试方法)。

这是我用来计算时间的方法:

def randints(min, max, amount):
    return tuple([random.randint(min, max) for i in range(amount)])

times = []
for i in range(1000):
    n = randints(-9999, 9999, 2)
    t = time.time() * 1000
    cmp4(*n)
    t2 = time.time() * 1000
    times.append(t2-t)

print('Average Time: ', sum(times)/len(times))

如果我对每种方法多次 运行,我会得到非常一致的结果:

cmp1 - 0.00027s

cmp2 - 0.00032s

cmp3 - 0.00037s

cmp4 - 0.00035s

所以我的问题是 为什么第 4 种方法比第一种方法慢? 肯定 2 个操作(一个按位,一个比较)应该比 4 快。

而且,是的,我知道只有几微秒的差异。

有更好的测试方法

y = [(random.randint(0,1), random.randint(0,1)) for _ in range(100_000)]

def test(cmp):
    [cmp(a, b) for a, b in y]

%timeit test(cmp1)
20.1 ms ± 315 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit test(cmp2)
17.3 ms ± 212 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit test(cmp3)
29.3 ms ± 588 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit test(cmp4)
21.9 ms ± 289 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

or的主要优点是短路,有效等价于:

def or(a, b):
    if a: return a
    return b

| 需要执行一个实际的(非常低级别的)操作,然后创建一个新的 python 整数对象,然后执行另一个操作。

我的测试使用了一个 50% 为零的数组。如果零的百分比更大或更小,结果可能会大不相同。

无论如何,您忘记了所有方法中最快的方法(因为所有 non-zero 个数字都是 True):

def cmp0(a, b):
    return a or b

bool(cmp0(0, 0)), bool(cmp0(-12, 0)), bool(cmp0(3.14, 0))
# --> (False, True, True)

%timeit test(cmp0)
12.8 ms ± 191 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

但是,如果您想尽可能清楚(python 中编程的核心内容),我会使用 a != 0 or b != 0.