coneybeare
coneybeare

Reputation: 33101

Weird Objective-C Mod Behavior for Negative Numbers

So I thought that negative numbers, when mod'ed should be put into positive space... I cant get this to happen in objective-c

I expect this:

-1 % 3 = 2
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

But get this

-1 % 3 = -1
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Why is this and is there a workaround?

Upvotes: 43

Views: 33221

Answers (12)

Albert Renshaw
Albert Renshaw

Reputation: 17892

Instead of a%b

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

You're expecting remainder and are using modulo. In math they are the same thing, in C they are different. GNU-C has Rem() and Mod(), objective-c only has mod() so you will have to use the code above to simulate rem function (which is the same as mod in the math world, but not in the programming world [for most languages at least])


Also note you could define an easy to use macro for this.

#define rem(a,b) ((int)(a-b*floor((float)a/(float)b)))

Then you could just use rem(-1,3) in your code and it should work fine.

Upvotes: 0

devios1
devios1

Reputation: 38005

UncleO's answer is probably more robust, but if you want to do it on a single line, and you're certain the negative value will not be more negative than a single iteration of the mod (for example if you're only ever subtracting at most the mod value at any time) you can simplify it to a single expression:

int result = (n + 3) % 3;

Since you're doing the mod anyway, adding 3 to the initial value has no effect unless n is negative (but not less than -3) in which case it causes result to be the expected positive modulus.

Upvotes: 1

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91554

We have a problem of language:

math-er-says: i take this number plus that number mod other-number
code-er-hears: I add two numbers and then devide the result by other-number
code-er-says: what about negative numbers?
math-er-says: WHAT? fields mod other-number don't have a concept of negative numbers?
code-er-says: field what? ...
  • the math person in this conversations is talking about doing math in a circular number line. If you subtract off the bottom you wrap around to the top.
  • the code person is talking about an operator that calculates remainder.

In this case you want the mathematician's mod operator and have the remainder function at your disposal. you can convert the remainder operator into the mathematician's mod operator by checking to see if you fell of the bottom each time you do subtraction.

Upvotes: 7

Anish Chandran
Anish Chandran

Reputation: 41

Not only java script, almost all the languages shows the wrong answer' what coneybeare said is correct, when we have mode'd we have to get remainder Remainder is nothing but which remains after division and it should be a positive integer....

If you check the number line you can understand that

I also face the same issue in VB and and it made me to forcefully add extra check like if the result is a negative we have to add the divisor to the result

Upvotes: 0

Tobias
Tobias

Reputation: 6507

Why: because that is the way the mod operator is specified in the C-standard (Remember that Objective-C is an extension of C). It confuses most people I know (like me) because it is surprising and you have to remember it.

As to a workaround: I would use uncleo's.

Upvotes: 1

Peter N Lewis
Peter N Lewis

Reputation: 17811

If n has a limited range, then you can get the result you want simply by adding a known constant multiple of 3 that is greater that the absolute value of the minimum.

For example, if n is limited to -1000..2000, then you can use the expression:

result = (n+1002) % 3;

Make sure the maximum plus your constant will not overflow when summed.

Upvotes: 9

UncleO
UncleO

Reputation: 8449

result = n % 3;
if( result < 0 ) result += 3;

Don't perform extra mod operations as suggested in the other answers. They are very expensive and unnecessary.

Upvotes: 54

Nosredna
Nosredna

Reputation: 86206

JavaScript does this, too. I've been caught by it a couple times. Think of it as a reflection around zero rather than a continuation.

Upvotes: 1

maxwellb
maxwellb

Reputation: 13944

If this will be the behavior, and you know that it will be, then for m % n = r, just use r = n + r. If you're unsure of what will happen here, use then r = r % n.

Edit: To sum up, use r = ( n + ( m % n ) ) % n

Upvotes: 5

user122376
user122376

Reputation:

There are two choices for the remainder, and the sign depends on the language. ANSI C chooses the sign of the dividend. I would suspect this is why you see Objective-C doing so also. See the wikipedia entry as well.

Upvotes: 0

Adam Rosenfield
Adam Rosenfield

Reputation: 400274

In C and Objective-C, the division and modulus operators perform truncation towards zero. a / b is floor(a / b) if a / b > 0, otherwise it is ceiling(a / b) if a / b < 0. It is always the case that a == (a / b) * b + (a % b), unless of course b is 0. As a consequence, positive % positive == positive, positive % negative == positive, negative % positive == negative, and negative % negative == negative (you can work out the logic for all 4 cases, although it's a little tricky).

Upvotes: 15

James Eichele
James Eichele

Reputation: 119144

I would have expected a positive number, as well, but I found this, from ISO/IEC 14882:2003 : Programming languages -- C++, 5.6.4 (found in the Wikipedia article on the modulus operation):

The binary % operator yields the remainder from the division of the first expression by the second. .... If both operands are nonnegative then the remainder is nonnegative; if not, the sign of the remainder is implementation-defined

Upvotes: 4

Related Questions