Python'da negatif sayılar üzerinde modulo işlemi


Yanıtlar:


137

C veya C ++ 'dan farklı olarak, Python'un modulo operatörü ( %) her zaman payda (bölen) ile aynı işarete sahip bir sayı döndürür. İfadeniz 3 verir çünkü

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

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

Negatif olmayan bir sonuç genellikle daha yararlı olduğu için C davranışı yerine seçilir. Bir örnek, hafta içi günleri hesaplamaktır. Bugün Salı ise (2. gün), N gün öncesindeki hafta içi gün nedir? Python'da hesaplayabiliriz

return (2 - N) % 7

ancak C'de, N ≥ 3 ise, geçersiz bir sayı olan negatif bir sayı elde ederiz ve bunu 7 ekleyerek manuel olarak düzeltmemiz gerekir:

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

( Farklı diller için sonuç işaretinin nasıl belirlendiğini öğrenmek için http://en.wikipedia.org/wiki/Modulo_operator adresine bakın .)


6
Şaşırtıcı bir şekilde, Python'un modülo operatörü (%) değil , her zaman payda (bölen) ile aynı işarete sahip sayı döndürür. Bkz stackoverflow.com/questions/48347515/...
zezollo


9

Negatif sayılarla tamsayı bölmesini ve modları ele almanın en iyi yolu yoktur. a/bAynı büyüklükte ve zıt işaretli olsaydı güzel olurdu (-a)/b. a % bGerçekten de bir modulo olsaydı iyi olurdu b. Gerçekten istediğimiz a == (a/b)*b + a%biçin ilk ikisi uyumsuzdur.

Hangisini saklamak zor bir soru ve her iki taraf için de tartışmalar var. C ve C ++ yuvarlak tamsayı bölümü sıfıra doğru (yani a/b == -((-a)/b)) ve görünüşe göre Python değil.


1
"A / b'nin (-a) / b ile aynı büyüklükte ve zıt işaretinde olması iyi olurdu." Bu neden güzel olur? Bu ne zaman istenen bir davranış olur?
user76284

Çünkü o zaman normal bölme ve çarpma ile aynı şekilde hareket eder ve bu nedenle sezgisel olarak çalışmak kolaydır. Yine de matematiksel olarak mantıklı gelmeyebilir.
Demis

6

Belirtildiği gibi, Python modulo , diğer dillerin gelenekleri için iyi gerekçeli bir istisna yapar .

Bu, negatif sayılara, özellikle //tamsayı bölme operatörü ile birlikte kullanıldığında, modulo'nun% sıklıkla olduğu gibi (math. Divmod'da olduğu gibi ) sorunsuz bir davranış sağlar :

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

Üretir:

 -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 %her zaman sıfır veya pozitif çıktı *
  • Python //her zaman negatif sonsuzluğa yuvarlanır

* ... sağ operand pozitif olduğu sürece. Diğer yandan11 % -10 == -9


Teşekkürler, örneğiniz anlamamı sağladı :)
Lamis

5

In piton , modülo operatörü bu gibi çalışır.

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

yani sonuç (sizin durumunuz için):

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

oysa C, JAVA, JavaScript gibi diğer diller floor yerine kısaltma kullanır.

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

sonuç:

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

Eğer python yuvarlama hakkında daha fazla bilgi gerekiyorsa, okuma bu .



1

Ayrıca Python'un garip bir davranışı olduğunu düşündüm. Bölmeyi iyi çözemediğim ortaya çıktı (kağıt üzerinde); Bölüme 0 değeri ve kalanına -5 değeri veriyordum. Korkunç ... Tam sayıların geometrik temsilini unuttum. Sayı doğrusu tarafından verilen tamsayıların geometrisini hatırlayarak, bölüm ve kalan bölüm için doğru değerler elde edilebilir ve Python'un davranışının iyi olup olmadığı kontrol edilebilir. (Endişenizi uzun süre önce çözdüğünüzü varsaymama rağmen).


1

Ayrıca python'daki bölünmenin de C'den farklı olduğunu belirtmekte fayda var:

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

C'de sonucu bekliyorsun

0

python'da x / y nedir?

>>> print x/y
-1

ve% modulo'dur - geri kalan değil! C veriminde x% y ise

-10

python verimi.

>>> print x%y
27

İkisini de C'deki gibi alabilirsin

Bölme:

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

Ve geri kalanı (yukarıdan bölümü kullanarak):

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

Bu hesaplama belki en hızlısı değildir, ancak C'deki ile aynı sonuçları elde etmek için x ve y'nin herhangi bir işaret kombinasyonu için çalışır, artı koşullu ifadelerden kaçınır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.