I wanted to try a small exercise of implementing this using scala(ignoring the fact that it is already natively implemented in java.lang.Math library).
The simplest implementation that I could think of is with a if expression this way:
1 2 3 4 5 6 7 8 | def atan2(x: Double, y: Double):Double = { if (x > 0 ) atan(y/x) else if (y >= 0 && x < 0 ) Pi + atan(y/x) else if (y < 0 && x < 0 ) atan(y/x) - Pi else if (y > 0 && x== 0 ) Pi/ 2 else if (y < 0 && x== 0 ) -Pi/ 2 else Double.NaN } |
However, I wanted to see at this point if it could be reimplemented using a case-match expression, and I could only come up with a souped up version of if/else this way:
1 2 3 4 5 6 7 8 9 10 | def atan2(x: Double, y: Double): Double = { true match { case _ if (x> 0 ) => atan(y/x) case _ if (y >= 0 && x < 0 ) => atan(y/x) + Pi case _ if (y < 0 && x < 0 ) => atan(y/x) - Pi case _ if (y > 0 && x== 0 ) => Pi/ 2 case _ if (y < 0 && x== 0 ) => -Pi/ 2 case _ => Double.NaN } } |
After reading up a little more on scala extractors, I could come up with a crazier version of the same:
1 2 3 4 5 6 7 8 9 10 | def atan2(x: Double, y: Double): Double = { (x, y) match { case xgt0() => atan(y/x) case ygte0Andxlt0() => atan(y/x) + Pi case ylt0Andxlt0() => atan(y/x) - Pi case ygt0Andxeq0() => Pi/ 2 case ylt0Andxeq0() => -Pi/ 2 case _ => Double.NaN } } |
However, this unfortunately requires defining 5 extractors this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | object xgt0 { def unapply(tup: (Double, Double)): Boolean = tup match { case (x,y) => (x> 0 )} } object ygte0Andxlt0 { def unapply(tup: (Double, Double)): Boolean = tup match { case (x, y) => (y >= 0 && x < 0 )} } object ylt0Andxlt0 { def unapply(tup: (Double, Double)): Boolean = tup match { case (x, y) => (y < 0 && x < 0 )} } object ygt0Andxeq0 { def unapply(tup: (Double, Double)): Boolean = tup match { case (x, y) => (y > 0 && x == 0 )} } object ylt0Andxeq0 { def unapply(tup: (Double, Double)): Boolean = tup match { case (x, y) => (y < 0 && x == 0 )} } |
The only conclusion I could make out of this is that if I had to re-write atan2 in scala the best approach is probably using the first one - using if expression. I am sure there is definitely a more scala way of doing this and would definitely appreciate any suggestions on these approaches
No comments:
Post a Comment