-- | This module provides a replacement for Haskell's 'atan2'. The
-- problem is that Haskell's standard implementation of 'atan2'
-- depends on the 'RealFloat' class, which limits its applicability.
-- So we provide a new 'ArcTan2' class with an 'arctan2' function.
-- 
-- Unlike Haskell's 'atan2', the 'arctan2' function may not take
-- signed zeros and signed infinities into account. But it works at
-- fixed-precision types such as 'FixedPrec'.

module Quantum.Synthesis.ArcTan2 where

import Data.Number.FixedPrec

-- ----------------------------------------------------------------------
-- * The arctan2 function

-- | We provide a replacement for Haskell's 'atan2', because the
-- latter depends on the 'RealFloat' class, which limits its
-- applicability.
class ArcTan2 a where
  arctan2 :: a -> a -> a
  
instance ArcTan2 Double where
  arctan2 = atan2

instance ArcTan2 Float where
  arctan2 = atan2

instance (Precision e) => ArcTan2 (FixedPrec e) where
  arctan2 y x
    | x == 0 && y == 0 = 0
    | abs y <= x       = atan (y/x)
    | abs x <= y       = pi/2 - atan (x/y)
    | abs x <= -y      = -pi/2 - atan (x/y)
    | y >= 0           = pi + atan (y/x)
    | otherwise        = -pi + atan (y/x)