```-- | Various floating point limit related numerical constants.
module Numeric.Limits(
-- * Significant digits
digits10,
-- * Minimum difference
epsilon,
-- * Extreme finite values
maxValue,
minValue,
-- * Abnormal values
infinity,
nan,
) where

-- | The number of decimal digits that the type can represent without loss of precision.
{-# SPECIALIZE digits10 :: Double -> Int #-}
{-# SPECIALIZE digits10 :: Float -> Int #-}
digits10 :: (RealFloat a) => a -> Int
digits10 x = count 0 (floatRadix x ^ floatDigits x)
where count n v = if v < 10 then n else count (n+1) (v `quot` 10)

-- | The difference between 1 and the smallest value greater than 1 that is representable for the type.
{-# SPECIALIZE epsilon :: Double #-}
{-# SPECIALIZE epsilon :: Float #-}
epsilon :: (RealFloat a) => a
epsilon = r
where r = 1 - encodeFloat (m-1) e
(m, e) = decodeFloat (1 `asTypeOf` r)

-- | Infinity value if the type supports it.
{-# SPECIALIZE infinity :: Double #-}
{-# SPECIALIZE infinity :: Float #-}
infinity :: (RealFloat a) => a
infinity = 1/0

-- | Not-a-number value if the type supports it.
{-# SPECIALIZE nan :: Double #-}
{-# SPECIALIZE nan :: Float #-}
nan :: (RealFloat a) => a
nan = 0/0

-- | The maximum finite value for the type.
{-# SPECIALIZE maxValue :: Double #-}
{-# SPECIALIZE maxValue :: Float #-}
maxValue :: (RealFloat a) => a
maxValue = x
where n = floatDigits x
(_, u) = floatRange x
x = encodeFloat (b^n - 1) (u - n)

-- | The minimum (positive) normalized value for the type.
{-# SPECIALIZE minValue :: Double #-}
{-# SPECIALIZE minValue :: Float #-}
minValue :: (RealFloat a) => a
minValue = x
where n = floatDigits x