2008-09-04 90 views
15

你能告訴我多少是(-2) % 5? 根據我的Python解釋器是3,但是你對此有一個明智的解釋嗎?帶負值的模量操作 - 奇怪的事情?

我讀過一些語言,結果可能是機器相關的,但我不確定。

+0

您可以使用`math.fmod`來獲得與C或Java中相同的行爲。 – Helio 2017-01-28 16:42:09

回答

16

順便說一句:大多數編程語言會不同意Python並給出結果-2。根據模數的解釋,這是正確的。然而,最商定的數學定義指出的一個b模量的(嚴格爲正)的休息一個/b除法的- [R。更確切地說,0 < = r < b的定義。

11

你的Python解釋器是正確的。 計算模量的一種(愚蠢)方法是減去或增加模量,直到結果值介於0和(模數-1)之間。

例如: 13模5 =(13 - 5)模5 =(13 - 10)模5 = 3

或你的情況:-2 MOD 5 =(-2 + 5)MOD 5 = 3

+1

這取決於如何定義整數除法。如果除法舍入爲0,那麼餘數應該與商有相同的符號,這樣`b *(a/b)+ a%b == a`。如果分裂趨向負無窮大(如在Python中),其餘部分應始終爲正值。 – augurar 2014-08-21 06:39:01

0

嗯,-2除以5將爲0,餘數爲3.我不認爲這應該是非常依賴平臺的,但我已經看到了陌生的東西。

+3

你肯定意思是:「-2除以5將爲-1,其餘爲3」,對嗎?無論如何,這就是Python所做的。 – tzot 2010-07-11 22:11:09

+0

在某些系統中,-2除以5爲0,餘數爲-2。在其他情況下,它是-1,餘數爲3.只是一個品味問題,沒有「正確的」答案。 – augurar 2014-08-21 06:33:55

0

這的確是3.在modular arithmetic,模量僅僅是一個除法的餘數,和-2除以5的餘數是3。

4

那麼,0%5應該是0,對不對?

-1%5應該是4,因爲這是下一個允許的數字以反方向行進(即它不能是5,因爲它超出了範圍)。

並通過邏輯下沿,-2必須是3

想到它是如何工作的最簡單的方法是,你不停地加上或減去5,直到數降至0(含)之間和5 (獨家)。

我不確定機器依賴 - 我從來沒有見過這樣的實現,但我不能說它從來沒有完成過。

0

結果取決於語言。 Python返回除數的符號,例如c#返回被除數的符號(即-2%5在c#中返回-2)。

0

一種解釋可能是使用2's complement存儲負數。當python解釋器嘗試執行模運算時,它將轉換爲無符號值。因此,不是在執行(-2)%5,而是實際計算0xFFFF_FFFF_FFFF_FFFD%5,它是3.

4

正如其他答案中所解釋的,對於具有負值的模運算有很多選擇。一般來說,不同的語言(和不同的機器體系結構)會給出不同的結果。

按照Python reference manual

模運算符總是產生一個結果與相同的符號作爲其第二個操作數(或零);結果的絕對值嚴格小於第二個操作數的絕對值。

是Python採取的選擇。基本上模被限定爲使得這總是成立:

x == (x/y)*y + (x%y) 

所以它是有道理的(-2)%5 = -2 - (-2/5)* 5 = 3

0

小心不要在所有操作系統和體系結構上依靠C/C++中的這種mod行爲。如果我沒有記錯,我試圖依靠C/C++代碼中

float x2 = x % n; 

保持X2的範圍從0到n-1,但負數躡手躡腳時,我會編一個操作系統,但事情會在另一個操作系統上正常工由於它只發生了一半的時間,所以這對於調試時間很困難!

6

象文檔中Binary arithmetic operations說,Python的保證:

的整數除法和模數運算符由以下身份連接:x == (x/y)*y + (x%y)。整數除法和模數還與內置函數divmod():divmod(x, y) == (x/y, x%y)連接。

而且真正的,

>>> divmod(-2, 5) 
(-1, 3). 

另一種方式來可視化這種方法的一致性是計算divmod對數字的一小序:

>>> for number in xrange(-10, 10): 
...  print divmod(number, 5) 
... 
(-2, 0) 
(-2, 1) 
(-2, 2) 
(-2, 3) 
(-2, 4) 
(-1, 0) 
(-1, 1) 
(-1, 2) 
(-1, 3) 
(-1, 4) 
(0, 0) 
(0, 1) 
(0, 2) 
(0, 3) 
(0, 4) 
(1, 0) 
(1, 1) 
(1, 2) 
(1, 3) 
(1, 4) 
0

似乎有一個共同的困惑術語「模數」和「餘數」之間。

在數學,餘應始終定義與商一致的,因此,如果a/b == c rem d然後(c * b) + d == a。根據你的商數如何,你會得到不同的餘數。

但是,模數應該總是給出0 <= r < divisor的結果,如果允許負整數,它只與圓到負無窮除法一致。如果劃分趨於零(這是常見的),模和餘數只對非負值是等價的。

某些語言(特別是C和C++)沒有定義所需的舍入/餘數行爲,並且%不明確。許多定義舍入爲零,但使用術語模數,其餘部分將更加正確。 Python是相對不尋常的,因爲它會變成負無窮,所以模和餘數是等價的。

Ada向零IIRC輪迴,但同時有modrem運營商。C政策旨在允許編譯人員爲機器選擇最有效的實施方式,但至少現在,IMO是一種錯誤的優化。一個好的編譯器可能會在負數無法發生的地方使用等價優化(並且幾乎可以肯定如果使用無符號類型的話)。另一方面,如果出現負數,則幾乎肯定會關注細節 - 爲了便於攜帶,您必須使用非常仔細設計的非常複雜的算法和/或檢查來確保獲得所需的結果,而不管舍入和餘數如何行爲。

換句話說,這種「優化」的收益主要是(如果不是總是)幻覺,而在某些情況下有非常實際的成本 - 所以這是一種錯誤的優化。