PEP: 238
Title: Changing the Division Operator
Version: $Revision: 1.19 $
Author: Moshe Zadka <pep at zadka.site.co.il>, Guido van Rossum <guido at python.org>
Status: Final
Type: Standards Track
Created: 11-Mar-2001
Python-Version: 2.2
Post-History: 16-Mar-2001, 26-Jul-2001, 27-Jul-2001
X-Translator: Matsui "Fe2+" Tetsushi

概要


    現在の除算 (/) 演算子は数値の型によって色々な意味を持っている。た
    とえば演算の対象が int や long の場合は数学的な除算結果の切り下げ
    (floor)を返す。一方で float や complex に対しては除算の適当な近似
    値を返す。このことが float や complex が渡されることを期待した式が、
    想定外とはいえ受け取ることができる整数に対してエラーを引き起こしが
    ちである。

    我々はこれに対処するため異なる演算に別々の演算子を導入することを提
    案する。x/y は数学的な意味での除算結果の適当な近似を返し(「真の除
    算」)、x//y は切り下げを返す(「切り下げ除算」)。また、意味の入
    り混じった現在の x/y を「旧式除算」と呼ぶ。

    過去のバージョンとの互換性が著しく損なわれるので、c.l.python での
    flamewar を呼び起こさないように、次のように緩やかな移行を提案する
    (開始は Pythton 2.2 から)。

    - 旧式除算は Python 2.x シリーズ中はデフォルトのままに留まる。
      真の除算は Python 3.0 で標準になる。

    - // 演算子ははっきりと切り下げ除算を求めるために使えるようになる。

    - 未来の除算を使うことを宣言するには、"from __future__ import
      division" と綴り、そのモジュールでは / が真の除算を意味するよう
      にする。

    - コマンドラインオプションにより int や long に対する旧式除算に実
      行時に警告が出るようにできる。もう一つ別のコマンドラインオプショ
      ンにより真の除算をデフォルトにできる。

    - 標準モジュールでは未来の除算を宣言し // 演算子と使い分ける。これ
      により旧式除算の使用を避ける。

動機


    旧来の除算演算子は任意の数値の入力に正しい答を与えるように数式を書
    くことを困難にする。他の演算子については、たとえば x*y**2 + z のよ
    うに公式を書くことができ、どのような数値の型 (int や long, float,
    complex) に対してもその答えは数学的に期待されるものに近い(勿論、有
    効数字の範囲内でということだ)。しかし、除算は問題を投げかける。も
    しその数式が除数も被除数も整数型になり得るとしたら、それは切り下げ
    除算を真の除算の代わりに与える。

    問題は動的に型付けされる言語に特有のものだ。C のように静的に型付け
    される言語では、入力(典型的には関数の引数のことだが)は double や
    float と宣言され、関数呼び出しが整数引数を渡すときは呼び出し時に
    double や float に変換される。Python には引数の型宣言がないので、
    整数引数が式の中に容易に入り込んでしまう。

    この問題が特に質が悪いのは int が他の全ての状況において float の完
    璧な代用になるからだ。math.sqrt(2) は math.sqrt(2.0) と同じ値を返
    すし、3.14*100 と 3.14*100.0 も同じ値を返す等々。それゆえ、数値を
    扱うルーチンの作者は浮動小数点数だけをコードのテストに使って正しく
    動くと疑いもせず、ユーザーがたまたま整数を入力してしまって間違った
    結果を得ることになる。

    もう一つ別の見方は、旧式除算は float と int の両方に対して問題なく
    動く多相的関数(polymorphic function)を書くことを難しくする、という
    ことだ。他の演算子ではこの問題は起こらない。どんなアルゴリズムでも
    int と float のどちらでも正しく動くようなものは、一方に対し丸め除
    算をもう一方に対し真の除算を必要とすることはない。

    正しい回避法は微妙なものだ。引数を float() で変換するのは、複素数
    かも知れない場合間違いである。0.0 を足すと引数がマイナス0のとき引
    数の正負を保存しない。どちらの場合にも通用する唯一の回答は一つの
    (普通は最初の)引数に 1.0 を掛けることである。これは float や 
    complex に対し値の正負を変えないし、int や long を対応する float 
    に変換する。

    筆者の意見ではこれは Python における真正のデザインバグで、できるだ
    け早く手直しされるべきだと思う。Python がますます使われるようになっ
    ていくことを考えれば、このバグを放置するコストはやがて古いコードを
    手直しするコストを上回ることだろう -- 手直しされるべきコードは限り
    があるが、将来このバグに悩まされるコードは限りがないわけだ。

    この変更を行なうさらにもう一つの理由は最終的に Python の数値モデル
    を統一したいという願望だ。このことは PEP 228 (現在はまだ不完全だが)
    の主題である。統一された数値モデルは、いかなる数値の型が使われてい
    るかユーザーが知る必要をほとんどなくす。これは初心者に対する朗報で
    あると同時に、熟練プログラマーにとっても色々な数値ごとの振舞の違い
    を考える必要をなくしてくれる。(勿論、計算の安定性や精度について考え
    なくても良くなるわけではない。)

    統一された数値モデルにおいては、異なった型 (int や long, float,
    complex, あるいはその他、たとえば新しい rational 型) は主に記憶容
    量の最適化のためにあり、ある程度は別の側面、たとえば不正確さや複素
    数であるかどうかを表すためにある。さらに、整数の 1 と浮動小数点数
    の 1 とは(不正確さを除けば)区別がつかず、どのような数値的文脈に
    おいても同じように振舞うべきである。明らかに、このモデルでは、a==b
    かつ c==d ならば a/c は b/d に等しくなければならない(不正確な数に
    関する丸めによって幾らか自由度はあるが)。そして、誰もが 1.0/2.0
    は 0.5 だということに同意するからには、1/2 も 0.5 でなければならな
    い。同様に、1//2 が 0 なので、1.0//2.0 も 0 でなければならない。


他の書き方


    美学からいうと x//y に不満を覚える人もいるだろう。それゆえいくつか
    の違った書き方が提案された。それらをここに書き記す。

    - x div y   これは新しいキーワードを導入する。しかし、div はよくあ
      る識別子なので、未来の除算を宣言したとき以外認識しないようにしな
      ければ、多数の現に存在するコードを動かなくしてしまう。変換が必要
      なコードの大部分は整数の除算部分だと思われるのに対して、これは未
      来の除算を宣言する必要を大幅に増やしてしまう。未来の除算の宣言と
      ともにであっても、絶対に必要でない限り新しいキーワードの追加には
      反対する一般的な感傷も障害になる。

    - div(x, y)   これは古いコードの書き換えをより困難にする。x/y を
      x//y や x div y で置き換えるのは単純な問い合わせ置換 (query
      replace) で済む。大抵の場合プログラマーはある特定のモジュールが
      整数でだけ動くのを簡単に確かめられるので全ての x/y を置き換えれ
      ばいい。(それでも問い合わせ置換はコメントや文字列リテラルの中に
      あるスラッシュを残すために必要である。)x/y の div(x, y) による
      置き換えにはより賢い道具が求められる。なぜならば、/ の左右の式が
      どこまで続くのかを "div(" と ")" を置く場所を決める前に解析しな
      ければならないからだ。

    - x \ y   バックスラッシュは既にトークンであり、行の継続を意味して
      いるし、Unix 的な目からはなにがしかの「エスケープ」を示している
      ように思われる。さらに(これは Terry Reedy によるものだが)これ
      は eval("x\y") といったものを正しく理解するのを困難にする。


別のやり方


    変換しなければならないコードの量を減らすために、いくつか別のやり方
    の提案があった。ここに集めたのはそれぞれに対する簡単な議論である。
    もし c.l.py で議論されたやり方の内ここに言及のないものをご存知の方
    は第2著者にメールして欲しい。

    - 旧来のまま / を残し、// を真の除算のために導入する。これはイカレ
      た演算子を言語に残し、イカレた振舞と付き合い続ける道である。また、
      PEP 228[0] 風の統一された数値モデルへの道を閉ざすものでもある。

    - int の除算は特別な "portmanteau" 型を返し、この型は整数の文脈で
      は整数のように振舞い、浮動小数点数の文脈では浮動小数点数として振
      舞うようにする。問題は、ほんの数個の演算によって整数としての値と
      浮動小数点数としての値が懸け離れてしまうことだ。このときどちらの
      値を比較に使うのか不明であるし、勿論、多くの文脈(文字列への変換
      とか)は明確な整数か浮動小数点数かの好みを持ち合わせていない。

    - どの意味で除算を使うかを、未来の除算を宣言する方法以外で、モジュー
      ルの中で指定する。これは旧式除算を永続的なしこりとして言語の内に
      留め、未来の世代の Python プログラマーにもこの問題も対処法も学ぶ
      ように要求し続ける。

    - "from __past__ import division" を旧式除算をモジュールの中で使う
      ために使う。これも旧式除算を永続的なしこりとして言語の内に留める
      ことになる。あるいは少なくとも当分の間は(そのうち過去の除算の宣
      言は ImportError を raise するようになるだろう)。

    - あるコードが書かれた対象の Python のバージョンを指定する命令か何
      かを使う。これは未来の Python 処理系に昔のバージョンを *正確に*
      エミュレートすることを要求する。これはやりすぎだろう。もっと簡単
      なのは複数の処理系をインストールしたままにしておくことだ。この方
      法に対するその他の意見はバージョンの指定はいつだって細か過ぎると
      いう意見だ。Python X.Y に対して書かれたコードは大抵 Python
      X.(Y-1) でも X.(Y+1) でも動く。つまり X.Y と指定するのは必要以上
      の制約である。と同時に、どれだけ未来あるいは過去のバージョンにな
      ると動かなくなるかは知る術がない。


API の変更


    移行期間中、我々は *3つ* の除算演算子を同じプログラムの中でサポー
    トしなければならない。3つとは、旧式除算(未来の除算の宣言のないモ
    ジュールの中の /)、真の除算(未来の除算の宣言のあるモジュールの中
    の /)、切り下げ除算(//)である。それぞれの演算子が2通りの姿で現
    れる。通常の演算子として、そして代入演算子として(/= や //=)。

    それぞれの名前は以下の通り。

    - 多重演算子メソッド

      __div__(), __floordiv__(), __truediv__();

      __idiv__(), __ifloordiv__(), __itruediv__().

    - 抽象 API C 関数

      PyNumber_Divide(), PyNumber_FloorDivide(),
      PyNumber_TrueDivide();

      PyNumber_InPlaceDivide(), PyNumber_InPlaceFloorDivide(),
      PyNumber_InPlaceTrueDivide().

    - バイトコード opcode

      BINARY_DIVIDE, BINARY_FLOOR_DIVIDE, BINARY_TRUE_DIVIDE;

      INPLACE_DIVIDE, INPLACE_FLOOR_DIVIDE, INPLACE_TRUE_DIVIDE.

    - PyNumberMethod スロット

      nb_divide, nb_floor_divide, nb_true_divide,

      nb_inplace_divide, nb_inplace_floor_divide,
      nb_inplace_true_divide.

    付け加えられた PyNumberMethod スロットは tp_flags にさらなるフラグ
    を要求する。このフラグは Py_TPFLAGS_HAVE_NEWDIVIDE と名付けられ、
    Py_TPFLAGS_DEFAULT に含まれる。

    真のあるいは切り下げ除算 API は対応するスロットを探し呼び出す。ス
    ロットが NULL の時は、例外を上げる。旧式除算スロットには戻らない。

    Python 3.0 では旧式除算の解釈はなくなる。旧式除算の API は真の除算
    と同義になる。


コマンドラインオプション


    -Q コマンドラインオプションは4種類の文字列を引数にとる。4種類と
    は "old"、"warn"、"warnall"、"new" である。デフォルトは Python 2.2
    では "old" だがやがて来る 2.x で "warn" に変わる。"old" という値は
    上で述べた旧式除算を意味する。"warn" という値では旧式除算が int ま
    たは long に適用された場合に警告を(DeprecationWarning を標準の警
    告の枠組を使って)発する。"warnall" では旧式除算が float や
    complex に対して使われている時にも警告を発する。これは後に述べる変
    換スクリプト fixdiv.py で使われる。"new" を指定するとデフォルトを
    変更して / 演算子が常に真の除算を意味するようにする。"new" オプショ
    ンはある種の教育的環境、すなわち真の除算が必要とされるが生徒たちに
    いつも未来の除算を宣言させるのが問題となるような、そういうところで
    使われることだけを意図している。

    このオプションは Python 3.0 ではサポートされなくなる。Python 3.0
    では / は常に真の除算として解釈される。

    (このオプションは当初 -D にするよう提案されていたが、既に Jython
    にあるオプションと被る。そこで Q -- Quotient(商)とした。引数の文
    字列についても他の名前が提案されていた。たとえば -Qclassic,
    -Qclassic-warn, -Qtrue, -Qold_division 等々。これらは大した利点も
    ないのに長過ぎるように思われる。とにかく classic という用語は言語
    自体においては使われていない(この PEP だけのものである)し、true
    もほとんど使われていない -- __truediv__ においてのみ使われる。)


切り下げ除算の意味


    切り下げ除算は Python の全ての数値型に対して実装され、

        a // b == floor(a/b)

    という意味を持つ。ただし結果の型は a と b が演算の前に coerce され
    た共通の型になる。

    細かくいうと、もし a と b が同じ型だったとすると、a//b もその型に
    なる。もし異なる型であった場合、最初に coerce され、他の数値演算子
    に適用されるのと同じ規則にしたがって共通の型になる。

    特に、もし a と b とがともに int か long であった場合、結果はこれ
    らの型に対する旧式除算と同じになる。(両方の型が混ざっていた場合に
    もこれは正しく、int//long も long//int もともに long を返す。)

    浮動小数点数の場合、結果は浮動小数点数になる。たとえば

      3.5//2.0 == 1.0

    複素数に対しては // は例外を上げる。なぜなら複素数に floor() を適
    用することはできないからである。

    ユーザーの定義するクラスや拡張型では、すべてはその実装による。


真の除算の意味


    int と long に対する真の除算はそれらを float に変換した後、float
    の除算を適用する。すなわち、2/1 でさえ float (2.0) を返し、int を
    返さない。float と complex に関しては、旧式除算と変わらない。


    注意しておくが、long については真の除算は情報の欠落を引き起こし得
    る。これは真の除算の致し方ない点である(有理数が言語に導入されない
    限りは)。意識的に long を使うアルゴリズムでは // を使うことを考え
    た方がいい。

    Python に有理数型が付け加えられた暁には(PEP 239[2] を参照)、int
    や long に対する真の除算は有理数を返すことになるだろう。これによっ
    て long に対する真の除算で情報が欠落する問題を解消できる。しかしそ
    れまでは、一貫性のためには、float が真の除算における唯一の選択肢で
    ある。


未来の除算の宣言


    "from __future__ import division" がモジュール中にあるかまたは
    -Qnew が指定されたら、演算子 / と /= は真の除算の opcode に翻訳さ
    れる。それ以外の時はそれらは旧式除算と解釈される(Python 3.0 にな
    るまでは。その時はそれらは真の除算と解釈される)。

    未来の除算の宣言のあるなしは // と //= の認識及び解釈に影響を及ぼ
    さない。

    未来の宣言についての一般的な規則は PEP 236[4] を参照せよ。

    (より長いフレーズも提案された。たとえば "true_division" とか
    "modern_division" とか。しかし解り易くなるようには思われない。)


未解決の事柄


    これらの問題はより多くのフィードバックや最初の実装を経験することに
    よって時とともに解決されることを期待する。

    - // を商演算子、/ を比演算子と呼ぼうという提案があった。確かな意
      見はないが -- ある人々にとって商は除算の同義語であり、比というと
      有理数のように聞こえるが、それは誤解である。私は少しややこしい語
      法でもそれにより明らかさを避けられるならばそれを好む。(*訳注1) 
      また、ある人々は「商」というと零に向かって丸めると思い、「切り下
      げ除算」と陽に言った時のように無限大に向かって丸めるとは思わない。
      (*訳注2)

      *訳注1 明らかさを避ける(avoids unambiguity)ではなく、曖昧さを避
             ける(avoids ambiguity)ではないだろうか。
      *訳注2 無限大に向かって、とは、マイナス無限大に向かって、という
             ことだろう。

    - コマンドラインオプションでデフォルトを変えるのは良くないと言う議
      論があった。間違った使い方をすると確かに危険である。たとえば、
      -Qnew を要求するサードパーティー製ライブラリーパッケージと -Qold
      を要求する別のパッケージとは一緒に使えなくなってしまう。しかしな
      がら、VPython の人々は真の除算をデフォルトにする手段を欲しがって
      いるし、他の教育者もそうである、と思う。これらの人々は彼らの環境
      で使えるライブラリーパッケージについて十分コントロールできるよう
      だ。

    - クラスが __div__()、__floordiv__()、__truediv__() の3つともサポー
      トしなければならないというのは大変に思える。それに、3.0 になった
      ときにはどうすべきか? 多分、__div__() と __floordiv__() だけで
      いいだろう。あるいは少なくとも真の除算は __truediv__() を最初に
      試して __div__() を次に試すようにすべきかも知れない。


解決済み


    - 問題: とても大きい long 整数では、float を返すという真の除算の定
      義は問題を引き起こす。というのも Python の long の使える範囲が 
      float の範囲よりもずっと大きいからだ。この問題はもし有理数がサポー
      トされればそのときには消えてなくなる。

      解決: long の真の除算に対して、Python は内部的に範囲の限定されな
      い倍精度浮動小数点数を使い、double で表現できないほど商が大きく
      ならない限り OverflowError は起こらないようにした。

    - 問題: 暫定的には、おそらく long から float への変換は long が大
      き過ぎる時には OverflowError を上げるように作られ得る。

      解決: これは実装された、が、上で述べたように long の真の除算への
      入力の大きさは問題にならなず、問題になるのは商の大きさだけだ。

    - 問題: Tim Peters が有効範囲内の float が返されたならば精度が保証
      されるということを確かめてくれるはずだ。


      解決: long の真の除算の商が float で表し得るなら、3回の丸め誤差
      以外には煩わされない: 1回ずつが内部的に使用される範囲の限定され
      ない倍精度浮動小数点数にそれぞれを変換するときに起こり、もう1回
      が割算の際に起こる。しかしながら次のことに注意して欲しい。商の大
      きさが double で表現し切れないほど *小さい* ときは、例外は発生せ
      ずに 0.0 が返される(「黙ってアンダーフローする」)。

FAQ


    Q. Python 3.0 はいつリリースされるのか?

    A. あまり遠い将来のことは考えてないので確かなことは言えない。我々
       としては移行期間として少なくとも2年は掛けてもいいことにしたい。
       Python 3.0 がもっと早く出てきた時には、過去との互換性を考えて
       2.x のラインを生かしておきたい、少なくとも Python 2.2 のリリー
       スから2年以上は。実際には Python 3.0 が出てから数年は 2.x を使
       い続けられるので、移行の時間をとることはできる。Python をインス
       トールしているところは Python 2.x と 3.x の両方をインストールし
       ておいてくれるものと期待される。

    Q. なぜ真の除算は float 除算と呼ばないのか?

    A. それは有理数を導入することが*できる*ように門戸を開いておきたい
       からだ。そのときには 1/2 は float ではなく有理数を返すようにし
       たいのだ。詳しくは PEP 239[2] を参照。

    Q. なぜ __truediv__ と __itruediv__ は必要なのか?

    A. ユーザー定義クラスを2級市民にしたくはないからだ。type/class 統
       合とは関係ない。

    Q. 未来の除算を宣言したり // を使ったりせず、今の規則と新しい規則
       の両方で動くコードはどう書けばいいのか?

    A. 真の除算として x*1.0/y を、整数の除算としては divmod(x, y)[0]
       を使うといい。特に後者は本来の意味を良く表している。それから、
       complex が来ないとわかっていれば真の除算として float(x)/y も使
       える。整数に対して、負にならないとわかっているならば int(x/y)
       も使える -- int() の説明には C の実装によって int() は四捨五入
       か切り捨てのどちらかになると書いてあるが、切り捨てでない C の実
       装は見たことがないので、int() の仕様を切り捨てに変えようと思っ
       ている。注意しなければいけないのは、旧式除算(と切り下げ除算)
       は負の無限大に向かって丸めるが、int() では零に向かうので負の数
       に関しては異なった答を返すということだ。

    Q. input()、compile()、execfile()、eval() それから exec に対してど
       のように除算の意味を教えればいいのか?

    A. 呼び出すモジュールの選択に従う。PEP 236[4] ではこれは解決した問
       題としてリストされており、PEP 264[5] を参照している。

    Q. codeop モジュールを使ってコンパイルされたコードについては?

    A. きちんと動く。PEP 264[5] を参照。

    Q. 変換ツールなどの助けはあるのか?

    A. 勿論。こういうのは PEP の守備範囲外のことだけど、Python 2.2a3
       と一緒にリリースされる二つの単純なツールを教えておこう。
       Tools/scripts/finddiv.py は除算演算子を見つけ出す("grep /" よ
       りは少し賢い)。Tools/scripts/fixdiv.py は実行時の解析に基づい
       たパッチを作り出す。

    Q. なんで俺の質問に答えてくれないんだ?

    A. それは我々の耳に届いていないから。もしそれが c.l.py で議論され
       ていて一般の関心も低くないと思うならば第2著者に知らせて欲しい。
       (私的なメールで送られてきたものに答える時間も気力もないので、
       c.l.py で議論されるという条件が先に来る。)


実装


    本質的にはここに述べられたことは全て CVS では実装されており、
    Python 2.2a3 でリリースされる。大部分は既に 2.2a2 でリリース済み。


参考文献

    [0] PEP 228, Reworking Python's Numeric Model
        http://www.python.org/peps/pep-0228.html

    [1] PEP 237, Unifying Long Integers and Integers, Zadka,
        http://www.python.org/peps/pep-0237.html

    [2] PEP 239, Adding a Rational Type to Python, Zadka,
        http://www.python.org/peps/pep-0239.html

    [3] PEP 240, Adding a Rational Literal to Python, Zadka,
        http://www.python.org/peps/pep-0240.html

    [4] PEP 236, Back to the __future__, Peters,
        http://www.python.org/peps/pep-0236.html

    [5] PEP 264, Future statements in simulated shells
        http://www.python.org/peps/pep-0264.html


Copyright

    This document has been placed in the public domain.


日本語訳について

    日本語訳は Fe2+ (VED03370@nifty.ne.jp) が行ないました。

    誤訳、誤植などありましたらお知らせ下さい。

    元の文書にしたがって、自由な改変および再配布を認めます。