views:

206

answers:

6

Possible Duplicate:
Mod of negative number is melting my brain!

I was wondering if there was a nicer algorithm for what I'm trying to do:

wrapIndex(-6, 3) = 0
wrapIndex(-5, 3) = 1
wrapIndex(-4, 3) = 2
wrapIndex(-3, 3) = 0
wrapIndex(-2, 3) = 1
wrapIndex(-1, 3) = 2
wrapIndex(0, 3) = 0
wrapIndex(1, 3) = 1
wrapIndex(2, 3) = 2
wrapIndex(3, 3) = 0
wrapIndex(4, 3) = 1
wrapIndex(5, 3) = 2

I came up with

function wrapIndex(i, i_max) {
        if(i > -1)
            return i%i_max;

        var x = i_max + i%i_max;
        if(x == i_max)
            return 0;

        return x;
    }

Is there a nicer way to do this?

+2  A: 

You could do this:

function wrapIndex(i, i_max) {
    if (i < 0) i = (i % i_max) + i_max;
    return i % i_max;
}
Gumbo
Previous version was correct :) (i % i_max) + i_max may be equal i_max if (i % i_max) == 0
Maciej Hehl
@Maciej Hehl: Dammit, you’re right.
Gumbo
+4  A: 

Nicer is a matter of taste, but How about

var x = (i_max + i % i_max) % i_max;
Maciej Hehl
I really feel uncomfortable upvoting this, since I don't know the exact operation precedence rules for Java, or whatever language this question is asked for, but I'm sure you know what you're doing (thanks for the correction, I see that at least 3 people including me has made that error here already)
polygenelubricants
@polygenelubricants: `%` has precedence over `+` in essentially all modern languages.
Stephen Canon
+8  A: 

This solution is branchless, but performs % twice:

function wrapIndex(i, i_max) {
   return ((i % i_max) + i_max) % i_max;
}

It should be said the C#/Java behavior of % is assumed, i.e. the result has the same sign as the dividend. Some languages define the remainder calculation to take the sign of the divisor instead (e.g. mod in Clojure). Some languages have both variants (mod/rem pair in Common Lisp, Haskell, etc). Algol-68 has %x which always returns a non-negative number. C++ leaves it up to implementation.

See also

polygenelubricants
+1 because it actually works. ;-)
Paul Sasik
Version with a branch returns i_max for negative multiple of i_max
Maciej Hehl
@Maciej: You're right; taking it out completely (since I'm not a fan of it anyway; was just trying to be "complete").
polygenelubricants
+3  A: 

The solution with two % operations works, but this is somewhat faster in most languages on most hardware (there are exceptions, however):

int wrapIndex(int i, int i_max) {
    i = i%i_max;
    return i<0 ? i+i_max : i;
}
Stephen Canon
A: 

Many users give answers, just beware negative numbers, since different languages may behave differently. By example this C snippet writes "-1"

int main ()
{
    printf("%d\n", (-4) % 3);
}

While in python we have a different output value

Python 2.6.4 (r264:75706, Dec  7 2009, 18:43:55) 
[GCC 4.4.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> (-4) % 3
2

EDIT: Actually I don't think you'll have negative indexes! However it's good to know that.

Dacav
A: 

Why are you unsatisfied with your existing solution?

rpg
I just wanted to know if there is a nicer way, without the need of branching ;) Always looking for the "perfect solution" to a problem :D
x3ro
Unless it is a speed issue, I wouldn't bother. Your needs may vary.
rpg