Sign in to follow this  

if statements V.S. % for wrapping values

This topic is 2659 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi Guys,

I was just wondering is there any efficiency / other reasons to use one or the other in the following two examples:

Example A:


angle= (angle+ diff) % 360;
angle= angle< 0 ? angle= 360+angle: angle;





Example B:


float angleTemp = angle+diff;
if(angleTemp >= 360)
{
angleTemp -= 360;
}
if(angleTemp < 0)
{
angleTemp += 360;
}

angle = angleTemp;





The modulator approach only just occurred to me and I was wondering whether it would be more or less efficient. Especially as some people would consider Example A less readable. My initial thought is that the difference would be more or less negligible but I thought i'd pose the question and find out.

-Thanks Chris

Share this post


Link to post
Share on other sites
How about

angle= (angle+ diff+360) % 360;



Avoiding conditional statements could be faster, but never try to estimate the behavour of a CPU compiler, they are really good nowadways :-)

Share this post


Link to post
Share on other sites
If you're after efficiency the best option is to use a new unit of angular measure, where a full circle is a power of two. For example 512 units in a circle. You can then simply do this:

angle = (angle + diff) & 511;

Edit: You can simplify even further if you use 2^32 as a full circle (assuming you store angles in 32-bit unsigned integers). If you do that the code becomes:

angle += diff;

Share this post


Link to post
Share on other sites
If this is not only for efficiency, how about

while (angle < 0) angle += 360;
while (angle >= 360) angle -= 360;


which also works in case some angular speed exceeds 360 by some factor.

Share this post


Link to post
Share on other sites
I don't see how example A is any less readable, since it's usually pretty clear what you're trying to do with a modulus operator (especially in the context of angles and '360'). Plus it doesn't matter how large angle/diff are, you only need a single conditional to normalize the result. Using loops would work for example B (instead of 'if' statements which don't properly normalize all angle values), but then you linearize the amount of time it takes to normalize the angle and in the worst case you're counting down from INT_MAX/FLT_MAX/etc. in 360 increments.

Share this post


Link to post
Share on other sites
An if that may or may not execute a simple statement is often converted into a cmov instruction, which doesn't involve a branch. That's probably the fastest thing to do. But, as always, only worry about this after a profiler tells you it's a bottleneck. Then check your compiler's output (in assembly code) and test what is faster in your particular usage.

Also, since you seem to be using floating-point numbers, % won't work: You should use fmod instead. Unfortunately the same brain-dead logic that lead to defining integer division as rounding towards zero made its way to the behavior of fmod, so you may have to do something about the negatives. Or you could roll your own:
double sane_fmod(double x, double y) {
return x - y * std::floor(x / y);
}

//...
angle = sane_fmod(angle, 2*Pi); // You should be using radians anyway


Share this post


Link to post
Share on other sites
Thanks guys, thats really interesting!

Im not 100% sure how Adam_42s solution works, cause bit manipulation isnt a strong point. but the concept makes sense! so thanks for that I will have to play with that!

I also really liked Ashaman73 solution, its definitely an improvement on example A!

And phresnel, that is a very good point and a good improvement on example b I will definitely keep that in mind! As well as Zipsters comment on the potential problems which is another good point! I think Ashaman73s example is my favourite and I think I might stick to that for all future wrapping!

Thanks for all your comments its always good to see different ways of doing things and why! I appreciate all your input! Thanks, Chris

Share this post


Link to post
Share on other sites
Oops.

angle = angle >= 0
? angle % 360
: 360 - (-angle % 360);




Constant time for negative and constant time for positive numbers, and works for arbitrary large angles in the integer case.

Share this post


Link to post
Share on other sites
IF statements are faster than modulo/division by at least an order of magnitude on most modern machines. Of course it won't make any difference unless the code is a hot spot, but modulo/division is slower than virtually any other operation.

Share this post


Link to post
Share on other sites
Quote:
Original post by taz0010
IF statements are faster than modulo/division by at least an order of magnitude on most modern machines. Of course it won't make any difference unless the code is a hot spot, but modulo/division is slower than virtually any other operation.


Modulo/division by a constant is implemented using multiplication and bit shifts (at least in recent versions of gcc), and is faster than a hard-to-predict branch. We recently had to optimize a tight loop that contained this type of code, and the alternatives we tried were (from fastest to slowest):
* An if statement that the compiler turned into a CMOV.
* Take modulo a constant.
* An if statement that the compiler turned into a conditional jump.
* Take modulo a variable.

In any case, I only found this out after trying out several possibilities, timing them and looking at the compiler-generated assembly to understand the differences. The results may not apply to a different program or machine, so you'll have to test instead of relying on possibly outdated rules of thumb.

Share this post


Link to post
Share on other sites

This topic is 2659 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this