-
Get a monthly update on best practices for delivering successful software.
Math is fun!
I never understand why people hate math so much. I guess I hated history & literature as much as fans of those subjects hate math. I remember always hearing that you would never use math in real life, which is just not true. I use it all the time, and this post is about one of those times.
A coworker of mine is creating an iPhone app, and whenever he encounters tricky math, pulls me in, as he realizes I have fun with it. His problem was:
given two points on a circle, find the shortest number of degrees between them
So given points at 4° and 20°, the result should be 16°. Seems easy enough, except a few fun scenarios. 356° and 4° results in 8°, and 360° and 0° are the same.
I thought through it, and my original approach was going to figure out what quadrant each angle was in, and then do some calculations to adjust the distance to keep the answer <= 180°. But then I realized that was going to be nasty, and then I remembered our good friend the radian.
Each circle has 2∏ radians, so 360° = 2∏. So my approach was to convert each angle to radians, compute the absolute value of the distance between them, and then convert back to degrees. I had to adjust a couple of things. First, I convert 0° to 360°, and if the distance between the two angles is greater than ∏ (180°), subtract it from 2∏.
He needed to do this in Cocoa, but I quickly generated some code in ruby, which he then converted.
So I started with a test:
def test_diff_deg assert_equal 4, diff_deg(2,358) assert_equal 180, diff_deg(90,270) assert_equal 0, diff_deg(0,360) assert_equal 0, diff_deg(90,90) assert_equal 4, diff_deg(178,182) assert_equal 180, diff_deg(358,178) end
Then I wrote the code:
def diff_deg(a,b) #adjust for zero a = 360 if a == 0 b = 360 if b == 0 # convert to radians a_rad = Math::PI * a / 180 b_rad = Math::PI * b / 180 # compute the positive distance between them in radians dif = (a_rad-b_rad).abs # constrain to the shortest path, so trim if it's > 180° dif = 2*Math::PI - dif if dif > Math::PI #return the result in degrees deg = (180 * dif / Math::PI).round(6) end
Have fun with Math!
Related posts:
I don’t feel there was any need for converting it to radians… You just want to figure out the difference and constrain it to be below 180!
def diff_deg(a,b)
#adjust for zero
a = 360 if a == 0
b = 360 if b == 0
dif = (a-b).abs
# constrain to the shortest path, so trim if it’s > 180°
dif = (dif > 180) ? (360-dif) : dif
end
Comment by Shalom Craimer, Wednesday, April 29, 2009 @ 5:05 am
Let thita = abs(thita1 – thita2)
answer = min{thita, 360 – thita}
Comment by mathfan, Wednesday, April 29, 2009 @ 5:44 am
You don’t need to convert to radians and back to use the same result:
http://gist.github.com/103790
Comment by Steve Tooke, Wednesday, April 29, 2009 @ 8:06 am
I don’t see any reason to convert to radians and back to degrees. The code would be a lot simpler if you didn’t:
def diff_deg(a,b)
dif = ((a % 360) – (b % 360)).abs
dif = 360 – dif if dif > 180
dif
end
Comment by Craig Buchek, Wednesday, April 29, 2009 @ 9:13 am
Math can be fun. I would love to see the Objective-C test and the Objective-C code to compare.
Comment by Derek Neighbors, Wednesday, April 29, 2009 @ 9:54 am
how about this?
def diff_deg(a,b)
(diff=(a-b).abs)>180&&360-diff||diff
end
Comment by marocchino, Friday, May 1, 2009 @ 7:44 pm