Operasi modulo pada bilangan negatif dengan Python


96

Saya telah menemukan beberapa perilaku aneh dengan Python terkait bilangan negatif:

>>> -5 % 4
3

Adakah yang bisa menjelaskan apa yang sedang terjadi?


25
terlihat tepat untuk saya
wheaties

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


8
Anda bisa menggunakan math.fmoduntuk mendapatkan perilaku yang sama seperti di C atau Java.
0x2b3bfa0

Jawaban:


137

Tidak seperti C atau C ++, operator modulo Python ( %) selalu mengembalikan angka yang memiliki tanda yang sama dengan penyebut (pembagi). Ekspresi Anda menghasilkan 3 karena

(-5) / 4 = -1,25 -> lantai (-1,25) = -2

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

Ini dipilih daripada perilaku C karena hasil nonnegatif seringkali lebih berguna. Contohnya adalah menghitung hari kerja. Jika hari ini adalah Selasa (hari # 2), apakah hari kerja N hari sebelumnya? Dengan Python kita bisa menghitung dengan

return (2 - N) % 7

tetapi di C, jika N ≥ 3, kita mendapatkan angka negatif yang merupakan angka yang tidak valid, dan kita perlu memperbaikinya secara manual dengan menambahkan 7:

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

(Lihat http://en.wikipedia.org/wiki/Modulo_operator untuk mengetahui bagaimana tanda hasil ditentukan untuk bahasa yang berbeda.)


6
Anehnya, operator modulo Python (%) tidak selalu mengembalikan bilangan yang memiliki tanda yang sama dengan penyebut (pembagi). Lihat stackoverflow.com/questions/48347515/…
zezollo


9

Tidak ada satu cara terbaik untuk menangani pembagian integer dan mod dengan bilangan negatif. Alangkah baiknya jika a/bbesarnya sama dan tanda berlawanan (-a)/b. Alangkah baiknya jika a % bmemang sebuah modulo b. Karena kami benar-benar ingin a == (a/b)*b + a%b, dua yang pertama tidak cocok.

Yang mana yang harus disimpan adalah pertanyaan yang sulit, dan ada argumen untuk kedua belah pihak. Pembagian integer bulat C dan C ++ menuju nol (jadi a/b == -((-a)/b)), dan ternyata Python tidak.


1
"Alangkah baiknya jika a / b sama besarnya dan bertanda berlawanan dari (-a) / b." Mengapa itu menyenangkan? Kapan itu perilaku yang diinginkan?
pengguna76284

Karena itu kemudian akan bertindak dengan cara yang sama seperti pembagian dan perkalian reguler, dan dengan demikian secara intuitif mudah untuk dikerjakan. Itu mungkin tidak masuk akal secara matematis.
Demis

6

Seperti yang ditunjukkan, Python modulo membuat pengecualian yang beralasan untuk konvensi bahasa lain.

Ini memberikan bilangan negatif perilaku yang mulus, terutama bila digunakan dalam kombinasi dengan //operator integer-divide, seperti yang %sering dilakukan modulo (seperti dalam math. Divmod ):

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

Menghasilkan:

 -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 %selalu menghasilkan nol atau positif *
  • Python //selalu membulatkan ke arah negatif tak terhingga

* ... selama operan kanannya positif. Di samping itu11 % -10 == -9


Terima kasih atas contoh Anda yang membuat saya memahaminya :)
Lamis

5

Di python , operator modulo bekerja seperti ini.

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

jadi hasilnya adalah (untuk kasus Anda):

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

sedangkan bahasa lain seperti C, JAVA, JavaScript menggunakan pemotongan, bukan floor.

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

yang mengakibatkan:

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

Jika Anda memerlukan informasi lebih lanjut tentang pembulatan dengan python, baca ini .


3

Modulo, kelas kesetaraan untuk 4:

  • 0: 0, 4, 8, 12 ... dan -4, -8, -12 ...
  • 1: 1, 5, 9, 13 ... dan -3, -7, -11 ...
  • 2: 2, 6, 10 ... dan -2, -6, -10 ...
  • 3: 3, 7, 11 ... dan -1, -5, -9 ...

Berikut link ke perilaku modulo dengan bilangan negatif . (Ya, saya mencarinya di Google)


@NullUserException - ya, itu benar. tetap. Terima kasih.
Wheaties

1

Saya juga berpikir itu adalah perilaku aneh Python. Ternyata saya tidak menyelesaikan pembagian dengan baik (di atas kertas); Saya memberikan nilai 0 untuk hasil bagi dan nilai -5 untuk sisanya. Mengerikan ... Saya lupa representasi geometris dari bilangan bulat. Dengan mengingat geometri bilangan bulat yang diberikan oleh garis bilangan, seseorang bisa mendapatkan nilai yang benar untuk hasil bagi dan sisanya, dan memeriksa apakah perilaku Python baik-baik saja. (Meskipun saya berasumsi bahwa Anda telah menyelesaikan masalah Anda sejak lama).


1

Perlu juga disebutkan bahwa pembagian python juga berbeda dari C: Pertimbangkan

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

di C Anda mengharapkan hasilnya

0

apa x / y dengan python?

>>> print x/y
-1

dan% adalah modulo - bukan sisanya! Sedangkan x% y di C. menghasilkan

-10

python menghasilkan.

>>> print x%y
27

Anda bisa mendapatkan keduanya seperti di C

Divisi:

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

Dan sisanya (menggunakan pembagian dari atas):

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

Penghitungan ini mungkin bukan yang tercepat tetapi berfungsi untuk kombinasi tanda apa pun dari x dan y untuk mencapai hasil yang sama seperti di C plus, ini menghindari pernyataan bersyarat.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.