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:
/
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]
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).
It is better to use library functions. They handle special cases like NaN and infinities.
public static double normalizeAngleDegrees(double angle) {
return Math.toDegrees(Math.atan2(Math.sin(Math.toRadians(angle)), Math.cos(Math.toRadians(angle))));
}
Try this instead!
atan2(sin(angle), cos(angle))
atan2
has a range of [-π, π). This takes advantage of the fact that tan θ = sin θ / cos θ, and that atan2
is smart enough to know which quadrant θ is in.
Since you want degrees, you will want to convert your angle to and from radians:
atan2(sin(angle * PI/180.0), cos(angle * PI/180.0)) * 180.0/PI
Update
My previous example was perfectly legitimate, but restricted the range to ±90°. atan2
's range is the desired value of -179° to 180°. Preserved below.
Try this:
asin(sin(angle)))
The domain of sin
is the real line, the range is [-1, 1]
. The domain of asin
is [-1, 1]
, and the range is [-PI/2, PI/2]
. Since asin
is the inverse of sin
, your input isn't changed (much, there's some drift because you're using floating point numbers). So you get your input value back, and you get the desired range as a side effect of the restricted range of the arcsine.
Since you want degrees, you will want to convert your angle to and from radians:
asin(sin(angle * PI/180.0)) * 180.0/PI
(Caveat: Trig functions are bazillions of times slower than simple divide and subtract operations, even if they are done in an FPU!)
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;
Well, one more solution, this one with just one division and no loops.
static double normalizeAngle(double angle)
{
angle %= 360.0; // [0..360) if angle is positive, (-360..0] if negative
if (angle > 180.0) // was positive
return angle - 360.0; // was (180..360) => returning (-180..0)
if (angle <= -180.0) // was negative
return angle + 360.0; // was (-360..180] => returning (0..180]
return angle; // (-180..180]
}