4

Incrementing and wrapping back to zero is easy:

i = (i + 1) % Max;

But decrementing is not as straight forward. Basically to decrement and wrap you usually find code like this:

i--;
if (i < 0)
   i = Max;

How can we write the previous code without using if statements?

I know that probably bit-wise operators will be involved. Usually when I'm faced with such problems I try to come up with some equations with two terms A and B, then try to find the actual values of these two terms. For example:

i = A + B

if i was in the range ]0, Max] then we'd get:

i = 0 + B and B = i-1

otherwise if i == 0:

i = A + 0 and A = Max

similarly we can write:

i = i == 0 ? Max : i - 1;

How to write the previous equation without any ifs or ternary operators? I tried so many bit-wise operations and different arithmetic combos but to no avail.

Any ideas?

vexe
  • 5,433
  • 12
  • 52
  • 81
  • 1
    Umm, no? that doesn't work. Say `Max = 10` and `i = 0`, then `i = -1 % 10 `that's still equal to `-1` – vexe Nov 12 '15 at 04:26

2 Answers2

5
i = (Max-1 + i)%Max

will work as long as 0<=i<Max.

David Munro
  • 273
  • 1
  • 8
  • 1
    This may overflow if Max > INTMAX/2, but is good for smaller Max values – Chris Dodd Nov 12 '15 at 04:32
  • Thanks for the answer. However I wanted to wrap back to `Max`, this wraps to `Max - 1`. But considering that most the usage cases are for indices decrementing, usually the max is the count of the array and we want to wrap back to count-1, in that case this works perfectly. I tried to modify your code to wrap to `Max` by adding + 1 to the entire result, but now it doesn't decrement `i` when `0 < i < Max` – vexe Nov 12 '15 at 04:35
  • 2
    Sorry, my answer is the exact decrement analog of your increment example, `(i+1)%Max`. Reading the rest of your post more carefully, it looks like what you want is `(Max-i)%(Max+1)`, that is you want to cycle through the `Max+1` values Max, Max-1, ..., 0, Max, Max-1, ... – David Munro Nov 12 '15 at 04:59
  • @Chris Dodd Yes, it's also probably slower than the ternary operator code the OP presents, unless Max (or is it Max+1) is a power of two.. – David Munro Nov 12 '15 at 05:01
  • May I ask you to explain your logical thought process when you wrote the answers? In other words, how did you come up with them? – vexe Nov 12 '15 at 05:04
  • And yeah you're right. It's almost 3 times slower. Wonder if there's a faster way without the module. Still interested in knowing how you come up with the answers and your thought process. – vexe Nov 12 '15 at 05:40
  • @vexe: this is just `i = (i - 1) mod Max`, the problem being that C's `%` operator is remainder rather than modulus, so you need to correct the range to positive by adding `Max`. As for slowness, its just as slow as your "increment and wrap" -- that is also much faster to do with a conditional. – Chris Dodd Nov 12 '15 at 16:47
  • 1
    Thanks. Right so we could have also written `i = (i - 1 + Max) % Max;` which is a bit clearer imho. What about the `(Max-i) % (Max+i)`? what's the logic behind that? – vexe Nov 12 '15 at 20:36
  • `Max` is congruent to `-1` modulo `Max+1`, just as `Max-1` is congruent to `-1` modulo `Max`. But I should have been cleverer and noticed the objection Chris Dodd raised. The workaround for that is `i=Max-1-(Max-i)%Max`. Just leave off the `%Max` to see that it usually gives `Max-1-(Max-i)` equals `i-1`, and check that when `i==0` it wraps correctly. – David Munro Nov 13 '15 at 05:21
  • The real point is that the % operator is extremely slow -- much slower than a multiply. Although branching can be slow, in this case the condition is trivial as are both branches -- the ternary operator will beat any expression with `%` in it for either incrementing or decrementing. The only exception is if `Max` is a power of two, in which case `(i-1)&(Max-1)` is the same thing as `(Max-1-i)%Max` and will also beat the ternary expression. – David Munro Nov 13 '15 at 05:27
  • One more arcane point: Although `(-1)%10` equals `-1` for every C compiler I've ever used, the ISO C standard does not guarantee this. A fully conforming implementation of C could return `9`, in other words `%` could be the mathematical modulo operation -- as long as `(-1)/10` returned `-1` (instead of `0` as it does for every C compiler I know). In other words, you should not write a C program which requires `(-1)%10` to be `-1` (or `(-1)/10` to be `0`)in order to work properly. – David Munro Nov 13 '15 at 05:32
-1

you can modify it to fit the range you need

var offset, 
    max = 10, 
    str = '', 
    counter = document.getElementById('counter');

for(var i = 0; i < (max * max); i++){
  offset = ((max + i) % max);
  str += (max - offset)+"<br/>";
}

counter.innerHTML = str;
<div id='counter'></div>
Gacci
  • 1,388
  • 1
  • 11
  • 23
  • Umm, could you explain how this works? Looks to me that `(max+i) % max` is just `i % max` which gives the same values for the loop variable `i`, so `offset = i` and then `max - offset` is `max - i`. if I change `i < Max*Max` to `i < Max` and `offset = i` I would get the same output. Sorry not seeing how this helps maybe I'm missing something obvious. I like the "Run code snippet" feature this is the first time I see it! – vexe Nov 12 '15 at 04:43