為什麼負數的取餘計算各個程式設計語言結果不統一?
最後更新:2016-06-06
來源:互聯網
上載者:User
回複內容: 帶正負號的整數的除法與餘數
數學上都正確,這個定義本來就有好幾個
比如按
或者按
IEEE標準是則是,然而round標準也有好幾個。。。
如果round是IEEE預設的round to the nearest,從標準的角度似乎應該是3。。。但IEEE好像也沒說其他的round標準不對。。。
PS:很多語言乾脆提供了兩個函數,rem和mod就是商向0或負無窮方向取整的選擇,c從c99開始規定向0取整,py則規定向負無窮取整,選擇而已,無所謂對錯就算是相同語言不同編譯器也會不一樣的。
在我發現這個問題之後,每當我更新IDE/編譯器的時候都會用我的測試程式跑一遍,看看是不是和上個版本有什麼不同。
有的時候一些小改動很坑的。
PS:有時候也不行,不能保證測試結果是唯一的。問題的關鍵在於商是向負無窮取值還是向0取值 -7/10=0....-7
or
-7/10=-1....3
其他語言我不清楚,貌似c11規定向0取值關於負數的餘數,樓上很多網友已經闡述了純數學概念上的意義。我想從另一個角度說說我的看法。先明確一點:我們討論的是“被除數”(分子)是負整數,而除數(分母)是正整數的情況。
先看一個例子: (-17) mod 5 =?
答案一: (-17) = (-3)*5 + (-2),所以餘數是 -2 。
答案二: (-17) = (-4)*5 + (+3),所以餘數是 +3 。
首先,從“純數學”概念上說,兩個答案都“對”,就好像解方程的時候出現“複數解”一樣,也是一個解。所以各種編譯器按照各自的邏輯來產生餘數。
但是,從人類思維角度上說,“負數”的起源是因為“不足、欠缺”,使用負數是為了知道有多欠缺,然後去補救。從這個角度才能正確理解“負數的餘數”的實際意義(區別於純數學概念)。
打個比方,你和另外5個同學住在宿舍裡,你很勤快,那5個人很懶,讓你幫忙買早餐,比如說,油條、豆漿 …… 你提著他們的早餐回來,對他們說:“一共17塊錢。”就是說,他們5個人一共欠你17元。平均每人給你 17/5=3.4元。
於是他們就翻箱倒櫃 —— 不是沒有錢,而是在找零錢,每人都要拿0.4元,嗯,各位看官不妨找找自己身上有沒有4毛錢 …… 結果就是,都找不到零錢,怎麼辦?於是有兩種辦法:
辦法一:每人給你3塊錢,但是總共還欠你2塊錢,餘數= -2
辦法二:每人給你4塊錢,但是你要給回他們3塊錢,餘數 = +3
現在問題是:各位作為人類,傾向於採用哪一個辦法?
上面說了,人類之所以使用負數,是為了知道“不足”,然後進行補救。現在既然欠了錢要還,我想那5位同學都會給你4塊錢,倒不是說他們是為了給你3塊錢跑腿費,而是他們想“了(liao)了(le)這筆賬”,他們不想5個人 每人都欠你0.4元的人情(何況你還真的跑腿了),既然都還錢了,為什麼還要留一筆“遺留問題”呢?
所以,
從人類思維習慣和實際需要來說
(再說一遍:區別於純數學概念),無論被除數(分子)是正數還是負數,餘數都應該取正數, 這樣才符合人類的思維習慣和實際需要。
題外話:就好像除數(分母)通常是正數一樣,如果用一個負數來做除數(分母),人們會覺得很彆扭,很難理解。
其實,如果允許餘數可以是負數的話,那麼 23%5 同樣有兩個答案,可以看作 +3,也可以是 -2,但我相信沒有人會用 -2,第一反應肯定是用 +3 。
現在回到題主的問題: (-7)%10=? 是 +3 還是 -7 ?
如果說人話,就是:現在欠你7塊錢,由10個人來還,怎麼辦?
辦法一:每人還你一塊錢,結果多出3塊錢,餘數=+3
辦法二:每人還給你
0元 ,餘數 = -7 ,結果最後,一切照舊,依然欠你7塊錢 ……
數學語言說:向負無窮取值還是向0取值 ……
==========分割線==========分割線==========分割線==========分割線==========
說到這裡,可能有人說,數學不是憑情感、看習慣的,數學是嚴謹的。
我非常贊同這個觀點,對於數學這種推崇嚴密和嚴謹的科學,同樣的運算元、同樣的運算子,必然得到同樣的運算結果。那麼,餘數這種“可正可負”的“雙重標準”是致命的 Fatal Error ,會摧毀數學大殿的根基。試想一下,-7伏和+3伏是兩個截然相反的脈衝訊號,足以讓太空梭掉進茫茫大海了……
還是以 (-7)%10 為例。同餘定理是數學的基礎定理之一,中學生都懂,我們來看看:
13 %10 = 3
(13+10)%10= 3
(13+20)%10= 3
(13-10)%10= 3
(13-20)%10=(-7)%10=? —— 問題來了。
顯然,根據餘數定理,答案無疑就是+3 ,而不是 -7 。這與我的上述觀點互相印證。
如果認為 (-7)%10=-7 的話,那麼連中學生都懂的餘數定理就不成立了,數學變得如此脆弱,如此不堪一擊。
餘數定理是電腦表示負數、補數的理論基礎,那些編譯器產生的混亂結果,恰恰說明這些編譯器的開發人員不懂得餘數的概念和意義。畢竟,搞電腦和搞數學是不同的領域。 因為數學上一般不關心負數的餘數,數論一般討論的都是正整數。可能是程式員沒有區分開 取餘和模數,百度一下取餘,模數。僅供參考說的好像各個程式設計語言內部是統一的一樣。。
請題主先把cl、gcc、clang、cmake、tc等實現的各主要版本都實驗一遍。。