views:

4009

answers:

9

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?

+1  A: 

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

e.James
+6  A: 

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).

Adam Rosenfield
+1 for the _why_.
Matt B.
A: 

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.

kwbeam
+1  A: 

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

maxwellb
If you just said he should do (-1 + 3) % 3 = 2, I agree. :-)
Nosredna
I would say do ( 3 + ( -1 % 3 ) ) % 3 == (3 + (-1) ) % 3 == ( 2 % 3 ) == 2
maxwellb
Gotcha. That's good. It can be done with a conditional (if or ternary) as well.
Nosredna
A: 

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.

Nosredna
+10  A: 
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.

UncleO
Doesn't it depend on the processor whether conditionals are better or worse than a modulo?
Nosredna
I've never seen a processor where division or modulo isn't the slowest operation. Checking for negative reduces to testing the value of a bit, so is usually one of the fastest instructions.
UncleO
Yeah. That's probably right. I think in the Core Duo Intels, a division is something like 15-17 cycles. I see a lot of people try to avoid branching nowadays. But with a mod the branch is probably worthwhile.
Nosredna
It's my understanding that the idea behind avoiding branches is to prevent stalling the pipeline. But performing two mods might stall the pipeline anyway; the second mod operation needs to wait for the result from the first.
UncleO
The if() will almost certainly be faster than the second mod; any decent optimizing compiler can turn the if() into a cmov (conditional move) instruction, which will do the same thing without branching.
Adam Rosenfield
+1  A: 

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.

Peter N Lewis
+1  A: 

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.

Tobias
+1  A: 

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 device 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.

Arthur Ulfeldt