I want to decrease a value by one and if it reaches zero, set it to the maximum value. Is there a way to do this via math without resorting to if (n-1 == 0) { n = max; }
The opposite scenario of increasing a value by one and then setting it to zero when it is greater than max can easily be achieved using n = (n + 1) % (max + 1);
. Furthermore, this is even better since you can increase by whatever amount (not just one) and it will still "wrap" correctly.
Thanks for the answers so far. To be clear, I meant without any boolean logic (if/else) or boolean operators (!, &&, etc) at all. I was just curious as to how to do this. Does the correct answer below really make it more unreadable as long as a comment is provided? It would be necessary to use that for the more general case for subtracting an arbitrary number and expecting the correct wrap around.
n = max - ((max - n +1)%max)
If you're doing this purely for performance reasons then I would advise against it. %
is usually quite an expensive operation on most architectures - a simple comparison, branch and addition will usually be more efficient. Of course the usual caveats about speculative/premature optimisation apply.
The problem is that the %
operator in C returns a negative result when faced with a negative dividend. This is often not what is needed.
If you want a mod
function that will fulfill -1 mod n == n-1
, then, in C, you have to do the following:
int mod(int a, int b)
{
return (a%b + b) % b;
}
You can then do
n=mod(n-1, max+1);
to decrement n
and have it wrap around to max
when n==0
. Note that, as for the increment case, this will work for arbitrary step sizes.
There are enough variations in math between languages that I doubt there's a language-agnostic way to do this. There's simply too much variation in how languages write expressions for a basic single technique to work with every possible language.
If you pick a specific language, there's a pretty good chance that it's possible. For example, in C or C++, you could do something like: n = (n-1) + ((n-1) == 0) * max;
In case you care how that works: in C, a comparison ( ==
in this case) produces a result of 0 for false, and 1 for true. So what we're doing is adding max * 0
when/if n-1 != 0
, and max * 1
when/if n-1 == 0
.
There might be a better way but I think n = max - (max - n + 1) % (max + 1)
works. I'm assuming you want to include 0 at both ends since for your increment expression you do include 0.
Actually you can do also
n = (n - 1) + ((!(n - 1)) * max);
How about this:
n = !n*max + (!!n)*n;
Re: no booleans
Well, through the magic of integer division (C-style), my previous answer can be written as:
n = ((max-n)/max) * max + ((max+n-1)/max)*n;
Just to ask: why do you want to avoid a boolean operation?
If you want to avoid conditional code in your application you might use boolean expressions that are store in boolean values. Those will be mapped to the SETcc instructions on an i386 and I assume analog instuctions exist on other ISAs.
In that case you can use a boolean expression and still have non conditional code and you could use:
Under the assumption that a boolean result of true equals to the Ordinal 1 (this is the case in Delphi code) and a boolean value of false equals to 0 you could write
next := current - 1 + ( ( 1 + max ) and -Ord( current = 0 ) );
Don't vote this down because I gave an answer with boolean operations. I just want to check if this is a differnet solution to the underlying problem.
Still: I think the conditional code is much much more readable.
Why not just compare to 1?
if(n==1) { n = max; }
In any short-circuit logic evaluation language (most modern languages) you can do something like this:
--n<=0 && n=max;
You might get the hairy eyeball from some of your coworkers if your team isn't accustomed to using && as an if-then operator.
To do the forward looping increment:
++n>max && n=1;
These examples are assuming a 1-indexed counter since your question seems to suppose that. 0-indexed equivalents are:
--n<0 && n=max-1;
++n>=max && n=0;
精彩评论