Objective-C中的模运算符返回错误的结果

时间:2010-03-12 05:44:02

标签: objective-c math modulo

当我在Objective-C中进行模运算时,我得到的结果让我有点吓坏了。 -1%3现在是-1,这不是正确的答案:根据我的理解,它应该是2. -2%3出现-2,这也是不对的:它应该是1.

除了%运算符之外,我还应该使用另一种方法来获得正确的结果吗?

6 个答案:

答案 0 :(得分:7)

Objective-C是C99的超集,当a % b为负时,C99将a定义为否定。另请参阅the Wikipedia entry on the Modulo operationthis StackOverflow question

(a >= 0) ? (a % b) : ((a % b) + b)这样的东西(尚未经过测试,可能有不必要的括号)应该可以得到你想要的结果。

答案 1 :(得分:3)

Spencer,有一种简单的方法可以考虑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, 0 ,1,2, 3 ,4,5, 6 ,7,8, 9 ......

这些是除以3时余数为零的所有数字,即这些都是mod为零的数字。

现在让我们将整个小组改为一个。

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

这些是除以3时余数为1的所有数字,即这些都是mod为1的数字。

现在让我们再将整个小组改为一个。

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

这些是除以3时余数为2的所有数字,即这些都是mod为2的数字。

您会注意到,在每种情况下,所选数字的间隔为3.我们总是采用每三个数字,因为我们正在考虑模3。(如果我们做模5,我们会采取每一个第五号)。

因此,您可以将此模式向后转换为负数。保持3的间距。你将获得这三个同余类(一种特殊类型的等价类,因为它们在数学中被称为):

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

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

...- 9,-8, -7 ,-6,-5, -4 , - 3,-2, -1 < / strong>,0,1, 2 ,3,4, 5 ,6,7, 8 ,9 ...

所有这些等价数字的标准数学表示是使用类的残差,这意味着取最小的非负数。

通常情况下,当我在思考mod并且我正在处理负数时,我只想到连续添加模数,直到我得到第一个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,这是数学家通常使用的形式。

答案 2 :(得分:2)

ANSI C99 6.5.5乘法运算符 -

6.5.5.5:/运算符的结果是第一个操作数除以第二个操作数的商; %运算符的结果是余数。在这两个操作中,如果第二个操作数的值为零,则行为未定义。

6.5.5.6:当整数被分割时,/运算符的结果是代数商,丢弃了任何小数部分(* 90)。如果商a/b可表示,则表达式(a/b)*b + a%b应等于a

* 90:这通常被称为“截断为零”。

您正在考虑的模数行为的类型称为“模数算术”或“数论”样式模/余数。使用模运算符的模运算/数论定义,得到否定结果是非感性的。这显然不是C99定义和使用的模数行为的风格。 C99方式并没有什么“错误”,这不是你所期待的。 :)

答案 3 :(得分:1)

负数的模数并不像你想象的那么简单。见http://mathforum.org/library/drmath/view/52343.html

答案 4 :(得分: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);
}

希望有所帮助!甲

答案 5 :(得分:0)

最后会给出正确答案的显式函数,但首先,这里是对所讨论的其他一些观点的解释:

实际上,如果负数a在b的一个倍数范围内,(a >= 0) ? (a % b) : ((a % b) + b)只能得到正确答案。

换句话说:如果你想找到:-1%3,那么确定(a >= 0) ? (a % b) : ((a % b)+ b)会有效,因为你在((a % b) + b)的最后添加了回来。

-1 % 3 = -1-1 + 3 = 2,这是正确答案。

但是,如果你尝试使用a = -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除以整数,你会得到一个意外的答案。当然这意味着你的结果也是浮动的。它将是一个写为float的整数,如2.000000,因此您可能希望将整个答案转换回整数。

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