{- - Copyright (C) 2009-2010 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