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

Objective-C中的模运算符返回错误的结果,objective-c,math,modulo,Objective C,Math,Modulo,当我在Objective-C中进行模运算时,得到的结果让我有点吓坏了。-1%3变成了-1,这不是正确的答案:根据我的理解,它应该是2-2%3等于-2,这也不对:应该是1 除了%运算符之外,我还应该使用另一种方法来获得正确的结果吗?负数模并不像您想象的那么简单。参见目标-C是C99的超集,C99将a%b定义为负值,当a为负值时。另见和 类似于(a>=0)的东西?(a%b):((a%b)+b)(尚未测试,可能有不必要的括号)应该会给出您想要的结果。ANSI C99 6.5.5乘法运算符- 6.5.5

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


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

负数模并不像您想象的那么简单。参见

目标-C是C99的超集,C99将
a%b
定义为负值,当
a
为负值时。另见和


类似于
(a>=0)的东西?(a%b):((a%b)+b)
(尚未测试,可能有不必要的括号)应该会给出您想要的结果。

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方式没有什么“错误”,只是不是您所期望的。:)

最后是一个明确的函数,它将为您提供正确的答案,但首先,这里是对所讨论的其他一些想法的解释:

实际上,
(a>=0)?(a%b):((a%b)+b)
只有在负数a在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除以整数,您将得到一个意外的否定答案。当然,这意味着您的结果也将是一个浮点。它将是一个写为浮点的整数,如2.000000,因此您可能希望将整个答案转换回整数

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

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。(如果我们做的是mod 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,0,1,2,3,4,5,6,7,8,9

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

所以通常,当我考虑mods时,我在处理一个负数,我只想一次又一次地连续地加模数,直到得到第一个0或正数
//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);
}