2010-03-12 191 views
9

當我在Objective-C中進行模運算時,我得到的結果有點嚇壞了。 -1%3出來是-1,這是不正確的答案:根據我的理解,它應該是-2 -2%3出現-2,這也是不正確的:它應該是1.Objective-C中的Modulo運算符返回錯誤結果

除了%運算符以獲得正確的結果之外,還有另外一種方法嗎?

+0

好奇,如果任何這些答案重新模數你正在尋找 – kris 2011-11-10 16:02:42

+1

使用frem(a,b) - 你期待的模數(這是標準數學中使用的那種)在編碼中被稱爲「餘數」 。 C有fmod()和frem(),你使用的是mod(又名「%」),你需要使用rem。數學模數===代碼中的剩餘(rem)。啞巴,我知道。 – 2016-07-07 07:36:05

+0

它引起了我的注意,frem(a,b)僅在GNU C中,沒有被帶入Obj-C。相當於這樣:'a-b * floor((float)a /(float)b)' – 2016-07-07 07:44:46

回答

7

Objective-C是C99的超集,而C99的定義a % ba爲負數時爲負數。另見the Wikipedia entry on the Modulo operationthis StackOverflow question

類似於(a >= 0) ? (a % b) : ((a % b) + b)(尚未經過測試,可能有不必要的括號)應該會給你想要的結果。

+0

太棒了!它對我很有幫助,但是我記錄了兩種導致我錯誤的情況:(1)-n mod n給出了n而不是0.(2)將它定義爲宏時,有些括號中出現混淆。我最終這樣做: #define模塊(a,b)(a> = 0 || - (a)==(b))? (a)%(b):((a)%(b)+ b) – kahlo 2013-08-25 20:10:49

2

ANSI C99 6.5.5乘operators-

6.5.5.5:在操作者/的結果是由第二所述第一操作數的除法的商;餘下的是%運算符的結果。在兩種操作中,如果第二個操作數的值爲零,則行爲未定義。

6.5.5.6:當整數分開時,/算子的結果是捨棄任何小數部分(* 90)的代數商。如果商a/b可表示,則表示(a/b)*b + a%b應等於a

* 90:這通常稱爲「向零截斷」。

您正在考慮的模行爲的類型稱爲「模運算」或「數論」樣式模/餘數。使用模運算符的模算術/數論定義,得到否定結果是不合理的。這顯然不是C99定義和使用的模行爲的風格。 C99的方式沒有什麼「錯誤」,這不符合你的期望。 :)

0

一個明確的功能,會給你正確的答案是在年底,但首先,這裏所討論的的一些其他的想法解釋:

其實,(a >= 0) ? (a % b) : ((a % b) + b)只會導致如果負數a在b的一個倍數內,則爲正確答案。

換句話說:如果您想查找:-1%3,那麼當然,(a >= 0) ? (a % b) : ((a % b)+ b)將起作用,因爲您在((a % b) + b)的末尾加回。

-1 % 3 = -1 and -1 + 3 = 2,這是正確的答案。

但是,如果你嘗試它= -4和b = 3,那麼它將無法工作:

-4 % 3 = -4-4 + 3 = -1

雖然這在技術上也等同於2(模3),但我不認爲這是您正在尋找的答案。您可能期待規範形式:答案應始終爲0到n-1之間的非負數。

你不得不增加+3兩次得到的答案:

-4 + 3 = -1 
-1 + 3 = 2 

這裏是做一個明確的方式:

a - floor((float) a/b)*b 

**要小心!確保你保持(浮)鑄在那裏。否則,它會將a/b分成整數,您會得到意想不到的答案。當然,這意味着你的結果也將是一個浮動。它將是一個寫成浮點數的整數,如2.000000,因此您可能希望將整個答案轉換回整數。

(int) (a - floor((float) a/b)*b) 
3

斯賓塞,有一種簡單的方法來思考mods(它在數學中定義的方式,而不是編程)。它實際上是相當簡單:

採取所有的整數:

...- 9,-8,-7,-6,-5,-4,-3,-2,-1,0, 1,2,3,4,5,6,7,8,9 ...

現在我們來考慮3的倍數(如果您正在考慮mod 3)。讓我們從0開始,並且3的正整數:

... -9,-8,-7,-6,-5,-4,-3,-2,-1,,1 ,2,3 ,4,5,6 ,7,8,9 ...

這些都是當除以3具有一個零剩餘的數字,即,這些都是修改爲零的那些。

現在讓我們把這整個組合起來。

...- 9,-8,-7,-6,-5,-4,-3,-2,-1,0,,2,3,4 ,5, 6,,8,9 ...

這些都是當除以3具有一爲1其餘部分的數字,即,這些都認爲國防部爲1

現在讓我們移的那些這整個組合再次由一個。

...- 9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2 ,3,4,5 , 6,7,8 ,9 ...

這些都是當除以3即有2個剩餘數量,即這些都認爲國防部於2

你的那些注意,在每種情況下,選中的數字間隔爲3.因爲我們考慮模3,所以我們總是取每三位數。(如果我們在做模5,我們會每五位取一個數)。

所以,你可以將這種模式向後轉換爲負數。只需保持3的間距。你會得到這三個相同級(一種特殊類型的等價類,因爲他們是所謂的在數學):

... -9,-8,-7,-6,-5,-4,-3 ,-2,-1,,1,2,3 ,4,5,6 ,7,8,9 ...

...- 9,-8,-7,-6,-5 ,-4,-3,-2 ,-1,0,,2,3,4 ,5,6,7 ,8,9 ...

...- 9,-8,-7 ,-6,-5,-4 ,-3,-2,-1 ,0, 1,,3,4,,6,7,,9 ...

所有這些等效數字的標準數學表示法是使用該類的殘基,這意味着取最小的非負數。

所以通常情況下,當我想MODS的,我處理的是一個負數,我只是覺得先後連連加模數,直到我得到的第一個0或正數:

如果我們在做mod 3,然後用-1,只需加3一次:-1 + 3 = 2. 隨着-4,兩次加3,因爲一次不夠。如果我們加一次+3,我們得到-4 + 3 = -1,這仍然是負值。所以我們再次加上+3:-1 + 3 = 2.

讓我們嘗試一個更大的負數,比如-23。如果不斷增加+3,你會得到:

-23,-20,-17,-14,-11,-8,-5,-2,1。我們得到了一個正數,所以我們停止。殘差是1,這是數學家通常使用的形式。

1

我有同樣的問題,但我解決了它!您只需檢查數字是正數還是負數,如果數字是負數,則需要再添加一個數字:

//neg 
// -6 % 7 = 1 
int testCount = (4 - 10); 
if (testCount < 0) { 
    int moduloInt = (testCount % 7) + 7; // add 7 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 
else{ 
    int moduloInt = testCount % 7; 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 

// pos 
// 1 % 7 = 1 
int testCount = (6 - 5); 
if (testCount < 0) { 
    int moduloInt = (testCount % 7) + 7; // add 7 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 
else{ 
    int moduloInt = testCount % 7; 
    NSLog(@"\ntest modulo: %d",moduloInt); 
} 

希望對您有所幫助!答: