module Agda.Utils.Float
( asFinite
, isPosInf
, isNegInf
, isPosZero
, isNegZero
, isSafeInteger
, doubleEq
, doubleLe
, doubleLt
, intToDouble
, doublePlus
, doubleMinus
, doubleTimes
, doubleNegate
, doubleDiv
, doublePow
, doubleSqrt
, doubleExp
, doubleLog
, doubleSin
, doubleCos
, doubleTan
, doubleASin
, doubleACos
, doubleATan
, doubleATan2
, doubleSinh
, doubleCosh
, doubleTanh
, doubleASinh
, doubleACosh
, doubleATanh
, doubleRound
, doubleFloor
, doubleCeiling
, doubleDenotEq
, doubleDenotOrd
, doubleToWord64
, doubleToRatio
, ratioToDouble
, doubleDecode
, doubleEncode
, toStringWithoutDotZero
) where
import Data.Bifunctor ( second )
import Data.Function ( on )
import Data.Maybe ( fromMaybe )
import Data.Ratio ( (%), numerator, denominator )
import Data.Word ( Word64 )
import Agda.Utils.List ( stripSuffix )
import GHC.Float (castDoubleToWord64, castWord64ToDouble)
{-# INLINE doubleEq #-}
doubleEq :: Double -> Double -> Bool
doubleEq :: Double -> Double -> Bool
doubleEq = Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
(==)
{-# INLINE doubleLe #-}
doubleLe :: Double -> Double -> Bool
doubleLe :: Double -> Double -> Bool
doubleLe = Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
(<=)
{-# INLINE doubleLt #-}
doubleLt :: Double -> Double -> Bool
doubleLt :: Double -> Double -> Bool
doubleLt = Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
(<)
truncateDouble :: Double -> Double
truncateDouble :: Double -> Double
truncateDouble = Word64 -> Double
castWord64ToDouble (Word64 -> Double) -> (Double -> Word64) -> Double -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Word64
castDoubleToWord64
{-# INLINE intToDouble #-}
intToDouble :: Integral a => a -> Double
intToDouble :: forall a. Integral a => a -> Double
intToDouble = Double -> Double
truncateDouble (Double -> Double) -> (a -> Double) -> a -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral
{-# INLINE doublePlus #-}
doublePlus :: Double -> Double -> Double
doublePlus :: Double -> Double -> Double
doublePlus Double
x Double
y = Double -> Double
truncateDouble (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
y)
{-# INLINE doubleMinus #-}
doubleMinus :: Double -> Double -> Double
doubleMinus :: Double -> Double -> Double
doubleMinus Double
x Double
y = Double -> Double
truncateDouble (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
y)
{-# INLINE doubleTimes #-}
doubleTimes :: Double -> Double -> Double
doubleTimes :: Double -> Double -> Double
doubleTimes Double
x Double
y = Double -> Double
truncateDouble (Double
x Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
y)
{-# INLINE doubleNegate #-}
doubleNegate :: Double -> Double
doubleNegate :: Double -> Double
doubleNegate = Double -> Double
forall a. Num a => a -> a
negate
{-# INLINE doubleDiv #-}
doubleDiv :: Double -> Double -> Double
doubleDiv :: Double -> Double -> Double
doubleDiv = Double -> Double -> Double
forall a. Fractional a => a -> a -> a
(/)
{-# INLINE doublePow #-}
doublePow :: Double -> Double -> Double
doublePow :: Double -> Double -> Double
doublePow Double
x Double
y = Double -> Double
truncateDouble (Double
x Double -> Double -> Double
forall a. Floating a => a -> a -> a
** Double
y)
{-# INLINE doubleSqrt #-}
doubleSqrt :: Double -> Double
doubleSqrt :: Double -> Double
doubleSqrt = Double -> Double
forall a. Floating a => a -> a
sqrt
{-# INLINE doubleExp #-}
doubleExp :: Double -> Double
doubleExp :: Double -> Double
doubleExp Double
x = Double -> Double
truncateDouble (Double -> Double
forall a. Floating a => a -> a
exp Double
x)
{-# INLINE doubleLog #-}
doubleLog :: Double -> Double
doubleLog :: Double -> Double
doubleLog = Double -> Double
forall a. Floating a => a -> a
log
{-# INLINE doubleSin #-}
doubleSin :: Double -> Double
doubleSin :: Double -> Double
doubleSin = Double -> Double
forall a. Floating a => a -> a
sin
{-# INLINE doubleCos #-}
doubleCos :: Double -> Double
doubleCos :: Double -> Double
doubleCos = Double -> Double
forall a. Floating a => a -> a
cos
{-# INLINE doubleTan #-}
doubleTan :: Double -> Double
doubleTan :: Double -> Double
doubleTan = Double -> Double
forall a. Floating a => a -> a
tan
{-# INLINE doubleASin #-}
doubleASin :: Double -> Double
doubleASin :: Double -> Double
doubleASin = Double -> Double
forall a. Floating a => a -> a
asin
{-# INLINE doubleACos #-}
doubleACos :: Double -> Double
doubleACos :: Double -> Double
doubleACos = Double -> Double
forall a. Floating a => a -> a
acos
{-# INLINE doubleATan #-}
doubleATan :: Double -> Double
doubleATan :: Double -> Double
doubleATan = Double -> Double
forall a. Floating a => a -> a
atan
{-# INLINE doubleATan2 #-}
doubleATan2 :: Double -> Double -> Double
doubleATan2 :: Double -> Double -> Double
doubleATan2 = Double -> Double -> Double
forall a. RealFloat a => a -> a -> a
atan2
{-# INLINE doubleSinh #-}
doubleSinh :: Double -> Double
doubleSinh :: Double -> Double
doubleSinh = Double -> Double
forall a. Floating a => a -> a
sinh
{-# INLINE doubleCosh #-}
doubleCosh :: Double -> Double
doubleCosh :: Double -> Double
doubleCosh = Double -> Double
forall a. Floating a => a -> a
cosh
{-# INLINE doubleTanh #-}
doubleTanh :: Double -> Double
doubleTanh :: Double -> Double
doubleTanh = Double -> Double
forall a. Floating a => a -> a
tanh
{-# INLINE doubleASinh #-}
doubleASinh :: Double -> Double
doubleASinh :: Double -> Double
doubleASinh = Double -> Double
forall a. Floating a => a -> a
asinh
{-# INLINE doubleACosh #-}
doubleACosh :: Double -> Double
doubleACosh :: Double -> Double
doubleACosh = Double -> Double
forall a. Floating a => a -> a
acosh
{-# INLINE doubleATanh #-}
doubleATanh :: Double -> Double
doubleATanh :: Double -> Double
doubleATanh = Double -> Double
forall a. Floating a => a -> a
atanh
{-# INLINE negativeZero #-}
negativeZero :: Double
negativeZero :: Double
negativeZero = -Double
0.0
positiveInfinity :: Double
positiveInfinity :: Double
positiveInfinity = Double
1.0 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
0.0
negativeInfinity :: Double
negativeInfinity :: Double
negativeInfinity = -Double
positiveInfinity
nan :: Double
nan :: Double
nan = Double
0.0 Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
0.0
isPosInf :: Double -> Bool
isPosInf :: Double -> Bool
isPosInf Double
x = Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0.0 Bool -> Bool -> Bool
&& Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x
isNegInf :: Double -> Bool
isNegInf :: Double -> Bool
isNegInf Double
x = Double
x Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
< Double
0.0 Bool -> Bool -> Bool
&& Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x
isPosZero :: Double -> Bool
isPosZero :: Double -> Bool
isPosZero Double
x = Double -> Double -> Bool
doubleDenotEq Double
x Double
0.0
isNegZero :: Double -> Bool
isNegZero :: Double -> Bool
isNegZero Double
x = Double -> Double -> Bool
doubleDenotEq Double
x (-Double
0.0)
doubleRound :: Double -> Maybe Integer
doubleRound :: Double -> Maybe Integer
doubleRound = (Double -> Integer) -> Maybe Double -> Maybe Integer
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Double -> Integer
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Maybe Double -> Maybe Integer)
-> (Double -> Maybe Double) -> Double -> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Maybe Double
asFinite
doubleFloor :: Double -> Maybe Integer
doubleFloor :: Double -> Maybe Integer
doubleFloor = (Double -> Integer) -> Maybe Double -> Maybe Integer
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Double -> Integer
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor (Maybe Double -> Maybe Integer)
-> (Double -> Maybe Double) -> Double -> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Maybe Double
asFinite
doubleCeiling :: Double -> Maybe Integer
doubleCeiling :: Double -> Maybe Integer
doubleCeiling = (Double -> Integer) -> Maybe Double -> Maybe Integer
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Double -> Integer
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Maybe Double -> Maybe Integer)
-> (Double -> Maybe Double) -> Double -> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Maybe Double
asFinite
normaliseNaN :: Double -> Double
normaliseNaN :: Double -> Double
normaliseNaN Double
x
| Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x = Double
nan
| Bool
otherwise = Double
x
doubleToWord64 :: Double -> Maybe Word64
doubleToWord64 :: Double -> Maybe Word64
doubleToWord64 Double
x
| Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x = Maybe Word64
forall a. Maybe a
Nothing
| Bool
otherwise = Word64 -> Maybe Word64
forall a. a -> Maybe a
Just (Double -> Word64
castDoubleToWord64 Double
x)
doubleDenotEq :: Double -> Double -> Bool
doubleDenotEq :: Double -> Double -> Bool
doubleDenotEq = Maybe Word64 -> Maybe Word64 -> Bool
forall a. Eq a => a -> a -> Bool
(==) (Maybe Word64 -> Maybe Word64 -> Bool)
-> (Double -> Maybe Word64) -> Double -> Double -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Double -> Maybe Word64
doubleToWord64
doubleDenotOrd :: Double -> Double -> Ordering
doubleDenotOrd :: Double -> Double -> Ordering
doubleDenotOrd = Maybe Word64 -> Maybe Word64 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Maybe Word64 -> Maybe Word64 -> Ordering)
-> (Double -> Maybe Word64) -> Double -> Double -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` Double -> Maybe Word64
doubleToWord64
asFinite :: Double -> Maybe Double
asFinite :: Double -> Maybe Double
asFinite Double
x
| Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x = Maybe Double
forall a. Maybe a
Nothing
| Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x = Maybe Double
forall a. Maybe a
Nothing
| Bool
otherwise = Double -> Maybe Double
forall a. a -> Maybe a
Just Double
x
toStringWithoutDotZero :: Double -> String
toStringWithoutDotZero :: Double -> Suffix Char
toStringWithoutDotZero Double
d = Suffix Char -> Maybe (Suffix Char) -> Suffix Char
forall a. a -> Maybe a -> a
fromMaybe Suffix Char
s (Maybe (Suffix Char) -> Suffix Char)
-> Maybe (Suffix Char) -> Suffix Char
forall a b. (a -> b) -> a -> b
$ Suffix Char -> Suffix Char -> Maybe (Suffix Char)
forall a. Eq a => Suffix a -> Suffix a -> Maybe (Suffix a)
stripSuffix Suffix Char
".0" Suffix Char
s
where s :: Suffix Char
s = Double -> Suffix Char
forall a. Show a => a -> Suffix Char
show Double
d
doubleToRatio :: Double -> (Integer, Integer)
doubleToRatio :: Double -> (Integer, Integer)
doubleToRatio Double
x
| Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x = (Integer
0, Integer
0)
| Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x = (Integer -> Integer
forall a. Num a => a -> a
signum (Double -> Integer
forall b. Integral b => Double -> b
forall a b. (RealFrac a, Integral b) => a -> b
floor Double
x), Integer
0)
| Bool
otherwise = let r :: Rational
r = Double -> Rational
forall a. Real a => a -> Rational
toRational Double
x in (Rational -> Integer
forall a. Ratio a -> a
numerator Rational
r, Rational -> Integer
forall a. Ratio a -> a
denominator Rational
r)
ratioToDouble :: Integer -> Integer -> Double
ratioToDouble :: Integer -> Integer -> Double
ratioToDouble Integer
n Integer
d
| Integer
d Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0 = case Integer -> Integer -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Integer
n Integer
0 of
Ordering
LT -> Double
negativeInfinity
Ordering
EQ -> Double
nan
Ordering
GT -> Double
positiveInfinity
| Bool
otherwise = Rational -> Double
forall a. Fractional a => Rational -> a
fromRational (Integer
n Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% Integer
d)
doubleDecode :: Double -> Maybe (Integer, Integer)
doubleDecode :: Double -> Maybe (Integer, Integer)
doubleDecode Double
x
| Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x = Maybe (Integer, Integer)
forall a. Maybe a
Nothing
| Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x = Maybe (Integer, Integer)
forall a. Maybe a
Nothing
| Bool
otherwise = (Integer, Integer) -> Maybe (Integer, Integer)
forall a. a -> Maybe a
Just ((Integer -> Integer -> (Integer, Integer))
-> (Integer, Integer) -> (Integer, Integer)
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Integer -> Integer -> (Integer, Integer)
normalise ((Int -> Integer) -> (Integer, Int) -> (Integer, Integer)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Double -> (Integer, Int)
forall a. RealFloat a => a -> (Integer, Int)
decodeFloat Double
x)))
where
normalise :: Integer -> Integer -> (Integer, Integer)
normalise :: Integer -> Integer -> (Integer, Integer)
normalise Integer
mantissa Integer
exponent
| Integer -> Bool
forall a. Integral a => a -> Bool
even Integer
mantissa = Integer -> Integer -> (Integer, Integer)
normalise (Integer
mantissa Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
2) (Integer
exponent Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1)
| Bool
otherwise = (Integer
mantissa, Integer
exponent)
isSafeInteger :: Double -> Bool
isSafeInteger :: Double -> Bool
isSafeInteger Double
x = case Double -> (Integer, Double)
forall b. Integral b => Double -> (b, Double)
forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction Double
x of
(Integer
n, Double
f) -> Double
f Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
== Double
0.0 Bool -> Bool -> Bool
&& Integer
minMantissa Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
n Bool -> Bool -> Bool
&& Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
maxMantissa
doubleRadix :: Integer
doubleRadix :: Integer
doubleRadix = Double -> Integer
forall a. RealFloat a => a -> Integer
floatRadix (Double
forall a. HasCallStack => a
undefined :: Double)
doubleDigits :: Int
doubleDigits :: Int
doubleDigits = Double -> Int
forall a. RealFloat a => a -> Int
floatDigits (Double
forall a. HasCallStack => a
undefined :: Double)
doubleRange :: (Int, Int)
doubleRange :: (Int, Int)
doubleRange = Double -> (Int, Int)
forall a. RealFloat a => a -> (Int, Int)
floatRange (Double
forall a. HasCallStack => a
undefined :: Double)
minMantissa :: Integer
minMantissa :: Integer
minMantissa = - Integer
maxMantissa
maxMantissa :: Integer
maxMantissa :: Integer
maxMantissa = (Integer
doubleRadix Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
doubleDigits) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1
minExponent :: Integer
minExponent :: Integer
minExponent = Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int -> Integer) -> Int -> Integer
forall a b. (a -> b) -> a -> b
$ ((Int, Int) -> Int
forall a b. (a, b) -> a
fst (Int, Int)
doubleRange Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
doubleDigits) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
maxExponent :: Integer
maxExponent :: Integer
maxExponent = Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Int -> Integer) -> Int -> Integer
forall a b. (a -> b) -> a -> b
$ (Int, Int) -> Int
forall a b. (a, b) -> b
snd (Int, Int)
doubleRange Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
doubleDigits
doubleEncode :: Integer -> Integer -> Maybe Double
doubleEncode :: Integer -> Integer -> Maybe Double
doubleEncode Integer
mantissa Integer
exponent
= if Integer
minMantissa Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
mantissa Bool -> Bool -> Bool
&& Integer
mantissa Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
maxMantissa Bool -> Bool -> Bool
&&
Integer
minExponent Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
exponent Bool -> Bool -> Bool
&& Integer
exponent Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
maxExponent
then Double -> Maybe Double
forall a. a -> Maybe a
Just (Integer -> Int -> Double
forall a. RealFloat a => Integer -> Int -> a
encodeFloat Integer
mantissa (Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
exponent))
else Maybe Double
forall a. Maybe a
Nothing