kfr

Fast, modern C++ DSP framework, FFT, Sample Rate Conversion, FIR/IIR/Biquad Filters (SSE, AVX, AVX-512, ARM NEON)
Log | Files | Refs | README

commit 609dc3a14cbd60fe438637d7582dd5c78aeb3690
parent b063114b7bb195a28a3d6e40a9ba203594891523
Author: d.levin256@gmail.com <d.levin256@gmail.com>
Date:   Wed, 10 Aug 2016 10:18:48 +0300

Merge branch 'dev'

Diffstat:
M.travis.yml | 29++++++++++++++++++++++++++---
Acmake/arm.cmake | 29+++++++++++++++++++++++++++++
Minclude/kfr/base/asin_acos.hpp | 4++--
Minclude/kfr/base/atan.hpp | 34++++++++++++++++++++++++----------
Minclude/kfr/base/function.hpp | 48+++++++++++++++++++++++++++++++++++++++++++++++-
Minclude/kfr/base/gamma.hpp | 8++++----
Minclude/kfr/base/hyperbolic.hpp | 72++++++++++++++++++++++++++++++++++++------------------------------------
Minclude/kfr/base/log_exp.hpp | 142+++++++++++++++++++++++++++++++------------------------------------------------
Minclude/kfr/base/min_max.hpp | 6++++--
Minclude/kfr/base/round.hpp | 8++++----
Minclude/kfr/base/saturation.hpp | 18++++++++----------
Minclude/kfr/base/sin_cos.hpp | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Minclude/kfr/base/sqrt.hpp | 4++--
Minclude/kfr/base/tan.hpp | 12++++++------
Minclude/kfr/base/vec.hpp | 118++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Minclude/kfr/cometa.hpp | 17+++++++++++++----
Minclude/kfr/dsp/units.hpp | 50+++++++++++++++++++++++++-------------------------
Mtests/CMakeLists.txt | 31++++++++++++++++++++-----------
Mtests/intrinsic_test.cpp | 6++++--
Mtests/vec_test.cpp | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
20 files changed, 592 insertions(+), 280 deletions(-)

diff --git a/.travis.yml b/.travis.yml @@ -1,5 +1,4 @@ language: cpp - matrix: include: - os: linux @@ -15,15 +14,39 @@ matrix: - clang-3.8 - libmpfr-dev env: - - CXXCOMPILER=clang++-3.8 CCOMPILER=clang-3.8 + - TEST=LINUX-X86-64 CMAKEARGS="-DCMAKE_CXX_COMPILER=clang++-3.8 -DCMAKE_C_COMPILER=clang-3.8 -DCMAKE_BUILD_TYPE=Release .." + - os: linux + compiler: clang + sudo: required + dist: trusty + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + packages: + - g++-5 + - clang-3.8 + - qemu + - g++-arm-linux-gnueabihf + env: + - TEST=LINUX-ARMV7 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=../cmake/arm.cmake -DARCH_FLAGS=-DLIBC_WORKAROUND_GETS=1 .." - os: osx osx_image: xcode8 + env: + - TEST=XCODE8 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release .." - os: osx osx_image: xcode7.3 + env: + - TEST=XCODE7.3 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release .." - os: osx osx_image: xcode7 + env: + - TEST=XCODE7 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release .." - os: osx osx_image: beta-xcode6.3 + env: + - TEST=XCODE6.3 CMAKEARGS="-DCMAKE_BUILD_TYPE=Release .." before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi @@ -33,7 +56,7 @@ before_install: script: - mkdir build - cd build - - cmake -DCMAKE_CXX_COMPILER=$CXXCOMPILER -DCMAKE_C_COMPILER=$CCOMPILER -DCMAKE_BUILD_TYPE=Release .. + - cmake $CMAKEARGS - make -j4 - cd tests - ctest diff --git a/cmake/arm.cmake b/cmake/arm.cmake @@ -0,0 +1,29 @@ +set (CMAKE_SYSTEM_NAME Linux) +set (CMAKE_SYSTEM_VERSION 1) +set (UNIX True) +set (ARM True) +set (CMAKE_SYSTEM_PROCESSOR arm) + +include (CMakeForceCompiler) +CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++-3.8 Clang) +CMAKE_FORCE_C_COMPILER (/usr/bin/clang-3.8 Clang) +set (CMAKE_CXX_COMPILER_WORKS TRUE) +set (CMAKE_C_COMPILER_WORKS TRUE) + +set (ARM_ROOT "/usr/arm-linux-gnueabihf/include") +set (GCC_VER 4.8.4) +set (SYS_PATHS "-isystem ${ARM_ROOT}/c++/${GCC_VER} -isystem ${ARM_ROOT}/c++/${GCC_VER}/backward -isystem ${ARM_ROOT}/c++/${GCC_VER}/arm-linux-gnueabihf -isystem ${ARM_ROOT}") + +set (ARM_COMMON_FLAGS "-target arm-linux-gnueabihf -mcpu=cortex-a15 -mfpu=neon-vfpv4 -mfloat-abi=hard -static") + +set (CMAKE_CXX_FLAGS "${SYS_PATHS} ${ARM_COMMON_FLAGS}") +set (CMAKE_C_FLAGS " ${SYS_PATHS} ${ARM_COMMON_FLAGS}") + +set (CMAKE_CXX_LINK_FLAGS " ${ARM_COMMON_FLAGS} ${CMAKE_CXX_LINK_FLAGS}") +set (CMAKE_C_LINK_FLAGS " ${ARM_COMMON_FLAGS} ${CMAKE_C_LINK_FLAGS}") + +message(STATUS "${ARM_COMMON_FLAGS}") + +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/include/kfr/base/asin_acos.hpp b/include/kfr/base/asin_acos.hpp @@ -46,8 +46,8 @@ KFR_SINTRIN vec<Tout, N> acos(const vec<T, N>& x) const vec<Tout, N> xx = x; return atan2(sqrt(Tout(1) - xx * xx), xx); } -KFR_I_CONVERTER(asin) -KFR_I_CONVERTER(acos) +KFR_I_FLT_CONVERTER(asin) +KFR_I_FLT_CONVERTER(acos) } KFR_I_FN(asin) KFR_I_FN(acos) diff --git a/include/kfr/base/atan.hpp b/include/kfr/base/atan.hpp @@ -188,20 +188,34 @@ KFR_SINTRIN vec<f64, N> atan(const vec<f64, N>& s) return t; } -template <typename T> -KFR_SINTRIN T atandeg(const T& x) +template <size_t N> +KFR_SINTRIN vec<f32, N> atandeg(const vec<f32, N>& x) +{ + return atan(x) * c_radtodeg<f32>; +} + +template <size_t N> +KFR_SINTRIN vec<f64, N> atandeg(const vec<f64, N>& x) { - return atan(x) * c_radtodeg<T>; + return atan(x) * c_radtodeg<f64>; } -template <typename T1, typename T2> -KFR_SINTRIN common_type<T1, T2> atan2deg(const T1& y, const T2& x) +template <size_t N> +KFR_SINTRIN vec<f32, N> atan2deg(const vec<f32, N>& y, const vec<f32, N>& x) +{ + return atan2(y, x) * c_radtodeg<f32>; +} + +template <size_t N> +KFR_SINTRIN vec<f64, N> atan2deg(const vec<f64, N>& y, const vec<f64, N>& x) { - return atan2(y, x) * c_radtodeg<common_type<T1, T2>>; + return atan2(y, x) * c_radtodeg<f64>; } -KFR_I_CONVERTER(atan) -KFR_I_CONVERTER(atan2) +KFR_I_FLT_CONVERTER(atan) +KFR_I_FLT_CONVERTER(atan2) +KFR_I_FLT_CONVERTER(atandeg) +KFR_I_FLT_CONVERTER(atan2deg) } KFR_I_FN(atan) KFR_I_FN(atandeg) @@ -209,7 +223,7 @@ KFR_I_FN(atan2) KFR_I_FN(atan2deg) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> atan(const T1& x) +KFR_INTRIN flt_type<T1> atan(const T1& x) { return intrinsics::atan(x); } @@ -221,7 +235,7 @@ KFR_INTRIN internal::expression_function<fn::atan, E1> atan(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> atandeg(const T1& x) +KFR_INTRIN flt_type<T1> atandeg(const T1& x) { return intrinsics::atandeg(x); } diff --git a/include/kfr/base/function.hpp b/include/kfr/base/function.hpp @@ -41,8 +41,54 @@ namespace kfr return to_scalar(::kfr::intrinsics::fn(vecout(a), vecout(b)...)); \ } +#define KFR_I_FLT_CONVERTER(fn) \ + template <typename T1, typename... Args, \ + typename Tout = ::kfr::flt_type<::cometa::common_type<T1, Args...>>> \ + KFR_SINTRIN Tout fn(const T1& a, const Args&... b) \ + { \ + using vecout = vec1<Tout>; \ + return to_scalar(::kfr::intrinsics::fn(vecout(a), vecout(b)...)); \ + } + +namespace internal +{ +template <typename T> +struct flt_type_impl +{ + using type = fbase; +}; + +template <typename T, size_t N> +struct flt_type_impl<vec<T, N>> +{ + using type = vec<fbase, N>; +}; + +template <> +struct flt_type_impl<float> +{ + using type = float; +}; +template <> +struct flt_type_impl<double> +{ + using type = double; +}; + +template <size_t N> +struct flt_type_impl<vec<float, N>> +{ + using type = vec<float, N>; +}; +template <size_t N> +struct flt_type_impl<vec<double, N>> +{ + using type = vec<double, N>; +}; +} + template <typename T> -using flt_type = conditional<std::is_floating_point<deep_subtype<T>>::value, T, deep_rebind<T, fbase>>; +using flt_type = typename internal::flt_type_impl<T>::type; namespace intrinsics { diff --git a/include/kfr/base/gamma.hpp b/include/kfr/base/gamma.hpp @@ -58,14 +58,14 @@ KFR_SINTRIN vec<T, N> factorial_approx(const vec<T, N>& x) { return gamma(x + T(1)); } -KFR_I_CONVERTER(gamma) -KFR_I_CONVERTER(factorial_approx) +KFR_I_FLT_CONVERTER(gamma) +KFR_I_FLT_CONVERTER(factorial_approx) } KFR_I_FN(gamma) KFR_I_FN(factorial_approx) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 gamma(const T1& x) +KFR_INTRIN flt_type<T1> gamma(const T1& x) { return intrinsics::gamma(x); } @@ -77,7 +77,7 @@ KFR_INTRIN internal::expression_function<fn::gamma, E1> gamma(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 factorial_approx(const T1& x) +KFR_INTRIN flt_type<T1> factorial_approx(const T1& x) { return intrinsics::factorial_approx(x); } diff --git a/include/kfr/base/hyperbolic.hpp b/include/kfr/base/hyperbolic.hpp @@ -35,54 +35,54 @@ namespace kfr namespace intrinsics { -template <typename T, size_t N> -KFR_SINTRIN vec<T, N> sinh(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> sinh(const vec<T, N>& x) { - return (exp(x) - exp(-x)) * T(0.5); + return (exp(x) - exp(-x)) * Tout(0.5); } -template <typename T, size_t N> -KFR_SINTRIN vec<T, N> cosh(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> cosh(const vec<T, N>& x) { - return (exp(x) + exp(-x)) * T(0.5); + return (exp(x) + exp(-x)) * Tout(0.5); } -template <typename T, size_t N> -KFR_SINTRIN vec<T, N> tanh(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> tanh(const vec<T, N>& x) { - x = -2 * x; - return (1 - exp(x)) / (1 + exp(x)); + const vec<Tout, N> a = exp(2 * x); + return (a - 1) / (a + 1); } -template <typename T, size_t N> -KFR_SINTRIN vec<T, N> coth(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> coth(const vec<T, N>& x) { - x = -2 * x; - return (1 + exp(x)) / (1 - exp(x)); + const vec<Tout, N> a = exp(2 * x); + return (a + 1) / (a - 1); } -template <typename T, size_t N, KFR_ENABLE_IF(N > 1)> -KFR_SINTRIN vec<T, N> sinhcosh(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> sinhcosh(const vec<T, N>& x) { - const vec<T, N> a = exp(x); - const vec<T, N> b = exp(-x); - return subadd(a, b) * T(0.5); + const vec<Tout, N> a = exp(x); + const vec<Tout, N> b = exp(-x); + return subadd(a, b) * Tout(0.5); } -template <typename T, size_t N, KFR_ENABLE_IF(N > 1)> -KFR_SINTRIN vec<T, N> coshsinh(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> coshsinh(const vec<T, N>& x) { - const vec<T, N> a = exp(x); - const vec<T, N> b = exp(-x); - return addsub(a, b) * T(0.5); + const vec<Tout, N> a = exp(x); + const vec<Tout, N> b = exp(-x); + return addsub(a, b) * Tout(0.5); } -KFR_I_CONVERTER(sinh) -KFR_I_CONVERTER(cosh) -KFR_I_CONVERTER(tanh) -KFR_I_CONVERTER(coth) -KFR_I_CONVERTER(sinhcosh) -KFR_I_CONVERTER(coshsinh) +KFR_I_FLT_CONVERTER(sinh) +KFR_I_FLT_CONVERTER(cosh) +KFR_I_FLT_CONVERTER(tanh) +KFR_I_FLT_CONVERTER(coth) +KFR_I_FLT_CONVERTER(sinhcosh) +KFR_I_FLT_CONVERTER(coshsinh) } KFR_I_FN(sinh) KFR_I_FN(cosh) @@ -92,7 +92,7 @@ KFR_I_FN(sinhcosh) KFR_I_FN(coshsinh) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 sinh(const T1& x) +KFR_INTRIN flt_type<T1> sinh(const T1& x) { return intrinsics::sinh(x); } @@ -104,7 +104,7 @@ KFR_INTRIN internal::expression_function<fn::sinh, E1> sinh(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 cosh(const T1& x) +KFR_INTRIN flt_type<T1> cosh(const T1& x) { return intrinsics::cosh(x); } @@ -116,7 +116,7 @@ KFR_INTRIN internal::expression_function<fn::cosh, E1> cosh(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 tanh(const T1& x) +KFR_INTRIN flt_type<T1> tanh(const T1& x) { return intrinsics::tanh(x); } @@ -128,7 +128,7 @@ KFR_INTRIN internal::expression_function<fn::tanh, E1> tanh(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 coth(const T1& x) +KFR_INTRIN flt_type<T1> coth(const T1& x) { return intrinsics::coth(x); } @@ -140,7 +140,7 @@ KFR_INTRIN internal::expression_function<fn::coth, E1> coth(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 sinhcosh(const T1& x) +KFR_INTRIN flt_type<T1> sinhcosh(const T1& x) { return intrinsics::sinhcosh(x); } @@ -152,7 +152,7 @@ KFR_INTRIN internal::expression_function<fn::sinhcosh, E1> sinhcosh(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 coshsinh(const T1& x) +KFR_INTRIN flt_type<T1> coshsinh(const T1& x) { return intrinsics::coshsinh(x); } diff --git a/include/kfr/base/log_exp.hpp b/include/kfr/base/log_exp.hpp @@ -133,15 +133,15 @@ KFR_SINTRIN vec<f64, N> log(const vec<f64, N>& d) return x; } -template <typename T, size_t N, KFR_ENABLE_IF(is_f_class<T>::value)> -KFR_SINTRIN vec<T, N> log2(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> log2(const vec<T, N>& x) { - return log(x) * c_recip_log_2<T>; + return log(cast<Tout>(x)) * c_recip_log_2<Tout>; } -template <typename T, size_t N, KFR_ENABLE_IF(is_f_class<T>::value)> -KFR_SINTRIN vec<T, N> log10(const vec<T, N>& x) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> log10(const vec<T, N>& x) { - return log(x) * c_recip_log_10<T>; + return log(cast<Tout>(x)) * c_recip_log_10<Tout>; } template <size_t N> @@ -219,39 +219,15 @@ KFR_SINTRIN vec<f64, N> exp(const vec<f64, N>& d) return u; } -template <typename T, size_t N, KFR_ENABLE_IF(is_f_class<T>::value)> -KFR_SINTRIN vec<T, N> exp2(const vec<T, N>& x) -{ - return exp(x * c_log_2<T>); -} -template <typename T, size_t N, KFR_ENABLE_IF(is_f_class<T>::value)> -KFR_SINTRIN vec<T, N> exp10(const vec<T, N>& x) -{ - return exp(x * c_log_10<T>); -} - -template <typename T1, typename T2> -KFR_SINTRIN common_type<T1, T2> logn(const T1& a, const T2& b) -{ - return log(a) / log(b); -} - -template <typename T1, typename T2> -KFR_SINTRIN common_type<T1, T2> logm(const T1& a, const T2& b) -{ - return log(a) * b; -} - -template <typename T1, typename T2, typename T3> -KFR_SINTRIN common_type<T1, T2, T3> exp_fmadd(const T1& x, const T2& m, const T3& a) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> exp2(const vec<T, N>& x) { - return exp(fmadd(x, m, a)); + return exp(x * c_log_2<Tout>); } - -template <typename T1, typename T2, typename T3> -KFR_SINTRIN common_type<T1, T2, T3> log_fmadd(const T1& x, const T2& m, const T3& a) +template <typename T, size_t N, typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> exp10(const vec<T, N>& x) { - return fmadd(log(x), m, a); + return exp(x * c_log_10<Tout>); } template <typename T, size_t N> @@ -276,52 +252,46 @@ KFR_SINTRIN vec<T, N> cbrt(const vec<T, N>& x) return pow<T, N>(x, T(0.333333333333333333333333333333333)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> exp(const vec<T, N>& x) -{ - return exp(cast<Tout>(x)); -} -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> exp2(const vec<T, N>& x) -{ - return exp2(cast<Tout>(x)); -} -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> exp10(const vec<T, N>& x) +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> +KFR_SINTRIN vec<Tout, N> cbrt(const vec<T, N>& x) { - return exp10(cast<Tout>(x)); + return cbrt(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> log(const vec<T, N>& x) + +KFR_I_FLT_CONVERTER(exp) +KFR_I_FLT_CONVERTER(exp2) +KFR_I_FLT_CONVERTER(exp10) +KFR_I_FLT_CONVERTER(log) +KFR_I_FLT_CONVERTER(log2) +KFR_I_FLT_CONVERTER(log10) +KFR_I_FLT_CONVERTER(logb) +KFR_I_FLT_CONVERTER(pow) +KFR_I_FLT_CONVERTER(root) +KFR_I_FLT_CONVERTER(cbrt) + +template <typename T1, typename T2> +KFR_SINTRIN flt_type<common_type<T1, T2>> logn(const T1& a, const T2& b) { - return log(cast<Tout>(x)); + return log(a) / log(b); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> log2(const vec<T, N>& x) + +template <typename T1, typename T2> +KFR_SINTRIN flt_type<common_type<T1, T2>> logm(const T1& a, const T2& b) { - return log2(cast<Tout>(x)); + return log(a) * b; } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> log10(const vec<T, N>& x) + +template <typename T1, typename T2, typename T3> +KFR_SINTRIN flt_type<common_type<T1, T2, T3>> exp_fmadd(const T1& x, const T2& m, const T3& a) { - return log10(cast<Tout>(x)); + return exp(fmadd(x, m, a)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> -KFR_SINTRIN vec<Tout, N> cbrt(const vec<T, N>& x) + +template <typename T1, typename T2, typename T3> +KFR_SINTRIN flt_type<common_type<T1, T2, T3>> log_fmadd(const T1& x, const T2& m, const T3& a) { - return cbrt(cast<Tout>(x)); + return fmadd(log(x), m, a); } - -KFR_I_CONVERTER(exp) -KFR_I_CONVERTER(exp2) -KFR_I_CONVERTER(exp10) -KFR_I_CONVERTER(log) -KFR_I_CONVERTER(log2) -KFR_I_CONVERTER(log10) -KFR_I_CONVERTER(logb) -KFR_I_CONVERTER(pow) -KFR_I_CONVERTER(root) -KFR_I_CONVERTER(cbrt) } KFR_I_FN(exp) KFR_I_FN(exp2) @@ -339,7 +309,7 @@ KFR_I_FN(root) KFR_I_FN(cbrt) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 exp(const T1& x) +KFR_INTRIN flt_type<T1> exp(const T1& x) { return intrinsics::exp(x); } @@ -351,7 +321,7 @@ KFR_INTRIN internal::expression_function<fn::exp, E1> exp(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 exp2(const T1& x) +KFR_INTRIN flt_type<T1> exp2(const T1& x) { return intrinsics::exp2(x); } @@ -363,7 +333,7 @@ KFR_INTRIN internal::expression_function<fn::exp2, E1> exp2(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 exp10(const T1& x) +KFR_INTRIN flt_type<T1> exp10(const T1& x) { return intrinsics::exp10(x); } @@ -375,7 +345,7 @@ KFR_INTRIN internal::expression_function<fn::exp10, E1> exp10(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 log(const T1& x) +KFR_INTRIN flt_type<T1> log(const T1& x) { return intrinsics::log(x); } @@ -387,7 +357,7 @@ KFR_INTRIN internal::expression_function<fn::log, E1> log(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 log2(const T1& x) +KFR_INTRIN flt_type<T1> log2(const T1& x) { return intrinsics::log2(x); } @@ -399,7 +369,7 @@ KFR_INTRIN internal::expression_function<fn::log2, E1> log2(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 log10(const T1& x) +KFR_INTRIN flt_type<T1> log10(const T1& x) { return intrinsics::log10(x); } @@ -411,7 +381,7 @@ KFR_INTRIN internal::expression_function<fn::log10, E1> log10(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 logb(const T1& x) +KFR_INTRIN flt_type<T1> logb(const T1& x) { return intrinsics::logb(x); } @@ -423,7 +393,7 @@ KFR_INTRIN internal::expression_function<fn::logb, E1> logb(E1&& x) } template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> -KFR_INTRIN common_type<T1, T2> logn(const T1& x, const T2& y) +KFR_INTRIN flt_type<common_type<T1, T2>> logn(const T1& x, const T2& y) { return intrinsics::logn(x, y); } @@ -435,7 +405,7 @@ KFR_INTRIN internal::expression_function<fn::logn, E1, E2> logn(E1&& x, E2&& y) } template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> -KFR_INTRIN common_type<T1, T2> logm(const T1& x, const T2& y) +KFR_INTRIN flt_type<common_type<T1, T2>> logm(const T1& x, const T2& y) { return intrinsics::logm(x, y); } @@ -447,7 +417,7 @@ KFR_INTRIN internal::expression_function<fn::logm, E1, E2> logm(E1&& x, E2&& y) } template <typename T1, typename T2, typename T3, KFR_ENABLE_IF(is_numeric_args<T1, T2, T3>::value)> -KFR_INTRIN common_type<T1, T2, T3> exp_fmadd(const T1& x, const T2& y, const T3& z) +KFR_INTRIN flt_type<common_type<T1, T2, T3>> exp_fmadd(const T1& x, const T2& y, const T3& z) { return intrinsics::exp_fmadd(x, y, z); } @@ -459,7 +429,7 @@ KFR_INTRIN internal::expression_function<fn::exp_fmadd, E1, E2, E3> exp_fmadd(E1 } template <typename T1, typename T2, typename T3, KFR_ENABLE_IF(is_numeric_args<T1, T2, T3>::value)> -KFR_INTRIN common_type<T1, T2, T3> log_fmadd(const T1& x, const T2& y, const T3& z) +KFR_INTRIN flt_type<common_type<T1, T2, T3>> log_fmadd(const T1& x, const T2& y, const T3& z) { return intrinsics::log_fmadd(x, y, z); } @@ -471,7 +441,7 @@ KFR_INTRIN internal::expression_function<fn::log_fmadd, E1, E2, E3> log_fmadd(E1 } template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> -KFR_INTRIN common_type<T1, T2> pow(const T1& x, const T2& y) +KFR_INTRIN flt_type<common_type<T1, T2>> pow(const T1& x, const T2& y) { return intrinsics::pow(x, y); } @@ -483,7 +453,7 @@ KFR_INTRIN internal::expression_function<fn::pow, E1, E2> pow(E1&& x, E2&& y) } template <typename T1, typename T2, KFR_ENABLE_IF(is_numeric_args<T1, T2>::value)> -KFR_INTRIN common_type<T1, T2> root(const T1& x, const T2& y) +KFR_INTRIN flt_type<common_type<T1, T2>> root(const T1& x, const T2& y) { return intrinsics::root(x, y); } @@ -495,7 +465,7 @@ KFR_INTRIN internal::expression_function<fn::root, E1, E2> root(E1&& x, E2&& y) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 cbrt(const T1& x) +KFR_INTRIN flt_type<T1> cbrt(const T1& x) { return intrinsics::cbrt(x); } diff --git a/include/kfr/base/min_max.hpp b/include/kfr/base/min_max.hpp @@ -111,6 +111,8 @@ KFR_SINTRIN i16neon min(const i16neon& x, const i16neon& y) { return vminq_s16(* KFR_SINTRIN u16neon min(const u16neon& x, const u16neon& y) { return vminq_u16(*x, *y); } KFR_SINTRIN i32neon min(const i32neon& x, const i32neon& y) { return vminq_s32(*x, *y); } KFR_SINTRIN u32neon min(const u32neon& x, const u32neon& y) { return vminq_u32(*x, *y); } +KFR_SINTRIN i64neon min(const i64neon& x, const i64neon& y) { return select(x < y, x, y); } +KFR_SINTRIN u64neon min(const u64neon& x, const u64neon& y) { return select(x < y, x, y); } KFR_SINTRIN i8neon max(const i8neon& x, const i8neon& y) { return vmaxq_s8(*x, *y); } KFR_SINTRIN u8neon max(const u8neon& x, const u8neon& y) { return vmaxq_u8(*x, *y); } @@ -118,8 +120,8 @@ KFR_SINTRIN i16neon max(const i16neon& x, const i16neon& y) { return vmaxq_s16(* KFR_SINTRIN u16neon max(const u16neon& x, const u16neon& y) { return vmaxq_u16(*x, *y); } KFR_SINTRIN i32neon max(const i32neon& x, const i32neon& y) { return vmaxq_s32(*x, *y); } KFR_SINTRIN u32neon max(const u32neon& x, const u32neon& y) { return vmaxq_u32(*x, *y); } -KFR_SINTRIN i64neon min(const i64neon& x, const i64neon& y) { return select(x < y, x, y); } -KFR_SINTRIN u64neon min(const u64neon& x, const u64neon& y) { return select(x < y, x, y); } +KFR_SINTRIN i64neon max(const i64neon& x, const i64neon& y) { return select(x > y, x, y); } +KFR_SINTRIN u64neon max(const u64neon& x, const u64neon& y) { return select(x > y, x, y); } KFR_SINTRIN f32neon min(const f32neon& x, const f32neon& y) { return vminq_f32(*x, *y); } KFR_SINTRIN f32neon max(const f32neon& x, const f32neon& y) { return vmaxq_f32(*x, *y); } diff --git a/include/kfr/base/round.hpp b/include/kfr/base/round.hpp @@ -92,25 +92,25 @@ template <size_t N> KFR_SINTRIN vec<f32, N> floor(const vec<f32, N>& x) { vec<f32, N> t = cast<f32>(cast<i32>(x)); - return t - (bitcast<f32>(x < t) & 1.f); + return t - (tovec(x < t) & 1.f); } template <size_t N> KFR_SINTRIN vec<f64, N> floor(const vec<f64, N>& x) { vec<f64, N> t = cast<f64>(cast<i64>(x)); - return t - (bitcast<f64>(x < t) & 1.0); + return t - (tovec(x < t) & 1.0); } template <size_t N> KFR_SINTRIN vec<f32, N> ceil(const vec<f32, N>& x) { vec<f32, N> t = cast<f32>(cast<i32>(x)); - return t + (bitcast<f32>(x > t) & 1.f); + return t + (tovec(x > t) & 1.f); } template <size_t N> KFR_SINTRIN vec<f64, N> ceil(const vec<f64, N>& x) { vec<f64, N> t = cast<f64>(cast<i64>(x)); - return t + (bitcast<f64>(x > t) & 1.0); + return t + (tovec(x > t) & 1.0); } template <size_t N> KFR_SINTRIN vec<f32, N> round(const vec<f32, N>& x) diff --git a/include/kfr/base/saturation.hpp b/include/kfr/base/saturation.hpp @@ -111,21 +111,19 @@ KFR_SINTRIN u8neon satadd(const u8neon& x, const u8neon& y) { return vqaddq_u8(* KFR_SINTRIN i8neon satadd(const i8neon& x, const i8neon& y) { return vqaddq_s8(*x, *y); } KFR_SINTRIN u16neon satadd(const u16neon& x, const u16neon& y) { return vqaddq_u16(*x, *y); } KFR_SINTRIN i16neon satadd(const i16neon& x, const i16neon& y) { return vqaddq_s16(*x, *y); } - -KFR_SINTRIN u8neon satsub(const u8neon& x, const u8neon& y) { return vqsubq_u8(*x, *y); } -KFR_SINTRIN i8neon satsub(const i8neon& x, const i8neon& y) { return vqsubq_s8(*x, *y); } -KFR_SINTRIN u16neon satsub(const u16neon& x, const u16neon& y) { return vqsubq_u16(*x, *y); } -KFR_SINTRIN i16neon satsub(const i16neon& x, const i16neon& y) { return vqsubq_s16(*x, *y); } - KFR_SINTRIN u32neon satadd(const u32neon& a, const u32neon& b) { return vqaddq_u32(*a, *b); } KFR_SINTRIN i32neon satadd(const i32neon& a, const i32neon& b) { return vqaddq_s32(*a, *b); } KFR_SINTRIN u64neon satadd(const u64neon& a, const u64neon& b) { return vqaddq_u64(*a, *b); } KFR_SINTRIN i64neon satadd(const i64neon& a, const i64neon& b) { return vqaddq_s64(*a, *b); } -KFR_SINTRIN i32neon satsub(const i32neon& a, const i32neon& b) { return vqsubq_u32(*a, *b); } -KFR_SINTRIN i64neon satsub(const i64neon& a, const i64neon& b) { return vqsubq_s32(*a, *b); } -KFR_SINTRIN u32neon satsub(const u32neon& a, const u32neon& b) { return vqsubq_u64(*a, *b); } -KFR_SINTRIN u64neon satsub(const u64neon& a, const u64neon& b) { return vqsubq_s64(*a, *b); } +KFR_SINTRIN u8neon satsub(const u8neon& x, const u8neon& y) { return vqsubq_u8(*x, *y); } +KFR_SINTRIN i8neon satsub(const i8neon& x, const i8neon& y) { return vqsubq_s8(*x, *y); } +KFR_SINTRIN u16neon satsub(const u16neon& x, const u16neon& y) { return vqsubq_u16(*x, *y); } +KFR_SINTRIN i16neon satsub(const i16neon& x, const i16neon& y) { return vqsubq_s16(*x, *y); } +KFR_SINTRIN u32neon satsub(const u32neon& a, const u32neon& b) { return vqsubq_u32(*a, *b); } +KFR_SINTRIN i32neon satsub(const i32neon& a, const i32neon& b) { return vqsubq_s32(*a, *b); } +KFR_SINTRIN u64neon satsub(const u64neon& a, const u64neon& b) { return vqsubq_u64(*a, *b); } +KFR_SINTRIN i64neon satsub(const i64neon& a, const i64neon& b) { return vqsubq_s64(*a, *b); } KFR_HANDLE_ALL_SIZES_2(satadd) KFR_HANDLE_ALL_SIZES_2(satsub) diff --git a/include/kfr/base/sin_cos.hpp b/include/kfr/base/sin_cos.hpp @@ -238,91 +238,91 @@ KFR_SINTRIN vec<T, N> sinc(const vec<T, N>& x) return select(abs(x) <= c_epsilon<T>, T(1), sin(x) / x); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> sin(const vec<T, N>& x) { return sin(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> cos(const vec<T, N>& x) { return cos(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> fastsin(const vec<T, N>& x) { return fastsin(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> fastcos(const vec<T, N>& x) { return fastcos(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> sincos(const vec<T, N>& x) { return sincos(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> cossin(const vec<T, N>& x) { return cossin(cast<Tout>(x)); } -template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = ftype<T>> +template <typename T, size_t N, KFR_ENABLE_IF(!is_f_class<T>::value), typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> sinc(const vec<T, N>& x) { return sinc(cast<Tout>(x)); } -template <typename T> -KFR_SINTRIN T sindeg(const T& x) +KFR_I_FLT_CONVERTER(sin) +KFR_I_FLT_CONVERTER(cos) +KFR_I_FLT_CONVERTER(fastsin) +KFR_I_FLT_CONVERTER(fastcos) +KFR_I_FLT_CONVERTER(sincos) +KFR_I_FLT_CONVERTER(cossin) +KFR_I_FLT_CONVERTER(sinc) + +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout sindeg(const T& x) { - return sin(x * c_degtorad<T>); + return sin(x * c_degtorad<Tout>); } -template <typename T> -KFR_SINTRIN T cosdeg(const T& x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout cosdeg(const T& x) { - return cos(x * c_degtorad<T>); + return cos(x * c_degtorad<Tout>); } -template <typename T> -KFR_SINTRIN T fastsindeg(const T& x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout fastsindeg(const T& x) { - return fastsin(x * c_degtorad<T>); + return fastsin(x * c_degtorad<Tout>); } -template <typename T> -KFR_SINTRIN T fastcosdeg(const T& x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout fastcosdeg(const T& x) { - return fastcos(x * c_degtorad<T>); + return fastcos(x * c_degtorad<Tout>); } -template <typename T> -KFR_SINTRIN T sincosdeg(const T& x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout sincosdeg(const T& x) { - return sincos(x * c_degtorad<T>); + return sincos(x * c_degtorad<Tout>); } -template <typename T> -KFR_SINTRIN T cossindeg(const T& x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout cossindeg(const T& x) { - return cossin(x * c_degtorad<T>); + return cossin(x * c_degtorad<Tout>); } - -KFR_I_CONVERTER(sin) -KFR_I_CONVERTER(cos) -KFR_I_CONVERTER(fastsin) -KFR_I_CONVERTER(fastcos) -KFR_I_CONVERTER(sincos) -KFR_I_CONVERTER(cossin) -KFR_I_CONVERTER(sinc) } KFR_I_FN(sin) @@ -331,10 +331,18 @@ KFR_I_FN(fastsin) KFR_I_FN(fastcos) KFR_I_FN(sincos) KFR_I_FN(cossin) + +KFR_I_FN(sindeg) +KFR_I_FN(cosdeg) +KFR_I_FN(fastsindeg) +KFR_I_FN(fastcosdeg) +KFR_I_FN(sincosdeg) +KFR_I_FN(cossindeg) + KFR_I_FN(sinc) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> sin(const T1& x) +KFR_INTRIN flt_type<T1> sin(const T1& x) { return intrinsics::sin(x); } @@ -346,7 +354,7 @@ KFR_INTRIN internal::expression_function<fn::sin, E1> sin(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> cos(const T1& x) +KFR_INTRIN flt_type<T1> cos(const T1& x) { return intrinsics::cos(x); } @@ -358,7 +366,7 @@ KFR_INTRIN internal::expression_function<fn::cos, E1> cos(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> fastsin(const T1& x) +KFR_INTRIN flt_type<T1> fastsin(const T1& x) { return intrinsics::fastsin(x); } @@ -370,7 +378,7 @@ KFR_INTRIN internal::expression_function<fn::fastsin, E1> fastsin(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> fastcos(const T1& x) +KFR_INTRIN flt_type<T1> fastcos(const T1& x) { return intrinsics::fastcos(x); } @@ -382,7 +390,7 @@ KFR_INTRIN internal::expression_function<fn::fastcos, E1> fastcos(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> sincos(const T1& x) +KFR_INTRIN flt_type<T1> sincos(const T1& x) { return intrinsics::sincos(x); } @@ -394,7 +402,7 @@ KFR_INTRIN internal::expression_function<fn::sincos, E1> sincos(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> cossin(const T1& x) +KFR_INTRIN flt_type<T1> cossin(const T1& x) { return intrinsics::cossin(x); } @@ -406,7 +414,79 @@ KFR_INTRIN internal::expression_function<fn::cossin, E1> cossin(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN ftype<T1> sinc(const T1& x) +KFR_INTRIN flt_type<T1> sindeg(const T1& x) +{ + return intrinsics::sindeg(x); +} + +template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> +KFR_INTRIN internal::expression_function<fn::sindeg, E1> sindeg(E1&& x) +{ + return { fn::sindeg(), std::forward<E1>(x) }; +} + +template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> +KFR_INTRIN flt_type<T1> cosdeg(const T1& x) +{ + return intrinsics::cosdeg(x); +} + +template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> +KFR_INTRIN internal::expression_function<fn::cosdeg, E1> cosdeg(E1&& x) +{ + return { fn::cosdeg(), std::forward<E1>(x) }; +} + +template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> +KFR_INTRIN flt_type<T1> fastsindeg(const T1& x) +{ + return intrinsics::fastsindeg(x); +} + +template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> +KFR_INTRIN internal::expression_function<fn::fastsindeg, E1> fastsindeg(E1&& x) +{ + return { fn::fastsindeg(), std::forward<E1>(x) }; +} + +template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> +KFR_INTRIN flt_type<T1> fastcosdeg(const T1& x) +{ + return intrinsics::fastcosdeg(x); +} + +template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> +KFR_INTRIN internal::expression_function<fn::fastcosdeg, E1> fastcosdeg(E1&& x) +{ + return { fn::fastcosdeg(), std::forward<E1>(x) }; +} + +template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> +KFR_INTRIN flt_type<T1> sincosdeg(const T1& x) +{ + return intrinsics::sincosdeg(x); +} + +template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> +KFR_INTRIN internal::expression_function<fn::sincosdeg, E1> sincosdeg(E1&& x) +{ + return { fn::sincosdeg(), std::forward<E1>(x) }; +} + +template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> +KFR_INTRIN flt_type<T1> cossindeg(const T1& x) +{ + return intrinsics::cossindeg(x); +} + +template <typename E1, KFR_ENABLE_IF(is_input_expression<E1>::value)> +KFR_INTRIN internal::expression_function<fn::cossindeg, E1> cossindeg(E1&& x) +{ + return { fn::cossindeg(), std::forward<E1>(x) }; +} + +template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> +KFR_INTRIN flt_type<T1> sinc(const T1& x) { return intrinsics::sinc(x); } diff --git a/include/kfr/base/sqrt.hpp b/include/kfr/base/sqrt.hpp @@ -53,10 +53,10 @@ KFR_HANDLE_ALL_SIZES_FLT_1(sqrt) template <typename T, size_t N, typename Tout = flt_type<T>> KFR_SINTRIN vec<Tout, N> sqrt(const vec<T, N>& x) { - return apply([](T x) { return std::sqrt(static_cast<Tout>(x)); }, x); + return apply([](Tout x) { return std::sqrt(x); }, cast<Tout>(x)); } #endif -KFR_I_CONVERTER(sqrt) +KFR_I_FLT_CONVERTER(sqrt) } KFR_I_FN(sqrt) diff --git a/include/kfr/base/tan.hpp b/include/kfr/base/tan.hpp @@ -119,19 +119,19 @@ KFR_SINTRIN vec<f64, N> tan(const vec<f64, N>& x_full) const vec<f64, N> z = select(inverse, val / -x, val * x); return mulsign(z, x_full); } + +KFR_I_FLT_CONVERTER(tan) template <typename T> -KFR_SINTRIN T tandeg(const T& x) +KFR_SINTRIN flt_type<T> tandeg(const T& x) { - return tan(x * c_degtorad<T>); + return tan(x * c_degtorad<flt_type<T>>); } - -KFR_I_CONVERTER(tan) } KFR_I_FN(tan) KFR_I_FN(tandeg) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 tan(const T1& x) +KFR_INTRIN flt_type<T1> tan(const T1& x) { return intrinsics::tan(x); } @@ -143,7 +143,7 @@ KFR_INTRIN internal::expression_function<fn::tan, E1> tan(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 tandeg(const T1& x) +KFR_INTRIN flt_type<T1> tandeg(const T1& x) { return intrinsics::tandeg(x); } diff --git a/include/kfr/base/vec.hpp b/include/kfr/base/vec.hpp @@ -611,8 +611,15 @@ constexpr CMT_INLINE vec<SubType, N> pack(const Arg& x, const Args&... rest) } KFR_FN(pack) +namespace operators +{ +struct empty +{ +}; +} + template <typename T, size_t N> -struct vec : vec_t<T, N> +struct vec : vec_t<T, N>, operators::empty { static_assert(N > 0 && N <= 256, "Invalid vector size"); @@ -737,32 +744,6 @@ struct vec : vec_t<T, N> KFR_ASGN_OP(>>=, >>) #undef KFR_ASGN_OP - template <typename U, typename C = common_type<U, T>> - friend constexpr CMT_INLINE vec<C, N> operator+(const vec& x, const vec<U, N>& y) - { - return vec_op<C>::add(static_cast<vec<C, N>>(x).v, static_cast<vec<C, N>>(y).v); - } - template <typename U, typename C = common_type<U, T>> - friend constexpr CMT_INLINE vec<C, N> operator-(const vec& x, const vec<U, N>& y) - { - return vec_op<C>::sub(static_cast<vec<C, N>>(x).v, static_cast<vec<C, N>>(y).v); - } - template <typename U, typename C = common_type<U, T>> - friend constexpr CMT_INLINE vec<C, N> operator*(const vec& x, const vec<U, N>& y) - { - return vec_op<C>::mul(static_cast<vec<C, N>>(x).v, static_cast<vec<C, N>>(y).v); - } - template <typename U, typename C = common_type<U, T>> - friend constexpr CMT_INLINE vec<C, N> operator/(const vec& x, const vec<U, N>& y) - { - return vec_op<C>::div(static_cast<vec<C, N>>(x).v, static_cast<vec<C, N>>(y).v); - } - template <typename U, typename C = common_type<U, T>> - friend constexpr CMT_INLINE vec<C, N> operator%(const vec& x, const vec<U, N>& y) - { - return vec_op<C>::rem(static_cast<vec<C, N>>(x).v, static_cast<vec<C, N>>(y).v); - } - constexpr CMT_INLINE simd_t operator*() const { return v; } constexpr CMT_INLINE simd_t& operator*() { return v; } CMT_INLINE mask<T, N>& asmask() { return ref_cast<mask<T, N>>(*this); } @@ -811,6 +792,72 @@ private: }; }; +namespace operators +{ +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator+(const vec<T1, N>& x, const T2& y) +{ + return vec_op<C>::add(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator-(const vec<T1, N>& x, const T2& y) +{ + return vec_op<C>::sub(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator*(const vec<T1, N>& x, const T2& y) +{ + return vec_op<C>::mul(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator/(const vec<T1, N>& x, const T2& y) +{ + return vec_op<C>::div(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} + +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator+(const T1& x, const vec<T2, N>& y) +{ + return vec_op<C>::add(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator-(const T1& x, const vec<T2, N>& y) +{ + return vec_op<C>::sub(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator*(const T1& x, const vec<T2, N>& y) +{ + return vec_op<C>::mul(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator/(const T1& x, const vec<T2, N>& y) +{ + return vec_op<C>::div(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} + +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator+(const vec<T1, N>& x, const vec<T2, N>& y) +{ + return vec_op<C>::add(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator-(const vec<T1, N>& x, const vec<T2, N>& y) +{ + return vec_op<C>::sub(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator*(const vec<T1, N>& x, const vec<T2, N>& y) +{ + return vec_op<C>::mul(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +template <typename T1, typename T2, size_t N, typename C = common_type<T1, T2>> +constexpr CMT_INLINE vec<C, N> operator/(const vec<T1, N>& x, const vec<T2, N>& y) +{ + return vec_op<C>::div(*static_cast<vec<C, N>>(x), *static_cast<vec<C, N>>(y)); +} +} + template <typename T, size_t N> struct mask : public vec<T, N> { @@ -1252,10 +1299,15 @@ constexpr CMT_INLINE vec<T, N> apply(Fn&& fn) } template <typename T, int N> -CMT_INLINE vec<T, N> tovec(simd<T, N> x) +CMT_INLINE vec<T, N> tovec(const simd<T, N>& x) { return x; } +template <typename T, size_t N> +CMT_INLINE vec<T, N> tovec(const mask<T, N>& x) +{ + return *x; +} #ifdef CMT_ARCH_SSE2 CMT_INLINE f32x4 tovec(__m128 x) { return f32x4(x); } @@ -1443,6 +1495,16 @@ struct common_type<kfr::vec<T1, N>, kfr::vec<T2, N>> { using type = kfr::vec<typename common_type<T1, T2>::type, N>; }; +template <typename T1, typename T2, size_t N> +struct common_type<kfr::vec<T1, N>, T2> +{ + using type = kfr::vec<typename common_type<T1, T2>::type, N>; +}; +template <typename T1, typename T2, size_t N> +struct common_type<T1, kfr::vec<T2, N>> +{ + using type = kfr::vec<typename common_type<T1, T2>::type, N>; +}; template <typename T1, typename T2, size_t N> struct common_type<kfr::mask<T1, N>, kfr::mask<T2, N>> diff --git a/include/kfr/cometa.hpp b/include/kfr/cometa.hpp @@ -198,8 +198,15 @@ struct compound_type_traits<std::pair<T, T>> } }; +namespace ops +{ +struct empty +{ +}; +} + template <typename T, T val> -struct cval_t +struct cval_t : ops::empty { constexpr static T value = val; constexpr cval_t() noexcept = default; @@ -337,7 +344,7 @@ struct get_nth_type<index> } template <typename T, T... values> -struct cvals_t +struct cvals_t : ops::empty { using type = cvals_t<T, values...>; constexpr static size_t size() { return sizeof...(values); } @@ -371,7 +378,7 @@ struct cvals_t }; template <typename T> -struct cvals_t<T> +struct cvals_t<T> : ops::empty { using type = cvals_t<T>; constexpr static size_t size() { return 0; } @@ -591,7 +598,8 @@ constexpr inline Ret cfilter(cvals_t<T, vals...>, cvals_t<bool, flags...>) { \ return Ret{}; \ } - +namespace ops +{ // clang-format off CMT_UN_OP(-) CMT_UN_OP(+) @@ -617,6 +625,7 @@ CMT_BIN_OP(&) CMT_BIN_OP(|) CMT_BIN_OP(^) // clang-format on +} namespace details { diff --git a/include/kfr/dsp/units.hpp b/include/kfr/dsp/units.hpp @@ -38,28 +38,28 @@ using sample_rate_t = double; namespace intrinsics { -template <typename T, typename TF = ftype<T>> +template <typename T, typename TF = flt_type<T>> KFR_SINTRIN TF amp_to_dB(T amp) { return log(static_cast<TF>(amp)) * subtype<TF>(8.6858896380650365530225783783322); // return T( 20.0 ) * log10( level ); } -template <typename T, typename TF = ftype<T>> +template <typename T, typename TF = flt_type<T>> KFR_SINTRIN TF dB_to_amp(T dB) { return exp(dB * subtype<TF>(0.11512925464970228420089957273422)); // return exp10( dB / 20 ); } -template <typename T, typename TF = ftype<T>> +template <typename T, typename TF = flt_type<T>> KFR_SINTRIN TF amp_to_dB(T amp, T offset) { return log_fmadd(amp, subtype<TF>(8.6858896380650365530225783783322), offset); // return T( 20.0 ) * log10( level ); } -template <typename T, typename TF = ftype<T>> +template <typename T, typename TF = flt_type<T>> KFR_SINTRIN TF dB_to_amp(T dB, T offset) { auto offs = -subtype<TF>(0.11512925464970228420089957273422) * offset; @@ -67,51 +67,51 @@ KFR_SINTRIN TF dB_to_amp(T dB, T offset) // return exp10( dB / 20 ); } -template <typename T> -KFR_SINTRIN T power_to_dB(T x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout power_to_dB(T x) { - return log(x) * (10 * c_recip_log_10<T>); + return log(x) * (10 * c_recip_log_10<Tout>); } -template <typename T> -KFR_SINTRIN T dB_to_power(T x) +template <typename T, typename Tout = flt_type<T>> +KFR_SINTRIN Tout dB_to_power(T x) { - if (x == -c_infinity<T>) + if (x == -c_infinity<Tout>) return 0.0; else - return exp(x * (c_log_10<T> / 10.0)); + return exp(x * (c_log_10<Tout> / 10.0)); } -template <typename T, typename TF = ftype<T>> +template <typename T, typename TF = flt_type<T>> KFR_SINTRIN TF note_to_hertz(T note) { const subtype<TF> offset = 2.1011784386926213177653145771814; - return exp_fmadd(note, subtype<TF>(0.05776226504666210911810267678818), offset); + return intrinsics::exp_fmadd(note, subtype<TF>(0.05776226504666210911810267678818), offset); } -template <typename T, typename TF = ftype<T>> +template <typename T, typename TF = flt_type<T>> KFR_SINTRIN TF hertz_to_note(T hertz) { const subtype<TF> offset = -36.376316562295915248836189714583; - return log_fmadd(hertz, subtype<TF>(17.312340490667560888319096172023), offset); + return intrinsics::log_fmadd(hertz, subtype<TF>(17.312340490667560888319096172023), offset); } -template <typename T1, typename T2, typename T3, typename Tc = common_type<T1, T2, T3, f32>> +template <typename T1, typename T2, typename T3, typename Tc = flt_type<common_type<T1, T2, T3, f32>>> KFR_SINTRIN Tc note_to_hertz(T1 note, T2 tunenote, T3 tunehertz) { const Tc offset = log(tunehertz) - tunenote * subtype<Tc>(0.05776226504666210911810267678818); - return exp_fmadd(note, subtype<Tc>(0.05776226504666210911810267678818), offset); + return intrinsics::exp_fmadd(note, subtype<Tc>(0.05776226504666210911810267678818), offset); } -template <typename T1, typename T2, typename T3, typename Tc = common_type<T1, T2, T3, f32>> +template <typename T1, typename T2, typename T3, typename Tc = flt_type<common_type<T1, T2, T3, f32>>> KFR_SINTRIN Tc hertz_to_note(T1 hertz, T2 tunenote, T3 tunehertz) { const Tc offset = tunenote - log(tunehertz) * subtype<Tc>(17.312340490667560888319096172023); - return log_fmadd(hertz, subtype<Tc>(17.312340490667560888319096172023), offset); + return intrinsics::log_fmadd(hertz, subtype<Tc>(17.312340490667560888319096172023), offset); } } KFR_I_FN(note_to_hertz) @@ -122,7 +122,7 @@ KFR_I_FN(power_to_dB) KFR_I_FN(dB_to_power) template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 note_to_hertz(const T1& x) +KFR_INTRIN flt_type<T1> note_to_hertz(const T1& x) { return intrinsics::note_to_hertz(x); } @@ -134,7 +134,7 @@ KFR_INTRIN internal::expression_function<fn::note_to_hertz, E1> note_to_hertz(E1 } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 hertz_to_note(const T1& x) +KFR_INTRIN flt_type<T1> hertz_to_note(const T1& x) { return intrinsics::hertz_to_note(x); } @@ -146,7 +146,7 @@ KFR_INTRIN internal::expression_function<fn::hertz_to_note, E1> hertz_to_note(E1 } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 amp_to_dB(const T1& x) +KFR_INTRIN flt_type<T1> amp_to_dB(const T1& x) { return intrinsics::amp_to_dB(x); } @@ -158,7 +158,7 @@ KFR_INTRIN internal::expression_function<fn::amp_to_dB, E1> amp_to_dB(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 dB_to_amp(const T1& x) +KFR_INTRIN flt_type<T1> dB_to_amp(const T1& x) { return intrinsics::dB_to_amp(x); } @@ -170,7 +170,7 @@ KFR_INTRIN internal::expression_function<fn::dB_to_amp, E1> dB_to_amp(E1&& x) } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 power_to_dB(const T1& x) +KFR_INTRIN flt_type<T1> power_to_dB(const T1& x) { return intrinsics::power_to_dB(x); } @@ -182,7 +182,7 @@ KFR_INTRIN internal::expression_function<fn::power_to_dB, E1> power_to_dB(E1&& x } template <typename T1, KFR_ENABLE_IF(is_numeric<T1>::value)> -KFR_INTRIN T1 dB_to_power(const T1& x) +KFR_INTRIN flt_type<T1> dB_to_power(const T1& x) { return intrinsics::dB_to_power(x); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt @@ -63,29 +63,38 @@ add_executable(complex_test complex_test.cpp ${KFR_SRC}) add_executable(vec_test vec_test.cpp ${KFR_SRC}) add_executable(stat_test stat_test.cpp ${KFR_SRC}) +if (ARM) + find_program(EMULATOR "qemu-arm") +else () + set(EMULATOR "") +endif () + if (NOT IOS) enable_testing() add_test(NAME basic_vector_test - COMMAND ${PROJECT_BINARY_DIR}/tests/basic_vector_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/basic_vector_test) add_test(NAME intrinsic_test - COMMAND ${PROJECT_BINARY_DIR}/tests/intrinsic_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/intrinsic_test) add_test(NAME fracdelay_test - COMMAND ${PROJECT_BINARY_DIR}/tests/fracdelay_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/fracdelay_test) add_test(NAME conv_test - COMMAND ${PROJECT_BINARY_DIR}/tests/conv_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/conv_test) if (MPFR_FOUND) add_test(NAME transcendental_test - COMMAND ${PROJECT_BINARY_DIR}/tests/transcendental_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/transcendental_test) endif () add_test(NAME complex_test - COMMAND ${PROJECT_BINARY_DIR}/tests/complex_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/complex_test) add_test(NAME vec_test - COMMAND ${PROJECT_BINARY_DIR}/tests/vec_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/vec_test) add_test(NAME stat_test - COMMAND ${PROJECT_BINARY_DIR}/tests/stat_test) - add_test(NAME multiarch - COMMAND ${PROJECT_BINARY_DIR}/tests/multiarch) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/stat_test) + + if (NOT ARM) + add_test(NAME multiarch + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/multiarch) + endif () add_test(NAME dft_test - COMMAND ${PROJECT_BINARY_DIR}/tests/dft_test) + COMMAND ${EMULATOR} ${PROJECT_BINARY_DIR}/tests/dft_test) endif () diff --git a/tests/intrinsic_test.cpp b/tests/intrinsic_test.cpp @@ -159,10 +159,12 @@ TEST(intrin_abs) TEST(intrin_sqrt) { testo::assert_is_same<decltype(kfr::sqrt(9)), fbase>(); + testo::assert_is_same<decltype(kfr::intrinsics::sqrt(9)), fbase>(); testo::assert_is_same<decltype(kfr::sqrt(make_vector(9))), vec<fbase, 1>>(); testo::assert_is_same<decltype(kfr::sqrt(make_vector(9, 25))), vec<fbase, 2>>(); - CHECK(kfr::sqrt(9) == 3.0); - CHECK(kfr::sqrt(-9) == qnan); + CHECK(kfr::sqrt(9) == fbase(3.0)); + CHECK(kfr::sqrt(2) == fbase(1.4142135623730950488)); + CHECK(kfr::sqrt(-9) == fbase(qnan)); CHECK(kfr::sqrt(make_vector(9)) == make_vector<fbase>(3.0)); CHECK(kfr::sqrt(make_vector(-9)) == make_vector<fbase>(qnan)); testo::matrix(named("type") = float_types, named("value") = std::vector<int>{ 0, 2, 65536 }, diff --git a/tests/vec_test.cpp b/tests/vec_test.cpp @@ -7,7 +7,7 @@ #include <kfr/io/tostring.hpp> #include "testo/testo.hpp" -#include <kfr/dsp/mixdown.hpp> +#include <kfr/dsp.hpp> #include <kfr/math.hpp> using namespace kfr; @@ -120,17 +120,85 @@ TEST(vec_conv) testo::assert_is_same<common_type<i32, f32>, f32>(); testo::assert_is_same<common_type<f32, f64>, f64>(); testo::assert_is_same<common_type<i32, f32x4>, f32x4>(); - testo::assert_is_same<common_type<f32x4, f64>, f32x4>(); + testo::assert_is_same<common_type<f32x4, f64>, f64x4>(); + testo::assert_is_same<common_type<f64, f32x4>, f64x4>(); testo::assert_is_same<common_type<f32x4, f64x4>, f64x4>(); testo::assert_is_same<decltype(min(1, 2)), int>(); testo::assert_is_same<decltype(min(1, 2u)), unsigned int>(); testo::assert_is_same<decltype(min(1, 2)), int>(); - testo::assert_is_same<decltype(min(pack(1), 2u)), i32x1>(); - testo::assert_is_same<decltype(min(2u, pack(1))), i32x1>(); + testo::assert_is_same<decltype(min(pack(1), 2u)), u32x1>(); + testo::assert_is_same<decltype(min(2u, pack(1))), u32x1>(); testo::assert_is_same<decltype(min(pack(1), pack(2u))), u32x1>(); testo::assert_is_same<decltype(min(pack(1, 2, 3), pack(1.0, 2.0, 3.0))), f64x3>(); testo::assert_is_same<decltype(min(pack(1.0, 2.0, 3.0), pack(1, 2, 3))), f64x3>(); + + testo::assert_is_same<decltype(pack(11) * pack(0.5)), f64x1>(); + testo::assert_is_same<decltype(pack(11) * 0.5), f64x1>(); + + testo::assert_is_same<decltype(kfr::sin(2)), fbase>(); + testo::assert_is_same<decltype(kfr::sin(pack(2))), vec<fbase, 1>>(); + testo::assert_is_same<decltype(kfr::sindeg(2)), fbase>(); + testo::assert_is_same<decltype(kfr::sindeg(pack(2))), vec<fbase, 1>>(); + + CHECK(pack(11) * pack(0.5) == 5.5); + CHECK(pack(11) * 0.5 == 5.5); + CHECK(kfr::sin(2) == fbase(0.90929742682568169539601986591174)); + CHECK(kfr::sin(pack(2)) == pack(fbase(0.90929742682568169539601986591174))); + CHECK(kfr::sindeg(2) == fbase(0.03489949670250097164599518162533)); + CHECK(kfr::sindeg(pack(2)) == pack(fbase(0.03489949670250097164599518162533))); + CHECK(kfr::cos(2) == fbase(-0.41614683654714238699756822950076)); + CHECK(kfr::cos(pack(2)) == pack(fbase(-0.41614683654714238699756822950076))); + CHECK(kfr::cosdeg(2) == fbase(0.99939082701909573000624344004393)); + CHECK(kfr::cosdeg(pack(2)) == pack(fbase(0.99939082701909573000624344004393))); + + CHECK(kfr::log(2) == fbase(0.6931471805599453)); + CHECK(kfr::log(pack(2)) == pack(fbase(0.6931471805599453))); + CHECK(kfr::log2(2) == fbase(1.0)); + CHECK(kfr::log2(pack(2)) == pack(fbase(1.0))); + CHECK(kfr::log10(2) == fbase(0.30102999566398119521373889472449)); + CHECK(kfr::log10(pack(2)) == pack(fbase(0.30102999566398119521373889472449))); + + CHECK(kfr::exp(2) == fbase(7.3890560989306502)); + CHECK(kfr::exp(pack(2)) == pack(fbase(7.3890560989306502))); + CHECK(kfr::exp2(2) == fbase(4.0)); + CHECK(kfr::exp2(pack(2)) == pack(fbase(4.0))); + + CHECK(kfr::logn(2, 10) == fbase(0.30102999566398119521373889472449)); + CHECK(kfr::logn(pack(2), pack(10)) == pack(fbase(0.30102999566398119521373889472449))); + + CHECK(kfr::pow(2, fbase(0.9)) == fbase(1.8660659830736148319626865322999)); + CHECK(kfr::pow(pack(2), pack(fbase(0.9))) == pack(fbase(1.8660659830736148319626865322999))); + + CHECK(kfr::root(fbase(1.5), 2) == fbase(1.2247448713915890490986420373529)); + CHECK(kfr::root(pack(fbase(1.5)), pack(2)) == pack(fbase(1.2247448713915890490986420373529))); + + testo::epsilon<float>() *= 10.0; + testo::epsilon<double>() *= 10.0; + + CHECK(kfr::sinh(2) == fbase(3.6268604078470187676682139828013)); + CHECK(kfr::sinh(pack(2)) == pack(fbase(3.6268604078470187676682139828013))); + CHECK(kfr::cosh(2) == fbase(3.7621956910836314595622134777737)); + CHECK(kfr::cosh(pack(2)) == pack(fbase(3.7621956910836314595622134777737))); + + CHECK(kfr::tanh(2) == fbase(0.96402758007581688394641372410092)); + CHECK(kfr::tanh(pack(2)) == pack(fbase(0.96402758007581688394641372410092))); + CHECK(kfr::coth(2) == fbase(1.0373147207275480958778097647678)); + CHECK(kfr::coth(pack(2)) == pack(fbase(1.0373147207275480958778097647678))); + + testo::epsilon<float>() *= 10.0; + testo::epsilon<double>() *= 10.0; + + CHECK(kfr::tan(2) == fbase(-2.1850398632615189916433061023137)); + CHECK(kfr::tan(pack(2)) == pack(fbase(-2.1850398632615189916433061023137))); + CHECK(kfr::tandeg(2) == fbase(0.03492076949174773050040262577373)); + CHECK(kfr::tandeg(pack(2)) == pack(fbase(0.03492076949174773050040262577373))); + + testo::epsilon<float>() *= 10.0; + testo::epsilon<double>() *= 10.0; + + CHECK(kfr::note_to_hertz(60) == fbase(261.6255653005986346778499935233)); + CHECK(kfr::note_to_hertz(pack(60)) == pack(fbase(261.6255653005986346778499935233))); } TEST(vec_matrix)