Angles on a compass

MJ -- To determine the difference between two directions on a compass the proc below can be used. It can most likely be written shorter, but it should at least give the correct answer.

For two compass courses $a and $b it will calculate the difference in degrees and whether you need to go clockwise (positive return) or counterclockwise (negative return) to go from course $a to $b.

 proc anglediff {a b} {
  set a [expr {$a%360}]
  set b [expr {$b%360}]
  set dclockwise [expr (360-$a+$b)%360]

  return [expr {$dclockwise<=180?$dclockwise:-(360-$dclockwise)}]
 }

 # and some tests:

 proc assert_equal {a b} {
  if {$a != $b} { error "assertion $a==$b failed"}
 }

 assert_equal [anglediff   1  359]  -2
 assert_equal [anglediff   0  180] 180
 assert_equal [anglediff -10   10]  20
 assert_equal [anglediff 360    0]   0
 assert_equal [anglediff 180 -180]   0
 assert_equal [anglediff -10  340] -10

dzach I use a similar routine often. Only, to make it work with decimal angles, one has to use fmod():

 proc anglediff {a b} {
  set dclockwise [expr {fmod(360-fmod($a,360)+fmod($b,360),360)}]
  expr {$dclockwise<=180?$dclockwise:-(360-$dclockwise)}
 }
 % anglediff   1  359
 -2.0
 % time {anglediff   1  359} 1000
 3.232 microseconds per iteration

To make it faster, I use C and critcl:

 critcl::cproc dcourse {double a double b} double {
         double dc = fmod(360.0 - fmod(a,360) + fmod(b,360), 360);
         return dc <= 180 ? dc : dc - 360;
 }
 % load ./dcourse.so
 % dcourse 1 359
 -2.0
 % time {dcourse 1 359} 1000
 0.782 microseconds per iteration