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


94

Pythonで、負の数に関して奇妙な動作を見つけました。

>>> -5 % 4
3

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


25
私には正しく見えます
ウィーティーズ2010年

6
..., -9, -5, -1, 3, 7, ...
NullUserException 2010年


8
を使用math.fmodして、CまたはJavaと同じ動作を得ることができます。
0x2b3bfa0 2017年

回答:


136

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

(-5)/ 4 = -1.25->フロア(-1.25)= -2

(-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を参照してください。)


6
驚いたことに、Pythonのモジュロ演算子(%) 、分母(除数)と同じ符号の数値を常に返すと限りません。参照してくださいstackoverflow.com/questions/48347515/...
zezollo

33

グイドヴァンロッサムからの説明は次のとおりです。

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

基本的に、a / b = qで、余りがrの場合、関係b * q + r = aおよび0 <= r <bが保持されます。


4
C ++やJavaのような言語も最初の関係を保持しますが、Pythonはフロアであるのに対しa、それらは否定的、肯定的bです。それは常に真実でabs(r) < bあり、彼らはiffをceilしr <= 0ます。
Evgeni Sergeev 2014

9

整数の除算と負の数のmodを処理する最良の方法はありません。a/b同じ大きさと反対の符号があればいいのですが(-a)/ba % b確かにモジュロbであるといいでしょう。本当に欲しいa == (a/b)*b + a%bので、最初の2つは互換性がありません。

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


1
「a / bが同じ大きさで、(-a)/ bの符号が反対であればいいのですが。」なぜそれがいいのでしょうか?それはいつ望ましい行動ですか?
user762 8419年

これは、通常の除算や乗算と同じように機能するため、直感的に操作しやすいためです。しかし、それは数学的には意味がないかもしれません。
デミス

6

指摘されているように、Pythonモジュロは、他の言語の規則に対して理にかなった例外を作ります。

これにより、特に//整数除算演算子と組み合わせて使用​​すると、負の数がシームレスに動作します%。モジュロがよくあるように(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は//常に負の無限大に向かって丸めます

* ...右のオペランドが正である限り。一方11 % -10 == -9


あなたの例に感謝して私はそれを理解しました:)
Lamis 2016年

5

python、モジュロ演算子は、このように動作します。

>>> mod = n - math.floor(n/base) * base

したがって、結果は(あなたの場合):

mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3

一方、C、JAVA、JavaScriptなどの他の言語では、floorの代わりに切り捨てが使用されます。

>>> mod = n - int(n/base) * base

その結果:

mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1

Pythonでの丸めについてさらに情報が必要な場合は、こちらをお読みください。


3

モジュロ、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 .. ..

これは、負の数を使用したモジュロの動作へのリンクです。(はい、ググった)


@ NullUserException-うん、そうだった。修繕。ありがとう。
ウィーティーズ2010年

1

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


1

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と同じ結果を達成し、さらに条件付きステートメントを回避します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.