{-# LANGUAGE CPP, ForeignFunctionInterface #-} {-# LANGUAGE FlexibleContexts #-} module Data.Float ( Float , module Data.Float , module Data.Connection.Float ) where import Prelude hiding (Floating(..), RealFloat(..), Real(..), Enum(..)) import Foreign.C import Data.Word import Data.Prd.Nan import Data.Connection.Float import Data.Int (Int32) import Data.Prd import Data.Function (on) import Data.Connection --import Data.Numbers.CrackNum (floatToFP) import Data.Bits ((.&.)) import qualified Prelude as P import qualified Data.Bits as B import qualified GHC.Float as F --disp x = floatToFP x split :: Float -> Either Float Float split x = case signBit x of True -> Left x _ -> Right x lsbMask :: Float -> Word32 lsbMask x = 0x00000001 .&. floatWord32 x msbMask :: Float -> Word32 msbMask x = 0x80000000 .&. floatWord32 x -- floatWord32 maximal == exponent maximal expMask :: Float -> Word32 expMask x = 0x7f800000 .&. floatWord32 x -- chk f = f >= 0 ==> f == word32Float $ exponent f + significand f sigMask :: Float -> Word32 sigMask x = 0x007FFFFF .&. floatWord32 x signBit :: Float -> Bool signBit x = if isNan x then False else msbMask x /= 0 evenBit :: Float -> Bool evenBit x = lsbMask x == 0 -- | maximal (positive) finite value. maxNorm :: Float maxNorm = shift (-1) pInf -- | minimal (positive) normalized value. minNorm :: Float minNorm = word32Float 0x00800000 -- | maximal representable odd integer. -- -- @ maxOdd = 2**24 - 1@ -- maxOdd :: Float maxOdd = 16777215 -- | minimal (positive) value. minSub :: Float minSub = shift 0 1 -- | difference between 1 and the smallest representable value greater than 1. epsilon :: Float epsilon = shift 1 1 - 1 -- | first /NaN/ value. aNan :: Float aNan = 0/0 -- inc pInf -- | Positive infinity -- -- @nInf = 1/0@ -- pInf :: Float pInf = word32Float 0x7f800000 -- | Negative infinity -- -- @nInf = -1/0@ -- nInf :: Float nInf = word32Float 0xff800000 -- Bitwise equality eq' :: Float -> Float -> Bool eq' = (==) `on` floatWord32 {- instance Num Float where Float x + Float y = Float $ F.plusFloat x y Float x * Float y = Float $ F.timesFloat x y Float x - Float y = Float $ F.minusFloat x y negate x = Float $ F.negateFloat x abs x = Float $ F.fabsFloat x signum x = Float $ signum x fromInteger = Float . fromInteger -- TODO dont use fromInteger f32i64 :: Conn Float Int f32i64 = Conn (liftFloat' F.float2Int) (Float . F.int2Float) λ> unit f32i64 nan Float (-9.223372e18) λ> F.float2Int (3.0252336e+35) -9223372036854775808 λ> F.float2Int (3.0252336e+25) -9223372036854775808 TODO: different Conns for embedding a Float in the lower portion of a Double, versus middle / higher -} -- | -- -- @nan x == indeterminate x@ -- isNan :: Float -> Bool isNan x = F.isFloatNaN x == 1 pinf :: Float -> Bool pinf x = infinite x && positive x ninf :: Float -> Bool ninf x = infinite x && negative x infinite :: Float -> Bool infinite x = F.isFloatInfinite x == 1 denormalized :: Float -> Bool denormalized x = F.isFloatDenormalized x == 1 finite :: Float -> Bool finite x = F.isFloatFinite x == 1 nzero :: Float -> Bool nzero x = F.isFloatNegativeZero x == 1 ---------------------------------------------------------------- -- Ulps-based comparison ---------------------------------------------------------------- {- -- | -- Calculate relative error of two numbers: -- -- \[ \frac{|a - b|}{\max(|a|,|b|)} \] -- -- It lies in [0,1) interval for numbers with same sign and (1,2] for -- numbers with different sign. If both arguments are zero or negative -- zero function returns 0. If at least one argument is transfinite it -- returns NaN relativeError :: Float -> Float -> Float relativeError a b | a == 0 && b == 0 = 0 | otherwise = abs (a - b) / fmax (abs a) (abs b) -- TODO need / -- | Check that relative error between two numbers @a@ and @b@. If -- 'relativeError' returns Nan it returns @False@. eqRelErr :: Float -- ^ /eps/ relative error should be in [0,1) range -> Float -- ^ /a/ -> Float -- ^ /b/ -> Bool eqRelErr eps a b = relativeError a b < eps -} ---------------------------------------------------------------- -- Ulps-based comparison ---------------------------------------------------------------- ulps :: Float -> Float -> (Bool, Word32) ulps x y = o where x' = floatInt32 x y' = floatInt32 y o | x' >~ y' = (False, fromIntegral . abs $ x' - y') | otherwise = (True, fromIntegral . abs $ y' - x') ulpDistance :: Float -> Float -> Word32 ulpDistance x y = snd $ ulps x y ulpDelta :: Float -> Float -> Int ulpDelta x y = if lesser then d' else (-1) * d' where (lesser, d) = ulps x y d' = fromIntegral d ulpDelta' :: Float -> Float -> Int32 ulpDelta' x y = if lesser then d' else (-1) * d' where (lesser, d) = ulps x y d' = fromIntegral d -- | Compare two 'Float' values for approximate equality, using -- Dawson's method. -- -- required accuracy is specified in ULPs (units of least -- precision). If the two numbers differ by the given number of ULPs -- or less, this function returns @True@. within :: Word32 -> Float -> Float -> Bool within tol a b = ulpDistance a b <~ tol {- foreign import ccall unsafe "fdimf" fdim :: Float -> Float -> Float foreign import ccall unsafe "fmaxf" fmax :: Float -> Float -> Float foreign import ccall unsafe "fminf" fmin :: Float -> Float -> Float -- Arithmetic functions mul :: Float -> Float -> Float mul = liftFloat2 F.timesFloat -- | 'pow' returns the value of x to the exponent y. -- pow :: Float -> Float -> Float pow = liftFloat2 F.powerFloat add :: Float -> Float -> Float add = liftFloat2 F.plusFloat sub :: Float -> Float -> Float sub = liftFloat2 F.minusFloat neg :: Float -> Float neg = liftFloat F.negateFloat div :: Float -> Float -> Float div = liftFloat2 F.divideFloat -- | 'sqrt' returns the non-negative square root of x. -- sqrt :: Float -> Float sqrt = liftFloat F.sqrtFloat -- | 'fabs' returns the absolute value of a floating-point number x. -- fabs :: Float -> Float fabs = liftFloat F.fabsFloat -- | 'fma a x b' returns /a*x + b/ foreign import ccall unsafe "fmaf" fma :: Float -> Float -> Float -> Float -- | 'cbrt' returns the cube root of x. -- foreign import ccall unsafe "cbrtf" cbrt :: Float -> Float -- Exponential and logarithmic functions -- | 'exp' returns /e/ raised to the value of the given argument /x/. -- exp :: Float -> Float exp = liftFloat F.expFloat -- | 'exp2' returns 2 raised to the value of the given argument /x/. -- foreign import ccall unsafe "exp2f" exp2 :: Float -> Float -- | 'exmp1' returns the exponential of /x-1/. -- expm1 :: Float -> Float expm1 = liftFloat F.expm1Float -- | 'log' returns the value of the natural logarithm of argument x. -- log :: Float -> Float log = liftFloat F.logFloat -- | 'log1pf' returns the log of 1+x. -- log1p :: Float -> Float log1p = liftFloat F.log1pFloat -- | 'ilogb' returns x's exponent n, in integer format. -- ilogb(+-Infinity) re- turns INT_MAX and ilogb(0) returns INT_MIN. -- foreign import ccall unsafe "ilogbf" ilogb :: Float -> CInt -- | ldexp function multiplies a floating-point number by an integral power of 2. -- ldexp is not defined in the Haskell 98 report. -- foreign import ccall unsafe "ldexpf" ldexp :: Float -> CInt -> Float -- | 'log10' returns the value of the logarithm of argument x to base 10. -- log10 is not defined in the Haskell 98 report. -- foreign import ccall unsafe "log10f" log10 :: Float -> Float -- | 'log1pf' returns the log of 1+x. -- --foreign import ccall unsafe "log1pf" log1p :: Float -> Float foreign import ccall unsafe "log2f" log2 :: Float -> Float -- | 'logb' returns x's exponent n, a signed integer converted to floating-point. -- -- > logb(+-Infinity) = +Infinity; -- > logb(0) = -Infinity with a division by zero exception. -- foreign import ccall unsafe "logbf" logb :: Float -> Float -- | scalbn(x, n) returns x*(2**n) computed by exponent manipulation. foreign import ccall unsafe "scalbnf" scalbn :: Float -> CInt -> Float -- | scalbln(x, n) returns x*(2**n) computed by exponent manipulation. foreign import ccall unsafe "scalblnf" scalbln :: Float -> CLong -> Float -- Trigonometric functions -- | 'hypot' returns the sqrt(x*x+y*y) in such a way that -- underflow will not happen, and overflow occurs only if the final result -- deserves it. -- -- > hypot(Infinity, v) = hypot(v, Infinity) = +Infinity for all v, including NaN. -- foreign import ccall unsafe "hypotf" hypot :: Float -> Float -> Float -- | 'tan' returns the tangent of x (measured in radians). -- A large magnitude argument may yield a result with little or no -- significance. -- tan :: Float -> Float tan = liftFloat F.tanFloat -- | 'sin' returns the sine of x (measured in radians). -- A large magnitude argument may yield a result with little or no -- significance. -- sin :: Float -> Float sin = liftFloat F.sinFloat -- | 'cos' returns the cosine of x (measured in radians). -- -- A large magnitude argument may yield a result with little or no significance. -- cos :: Float -> Float cos = liftFloat F.cosFloat -- | 'atan' returns the principal value of the arc tangent of x -- in the range [-pi/2, +pi/2]. -- atan :: Float -> Float atan = liftFloat F.atanFloat -- | 'atan2' returns the principal value of the arc tangent of -- y/x, using the signs of both arguments to determine the quadrant of the -- return value. -- foreign import ccall unsafe "atan2f" atan2 :: Float -> Float -> Float -- | 'asin' returns the principal value of the arc sine of x in the range [-pi/2, +pi/2]. -- asin :: Float -> Float asin = liftFloat F.asinFloat -- | 'acos' returns the principal value of the arc cosine of x in the range [0, pi] -- acos :: Float -> Float acos = liftFloat F.acosFloat -- | 'tanh' returns the hyperbolic tangent of x. -- tanh :: Float -> Float tanh = liftFloat F.tanhFloat -- | 'sinh' returns the hyperbolic sine of x. -- sinh :: Float -> Float sinh = liftFloat F.sinhFloat -- | 'cosh' returns the hyperbolic cosine of x. -- cosh :: Float -> Float cosh = liftFloat F.coshFloat -- | 'atanh' returns the inverse hyperbolic tangent of x. -- atanh :: Float -> Float atanh = liftFloat F.atanh -- | 'asinh' returns the inverse hyperbolic sine of x. -- asinh :: Float -> Float asinh = liftFloat F.asinh -- | 'acosh' returns the inverse hyperbolic cosine of x. -- acosh :: Float -> Float acosh = liftFloat F.acosh liftFloat :: (F.Float -> F.Float) -> Float -> Float liftFloat f x = Float $ f x liftFloat' :: (F.Float -> a) -> Float -> a liftFloat' f x = f x liftFloat2 :: (F.Float -> F.Float -> F.Float) -> Float -> Float -> Float liftFloat2 f x (Float y) = Float $ f x y liftFloat2' :: (F.Float -> F.Float -> a) -> Float -> Float -> a liftFloat2' f x (Float y) = f x y -}