-- | For some values, we want to have different kind of extreme values.
-- Consider a @Double@ representing an energy. We want @near infinities@
-- that do not lead to numeric problems.
--
-- TODO benchmark different extremes and their interplay with algebraic
-- operations.
--
-- TODO consider the @ieee754@ package

module Biobase.Types.NumericalExtremes where



-- | Very large and small numbers with some numerical safety to @1/0@ or
-- @maxBound@ (depending on if we are @Integral@ or @RealFloat@.
--
-- We have:
--
-- @maxFinite >= maxExtreme >= maxLarge@
--
-- @maxLarge >= minLarge@
--
-- @minLarge >= minExtreme >= minFinite@.

class NumericalExtremes x where
  maxFinite   :: x  -- ^ Largest finite number
  minFinite   :: x  -- ^ Smallest finite number
  maxExtreme  :: x  -- ^ Around @1/ 10@ of the largest finite number
  minExtreme  :: x  -- ^ Around @1/ 10@ of the smallest finite number
  maxLarge    :: x  -- ^ Around @1/100@ of the largest finite number
  minLarge    :: x  -- ^ Around @1/100@ of the smallest finite number

-- | Small numbers.

class NumericalEpsilon x where
  epsilon   :: x  -- ^ Smallest positive number @/= 0.0@.



instance NumericalExtremes Int where
  maxFinite  = maxBound
  minFinite  = minBound
  maxLarge   = maxBound `div` 100
  minLarge   = minBound `div` 100
  maxExtreme = maxBound `div`  10
  minExtreme = minBound `div`  10
  {-# Inline maxFinite  #-}
  {-# Inline minFinite  #-}
  {-# Inline maxExtreme #-}
  {-# Inline minExtreme #-}
  {-# Inline maxLarge   #-}
  {-# Inline minLarge   #-}



instance NumericalExtremes Double where
  maxFinite  =  1.79e+308
  minFinite  = -1.79e+308
  maxExtreme =  1.79e+307
  minExtreme = -1.79e+307
  maxLarge   =  1.79e+306
  minLarge   = -1.79e+306
  {-# Inline maxFinite  #-}
  {-# Inline minFinite  #-}
  {-# Inline maxExtreme #-}
  {-# Inline minExtreme #-}
  {-# Inline maxLarge   #-}
  {-# Inline minLarge   #-}



instance NumericalEpsilon Double where
  epsilon = 2.2e-16
  {-# Inline epsilon #-}