2010-03-12 192 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); 
} 

希望对您有所帮助!答: