PEP 238:除算演算子の変更
Python 2.xでは、除算演算は整数の除算と浮動小数点数/複素数の除算に分かれていました。整数の除算は切り捨て除算で、除算結果は最も近い整数(intまたはlong)になるように切り捨てられます。
>>> 5 / 2 2 >>> -5 / 2 -3
浮動小数点数と複素数の除算は、いわゆる「真の除算(true division)」であり、算術演算として妥当な近似値が返されます。
>>> 5.0 / 2 2.5 >>> -5 / 2.0 -2.5 >>> complex(5, 0) / 2 (2.5+0j)
2種類の除算が存在するのは、言語のデザインにおいて非常に深刻な問題と言えます。整数と浮動小数点数や複素数の演算を行うアルゴリズムを作成する場合は、非常に厄介なことになります。例えば関数ライブラリを開発するときに、真の除算を行うようにしたいと思っても、どうすれば安全に実現できるのか、すぐには明確な答えが見つかりません(__future__による回避策については後述します)。
例えば、整数、浮動小数点数、複素数の平均値を返す関数を作成するとします。単純な方法として次のようなコードが考えられます。
def average(*numbers): return sum(numbers) / len(numbers)
対象となるすべての数値が整数で、平均値が整数でない場合には、この関数は失敗します。
>>> average(1,4) 2
では、どのようにすれば真の除算ができるのでしょうか。すべての引数を浮動小数点数型に変換するという方法では、複素数があると対応できません。すべての数値に0.0を足すという方法では、元の数値が浮動小数点数-0.0の場合に符号が消えてしまいます(IEEE 754の浮動小数点数標準によると、0.0と-0.0は同一値ではありません)。
>>> x=-0.0 >>> x -0.0 >>> x + 0.0 0.0
型と符号を維持し、かつ、真の除算を行う唯一安全な方法は、引数を1.0倍することです。この方法は、単純なaverage関数を作成しようとするときに容易に考えつく方法とは言えず、無視できないオーバーヘッドもあります。
def average(*numbers):
return sum([n * 1.0 for n
in numbers]) / len(numbers)
>>> average(1,4)
2.5
幸い、Python 3.0では、除算は常に真の除算となり、(結果が整数でも)浮動小数点数または複素数(オペランドに複素数がある場合)を返します。
>>> 5 / 2 2.5 >>> -5 / 2 -2.5 >>> 4 / 2 2.0 >>> complex(5, 0) / 2 (2.5+0j)
Python 3.0で切り捨て除算を行うには、//演算子を使用します。両方のオペランドが整数の場合、結果は整数になります。オペランドの一方が浮動小数点数で、もう一方が浮動小数点数または整数の場合、結果は浮動小数点数(ただし、整数と等しい浮動小数点数)になります。切り捨て除算は複素数には対応しません。
>>> 5 // 2 2 >>> 5.0 // 2 2.0 >>> complex(5,0) // 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: can't take floor of a complex number.
あまり知られていませんが、明示的切り捨て除算は、Python 2.2から使用できました。また、真の除算の動作も、Python 2.2で次のステートメントを使用することによって利用できます。
from __future__ import division
これは、Python 3.0へ移行するコードを段階的に準備する場合に便利です。数値処理コードがある場合、またはPython 2.x方式の除算を行うコードを呼び出す場合、厄介なバグが発生する可能性があります。除算演算子を実際に使用しているコードを変更するだけではなく、呼び出し側もすべて確認しなければならなくなるからです。Python 3.0移行時の除算演算子対策に関するさらに具体的な情報については、今後の記事で取り上げる予定です。
インタープリタに-Qコマンドライン引数を渡して、除算の動作を制御することもできます。この引数に指定できる値は、old(デフォルト)、warn、warnall、new(真の除算)です。ただし、これを行う意味と理由を十分に理解している場合を除き、この方法はお勧めしません。除算のような重要な動作の制御をコマンドライン引数に依存するのは、極めて危険です。
