tags:

views:

415

answers:

8

Is there an easy way to convert an angle (in degrees) to be between -179 and 180? I'm sure I could use mod (%) and some if statements, but it gets ugly:


//Make angle between 0 and 360
angle%=360;

//Make angle between -179 and 180
if (angle>180) angle-=360;

It just seems like there should be a simple math operation that will do both statements at the same time. I may just have to create a static method for the conversion for now.

+4  A: 

Not that smart, too, but no if.

angle = (angle + 179) % 360 - 179;

But I am not sure how Java handles modulo for negative numbers. This works only if -1 modulo 360 equals 359.

UPDATE

Just checked the docs and a % b yields a value between -(|b| - 1) and +(|b| - 1) hence the code is broken. To account for negative values returned by the modulo operator one has to use the following.

angle = ((angle + 179) % 360 + 360) % 360 - 179;

But ... no ... never ... Use something similar to your initial solution, but fixed for values smaller then -179.

Daniel Brückner
too cryptic IMO.
missingfaktor
It should be "angle = (angle + 179) % 360 - 179". Otherwise 180 gets converted to -180.
Romulo A. Ceccon
Already fixed that.
Daniel Brückner
Too cryptic IMO. ... I absolutely agree. Still thinking about a better solution.
Daniel Brückner
this fails if the starting angle is less then -179
Matthew Whited
I'm not sure being cryptic can be regarded as a problem - with commonly used math, you just want it to be efficient. Of course, two additions and a mod probably isn't better than a mod, a comparison, and sometimes an addition.
Jefromi
@Matthew Whited Because -1 modulo 360 yields -1?
Daniel Brückner
@Daniel, The code is fine, there needs to be a check before that line of course for out of range angles (less than -179 , greater than 180), but that needs to be done somewhere anyway, no matter how you code up this piece.
amischiefr
-1 is great than -179 and less then 180 so it would be find. But try it with -181 (which is less then -179)
Matthew Whited
A: 

How about

(angle % 360) - 179

This will actually return different results than the naive approach presented in the question, but it will keep the angle between the bounds specified. (I suppose that might make this the wrong answer, but I will leave it here in case it solves another persons' similar problem).

pkaeding
I think you mean `( (angle + 180) % 360 ) - 180`
Jefromi
And there's the off-by-one issue (fixed in Daniel's answer).
Jefromi
+2  A: 

Maybe not helpful, but I always liked using non-degree angles.

An angle range from 0 to 255 can be kept in bounds using bitwise operations, or for a single byte variable, simple allowed to overflow.

An angle range from -128 to 127 isn't quite so easy with bitwise ops, but again, for a single-byte variable, you can let it overflow.

I thought it was a great idea many years back for games, where you're probably using a lookup table for angles. These days, not so good - the angles are used differently, and are float anyway.

Still - maybe worth a mention.

Steve314
+1 that is a very interesting idea, and if more granularity is needed than more bits can be used -- two bytes for example give 65536 distinct angles.
GregS
+3  A: 
Seth
+1 for taking advantage of limited-range functions for normalizing. A bit of overhead is involved, but this is by far the most concise answer that is actually correct.
Platinum Azure
+1 clean but slow. I'm tempted to choose this answer.
User1
Even better now, since the value is in the correct range. However, now you're doing three trig functions instead of two!
Seth
+10  A: 

I'm a little late to the party, I know, but...

Most of these answers are no good, because they try to be clever and concise and then don't take care of edge cases.

It's a little more verbose, but if you want to make it work, just put in the logic to make it work. Don't try to be clever.

int normalizeAngle(int angle)
{
    int newAngle = angle;
    while (newAngle <= -180) newAngle += 360;
    while (newAngle > 180) newAngle -= 360;
    return newAngle;
}

This works and is reasonably clean and simple, without trying to be fancy. Note that only zero or one of the while loops can ever be run.

Platinum Azure
+1, best answer so far!
Jim Lewis
And it handles angles with non-integer degrees!
Aniko
could you start with newAngle = angle % 360 at the beginning so you don't have to worry about normalizeAngle(Integer.MAX_VALUE) ? that would fall in the "don't take care of edge cases" category probably.
Jimmy
-1: This answer is ridiculously slow for angles that are not near 0. This is the solution for people who oppose division on religious grounds.
GregS
+1, reminds me of pythonic philosophy!
missingfaktor
Its pretty slow for a large number. :(
Peter Lawrey
A: 
int angle = -394;

// shortest
angle %= 360;
angle = angle < -170 ? angle + 360 : (angle > 180 ? angle - 380 : angle);

// cleanest
angle %= 360;
if (angle < -179) angle += 360;
else if (angle > 180) angle -= 360;
Matthew Whited
A: 

A short way which handles negative numbers is

double mod = x - Math.floor((x + 179.0) / 360) * 360;

Cast to taste.

BTW: It appears that angles between (180.0, 181.0) are undefined. Shouldn't the range be (-180, 180] (exclusive, inclusive]

Peter Lawrey
+3  A: 
// reduce the angle  
angle =  angle % 360; 

// force it to be the positive remainder, so that 0 <= angle < 360  
angle = (angle + 360) % 360;  

// force into the minimum absolute value residue class, so that -180 < angle <= 180  
if (angle > 180)  
    angle -= 360;  
GregS
That's the correct answer with the least calculations necessary.
ΤΖΩΤΖΙΟΥ