web-dev-qa-db-ja.com

Pythonの負の数のモジュロ演算

Pythonで負の数に関する奇妙な振る舞いを見つけました:

>>> -5 % 4
3

誰が何が起こっているのか説明できますか?

59
facha

CやC++とは異なり、Pythonのモジュロ演算子(%)は、常に分母(除数)と同じ符号を持つ数値を返します。あなたの式は3をもたらします

(-5)%4 =(-2×4 + 3)%4 = 3。

多くの場合、非負の結果がより有用であるため、Cの動作よりも選択されます。例は、平日を計算することです。今日が火曜日(2日目)の場合、平日[〜#〜] n [〜#〜]日前は何ですか? Pythonで計算できます

return (2 - N) % 7

しかし、Cでは、[〜#〜] n [〜#〜]≥3の場合、無効な数値である負の数値が得られ、 7を追加して手動で修正する必要があります。

int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;

http://en.wikipedia.org/wiki/Modulo_operator を参照してください。異なる言語で結果の符号がどのように決定されるかについて。)

95
kennytm

Guido van Rossumの説明を次に示します。

http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html

基本的に、剰余rを含むa/b = qが関係b * q + r = aおよび0 <= r <bを維持するようにします。

25
Kevin

整数の除算と負の数のmodを処理する最適な方法はありません。 _a/b_が_(-a)/b_と同じ大きさで反対の符号であるといいでしょう。 _a % b_が実際にモジュロbであった場合、それは素晴らしいでしょう。 a == (a/b)*b + a%bが本当に必要なので、最初の2つは互換性がありません。

どちらを保持するかは難しい質問であり、双方に議論があります。 CおよびC++は整数除算をゼロに丸めます(そのためa/b == -((-a)/b))、明らかにPythonはそうではありません。

8
David Thornley

指摘したように、Python moduloは、他の言語の規約に対して 十分な理由がある 例外を作成します。

これにより、//整数除算演算子と組み合わせて使用​​される場合、特に%モジュロがしばしば(math . divmod のように)負の数にシームレスな動作が与えられます。

for n in range(-8,8):
    print n, n//4, n%4

生産物:

 -8 -2 0
 -7 -2 1
 -6 -2 2
 -5 -2 3

 -4 -1 0
 -3 -1 1
 -2 -1 2
 -1 -1 3

  0  0 0
  1  0 1
  2  0 2
  3  0 3

  4  1 0
  5  1 1
  6  1 2
  7  1 3
  • Python %は、除数が正の場合、常にゼロまたは正を出力します
  • Python //は常に負の無限大に向かって丸めます
4
Bob Stein

モジュロ、4の等価クラス

  • 0:0、4、8、12 ...および-4、-8、-12 ...
  • 1:1、5、9、13 ...および-3、-7、-11 ...
  • 2:2、6、10 ...および-2、-6、-10 ...
  • 3:3、7、11 ...および-1、-5、-9 ...

負の数でのモジュロの動作 へのリンクです。 (はい、グーグルで検索しました)

3
wheaties

また、Pythonの奇妙な動作だと思いました。分割をうまく解決していないことが判明しました(紙上)。商に0の値を、余りに-5の値を与えていました。ひどい...整数の幾何学的表現を忘れてしまいました。数値の行で指定された整数のジオメトリを呼び出すことにより、商と剰余の正しい値を取得し、Pythonの動作が正常であることを確認できます。 (私はあなたがずっと前にあなたの懸念をすでに解決していると仮定しますが)。

1
joser

また、pythonの除算もCとは異なることを考慮してください:

>>> x = -10
>>> y = 37

cでは結果が期待できます

0

pythonのx/yとは何ですか?

>>> print x/y
-1

そして、%は剰余ではなく剰余です! Cのx%yは

-10

pythonが生成されます。

>>> print x%y
27

Cのように両方を取得できます

分裂:

>>> from math import trunc
>>> d = trunc(float(x)/y)
>>> print d
0

そして、残り(上記の分割を使用):

>>> r = x - d*y
>>> print r
-10

この計算はおそらく最速ではありませんが、xとyの符号の組み合わせがCの場合と同じ結果を達成し、条件ステートメントを回避するように機能しています。

0
bebbo