Mod operator with negative numbers

jaynabonne
Just to record this somewhere, here is how the mod operator (%) handles negative numbers:

1 % 4 = 1
6 % 4 = 2
-1 % 4 = -1
-2 % 4 = -2
-3 % 4 = -3
-4 % 4 = 0
-7 % 4 = -3
5 % -4 = 1
-5 % -4 = -1


The key points:
- The mod of a negative number is the negative of the mod of the same positive number.
- Mod to a negative base returns the same value as mod to the positive base.

The first point means that you can't expect the result of "mod n" to be in the range "0 - (n-1)" for all numbers. If you do need a mod that behaves that way, you can use something like:

<function name="SafeMod" parameters="n,base" type="int">
return (((n % base) + base) % base)
</function>


If you know your "n" will always be positive, you can just use "n%base" straight.

sharpnova
Just to clarify, since it wasn't stated in the OP.

This is incorrect behavior for MOD.

In general, (-1)%n = n-1

The mod function should never return a negative value. My guess is that the function was handwritten, for Quest, by someone who didn't understand what MOD is meant to do.

And I *do* think that this misformulation of the function has potentially annoying consequences for game creators.

jaynabonne
sharpnova wrote:My guess is that the function was handwritten, for Quest, by someone who didn't understand what MOD is meant to do.


I think that's a bit harsh and doesn't reflect the history of mod in programming languages. For example, Ruby and Python use the mathematically correct rule, while C and Java do not. And the C++ spec states that the handling of mod is "implementation dependent," which means it can vary from platform to platform, depending on the underlying hardware and the library implementation. And I'm quite sure that these people understand what the mod function is and does. There are just other considerations (like performance).

The point of my post wasn't to criticize or condemn but rather to inform. The mod operator *does* vary depending on implementation, which is why I went through this exercise to begin with, so that those who care could know what Quest does. Quest, by the way, is built on top of FLEE which is built using VB/.NET. So perhaps you can blame Microsoft for the "handwritten implementation" by "someone who didn't understand".

Entropic Pen
So before everyone stops giving two bothers about Mod operators... tell us how this could be used in practice b/c I sure don't know!

jaynabonne
Mod ("modulo") is good for cylic things. I used them in the exit generation and navigation code I posted for imamy. To refresh a bit, the mod function to a base returns a number which is (naïvely) the remainder when divided by that base. That definition isn't 100% accurate, but it works for positive numbers, and it might be easier to understand if the concept is new. Here is the first set of numbers mod 4:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14...
0 1 2 3 0 1 2 3 0 1 2 3 0 1 2...


As you can see, the mod function repeats. You can talk about two numbers being "equivalent mod X" if they have the same value mod X. For example, 3, 7 and 11 are all equivalent mod 4.

Let's say you have a rotation attribute with these values:

North = 0
East = 1
South = 2
West = 3

where each succeeding number goes 90 degrees further right. This allows you to have a single "direction" index. So how do you rotate right? Generally, you add 1 to the direction index. So North (0) goes to East (1) goes to South (2), etc. And to rotate left, you'd subtract 1.

When you get to the ends, though, you need to wrap. Now, you can put "if"s in saying "Add 1. If the new value is 4 set it to 0" and similarly for left rots. It's easier just to use:

dir = (dir + 1) % 4

The problem comes in with negative numbers. If you look at the above pattern for 0-14, you'll see a pattern of 0,1,2,3, repeating over and over. A technically correct mod preserves that going further negative, so that -1 would be 3, -2 would be 2, -3 would be 1, and -4 would be zero again:

-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4
1 2 3 0 1 2 3 0 1 2 3 0


The mod n values are always [0..n-1]. However, some implementations seem to do it strictly as if it were a remainder, such that -1 mod 4 would be -1, -2 would be -2, etc

-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4
-3 -2 -1 0 -3 -2 -1 0 1 2 3 0


And this causes problems! Because now in our case, if we go left from 0, we end up at -1, not 3. There are ways around this. For example, we can do this:

Right: 
dir = (dir + 1) % 4
Left:
dir = (dir + 3) % 4

and that will always work. (It might seem off, but think: if we add 4, we're back to the same number, mod 4. So adding 3 gets us to the number just left of it. The number 3 is the equivalent of -1.)

I don't know if that answers it all (or too much), but it's one use for mod. You see things like mod all the time - time on a clock (which is mod 12 hours), degrees in a circle (which are mod 360), etc.

Edit: fixed the directions above.

This topic is now closed. Topics are closed after 14 days of inactivity.

Support

Forums