-- | 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 >= extremelyLarge >= veryLarge@
--
-- @veryLarge >= verySmall@
--
-- @verySmall >= extremelySmall >= minFinite@.
--
-- TODO the small stuff should actually be around zero, but positive and go
-- into @NumericalEpsilon@. Here we should actually use other names.

class NumericalExtremes x where
  -- | Largest finite number
  maxFinite       :: x
  -- | Smallest finite number
  minFinite       :: x
  -- | Around @1/100@ of the largest finite number
  veryLarge       :: x
  -- | Around @1/100@ of the smallest finite number
  verySmall       :: x
  -- | Around @1/ 10@ of the largest finite number
  extremelyLarge  :: x
  -- | Around @1/ 10@ of the smallest finite number
  extremelySmall  :: x

-- | Small numbers.

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



instance NumericalExtremes Int where
  maxFinite      = maxBound
  minFinite      = minBound
  veryLarge      = maxBound `div` 100
  verySmall      = minBound `div` 100
  extremelyLarge = maxBound `div`  10
  extremelySmall = minBound `div`  10
  {-# Inline veryLarge      #-}
  {-# Inline verySmall      #-}
  {-# Inline extremelyLarge #-}
  {-# Inline extremelySmall #-}



instance NumericalExtremes Double where
  maxFinite      =  1.79e+308
  minFinite      = -1.79e+308
  veryLarge      = maxFinite / 100
  verySmall      = minFinite / 100
  extremelyLarge = maxFinite /  10
  extremelySmall = minFinite /  10
  {-# Inline veryLarge      #-}
  {-# Inline verySmall      #-}
  {-# Inline extremelyLarge #-}
  {-# Inline extremelySmall #-}

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