Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonの除算演算子とは?「/」と「//」の違いを徹底解説

はじめに:式のデータ型は引数で決まる

一般に、式のデータ型は引数の型によって決まります。このルールはほとんどの演算子に共通しており、たとえば2つの整数を足し合わせれば、結果も整数になるのが自然です。

しかし、除算の場合には話が少し複雑になります。開発者の間で2つの異なる期待が存在するからです。除算によって正確な浮動小数点数(float)を得たいケースもあれば、小数点以下を切り捨てた整数の結果を求めたいケースもあるのです。

Python 2における「/」演算子の挙動

従来のPythonでは、除算演算子「/」の振る舞いは引数の型だけに依存していました。たとえばPython 2.7では、20 / 7 は両方の引数が整数であるため 2 となります。一方、20./7 のように片方でも浮動小数点数を含めると、2.857142857142857 という浮動小数点の結果が返されます。

この仕様は、プログラムの作者が想定していなかったデータ型が渡された場合に、思わぬ不具合の原因となっていました。

摂氏から華氏への変換プログラムで見る問題点

具体例として、摂氏温度を華氏温度へ変換するシンプルなプログラムを考えてみましょう。入力の数値が同じであっても、整数(18)と浮動小数点数(18.0)のどちらを渡すかで、まったく異なる結果になってしまいます。

#Conversion of celcius to Fahrendheit in python 2.6
>>> print 18*9/5 + 32
64
>>> print 18.0*9/5 + 32
64.4
>>> 18 == 18.0
True

このように、18.0 を渡せば正しい結果 64.4 が得られますが、18 を渡すと誤った結果 64 になってしまいます。これは、Python 2.xではすべての引数が整数の場合に「/」演算子がフロア除算(切り捨て除算)として動作するためです。一方、引数のどれかひとつでも浮動小数点数であれば、「/」は浮動小数点の結果を返します。

解決策として導入された「//」演算子

明示的な型変換関数(たとえば float(x))を使えば、この問題を回避できます。しかし、予期しないデータ型という稀なケースのためだけに、あちこちで変換処理を書き散らかすのは、Pythonが目指す「シンプルで簡潔な言語」という思想に反します。

そこで、Python 2.2以降では期待される挙動を明確にするための新しい除算演算子が導入されました。将来のPythonでは、通常の「/」演算子は常に浮動小数点の結果を返し、切り捨て除算には専用の「//」演算子を使うことになったのです。

>>> # Python 2.7 program to demonstrate the use of "//" for both integers and floating point number
>>> print 9//2
4
>>> print -9//2
-5
>>> print 9.0//2
4.0
>>> print -9.0//2
-5.0

ここで注目したいのは、「//」演算子がオペランドの符号に関わらず、結果をマイナス無限大方向へ切り捨てる(floor)という点です。そのため -9//2-4 ではなく -5 になります。

Python 3.xでの除算操作

Python 3.xでは、上記のような欠点は取り除かれました。「/」演算子は、引数が整数であっても浮動小数点数であっても、常に浮動小数点除算を行います。

>>> #Conversion of celcius to Fahrendheit in python 3.x
>>> #Passing 18 (integer)
>>> print (18*9/5 + 32)
64.4
>>> #Passing 18.0(float)
>>> print(18.0*9/5 + 32)
64.4

さらに、正の数と負の数のどちらを渡しても、挙動に一貫性があります。

>>> print(9/2)
4.5
>>> print(-9/2)
-4.5
>>> print(9.0/2)
4.5
>>> print(-9.0/2)
-4.5

まとめ

Pythonの除算演算子の挙動は、バージョンによって大きく異なります。

  • Python 2.x: 「/」は引数がすべて整数なら切り捨て除算、片方でもfloatなら真の除算になる。
  • Python 2.2以降: 明示的な切り捨て除算として「//」演算子が利用可能に。
  • Python 3.x: 「/」は常に浮動小数点除算を返し、「//」が切り捨て除算を担当する。

Python 2系のコードを3系へ移行する際は、この除算の挙動の違いに特に注意が必要です。意図しない丸めエラーを避けるためにも、「/」と「//」の役割を正しく理解しておきましょう。

  1. Pythonでタプル同士を除算する方法

    Pythonでタプル同士の除算(要素ごとの割り算)を行いたい場合、「zip」メソッドとジェネレータ式を組み合わせるとシンプルに実現できます。zipメソッドは、複数のイテラブル(反復可能なオブジェクト)を受け取り、それらの要素を対応する位置ごとにまとめてタプルとして返す機能を持っています。一方、ジェネレータとは、イテレータを手軽に作成するための仕組みです。内部的には「__iter__()」と「__next__()」というメソッドを持つクラスが自動的に実装され、内部状態も自動的に管理されます。さらに、返せる値がなくなった時点では「StopIteration」例外を発生させることで、反復処理の終了を

  2. Pythonでパターンを出力する方法|三角形・数字・アルファベット・ピラミッドのコード例

    Pythonでパターンを出力するには、ネストされた(入れ子構造の)forループを使用します。外側のループで行数を制御し、内側のループで列数を処理します。そしてprint文を工夫することで、目的に応じたさまざまなパターンを作成できます。パターンには、星(アスタリスク)パターン、数字パターン、アルファベットパターンなどがあり、三角形やピラミッドなど、さまざまな形状にも対応できます。パターン出力の基本これらのパターンは、print文を少し変更しながらforループを組み合わせることで出力できます。基本的な考え方はどのパターンも共通しており、違いはごくわずかです。ここからは、代表的なパターンのコードを実