Edited at

「x > 0 and x < 100」と「0 < x < 100」ってどっちの書き方するのがいいか試してみた

More than 1 year has passed since last update.


はじめに

Pythonでは、

if x > 0 and x < 100:

みたいな範囲条件を以下のように書けます。

if 0 < x < 100:

英語っぽく書けるようにって配慮でしょうね。

ふとどっちの方が速いのか気になりました。


ともかく測ってみよう

計測用コード


perf.py

import random

import time
import numpy as np

random.seed(1234)
arr = []
for _ in range(10):
s = time.time()
for _ in range(1000 * 1000):
x = random.random()
if x > 0.2 and x < 0.8:
pass
e = time.time()
arr.append(e - s)
print(np.average(arr))

random.seed(1234)
arr = []
for _ in range(10):
s = time.time()
for _ in range(1000 * 1000):
x = random.random()
if 0.2 < x < 0.8:
pass
e = time.time()
arr.append(e - s)
print(np.average(arr))


実行結果

0.322909283638

0.334062027931

実行ごとに差はあるけど自分でand書いた方が速い。


どう実行されるのか見てみよう

「x > 0 and x < 100」と「0 < x < 100」がそれぞれどういう命令コードになるのか見てみます。

>>> import dis

>>> co1 = compile('''
... x = 50
... x > 0 and a < 100
... '''
, '', 'exec')
>>> dis.dis(co1)
2 0 LOAD_CONST 0 (50)
2 STORE_NAME 0 (x)
3 4 LOAD_NAME 0 (x)
6 LOAD_CONST 1 (0)
8 COMPARE_OP 4 (>)
10 JUMP_IF_FALSE_OR_POP 18
12 LOAD_NAME 0 (x)
14 LOAD_CONST 2 (100)
16 COMPARE_OP 0 (<)
>> 18 POP_TOP
20 LOAD_CONST 3 (None)
22 RETURN_VALUE

>>> co2 = compile('''

... x = 50
... 0 < x < 100
... '''
, '', 'exec')
>>> dis.dis(co2)
2 0 LOAD_CONST 0 (50)
2 STORE_NAME 0 (x)
3 4 LOAD_CONST 1 (0)
6 LOAD_NAME 0 (x)
8 DUP_TOP
10 ROT_THREE
12 COMPARE_OP 0 (<)
14 JUMP_IF_FALSE_OR_POP 22
16 LOAD_CONST 2 (100)
18 COMPARE_OP 0 (<)
20 JUMP_FORWARD 4 (to 26)
>> 22 ROT_TWO
24 POP_TOP
>> 26 POP_TOP
28 LOAD_CONST 3 (None)
30 RETURN_VALUE

xが50とした場合、「0 < x < 100」の方がROT_THREE, JUMP_FORWARD分、命令が多いです。これが「0 < x < 100」の方が遅い理由と思われます。1


まとめ

というわけで「x > 0 and x < 100」って書くのと「0 < x < 100」って書くのどちらが速いか、何故速いのかを見てきました。前者の方が速く、後者が遅いのは余分な命令が実行されるからなようです。

ここでちゃぶ台ひっくり返しますが、個人的には後者の書き方の方が好みです。100万回ループして0.01秒しか違わないのなら人間が読みやすい方を選ぶべきです。


余談

身近にあるいくつかの環境で試してたのですがたまに「0 < x < 100」式の方が速い環境がありました。gccの違い?関係あるのかな。


余談その2

言うまでもないかもしれませんが、大体の言語では「0 < x < 100」と書くと予想に反する結果になります。初心者の人がついついこう書いてしまいがちですよね。

多くの言語では、

x = 200

0 < x < 100 → (0 < x) < 100 → true < 200 → true

となってしまいます。Javaみたいにbooleanとintの比較ができない言語だとコンパイル時点でエラーになったかな。





  1. 「x > 0 and x < 100」と「0 < x < 100」を見比べた場合、前者ではLOAD_NAME、後者はDUP_TOPでxの値をスタックに積んでいます。命令単体としてはLOAD_NAMEの方が時間はかかると思います。