[解決済み] Pythonが整数の除算を負の無限大に丸めるのは、数学的にどういう理由からですか?
質問
Pythonを知っています
//
は負の無限大に向かって丸くなり、C++では
/
は切り捨てで、0に丸めます。
と、ここまでで分かっているのはこんな感じです。
|remainder|
-12 / 10 = -1, - 2 // C++
-12 // 10 = -2, + 8 # Python
12 / -10 = -1, 2 // C++
12 // -10 = -2, - 8 # Python
12 / 10 = 1, 2 // Both
12 // 10 = 1, 2
-12 / -10 = 1, - 2 // Both
= 2, + 8
C++:
1. m%(-n) == m%n
2. -m%n == -(m%n)
3. (m/n)*n + m%n == m
Python:
1. m%(-n) == -8 == -(-m%n)
2. (m//n)*n + m%n == m
しかし、なぜPythonの
//
は負の無限大の方向に丸めるのでしょうか?それを説明する資料は見つからず、ただ漠然と言われるのを見つけたり聞いたりしていました。
数学的な理由によるものです。
.
例えば C++では-1/2は0に評価されますが、Pythonでは-1に評価されるのはなぜですか? :
これらのことを抽象的に扱う人は、次のように感じる傾向があります。 負の無限大に丸めるのがより理にかなっている ( というのは 数学で定義されているモジュロ関数と互換性があることを意味します。 が多少おかしな意味を持つよりも ).
しかし、私はC++の's
/
はモジュロ関数と互換性がありません。C++では
(m/n)*n + m%n == m
も適用されます。
では、Pythonが負の無限大に丸めることを選択する(数学的)理由は何でしょうか?
以下も参照してください。 この話題に関する Guido van Rossum の古いブログ記事 .
どのように解決するのですか?
<ブロッククオート
しかし、なぜPythonなのか
//
は負の無限大に向かって丸めることを選択したのでしょうか?
私は、もし は
を選択した理由がどこかに記録されているかどうかはわかりませんが (私の知る限り、どこかの PEP で非常に長く説明されているかもしれません)、それが理にかなっているさまざまな理由を思いつくことができるのは確かです。1 つの理由は、単純に、負の (または正の!) 無限大に丸めることは、すべての数字が同じように丸められることを意味しますが、ゼロに丸めることはゼロを特別なものにします。 これを数学的に言うと、-∞に向かって丸めることは 並進不変 つまり、方程式を満たすということです。
round_down(x + k) == round_down(x) + k
すべての実数に対して
x
とすべての整数に対して
k
. ゼロに向かって丸めることは、例えば、以来、そうではありません。
round_to_zero(0.5 - 1) != round_to_zero(0.5) - 1
もちろん、他の議論も存在します。例えば、あなたが引用している、(私たちが望む)
%
演算子との互換性 (どのように動作させたいか) に基づく議論などです。
確かに、私は
実
は、なぜ Python の
int()
関数は
ではなく
は浮動小数点数の引数を負の無限大の方向に丸めるように定義されているので
m // n
と同じになるように
int(m / n)
. (歴史的な理由と思われます。) また、Python には少なくとも
math.floor()
を満たす
m // n == math.floor(m / n)
.
しかし、C++の
/
はモジュロ関数と互換性がありません。C++では(m/n)*n + m%n == m
も適用されます。
その通りですが、そのアイデンティティを保持しながら
/
がゼロに向かって丸くなるように定義する必要があります。
%
を負の数に対して厄介な方法で定義する必要があります。 特に、以下のPythonの有用な数学的特性の両方を失います。
%
:
-
0 <= m % n < n
すべてm
であり、すべての正のn
であり -
(m + k * n) % n == m % n
すべての整数に対してm
,n
とk
.
の主な用途の1つは、これらのプロパティが有用であることです。
%
の主な用途の 1 つは、数値の周りを囲むことです。
m
を限られた長さの範囲に
n
.
例えば、方向を計算しようとする場合、次のようにします。
heading
が現在の
コンパスヘディング
で、度数(真北から時計回りにカウント。
0 <= heading < 360
を使って時計回りに数える)、そして
angle
度(ここで
angle > 0
は時計回りに回す場合、または
angle < 0
である。) Pythonの
%
演算子を使うと、新しい方位を簡単に計算することができます。
heading = (heading + angle) % 360
であり、これは単純にすべてのケースで動作します。
しかし、この式をC++で使おうとすると、丸め方のルールが異なり、それに応じて
%
演算子を使用すると、折り返しが常に期待どおりに機能するとは限らないことがわかります! たとえば、北西に向かってスタートする場合 (
heading = 315
) で始まり、時計回りに 90° 回転したとします (
angle = 90
) をすると、確かに北東を向くことになります (
heading = 45
). しかし、そのとき
引き返そうとする
反時計回りに90°回転して (
angle = -90
) を、C++ の
%
演算子を使えば、最終的に
heading = 315
には戻らず、代わりに
heading = -45
!
正しい回り込み動作をさせるために、C++の
%
演算子を用いて正しい折り返し動作を得るには、代わりに次のような式を書く必要があります。
heading = (heading + angle) % 360;
if (heading < 0) heading += 360;
として、あるいは
heading = ((heading + angle) % 360) + 360) % 360;
(もっと簡単な式
heading = (heading + angle + 360) % 360
が常に有効であることが保証されている場合のみ有効です。
heading + angle >= -360
.)
これは割り算の丸めルールが翻訳非可変であることの代償であり、その結果、翻訳非可変の
%
演算子の代償です。
関連
-
[解決済み] 整数の割り算の動作はどうなっていますか?
-
[解決済み] Pythonで型をチェックする標準的な方法は何ですか?
-
[解決済み] JavaScriptで整数の除算を行い、余りを別途取得する方法は?
-
[解決済み] PythonモジュールとPythonパッケージの違いは何ですか?
-
[解決済み] Pythonの短いリストにプリペンドするための慣用的な構文は何ですか?
-
[解決済み】Python 3 の `raw_input()` と `input()` の違いは何ですか?
-
[解決済み] SQLAlchemy: セッションの作成と再利用
-
[解決済み] Spyderを仮想環境で動作させるには?
-
[解決済み] Pythonによる一対のクロスプロダクト [重複] (英語)
-
[解決済み] Django filter queryset __in for *every* item in list
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 除算を強制的に浮動小数点にするにはどうしたらいいですか?除算は0に切り捨てられ続けますか?
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] Pythonの構文に新しいステートメントを追加することはできますか?
-
[解決済み] Python 3でバイナリデータを標準出力に書き込むには?
-
[解決済み] サブフォルダからのインポートモジュール
-
[解決済み] CSVデータを処理する際、1行目のデータを無視する方法を教えてください。
-
[解決済み] djangoフレームワークでフォームフィールドから値を取得するには?
-
[解決済み] Pandasを使って、既存のExcelファイルに新しいシートを保存する方法は?
-
[解決済み] if 節の終了方法
-
[解決済み] Pythonでファイルの読み込みと上書きをする