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
.
我在 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
.