grisette-0.8.0.0: src/Grisette/Internal/Core/Data/Class/IEEEFP.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- Module : Grisette.Internal.Core.Data.Class.IEEEFP
-- Copyright : (c) Sirui Lu 2024
-- License : BSD-3-Clause (see the LICENSE file)
--
-- Maintainer : siruilu@cs.washington.edu
-- Stability : Experimental
-- Portability : GHC only
module Grisette.Internal.Core.Data.Class.IEEEFP
( fpIsNaN,
fpIsPositiveZero,
fpIsNegativeZero,
fpIsPositiveInfinite,
fpIsNegativeInfinite,
fpIsPositive,
fpIsNegative,
fpIsInfinite,
fpIsZero,
fpIsNormal,
fpIsSubnormal,
fpIsPoint,
IEEEFPConstants (..),
IEEEFPRoundingMode (..),
IEEEFPOp (..),
IEEEFPRoundingOp (..),
IEEEFPConvertible (..),
IEEEFPToAlgReal (..),
)
where
-- | Check if a floating-point number is not-a-number.
fpIsNaN :: (RealFloat a) => a -> Bool
fpIsNaN = isNaN
{-# INLINE fpIsNaN #-}
-- | Check if a floating-point number is positive zero.
fpIsPositiveZero :: (RealFloat a) => a -> Bool
fpIsPositiveZero x = x == 0 && not (fpIsNegativeZero x)
{-# INLINE fpIsPositiveZero #-}
-- | Check if a floating-point number is negative zero.
fpIsNegativeZero :: (RealFloat a) => a -> Bool
fpIsNegativeZero = isNegativeZero
{-# INLINE fpIsNegativeZero #-}
-- | Check if a floating-point number is positive infinite.
fpIsPositiveInfinite :: (RealFloat a) => a -> Bool
fpIsPositiveInfinite x = isInfinite x && x > 0
{-# INLINE fpIsPositiveInfinite #-}
-- | Check if a floating-point number is negative infinite.
fpIsNegativeInfinite :: (RealFloat a) => a -> Bool
fpIsNegativeInfinite x = isInfinite x && x < 0
{-# INLINE fpIsNegativeInfinite #-}
-- | Check if a floating-point number is positive.
-- +0, +inf are considered positive. nan, -0, -inf are not positive.
fpIsPositive :: (RealFloat a) => a -> Bool
fpIsPositive x = not (fpIsNaN x) && (x > 0 || fpIsPositiveZero x)
{-# INLINE fpIsPositive #-}
-- | Check if a floating-point number is negative.
-- -0, -inf are considered negative. nan, +0, +inf are not negative.
fpIsNegative :: (RealFloat a) => a -> Bool
fpIsNegative x = not (fpIsNaN x) && (x < 0 || isNegativeZero x)
{-# INLINE fpIsNegative #-}
-- | Check if a floating-point number is infinite.
fpIsInfinite :: (RealFloat a) => a -> Bool
fpIsInfinite x = fpIsPositiveInfinite x || fpIsNegativeInfinite x
{-# INLINE fpIsInfinite #-}
-- | Check if a floating-point number is zero.
fpIsZero :: (RealFloat a) => a -> Bool
fpIsZero x = fpIsPositiveZero x || fpIsNegativeZero x
{-# INLINE fpIsZero #-}
-- | Check if a floating-point number is normal, i.e., not 0, not inf, not
-- nan, and not denormalized.
fpIsNormal :: (RealFloat a) => a -> Bool
fpIsNormal x =
not (fpIsZero x)
&& not (fpIsSubnormal x)
&& not (fpIsInfinite x)
&& not (fpIsNaN x)
{-# INLINE fpIsNormal #-}
-- | Check if a floating-point number is subnormal, i.e., denormalized. 0,
-- inf, or nan are not subnormal.
fpIsSubnormal :: (RealFloat a) => a -> Bool
fpIsSubnormal = isDenormalized
{-# INLINE fpIsSubnormal #-}
-- | Check if a floating-point number is a point, i.e., not inf, not nan.
fpIsPoint :: (RealFloat a) => a -> Bool
fpIsPoint x = not (fpIsInfinite x) && not (fpIsNaN x)
{-# INLINE fpIsPoint #-}
-- | Constants for IEEE floating-point numbers.
class IEEEFPConstants a where
-- | Positive infinity.
fpPositiveInfinite :: a
-- | Negative infinity.
fpNegativeInfinite :: a
-- | Not-a-number.
fpNaN :: a
-- | Negative zero.
fpNegativeZero :: a
-- | Positive zero.
fpPositiveZero :: a
-- | Smallest positive normalized number.
fpMinNormalized :: a
-- | Smallest positive subnormal number.
fpMinSubnormal :: a
-- | Largest positive normalized number.
fpMaxNormalized :: a
-- | Largest positive subnormal number.
fpMaxSubnormal :: a
-- | Operations on IEEE floating-point numbers, without rounding mode.
class IEEEFPOp a where
-- | IEEE754-2019 abs operation.
fpAbs :: a -> a
-- | IEEE754-2019 negate operation.
fpNeg :: a -> a
-- | IEEE754-2019 remainder operation.
fpRem :: a -> a -> a
-- | IEEE754-2019 minimum operation.
--
-- * The comparison for zeros follows -0 < 0
-- * Returns NaN if one operand is NaN.
fpMinimum :: a -> a -> a
-- | IEEE754-2019 minimumNumber operation.
--
-- * The comparison for zeros follows -0 < 0
-- * Returns the other operand if one operand is NaN.
fpMinimumNumber :: a -> a -> a
-- | IEEE754-2019 maximum operation.
--
-- * The comparison for zeros follows -0 < 0
-- * Returns NaN if one operand is NaN.
fpMaximum :: a -> a -> a
-- | IEEE754-2019 maximumNumber operation.
--
-- * The comparison for zeros follows -0 < 0
-- * Returns the other operand if one operand is NaN.
fpMaximumNumber :: a -> a -> a
-- | Rounding modes for floating-point operations.
class IEEEFPRoundingMode mode where
-- | Round to nearest, ties to even.
rne :: mode
-- | Round to nearest, ties to away from zero.
rna :: mode
-- | Round towards positive infinity.
rtp :: mode
-- | Round towards negative infinity.
rtn :: mode
-- | Round towards zero.
rtz :: mode
-- | Operations on IEEE floating-point numbers, with rounding mode.
class (IEEEFPRoundingMode mode) => IEEEFPRoundingOp a mode | a -> mode where
fpAdd :: mode -> a -> a -> a
fpSub :: mode -> a -> a -> a
fpMul :: mode -> a -> a -> a
fpDiv :: mode -> a -> a -> a
fpFMA :: mode -> a -> a -> a -> a
fpSqrt :: mode -> a -> a
fpRoundToIntegral :: mode -> a -> a
-- | Conversion from and to FPs.
class IEEEFPConvertible a fp mode | fp -> mode where
fromFPOr ::
-- | Default value when converting non-representable FPs. For example, when
-- converting to non-FP types, the NaN and infinities are not representable.
-- Additionally, when converting to bit-vectors, out-of-bound FPs are not
-- representable.
--
-- Note that out-of-bound means that the /value after conversion/ is out of
-- bound, not the /value before conversion/, meaning that converting from
-- 3.5 to 2-bit unsigned bit-vector is out-of-bound when rounding to
-- positive, but not when rounding to negative.
a ->
-- | Rounding mode. Ignored when converting to 'Grisette.AlgReal' because
-- every representable FP value is converted to an exact 'Grisette.AlgReal'.
mode ->
-- | FP value.
fp ->
a
toFP :: mode -> a -> fp
-- | Converting FP to real numbers.
class
(IEEEFPConvertible a fp mode, IEEEFPRoundingMode mode) =>
IEEEFPToAlgReal a fp mode
| fp -> mode
where
-- | Similar to 'fromFPOr' for 'Grisette.AlgReal', but dropped the ignored
-- rounding mode.
fpToAlgReal :: a -> fp -> a
fpToAlgReal d = fromFPOr d rna