From 9e5945120bbcfeff15ee7356398e06ab5ba25561 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Mon, 27 May 2024 14:10:57 +0200 Subject: Fast (C) Floating ops --- bench/Main.hs | 27 ++++++- cbits/arith.c | 130 +++++++++++++++++++++++++++++--- cbits/arith_lists.h | 21 ++++++ ox-arrays.cabal | 2 + src/Data/Array/Nested/Internal.hs | 56 +++++++------- src/Data/Array/Nested/Internal/Arith.hs | 63 ++++++++++++++++ 6 files changed, 259 insertions(+), 40 deletions(-) diff --git a/bench/Main.hs b/bench/Main.hs index 8f3b670..41eb3b3 100644 --- a/bench/Main.hs +++ b/bench/Main.hs @@ -6,7 +6,7 @@ import qualified Numeric.LinearAlgebra as LA import Test.Tasty.Bench import Data.Array.Nested -import Data.Array.Nested.Internal (mliftPrim2, arithPromoteRanked2) +import Data.Array.Nested.Internal (mliftPrim, mliftPrim2, arithPromoteRanked, arithPromoteRanked2) main :: IO () @@ -24,6 +24,14 @@ main = defaultMain let n = 1_000_000 in nf (\(a, b) -> runScalar (rsumOuter1 (arithPromoteRanked2 (mliftPrim2 (/)) a b))) (riota @Double n, riota n) + ,bench "sum(**) Double [1e6]" $ + let n = 1_000_000 + in nf (\(a, b) -> runScalar (rsumOuter1 (arithPromoteRanked2 (mliftPrim2 (**)) a b))) + (riota @Double n, riota n) + ,bench "sum(sin) Double [1e6]" $ + let n = 1_000_000 + in nf (\a -> runScalar (rsumOuter1 (arithPromoteRanked (mliftPrim sin) a))) + (riota @Double n) ,bench "sum Double [1e6]" $ let n = 1_000_000 in nf (\a -> runScalar (rsumOuter1 a)) @@ -42,6 +50,14 @@ main = defaultMain let n = 1_000_000 in nf (\(a, b) -> runScalar (rsumOuter1 (a / b))) (riota @Double n, riota n) + ,bench "sum(**) Double [1e6]" $ + let n = 1_000_000 + in nf (\(a, b) -> runScalar (rsumOuter1 (a ** b))) + (riota @Double n, riota n) + ,bench "sum(sin) Double [1e6]" $ + let n = 1_000_000 + in nf (\a -> runScalar (rsumOuter1 (sin a))) + (riota @Double n) ,bench "sum Double [1e6]" $ let n = 1_000_000 in nf (\a -> runScalar (rsumOuter1 a)) @@ -63,6 +79,15 @@ main = defaultMain in nf (\(a, b) -> LA.sumElements (a / b)) (LA.linspace @Double n (0.0, fromIntegral (n - 1)) ,LA.linspace @Double n (0.0, fromIntegral (n - 1))) + ,bench "sum(**) Double [1e6]" $ + let n = 1_000_000 + in nf (\(a, b) -> LA.sumElements (a ** b)) + (LA.linspace @Double n (0.0, fromIntegral (n - 1)) + ,LA.linspace @Double n (0.0, fromIntegral (n - 1))) + ,bench "sum(sin) Double [1e6]" $ + let n = 1_000_000 + in nf (\a -> LA.sumElements (sin a)) + (LA.linspace @Double n (0.0, fromIntegral (n - 1))) ,bench "sum Double [1e6]" $ let n = 1_000_000 in nf (\a -> LA.sumElements a) diff --git a/cbits/arith.c b/cbits/arith.c index a71c1b9..e20578b 100644 --- a/cbits/arith.c +++ b/cbits/arith.c @@ -18,6 +18,66 @@ typedef int32_t i32; typedef int64_t i64; +/***************************************************************************** + * Additional math functions * + *****************************************************************************/ + +#define GEN_ABS(x) \ + _Generic((x), \ + int: abs, \ + long: labs, \ + long long: llabs, \ + float: fabsf, \ + double: fabs)(x) + +// This does not result in multiple loads with GCC 13. +#define GEN_SIGNUM(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0) + +#define GEN_POW(x, y) _Generic((x), float: powf, double: pow)(x, y) +#define GEN_LOGBASE(x, y) _Generic((x), float: logf(y) / logf(x), double: log(y) / log(x)) +#define GEN_EXP(x) _Generic((x), float: expf, double: exp)(x) +#define GEN_LOG(x) _Generic((x), float: logf, double: log)(x) +#define GEN_SQRT(x) _Generic((x), float: sqrtf, double: sqrt)(x) +#define GEN_SIN(x) _Generic((x), float: sinf, double: sin)(x) +#define GEN_COS(x) _Generic((x), float: cosf, double: cos)(x) +#define GEN_TAN(x) _Generic((x), float: tanf, double: tan)(x) +#define GEN_ASIN(x) _Generic((x), float: asinf, double: asin)(x) +#define GEN_ACOS(x) _Generic((x), float: acosf, double: acos)(x) +#define GEN_ATAN(x) _Generic((x), float: atanf, double: atan)(x) +#define GEN_SINH(x) _Generic((x), float: sinhf, double: sinh)(x) +#define GEN_COSH(x) _Generic((x), float: coshf, double: cosh)(x) +#define GEN_TANH(x) _Generic((x), float: tanhf, double: tanh)(x) +#define GEN_ASINH(x) _Generic((x), float: asinhf, double: asinh)(x) +#define GEN_ACOSH(x) _Generic((x), float: acoshf, double: acosh)(x) +#define GEN_ATANH(x) _Generic((x), float: atanhf, double: atanh)(x) +#define GEN_LOG1P(x) _Generic((x), float: log1pf, double: log1p)(x) +#define GEN_EXPM1(x) _Generic((x), float: expm1f, double: expm1)(x) + +// Taken from Haskell's implementation: +// https://hackage.haskell.org/package/ghc-internal-9.1001.0/docs/src//GHC.Internal.Float.html#log1mexpOrd +#define LOG1MEXP_IMPL(x) do { \ + if (x > _Generic((x), float: logf, double: log)(2)) return GEN_LOG(-GEN_EXPM1(x)); \ + else return GEN_LOG1P(-GEN_EXP(x)); \ + } while (0) + +static float log1mexp_float(float x) { LOG1MEXP_IMPL(x); } +static double log1mexp_double(double x) { LOG1MEXP_IMPL(x); } + +#define GEN_LOG1MEXP(x) _Generic((x), float: log1mexp_float, double: log1mexp_double)(x) + +// Taken from Haskell's implementation: +// https://hackage.haskell.org/package/ghc-internal-9.1001.0/docs/src//GHC.Internal.Float.html#line-595 +#define LOG1PEXP_IMPL(x) do { \ + if (x <= 18) return GEN_LOG1P(GEN_EXP(x)); \ + if (x <= 100) return x + GEN_EXP(-x); \ + return x; \ + } while (0) + +static float log1pexp_float(float x) { LOG1PEXP_IMPL(x); } +static double log1pexp_double(double x) { LOG1PEXP_IMPL(x); } + +#define GEN_LOG1PEXP(x) _Generic((x), float: log1pexp_float, double: log1pexp_double)(x) + /***************************************************************************** * Kernel functions * @@ -37,22 +97,22 @@ typedef int64_t i64; for (i64 i = 0; i < n; i++) out[i] = x[i] op y; \ } +#define PREFIX_BINOP(name, op, typ) \ + static void oxarop_op_ ## name ## _ ## typ ## _sv(i64 n, typ *out, typ x, const typ *y) { \ + for (i64 i = 0; i < n; i++) out[i] = op(x, y[i]); \ + } \ + static void oxarop_op_ ## name ## _ ## typ ## _vv(i64 n, typ *out, const typ *x, const typ *y) { \ + for (i64 i = 0; i < n; i++) out[i] = op(x[i], y[i]); \ + } \ + static void oxarop_op_ ## name ## _ ## typ ## _vs(i64 n, typ *out, const typ *x, typ y) { \ + for (i64 i = 0; i < n; i++) out[i] = op(x[i], y); \ + } + #define UNARY_OP(name, op, typ) \ static void oxarop_op_ ## name ## _ ## typ(i64 n, typ *out, const typ *x) { \ for (i64 i = 0; i < n; i++) out[i] = op(x[i]); \ } -#define GEN_ABS(x) \ - _Generic((x), \ - int: abs, \ - long: labs, \ - long long: llabs, \ - float: fabsf, \ - double: fabs)(x) - -// This does not result in multiple loads with GCC 13. -#define GEN_SIGNUM(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0) - // Walk a orthotope-style strided array, except for the inner dimension. The // body is run for every "inner vector". #define TARRAY_WALK_NOINNER(again_label_name, rank, shape, strides, body) \ @@ -161,18 +221,24 @@ enum fbinop_tag_t { void oxarop_fbinary_ ## typ ## _sv(enum binop_tag_t tag, i64 n, typ *out, typ x, const typ *y) { \ switch (tag) { \ case FB_DIV: oxarop_op_fdiv_ ## typ ## _sv(n, out, x, y); break; \ + case FB_POW: oxarop_op_pow_ ## typ ## _sv(n, out, x, y); break; \ + case FB_LOGBASE: oxarop_op_logbase_ ## typ ## _sv(n, out, x, y); break; \ default: wrong_op("binary_sv", tag); \ } \ } \ void oxarop_fbinary_ ## typ ## _vs(enum binop_tag_t tag, i64 n, typ *out, const typ *x, typ y) { \ switch (tag) { \ case FB_DIV: oxarop_op_fdiv_ ## typ ## _vs(n, out, x, y); break; \ + case FB_POW: oxarop_op_pow_ ## typ ## _vs(n, out, x, y); break; \ + case FB_LOGBASE: oxarop_op_logbase_ ## typ ## _vs(n, out, x, y); break; \ default: wrong_op("binary_vs", tag); \ } \ } \ void oxarop_fbinary_ ## typ ## _vv(enum binop_tag_t tag, i64 n, typ *out, const typ *x, const typ *y) { \ switch (tag) { \ case FB_DIV: oxarop_op_fdiv_ ## typ ## _vv(n, out, x, y); break; \ + case FB_POW: oxarop_op_pow_ ## typ ## _vv(n, out, x, y); break; \ + case FB_LOGBASE: oxarop_op_logbase_ ## typ ## _vv(n, out, x, y); break; \ default: wrong_op("binary_vv", tag); \ } \ } @@ -204,9 +270,28 @@ enum funop_tag_t { }; #define ENTRY_FUNARY_OPS(typ) \ - void oxarop_funary_ ## typ(enum unop_tag_t tag, i64 n, typ *out, const typ *x) { \ + void oxarop_funary_ ## typ(enum funop_tag_t tag, i64 n, typ *out, const typ *x) { \ switch (tag) { \ case FU_RECIP: oxarop_op_recip_ ## typ(n, out, x); break; \ + case FU_EXP: oxarop_op_exp_ ## typ(n, out, x); break; \ + case FU_LOG: oxarop_op_log_ ## typ(n, out, x); break; \ + case FU_SQRT: oxarop_op_sqrt_ ## typ(n, out, x); break; \ + case FU_SIN: oxarop_op_sin_ ## typ(n, out, x); break; \ + case FU_COS: oxarop_op_cos_ ## typ(n, out, x); break; \ + case FU_TAN: oxarop_op_tan_ ## typ(n, out, x); break; \ + case FU_ASIN: oxarop_op_asin_ ## typ(n, out, x); break; \ + case FU_ACOS: oxarop_op_acos_ ## typ(n, out, x); break; \ + case FU_ATAN: oxarop_op_atan_ ## typ(n, out, x); break; \ + case FU_SINH: oxarop_op_sinh_ ## typ(n, out, x); break; \ + case FU_COSH: oxarop_op_cosh_ ## typ(n, out, x); break; \ + case FU_TANH: oxarop_op_tanh_ ## typ(n, out, x); break; \ + case FU_ASINH: oxarop_op_asinh_ ## typ(n, out, x); break; \ + case FU_ACOSH: oxarop_op_acosh_ ## typ(n, out, x); break; \ + case FU_ATANH: oxarop_op_atanh_ ## typ(n, out, x); break; \ + case FU_LOG1P: oxarop_op_log1p_ ## typ(n, out, x); break; \ + case FU_EXPM1: oxarop_op_expm1_ ## typ(n, out, x); break; \ + case FU_LOG1PEXP: oxarop_op_log1pexp_ ## typ(n, out, x); break; \ + case FU_LOG1MEXP: oxarop_op_log1mexp_ ## typ(n, out, x); break; \ default: wrong_op("unary", tag); \ } \ } @@ -253,7 +338,28 @@ NUM_TYPES_XLIST #define X(typ) \ NONCOMM_OP(fdiv, /, typ) \ + PREFIX_BINOP(pow, GEN_POW, typ) \ + PREFIX_BINOP(logbase, GEN_LOGBASE, typ) \ UNARY_OP(recip, 1.0/, typ) \ + UNARY_OP(exp, GEN_EXP, typ) \ + UNARY_OP(log, GEN_LOG, typ) \ + UNARY_OP(sqrt, GEN_SQRT, typ) \ + UNARY_OP(sin, GEN_SIN, typ) \ + UNARY_OP(cos, GEN_COS, typ) \ + UNARY_OP(tan, GEN_TAN, typ) \ + UNARY_OP(asin, GEN_ASIN, typ) \ + UNARY_OP(acos, GEN_ACOS, typ) \ + UNARY_OP(atan, GEN_ATAN, typ) \ + UNARY_OP(sinh, GEN_SINH, typ) \ + UNARY_OP(cosh, GEN_COSH, typ) \ + UNARY_OP(tanh, GEN_TANH, typ) \ + UNARY_OP(asinh, GEN_ASINH, typ) \ + UNARY_OP(acosh, GEN_ACOSH, typ) \ + UNARY_OP(atanh, GEN_ATANH, typ) \ + UNARY_OP(log1p, GEN_LOG1P, typ) \ + UNARY_OP(expm1, GEN_EXPM1, typ) \ + UNARY_OP(log1pexp, GEN_LOG1PEXP, typ) \ + UNARY_OP(log1mexp, GEN_LOG1MEXP, typ) \ ENTRY_FBINARY_OPS(typ) \ ENTRY_FUNARY_OPS(typ) FLOAT_TYPES_XLIST diff --git a/cbits/arith_lists.h b/cbits/arith_lists.h index 1137c18..2e37575 100644 --- a/cbits/arith_lists.h +++ b/cbits/arith_lists.h @@ -3,12 +3,33 @@ LIST_BINOP(BO_SUB, 2, -) LIST_BINOP(BO_MUL, 3, *) LIST_FBINOP(FB_DIV, 1, /) +LIST_FBINOP(FB_POW, 2, **) +LIST_FBINOP(FB_LOGBASE, 3, logBase) LIST_UNOP(UO_NEG, 1,) LIST_UNOP(UO_ABS, 2,) LIST_UNOP(UO_SIGNUM, 3,) LIST_FUNOP(FU_RECIP, 1,) +LIST_FUNOP(FU_EXP, 2,) +LIST_FUNOP(FU_LOG, 3,) +LIST_FUNOP(FU_SQRT, 4,) +LIST_FUNOP(FU_SIN, 5,) +LIST_FUNOP(FU_COS, 6,) +LIST_FUNOP(FU_TAN, 7,) +LIST_FUNOP(FU_ASIN, 8,) +LIST_FUNOP(FU_ACOS, 9,) +LIST_FUNOP(FU_ATAN, 10,) +LIST_FUNOP(FU_SINH, 11,) +LIST_FUNOP(FU_COSH, 12,) +LIST_FUNOP(FU_TANH, 13,) +LIST_FUNOP(FU_ASINH, 14,) +LIST_FUNOP(FU_ACOSH, 15,) +LIST_FUNOP(FU_ATANH, 16,) +LIST_FUNOP(FU_LOG1P, 17,) +LIST_FUNOP(FU_EXPM1, 18,) +LIST_FUNOP(FU_LOG1PEXP, 19,) +LIST_FUNOP(FU_LOG1MEXP, 20,) LIST_REDOP(RO_SUM1, 1,) LIST_REDOP(RO_PRODUCT1, 2,) diff --git a/ox-arrays.cabal b/ox-arrays.cabal index 875c54e..d0aed82 100644 --- a/ox-arrays.cabal +++ b/ox-arrays.cabal @@ -5,6 +5,8 @@ author: Tom Smeding license: BSD-3-Clause build-type: Simple +extra-source-files: cbits/arith_lists.h + library exposed-modules: Data.Array.Mixed diff --git a/src/Data/Array/Nested/Internal.hs b/src/Data/Array/Nested/Internal.hs index ef2ad6b..f8d16aa 100644 --- a/src/Data/Array/Nested/Internal.hs +++ b/src/Data/Array/Nested/Internal.hs @@ -1048,34 +1048,36 @@ instance (NumElt a, PrimElt a) => Num (Mixed sh a) where signum = mliftNumElt1 numEltSignum fromInteger _ = error "Data.Array.Nested.fromIntegral: No singletons available, use explicit mreplicate" -instance (FloatElt a, NumElt a, PrimElt a, Fractional a) => Fractional (Mixed sh a) where +instance (FloatElt a, NumElt a, PrimElt a) => Fractional (Mixed sh a) where fromRational _ = error "Data.Array.Nested.fromRational: No singletons available, use explicit mreplicate" recip = mliftNumElt1 floatEltRecip (/) = mliftNumElt2 floatEltDiv -instance (FloatElt a, NumElt a, PrimElt a, Floating a) => Floating (Mixed sh a) where +instance (FloatElt a, NumElt a, PrimElt a) => Floating (Mixed sh a) where pi = error "Data.Array.Nested.pi: No singletons available, use explicit mreplicate" - exp = mliftPrim exp - log = mliftPrim log - sqrt = mliftPrim sqrt - (**) = mliftPrim2 (**) - logBase = mliftPrim2 logBase - sin = mliftPrim sin - cos = mliftPrim cos - tan = mliftPrim tan - asin = mliftPrim asin - acos = mliftPrim acos - atan = mliftPrim atan - sinh = mliftPrim sinh - cosh = mliftPrim cosh - tanh = mliftPrim tanh - asinh = mliftPrim asinh - acosh = mliftPrim acosh - atanh = mliftPrim atanh - log1p = mliftPrim GHC.Float.log1p - expm1 = mliftPrim GHC.Float.expm1 - log1pexp = mliftPrim GHC.Float.log1pexp - log1mexp = mliftPrim GHC.Float.log1mexp + exp = mliftNumElt1 floatEltExp + log = mliftNumElt1 floatEltLog + sqrt = mliftNumElt1 floatEltSqrt + + (**) = mliftNumElt2 floatEltPow + logBase = mliftNumElt2 floatEltLogbase + + sin = mliftNumElt1 floatEltSin + cos = mliftNumElt1 floatEltCos + tan = mliftNumElt1 floatEltTan + asin = mliftNumElt1 floatEltAsin + acos = mliftNumElt1 floatEltAcos + atan = mliftNumElt1 floatEltAtan + sinh = mliftNumElt1 floatEltSinh + cosh = mliftNumElt1 floatEltCosh + tanh = mliftNumElt1 floatEltTanh + asinh = mliftNumElt1 floatEltAsinh + acosh = mliftNumElt1 floatEltAcosh + atanh = mliftNumElt1 floatEltAtanh + log1p = mliftNumElt1 floatEltLog1p + expm1 = mliftNumElt1 floatEltExpm1 + log1pexp = mliftNumElt1 floatEltLog1pexp + log1mexp = mliftNumElt1 floatEltLog1mexp mtoRanked :: forall sh a. Elt a => Mixed sh a -> Ranked (X.Rank sh) a mtoRanked arr @@ -1367,12 +1369,12 @@ instance (NumElt a, PrimElt a) => Num (Ranked n a) where signum = arithPromoteRanked signum fromInteger _ = error "Data.Array.Nested.fromIntegral: No singletons available, use explicit rreplicateScal" -instance (FloatElt a, NumElt a, PrimElt a, Fractional a) => Fractional (Ranked n a) where +instance (FloatElt a, NumElt a, PrimElt a) => Fractional (Ranked n a) where fromRational _ = error "Data.Array.Nested.fromRational: No singletons available, use explicit rreplicateScal" recip = arithPromoteRanked recip (/) = arithPromoteRanked2 (/) -instance (FloatElt a, NumElt a, PrimElt a, Floating a) => Floating (Ranked n a) where +instance (FloatElt a, NumElt a, PrimElt a) => Floating (Ranked n a) where pi = error "Data.Array.Nested.pi: No singletons available, use explicit rreplicateScal" exp = arithPromoteRanked exp log = arithPromoteRanked log @@ -1698,12 +1700,12 @@ instance (NumElt a, PrimElt a) => Num (Shaped sh a) where signum = arithPromoteShaped signum fromInteger _ = error "Data.Array.Nested.fromIntegral: No singletons available, use explicit sreplicateScal" -instance (FloatElt a, NumElt a, PrimElt a, Fractional a) => Fractional (Shaped sh a) where +instance (FloatElt a, NumElt a, PrimElt a) => Fractional (Shaped sh a) where fromRational _ = error "Data.Array.Nested.fromRational: No singletons available, use explicit sreplicateScal" recip = arithPromoteShaped recip (/) = arithPromoteShaped2 (/) -instance (FloatElt a, NumElt a, PrimElt a, Floating a) => Floating (Shaped sh a) where +instance (FloatElt a, NumElt a, PrimElt a) => Floating (Shaped sh a) where pi = error "Data.Array.Nested.pi: No singletons available, use explicit sreplicateScal" exp = arithPromoteShaped exp log = arithPromoteShaped log diff --git a/src/Data/Array/Nested/Internal/Arith.hs b/src/Data/Array/Nested/Internal/Arith.hs index 07d5d8a..95fcfcf 100644 --- a/src/Data/Array/Nested/Internal/Arith.hs +++ b/src/Data/Array/Nested/Internal/Arith.hs @@ -361,12 +361,75 @@ instance NumElt CInt where class FloatElt a where floatEltDiv :: SNat n -> RS.Array n a -> RS.Array n a -> RS.Array n a + floatEltPow :: SNat n -> RS.Array n a -> RS.Array n a -> RS.Array n a + floatEltLogbase :: SNat n -> RS.Array n a -> RS.Array n a -> RS.Array n a floatEltRecip :: SNat n -> RS.Array n a -> RS.Array n a + floatEltExp :: SNat n -> RS.Array n a -> RS.Array n a + floatEltLog :: SNat n -> RS.Array n a -> RS.Array n a + floatEltSqrt :: SNat n -> RS.Array n a -> RS.Array n a + floatEltSin :: SNat n -> RS.Array n a -> RS.Array n a + floatEltCos :: SNat n -> RS.Array n a -> RS.Array n a + floatEltTan :: SNat n -> RS.Array n a -> RS.Array n a + floatEltAsin :: SNat n -> RS.Array n a -> RS.Array n a + floatEltAcos :: SNat n -> RS.Array n a -> RS.Array n a + floatEltAtan :: SNat n -> RS.Array n a -> RS.Array n a + floatEltSinh :: SNat n -> RS.Array n a -> RS.Array n a + floatEltCosh :: SNat n -> RS.Array n a -> RS.Array n a + floatEltTanh :: SNat n -> RS.Array n a -> RS.Array n a + floatEltAsinh :: SNat n -> RS.Array n a -> RS.Array n a + floatEltAcosh :: SNat n -> RS.Array n a -> RS.Array n a + floatEltAtanh :: SNat n -> RS.Array n a -> RS.Array n a + floatEltLog1p :: SNat n -> RS.Array n a -> RS.Array n a + floatEltExpm1 :: SNat n -> RS.Array n a -> RS.Array n a + floatEltLog1pexp :: SNat n -> RS.Array n a -> RS.Array n a + floatEltLog1mexp :: SNat n -> RS.Array n a -> RS.Array n a instance FloatElt Float where floatEltDiv = divVectorFloat + floatEltPow = powVectorFloat + floatEltLogbase = logbaseVectorFloat floatEltRecip = recipVectorFloat + floatEltExp = expVectorFloat + floatEltLog = logVectorFloat + floatEltSqrt = sqrtVectorFloat + floatEltSin = sinVectorFloat + floatEltCos = cosVectorFloat + floatEltTan = tanVectorFloat + floatEltAsin = asinVectorFloat + floatEltAcos = acosVectorFloat + floatEltAtan = atanVectorFloat + floatEltSinh = sinhVectorFloat + floatEltCosh = coshVectorFloat + floatEltTanh = tanhVectorFloat + floatEltAsinh = asinhVectorFloat + floatEltAcosh = acoshVectorFloat + floatEltAtanh = atanhVectorFloat + floatEltLog1p = log1pVectorFloat + floatEltExpm1 = expm1VectorFloat + floatEltLog1pexp = log1pexpVectorFloat + floatEltLog1mexp = log1mexpVectorFloat instance FloatElt Double where floatEltDiv = divVectorDouble + floatEltPow = powVectorDouble + floatEltLogbase = logbaseVectorDouble floatEltRecip = recipVectorDouble + floatEltExp = expVectorDouble + floatEltLog = logVectorDouble + floatEltSqrt = sqrtVectorDouble + floatEltSin = sinVectorDouble + floatEltCos = cosVectorDouble + floatEltTan = tanVectorDouble + floatEltAsin = asinVectorDouble + floatEltAcos = acosVectorDouble + floatEltAtan = atanVectorDouble + floatEltSinh = sinhVectorDouble + floatEltCosh = coshVectorDouble + floatEltTanh = tanhVectorDouble + floatEltAsinh = asinhVectorDouble + floatEltAcosh = acoshVectorDouble + floatEltAtanh = atanhVectorDouble + floatEltLog1p = log1pVectorDouble + floatEltExpm1 = expm1VectorDouble + floatEltLog1pexp = log1pexpVectorDouble + floatEltLog1mexp = log1mexpVectorDouble -- cgit v1.2.3-70-g09d2