altfloat-0.2: Data/Floating/Types.hs
{-
- Copyright (C) 2009 Nick Bowler.
-
- License BSD2: 2-clause BSD license. See LICENSE for full terms.
- This is free software: you are free to change and redistribute it.
- There is NO WARRANTY, to the extent permitted by law.
-}
-- | Definition of the core floating point types and basic manipulation of
-- them.
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverlappingInstances #-}
{-# LANGUAGE MagicHash #-}
module Data.Floating.Types (
Double(..), Float(..), FloatConvert(..)
) where
import Prelude hiding (Double, Float)
import qualified GHC.Exts as GHC
import GHC.Integer
import GHC.Prim
import Foreign.C
import Data.Ratio
import Unsafe.Coerce
-- | The Double type. This is expected to be an identical declaration to
-- the one found in GHC.Prim. We avoid simply using GHC's type because we need
-- to define our own class instances.
data Double = D# Double#
-- | The Float type.
data Float = F# Float#
-- | This type is identical to CDouble. For some reason unknown to me, it is
-- impossible to marshal data from Double to CDouble without losing
-- information. The issue is further complicated by Foreign.C.Types not
-- exporting CDouble's constructor. Thus, to marshal data from Double to
-- CDouble, we construct an instance of this type and then use unsafeCoerce.
newtype FuckFFIDouble = FuckD Double
-- | The analogue of FuckFFIDouble for CFloat.
newtype FuckFFIFloat = FuckF Float
-- | Coercion to floating point types.
class FloatConvert a b where
-- | Convert to a floating point type. Conversions from integers and real
-- types are provided, as well as conversions between floating point types.
-- Conversions between floating point types preserve infinities, negative
-- zeros and NaNs.
toFloating :: a -> b
instance FloatConvert Double CDouble where
toFloating = unsafeCoerce . FuckD
instance FloatConvert CDouble Double where
toFloating f = let FuckD x = unsafeCoerce f in x
instance FloatConvert Float CFloat where
toFloating = unsafeCoerce . FuckF
instance FloatConvert CFloat Float where
toFloating f = let FuckF x = unsafeCoerce f in x
instance FloatConvert Double Float where
toFloating (D# x) = F# (double2Float# x)
instance FloatConvert Float Double where
toFloating (F# x) = D# (float2Double# x)
instance FloatConvert Integer Double where
toFloating x = D# (doubleFromInteger x)
instance FloatConvert Integer Float where
toFloating x = F# (floatFromInteger x)
instance Real a => FloatConvert a Double where
toFloating x = D# (num /## denom) where
D# num = toFloating . numerator . toRational $ x
D# denom = toFloating . denominator . toRational $ x
instance Real a => FloatConvert a Float where
toFloating x = F# (divideFloat# num denom) where
F# num = toFloating . numerator . toRational $ x
F# denom = toFloating . denominator . toRational $ x
instance FloatConvert a a where
toFloating = id