Help us understand the problem. What is going on with this article?

「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の方が時間はかかると思います。 

junjis0203
気になったことを徹底的に調べる探究者。そんな感じの調査レポートを書くことが多いですがどなたかの参考になりましたら幸いです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away