{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Numeric.Rounded.Hardware.Backend.C
( CFloat(..)
, CDouble(..)
, VUM.MVector(..)
, VU.Vector(..)
) where
import Control.DeepSeq (NFData (..))
import Data.Bifunctor
import Data.Coerce
import Data.Int (Int64)
import Data.Primitive (Prim)
import Data.Primitive.ByteArray
import Data.Ratio
import Data.Tagged
import qualified Data.Vector.Generic as VG
import qualified Data.Vector.Generic.Mutable as VGM
import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Primitive.Mutable as VPM
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Storable.Mutable as VSM
import qualified Data.Vector.Unboxed.Base as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import Data.Word (Word64)
import qualified FFIWrapper.Double as D
import qualified FFIWrapper.Float as F
import Foreign.C.String (CString, peekCString)
import Foreign.Ptr (Ptr, castPtr)
import Foreign.Storable (Storable)
import GHC.Generics (Generic)
import GHC.Exts (RealWorld)
import Numeric.Rounded.Hardware.Internal.Class
import Numeric.Rounded.Hardware.Internal.Conversion
import System.IO.Unsafe (unsafePerformIO)
newtype CFloat = CFloat Float
deriving (Eq,Ord,Show,Generic,Num,Storable)
instance NFData CFloat
roundedFloatFromInt64 :: RoundingMode -> Int64 -> Float
roundedFloatFromInt64 r x = staticIf
(-0x1000000 <= x && x <= 0x1000000 )
(fromIntegral x)
(F.roundedFromInt64 r x)
{-# INLINE roundedFloatFromInt64 #-}
roundedFloatFromWord64 :: RoundingMode -> Word64 -> Float
roundedFloatFromWord64 r x = staticIf
(x <= 0x1000000 )
(fromIntegral x)
(F.roundedFromWord64 r x)
{-# INLINE roundedFloatFromWord64 #-}
roundedFloatFromInteger :: RoundingMode -> Integer -> Float
roundedFloatFromInteger r x
| -0x1000000 <= x && x <= 0x1000000 = fromInteger x
| otherwise = fromInt r x
{-# NOINLINE [1] roundedFloatFromInteger #-}
{-# RULES
"roundeFloatFromInteger/Int" forall r (x :: Int).
roundedFloatFromInteger r (fromIntegral x) = roundedFloatFromInt64 r (fromIntegral x)
"roundeFloatFromInteger/Int64" forall r (x :: Int64).
roundedFloatFromInteger r (fromIntegral x) = roundedFloatFromInt64 r x
"roundeFloatFromInteger/Word" forall r (x :: Word).
roundedFloatFromInteger r (fromIntegral x) = roundedFloatFromWord64 r (fromIntegral x)
"roundeFloatFromInteger/Word64" forall r (x :: Word64).
roundedFloatFromInteger r (fromIntegral x) = roundedFloatFromWord64 r x
#-}
intervalFloatFromInteger :: Integer -> (Rounded 'TowardNegInf Float, Rounded 'TowardInf Float)
intervalFloatFromInteger x
| -0x1000000 <= x && x <= 0x1000000 = (Rounded (fromInteger x), Rounded (fromInteger x))
| otherwise = intervalFromInteger_default x
roundedFloatFromRealFloat :: RealFloat a => RoundingMode -> a -> Float
roundedFloatFromRealFloat r x | isNaN x = 0/0
| isInfinite x = if x > 0 then 1/0 else -1/0
| isNegativeZero x = -0
| otherwise = coerce (roundedFromRational r (toRational x) :: CFloat)
{-# NOINLINE [1] roundedFloatFromRealFloat #-}
{-# RULES
"roundedFloatFromRealFloat/Float" forall r (x :: Float).
roundedFloatFromRealFloat r x = x
#-}
instance RoundedRing CFloat where
roundedAdd = coerce F.roundedAdd
roundedSub = coerce F.roundedSub
roundedMul = coerce F.roundedMul
roundedFusedMultiplyAdd = coerce F.roundedFMA
intervalMul x x' y y' = (coerce F.intervalMul_down x x' y y', coerce F.intervalMul_up x x' y y')
intervalMulAdd x x' y y' z z' = (coerce F.intervalMulAdd_down x x' y y' z, coerce F.intervalMulAdd_up x x' y y' z')
roundedFromInteger r x = CFloat (roundedFloatFromInteger r x)
intervalFromInteger = coerce intervalFloatFromInteger
backendNameT = Tagged cBackendName
{-# INLINE roundedAdd #-}
{-# INLINE roundedSub #-}
{-# INLINE roundedMul #-}
{-# INLINE roundedFusedMultiplyAdd #-}
{-# INLINE intervalMul #-}
{-# INLINE roundedFromInteger #-}
{-# INLINE intervalFromInteger #-}
instance RoundedFractional CFloat where
roundedDiv = coerce F.roundedDiv
intervalDiv x x' y y' = (coerce F.intervalDiv_down x x' y y', coerce F.intervalDiv_up x x' y y')
intervalDivAdd x x' y y' z z' = (coerce F.intervalDivAdd_down x x' y y' z, coerce F.intervalDivAdd_up x x' y y' z')
roundedFromRational r x = CFloat $ fromRatio r (numerator x) (denominator x)
intervalFromRational = (coerce `asTypeOf` (bimap (CFloat <$>) (CFloat <$>) .)) intervalFromRational_default
roundedFromRealFloat r x = coerce (roundedFloatFromRealFloat r x)
{-# INLINE roundedDiv #-}
{-# INLINE intervalDiv #-}
{-# INLINE roundedFromRational #-}
{-# INLINE intervalFromRational #-}
{-# INLINE roundedFromRealFloat #-}
instance RoundedSqrt CFloat where
roundedSqrt = coerce F.roundedSqrt
{-# INLINE roundedSqrt #-}
instance RoundedRing_Vector VS.Vector CFloat where
roundedSum mode vec = CFloat $ unsafePerformIO $
VS.unsafeWith vec $ \ptr -> F.vectorSumPtr mode (VS.length vec) 0 (castPtr ptr)
zipWith_roundedAdd = zipWith_Storable (coerce F.vectorAddPtr)
zipWith_roundedSub = zipWith_Storable (coerce F.vectorSubPtr)
zipWith_roundedMul = zipWith_Storable (coerce F.vectorMulPtr)
zipWith3_roundedFusedMultiplyAdd = zipWith3_Storable (coerce F.vectorFMAPtr)
instance RoundedFractional_Vector VS.Vector CFloat where
zipWith_roundedDiv = zipWith_Storable (coerce F.vectorDivPtr)
instance RoundedSqrt_Vector VS.Vector CFloat where
map_roundedSqrt = map_Storable (coerce F.vectorSqrtPtr)
instance RoundedRing_Vector VU.Vector CFloat where
roundedSum mode (V_CFloat (VU.V_Float (VP.Vector off len (ByteArray arr)))) =
CFloat $ F.vectorSumByteArray mode len off arr
zipWith_roundedAdd = coerce (zipWith_Primitive F.vectorAddByteArray :: RoundingMode -> VP.Vector Float -> VP.Vector Float -> VP.Vector Float)
zipWith_roundedSub = coerce (zipWith_Primitive F.vectorSubByteArray :: RoundingMode -> VP.Vector Float -> VP.Vector Float -> VP.Vector Float)
zipWith_roundedMul = coerce (zipWith_Primitive F.vectorMulByteArray :: RoundingMode -> VP.Vector Float -> VP.Vector Float -> VP.Vector Float)
zipWith3_roundedFusedMultiplyAdd = coerce (zipWith3_Primitive F.vectorFMAByteArray :: RoundingMode -> VP.Vector Float -> VP.Vector Float -> VP.Vector Float -> VP.Vector Float)
instance RoundedFractional_Vector VU.Vector CFloat where
zipWith_roundedDiv = coerce (zipWith_Primitive F.vectorDivByteArray :: RoundingMode -> VP.Vector Float -> VP.Vector Float -> VP.Vector Float)
instance RoundedSqrt_Vector VU.Vector CFloat where
map_roundedSqrt = coerce (map_Primitive F.vectorSqrtByteArray :: RoundingMode -> VP.Vector Float -> VP.Vector Float)
newtype CDouble = CDouble Double
deriving (Eq,Ord,Show,Generic,Num,Storable)
instance NFData CDouble
roundedDoubleFromInt64 :: RoundingMode -> Int64 -> Double
roundedDoubleFromInt64 r x = staticIf
(-0x20000000000000 <= x && x <= 0x20000000000000 )
(fromIntegral x)
(D.roundedFromInt64 r x)
{-# INLINE roundedDoubleFromInt64 #-}
roundedDoubleFromWord64 :: RoundingMode -> Word64 -> Double
roundedDoubleFromWord64 r x = staticIf
(x <= 0x20000000000000 )
(fromIntegral x)
(D.roundedFromWord64 r x)
{-# INLINE roundedDoubleFromWord64 #-}
roundedDoubleFromInteger :: RoundingMode -> Integer -> Double
roundedDoubleFromInteger r x
| -0x20000000000000 <= x && x <= 0x20000000000000 = fromInteger x
| otherwise = fromInt r x
{-# NOINLINE [1] roundedDoubleFromInteger #-}
{-# RULES
"roundedDoubleFromInteger/Int" forall r (x :: Int).
roundedDoubleFromInteger r (fromIntegral x) = roundedDoubleFromInt64 r (fromIntegral x)
"roundedDoubleFromInteger/Int64" forall r (x :: Int64).
roundedDoubleFromInteger r (fromIntegral x) = roundedDoubleFromInt64 r x
"roundedDoubleFromInteger/Word" forall r (x :: Word).
roundedDoubleFromInteger r (fromIntegral x) = roundedDoubleFromWord64 r (fromIntegral x)
"roundedDoubleFromInteger/Word64" forall r (x :: Word64).
roundedDoubleFromInteger r (fromIntegral x) = roundedDoubleFromWord64 r x
#-}
intervalDoubleFromInteger :: Integer -> (Rounded 'TowardNegInf Double, Rounded 'TowardInf Double)
intervalDoubleFromInteger x
| -0x20000000000000 <= x && x <= 0x20000000000000 = (Rounded (fromInteger x), Rounded (fromInteger x))
| otherwise = intervalFromInteger_default x
roundedDoubleFromRealFloat :: RealFloat a => RoundingMode -> a -> Double
roundedDoubleFromRealFloat r x | isNaN x = 0/0
| isInfinite x = if x > 0 then 1/0 else -1/0
| isNegativeZero x = -0
| otherwise = coerce (roundedFromRational r (toRational x) :: CDouble)
{-# NOINLINE [1] roundedDoubleFromRealFloat #-}
{-# RULES
"roundedDoubleFromRealFloat/Double" forall r (x :: Double).
roundedDoubleFromRealFloat r x = x
"roundedDoubleFromRealFloat/Float" forall r (x :: Float).
roundedDoubleFromRealFloat r x = realToFrac x -- should be rewritten into float2Double
#-}
instance RoundedRing CDouble where
roundedAdd = coerce D.roundedAdd
roundedSub = coerce D.roundedSub
roundedMul = coerce D.roundedMul
roundedFusedMultiplyAdd = coerce D.roundedFMA
intervalMul x x' y y' = (coerce D.intervalMul_down x x' y y', coerce D.intervalMul_up x x' y y')
intervalMulAdd x x' y y' z z' = (coerce D.intervalMulAdd_down x x' y y' z, coerce D.intervalMulAdd_up x x' y y' z')
roundedFromInteger = coerce roundedDoubleFromInteger
intervalFromInteger = coerce intervalDoubleFromInteger
backendNameT = Tagged cBackendName
{-# INLINE roundedAdd #-}
{-# INLINE roundedSub #-}
{-# INLINE roundedMul #-}
{-# INLINE roundedFusedMultiplyAdd #-}
{-# INLINE intervalMul #-}
{-# INLINE roundedFromInteger #-}
{-# INLINE intervalFromInteger #-}
instance RoundedFractional CDouble where
roundedDiv = coerce D.roundedDiv
intervalDiv x x' y y' = (coerce D.intervalDiv_down x x' y y', coerce D.intervalDiv_up x x' y y')
intervalDivAdd x x' y y' z z' = (coerce D.intervalDivAdd_down x x' y y' z, coerce D.intervalDivAdd_up x x' y y' z')
roundedFromRational r x = CDouble $ fromRatio r (numerator x) (denominator x)
intervalFromRational = (coerce `asTypeOf` (bimap (CDouble <$>) (CDouble <$>) .)) intervalFromRational_default
roundedFromRealFloat r x = coerce (roundedDoubleFromRealFloat r x)
{-# INLINE roundedDiv #-}
{-# INLINE intervalDiv #-}
{-# INLINE roundedFromRational #-}
{-# INLINE intervalFromRational #-}
{-# INLINE roundedFromRealFloat #-}
instance RoundedSqrt CDouble where
roundedSqrt = coerce D.roundedSqrt
{-# INLINE roundedSqrt #-}
instance RoundedRing_Vector VS.Vector CDouble where
roundedSum mode vec = CDouble $ unsafePerformIO $
VS.unsafeWith vec $ \ptr -> D.vectorSumPtr mode (VS.length vec) 0 (castPtr ptr)
zipWith_roundedAdd = zipWith_Storable (coerce D.vectorAddPtr)
zipWith_roundedSub = zipWith_Storable (coerce D.vectorSubPtr)
zipWith_roundedMul = zipWith_Storable (coerce D.vectorMulPtr)
zipWith3_roundedFusedMultiplyAdd = zipWith3_Storable (coerce D.vectorFMAPtr)
instance RoundedFractional_Vector VS.Vector CDouble where
zipWith_roundedDiv = zipWith_Storable (coerce D.vectorDivPtr)
instance RoundedSqrt_Vector VS.Vector CDouble where
map_roundedSqrt = map_Storable (coerce D.vectorSqrtPtr)
instance RoundedRing_Vector VU.Vector CDouble where
roundedSum mode (V_CDouble (VU.V_Double (VP.Vector off len (ByteArray arr)))) =
CDouble $ D.vectorSumByteArray mode len off arr
zipWith_roundedAdd = coerce (zipWith_Primitive D.vectorAddByteArray :: RoundingMode -> VP.Vector Double -> VP.Vector Double -> VP.Vector Double)
zipWith_roundedSub = coerce (zipWith_Primitive D.vectorSubByteArray :: RoundingMode -> VP.Vector Double -> VP.Vector Double -> VP.Vector Double)
zipWith_roundedMul = coerce (zipWith_Primitive D.vectorMulByteArray :: RoundingMode -> VP.Vector Double -> VP.Vector Double -> VP.Vector Double)
zipWith3_roundedFusedMultiplyAdd = coerce (zipWith3_Primitive D.vectorFMAByteArray :: RoundingMode -> VP.Vector Double -> VP.Vector Double -> VP.Vector Double -> VP.Vector Double)
instance RoundedFractional_Vector VU.Vector CDouble where
zipWith_roundedDiv = coerce (zipWith_Primitive D.vectorDivByteArray :: RoundingMode -> VP.Vector Double -> VP.Vector Double -> VP.Vector Double)
instance RoundedSqrt_Vector VU.Vector CDouble where
map_roundedSqrt = coerce (map_Primitive D.vectorSqrtByteArray :: RoundingMode -> VP.Vector Double -> VP.Vector Double)
foreign import ccall unsafe "rounded_hw_backend_name"
c_backend_name :: CString
cBackendName :: String
cBackendName = unsafePerformIO (peekCString c_backend_name)
staticIf :: Bool -> a -> a -> a
staticIf _ _ x = x
{-# INLINE [0] staticIf #-}
{-# RULES
"staticIf/True" forall x y. staticIf True x y = x
"staticIf/False" forall x y. staticIf False x y = y
#-}
map_Storable :: (Storable a, Storable b) => (RoundingMode -> Int -> Int -> Ptr b -> Int -> Ptr a -> IO ()) -> RoundingMode -> VS.Vector a -> VS.Vector b
map_Storable f mode vec = unsafePerformIO $ do
let !len = VS.length vec
result <- VSM.new len
VS.unsafeWith vec $ \ptr ->
VSM.unsafeWith result $ \resultPtr ->
f mode len 0 resultPtr 0 ptr
VS.unsafeFreeze result
{-# INLINE map_Storable #-}
zipWith_Storable :: (Storable a, Storable b, Storable c) => (RoundingMode -> Int -> Int -> Ptr c -> Int -> Ptr a -> Int -> Ptr b -> IO ()) -> RoundingMode -> VS.Vector a -> VS.Vector b -> VS.Vector c
zipWith_Storable f mode vec vec' = unsafePerformIO $ do
let !len = min (VS.length vec) (VS.length vec')
result <- VSM.new len
VS.unsafeWith vec $ \ptr ->
VS.unsafeWith vec' $ \ptr' ->
VSM.unsafeWith result $ \resultPtr ->
f mode len 0 resultPtr 0 ptr 0 ptr'
VS.unsafeFreeze result
{-# INLINE zipWith_Storable #-}
zipWith3_Storable :: (Storable a, Storable b, Storable c, Storable d) => (RoundingMode -> Int -> Int -> Ptr d -> Int -> Ptr a -> Int -> Ptr b -> Int -> Ptr c -> IO ()) -> RoundingMode -> VS.Vector a -> VS.Vector b -> VS.Vector c -> VS.Vector d
zipWith3_Storable f mode vec1 vec2 vec3 = unsafePerformIO $ do
let !len = min (VS.length vec1) (min (VS.length vec2) (VS.length vec3))
result <- VSM.new len
VS.unsafeWith vec1 $ \ptr1 ->
VS.unsafeWith vec2 $ \ptr2 ->
VS.unsafeWith vec3 $ \ptr3 ->
VSM.unsafeWith result $ \resultPtr ->
f mode len 0 resultPtr 0 ptr1 0 ptr2 0 ptr3
VS.unsafeFreeze result
{-# INLINE zipWith3_Storable #-}
map_Primitive :: (Prim a, Prim b) => (RoundingMode -> Int -> Int -> MutableByteArray# RealWorld -> Int -> ByteArray# -> IO ()) -> RoundingMode -> VP.Vector a -> VP.Vector b
map_Primitive f mode (VP.Vector offA lenA (ByteArray arrA)) = unsafePerformIO $ do
result@(VPM.MVector offR lenR (MutableByteArray arrR)) <- VPM.unsafeNew lenA
f mode lenR offR arrR offA arrA
VP.unsafeFreeze result
{-# INLINE map_Primitive #-}
zipWith_Primitive :: (Prim a, Prim b, Prim c) => (RoundingMode -> Int -> Int -> MutableByteArray# RealWorld -> Int -> ByteArray# -> Int -> ByteArray# -> IO ()) -> RoundingMode -> VP.Vector a -> VP.Vector b -> VP.Vector c
zipWith_Primitive f mode (VP.Vector offA lenA (ByteArray arrA)) (VP.Vector offB lenB (ByteArray arrB)) = unsafePerformIO $ do
result@(VPM.MVector offR lenR (MutableByteArray arrR)) <- VPM.unsafeNew (min lenA lenB)
f mode lenR offR arrR offA arrA offB arrB
VP.unsafeFreeze result
{-# INLINE zipWith_Primitive #-}
zipWith3_Primitive :: (Prim a, Prim b, Prim c, Prim d) => (RoundingMode -> Int -> Int -> MutableByteArray# RealWorld -> Int -> ByteArray# -> Int -> ByteArray# -> Int -> ByteArray# -> IO ()) -> RoundingMode -> VP.Vector a -> VP.Vector b -> VP.Vector c -> VP.Vector d
zipWith3_Primitive f mode (VP.Vector offA lenA (ByteArray arrA)) (VP.Vector offB lenB (ByteArray arrB)) (VP.Vector offC lenC (ByteArray arrC))= unsafePerformIO $ do
result@(VPM.MVector offR lenR (MutableByteArray arrR)) <- VPM.unsafeNew (min lenA (min lenB lenC))
f mode lenR offR arrR offA arrA offB arrB offC arrC
VP.unsafeFreeze result
{-# INLINE zipWith3_Primitive #-}
newtype instance VUM.MVector s CFloat = MV_CFloat (VUM.MVector s Float)
newtype instance VU.Vector CFloat = V_CFloat (VU.Vector Float)
instance VGM.MVector VUM.MVector CFloat where
basicLength (MV_CFloat mv) = VGM.basicLength mv
basicUnsafeSlice i l (MV_CFloat mv) = MV_CFloat (VGM.basicUnsafeSlice i l mv)
basicOverlaps (MV_CFloat mv) (MV_CFloat mv') = VGM.basicOverlaps mv mv'
basicUnsafeNew l = MV_CFloat <$> VGM.basicUnsafeNew l
basicInitialize (MV_CFloat mv) = VGM.basicInitialize mv
basicUnsafeReplicate i x = MV_CFloat <$> VGM.basicUnsafeReplicate i (coerce x)
basicUnsafeRead (MV_CFloat mv) i = coerce <$> VGM.basicUnsafeRead mv i
basicUnsafeWrite (MV_CFloat mv) i x = VGM.basicUnsafeWrite mv i (coerce x)
basicClear (MV_CFloat mv) = VGM.basicClear mv
basicSet (MV_CFloat mv) x = VGM.basicSet mv (coerce x)
basicUnsafeCopy (MV_CFloat mv) (MV_CFloat mv') = VGM.basicUnsafeCopy mv mv'
basicUnsafeMove (MV_CFloat mv) (MV_CFloat mv') = VGM.basicUnsafeMove mv mv'
basicUnsafeGrow (MV_CFloat mv) n = MV_CFloat <$> VGM.basicUnsafeGrow mv n
instance VG.Vector VU.Vector CFloat where
basicUnsafeFreeze (MV_CFloat mv) = V_CFloat <$> VG.basicUnsafeFreeze mv
basicUnsafeThaw (V_CFloat v) = MV_CFloat <$> VG.basicUnsafeThaw v
basicLength (V_CFloat v) = VG.basicLength v
basicUnsafeSlice i l (V_CFloat v) = V_CFloat (VG.basicUnsafeSlice i l v)
basicUnsafeIndexM (V_CFloat v) i = coerce <$> VG.basicUnsafeIndexM v i
basicUnsafeCopy (MV_CFloat mv) (V_CFloat v) = VG.basicUnsafeCopy mv v
elemseq (V_CFloat v) x y = VG.elemseq v (coerce x) y
instance VU.Unbox CFloat
newtype instance VUM.MVector s CDouble = MV_CDouble (VUM.MVector s Double)
newtype instance VU.Vector CDouble = V_CDouble (VU.Vector Double)
instance VGM.MVector VUM.MVector CDouble where
basicLength (MV_CDouble mv) = VGM.basicLength mv
basicUnsafeSlice i l (MV_CDouble mv) = MV_CDouble (VGM.basicUnsafeSlice i l mv)
basicOverlaps (MV_CDouble mv) (MV_CDouble mv') = VGM.basicOverlaps mv mv'
basicUnsafeNew l = MV_CDouble <$> VGM.basicUnsafeNew l
basicInitialize (MV_CDouble mv) = VGM.basicInitialize mv
basicUnsafeReplicate i x = MV_CDouble <$> VGM.basicUnsafeReplicate i (coerce x)
basicUnsafeRead (MV_CDouble mv) i = coerce <$> VGM.basicUnsafeRead mv i
basicUnsafeWrite (MV_CDouble mv) i x = VGM.basicUnsafeWrite mv i (coerce x)
basicClear (MV_CDouble mv) = VGM.basicClear mv
basicSet (MV_CDouble mv) x = VGM.basicSet mv (coerce x)
basicUnsafeCopy (MV_CDouble mv) (MV_CDouble mv') = VGM.basicUnsafeCopy mv mv'
basicUnsafeMove (MV_CDouble mv) (MV_CDouble mv') = VGM.basicUnsafeMove mv mv'
basicUnsafeGrow (MV_CDouble mv) n = MV_CDouble <$> VGM.basicUnsafeGrow mv n
instance VG.Vector VU.Vector CDouble where
basicUnsafeFreeze (MV_CDouble mv) = V_CDouble <$> VG.basicUnsafeFreeze mv
basicUnsafeThaw (V_CDouble v) = MV_CDouble <$> VG.basicUnsafeThaw v
basicLength (V_CDouble v) = VG.basicLength v
basicUnsafeSlice i l (V_CDouble v) = V_CDouble (VG.basicUnsafeSlice i l v)
basicUnsafeIndexM (V_CDouble v) i = coerce <$> VG.basicUnsafeIndexM v i
basicUnsafeCopy (MV_CDouble mv) (V_CDouble v) = VG.basicUnsafeCopy mv v
elemseq (V_CDouble v) x y = VG.elemseq v (coerce x) y
instance VU.Unbox CDouble