diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index 5500d832..9f656b78 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -52,7 +54,11 @@ #include #include #include +#include #include +#include +#include #include #include +#include #include diff --git a/include/kyosu/functions/cosh.hpp b/include/kyosu/functions/cosh.hpp new file mode 100644 index 00000000..5771216f --- /dev/null +++ b/include/kyosu/functions/cosh.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_cosh : eve::elementwise + { + using callable_tag_type = callable_cosh; + + KYOSU_DEFERS_CALLABLE(cosh_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::cosh(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var cosh +//! @brief Computes the hyperbolic cosine of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T cosh(T z) noexcept; +//! template constexpr T cosh(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the hyperbolic cosine of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/cosh.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_cosh cosh = {}; +} diff --git a/include/kyosu/functions/coth.hpp b/include/kyosu/functions/coth.hpp new file mode 100644 index 00000000..70b3099a --- /dev/null +++ b/include/kyosu/functions/coth.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_coth : eve::elementwise + { + using callable_tag_type = callable_coth; + + KYOSU_DEFERS_CALLABLE(coth_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::coth(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var coth +//! @brief Computes the hyperbolic cotangent of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T coth(T z) noexcept; +//! template constexpr T coth(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the hyperbolic cotangent of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/coth.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_coth coth = {}; +} diff --git a/include/kyosu/functions/rec.hpp b/include/kyosu/functions/rec.hpp new file mode 100644 index 00000000..f8b70397 --- /dev/null +++ b/include/kyosu/functions/rec.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_rec : eve::elementwise + { + using callable_tag_type = callable_rec; + + KYOSU_DEFERS_CALLABLE(rec_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::rec(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var rec +//! @brief Computes the inverse of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T rec(T z) noexcept; +//! template constexpr T rec(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the inverse of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/rec.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_rec rec = {}; +} diff --git a/include/kyosu/functions/sinh.hpp b/include/kyosu/functions/sinh.hpp new file mode 100644 index 00000000..aeea7dc3 --- /dev/null +++ b/include/kyosu/functions/sinh.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_sinh : eve::elementwise + { + using callable_tag_type = callable_sinh; + + KYOSU_DEFERS_CALLABLE(sinh_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::sinh(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var sinh +//! @brief Computes the hyperbolic sine of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T sinh(T z) noexcept; +//! template constexpr T sinh(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the hyperbolic sine of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sinh.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sinh sinh = {}; +} diff --git a/include/kyosu/functions/sinhcosh.hpp b/include/kyosu/functions/sinhcosh.hpp new file mode 100644 index 00000000..74cb60a1 --- /dev/null +++ b/include/kyosu/functions/sinhcosh.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_sinhcosh : eve::elementwise + { + using callable_tag_type = callable_sinhcosh; + + KYOSU_DEFERS_CALLABLE(sinhcosh_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::sinhcosh(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var sinhcosh +//! @brief Computes simultaneously the hyperbolic sine and cosine of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto sinhcosh(T z) noexcept; +//! template constexpr auto sinhcosh(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns simultaneously the hyperbolic sine and cosine of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sinhcosh.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sinhcosh sinhcosh = {}; +} diff --git a/include/kyosu/functions/tanh.hpp b/include/kyosu/functions/tanh.hpp new file mode 100644 index 00000000..71d81642 --- /dev/null +++ b/include/kyosu/functions/tanh.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_tanh : eve::elementwise + { + using callable_tag_type = callable_tanh; + + KYOSU_DEFERS_CALLABLE(tanh_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::tanh(v); } + + template + KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) + { + return eve::tag_invoke(*this, target); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var tanh +//! @brief Computes the hyperbolic tangent of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T tanh(T z) noexcept; +//! template constexpr T tanh(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the hyperbolic tangent of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/tanh.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_tanh tanh = {}; +} diff --git a/include/kyosu/types/cayley_dickson.hpp b/include/kyosu/types/cayley_dickson.hpp index c00b911b..4910c2c5 100644 --- a/include/kyosu/types/cayley_dickson.hpp +++ b/include/kyosu/types/cayley_dickson.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace kyosu diff --git a/include/kyosu/types/impl/arithmetic.hpp b/include/kyosu/types/impl/arithmetic.hpp index 8e7a65ac..9de796bd 100644 --- a/include/kyosu/types/impl/arithmetic.hpp +++ b/include/kyosu/types/impl/arithmetic.hpp @@ -168,4 +168,11 @@ namespace kyosu::_ real(c) = 0; return c; } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C c) noexcept + { + return conj(c)/sqr_abs(c); + } } diff --git a/include/kyosu/types/impl/trigo.hpp b/include/kyosu/types/impl/trigo.hpp new file mode 100644 index 00000000..ccca98e0 --- /dev/null +++ b/include/kyosu/types/impl/trigo.hpp @@ -0,0 +1,154 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::_ +{ + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto [rz, iz] = z; + auto [s, c] = eve::sincos(iz); + auto [sh, ch] = eve::sinhcosh(rz); + auto r = c*ch; + auto i = s*sh; + i = eve::if_else(kyosu::is_eqz(kyosu::ipart(z)) || kyosu::is_real(z), eve::zero, i); + auto res = to_complex(r, i); + if (eve::any(kyosu::is_not_finite(z))) + { + res = eve::if_else(eve::is_infinite(rz) && eve::is_not_finite(iz), to_complex(eve::inf(eve::as(rz)), eve::nan(eve::as(rz))), res); + res = eve::if_else(eve::is_nan(rz) && eve::is_infinite(iz), to_complex(eve::nan(eve::as(rz)), eve::nan(eve::as(rz))), res); + } + return res; + } + else + { + auto e = kyosu::exp(z); + return eve::average(e, rec(e)); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto [rz, iz] = z; + auto [s, c] = eve::sincos(iz); + auto [sh, ch] = eve::sinhcosh(rz); + auto r = c*sh; + auto i = s*ch; + if (eve::all(kyosu::is_finite(z))) return to_complex(r, i); + auto infrz = kyosu::is_infinite(rz); + auto nanrz = kyosu::is_nan(rz); + if (eve::any(infrz || nanrz)) + { + r = eve::if_else(infrz && eve::is_not_finite(iz), rz, r); + i = eve::if_else(infrz && eve::is_nan(iz), eve::allbits, i); + r = eve::if_else(nanrz, eve::allbits, r); + i = eve::if_else(nanrz, eve::allbits, i); + } + i = eve::if_else(kyosu::is_real(z), eve::zero, i); + r = eve::if_else(kyosu::is_eqz(kyosu::real(z)), eve::zero, r); + return to_complex(r, i); + } + else + { + auto e = kyosu::exp(z); + return eve::average(e, -kyosu::rec(e)); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto [rz, iz] = z; + auto [s, c] = eve::sincos(iz); + auto [sh, ch] = eve::sinhcosh(rz); + auto rs = c*sh; + auto is = s*ch; + auto infrz = eve::is_infinite(rz); + auto nanrz = eve::is_nan(rz); + if (eve::any(infrz || nanrz)) + { + rs = eve::if_else(infrz && eve::is_not_finite(iz), rz, rs); + is = eve::if_else(infrz && eve::is_nan(iz), eve::allbits, is); + rs = eve::if_else(nanrz, eve::allbits, rs); + is = eve::if_else(nanrz, eve::allbits, is); + } + is = eve::if_else(kyosu::is_real(z), eve::zero, is); + rs = eve::if_else(kyosu::is_eqz(kyosu::real(z)), eve::zero, rs); + auto ss = to_complex(rs, is); + + auto rc = c*ch; + auto ic = s*sh; + ic = eve::if_else(kyosu::is_eqz(kyosu::real(z)) || kyosu::is_real(z), eve::zero, ic); + auto cc = to_complex(rc, ic); + if (eve::any(kyosu::is_not_finite(z))) + { + cc = kyosu::if_else(infrz && is_not_finite(iz), to_complex(eve::inf(eve::as(rz)), eve::nan(eve::as(rz))), cc); + cc = kyosu::if_else(nanrz && is_infinite(iz), to_complex(eve::nan(eve::as(rz)), eve::nan(eve::as(rz))), cc); + } + return kumi::tuple{ss, cc}; + } + else + { + auto e = kyosu::exp(z); + auto ie = kyosu::rec(e); + return kumi::tuple{ eve::average(e, -ie), eve::average(e, ie)}; + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto zz = z+z; + auto [rz, iz] = zz; + auto [s, c] = eve::sincos(iz); + auto [sh, ch] = eve::sinhcosh(rz); + auto tmp = c+ch; + auto rr = eve::if_else(eve::is_eqz(kyosu::real(z)), eve::zero, sh/tmp); + auto ii = eve::if_else(kyosu::is_real(z), eve::zero, s/tmp); + return kyosu::if_else(eve::is_infinite(rz), kyosu::to_complex(eve::sign(rz)), kyosu::to_complex(rr, ii)); + } + else + { + auto e = kyosu::expm1(z+z); + return e/(e+2); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + return kyosu::rec(kyosu::tanh(z)); + } + else + { + auto e = kyosu::expm1(z+z); + return (e+2)/e; + } + } + +} diff --git a/test/unit/complex/cosh.cpp b/test/unit/complex/cosh.cpp new file mode 100644 index 00000000..2b00ac7f --- /dev/null +++ b/test/unit/complex/cosh.cpp @@ -0,0 +1,48 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include +#include + +template < typename T > +auto cv(std::complex < T > const &sc) +{ + return kyosu::to_complex(sc.real(), sc.imag()); +} + +TTS_CASE_WITH( "Check behavior of cosh on scalar" + , tts::bunch + , tts::generate( tts::randoms(-10, 10), tts::randoms(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = typename T::value_type; + using c_t = std::complex; + using kc_t = kyosu::as_complex_t; + for(size_t i = 0; i < a0.size(); ++i) + { + auto e = a0[i]; + auto f = a1[i]; + + TTS_RELATIVE_EQUAL(kyosu::cosh(kc_t(e, f)), cv(std::cosh(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of cosh on wide" + , kyosu::simd_real_types + , tts::generate( tts::between(-10, 10) + , tts::between(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = T; + using ke_t = kyosu::as_complex_t; + using c_t = std::complex>; + ke_t e([&](auto i, auto){return cv(std::cosh(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::cosh(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/coth.cpp b/test/unit/complex/coth.cpp new file mode 100644 index 00000000..c3c6c998 --- /dev/null +++ b/test/unit/complex/coth.cpp @@ -0,0 +1,47 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include +#include + +template < typename T > +auto cv(std::complex < T > const &sc) +{ + return kyosu::to_complex(sc.real(), sc.imag()); +} + +TTS_CASE_WITH( "Check behavior of coth on scalar" + , tts::bunch + , tts::generate( tts::randoms(-10, 10), tts::randoms(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = typename T::value_type; + using c_t = std::complex; + using kc_t = kyosu::as_complex_t; + for(size_t i = 0; i < a0.size(); ++i) + { + auto e = a0[i]; + auto f = a1[i]; + TTS_RELATIVE_EQUAL(kyosu::coth(kc_t(e, f)), kyosu::rec(cv(std::tanh(c_t(e, f)))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of coth on wide" + , kyosu::simd_real_types + , tts::generate( tts::between(-10, 10) + , tts::between(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = T; + using ke_t = kyosu::as_complex_t; + using c_t = std::complex>; + ke_t e([&](auto i, auto){return kyosu::rec(cv(std::tanh(c_t(a0.get(i), a1.get(i))))); }); + TTS_RELATIVE_EQUAL(kyosu::coth(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/sinh.cpp b/test/unit/complex/sinh.cpp new file mode 100644 index 00000000..e88e89b1 --- /dev/null +++ b/test/unit/complex/sinh.cpp @@ -0,0 +1,48 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include +#include + +template < typename T > +auto cv(std::complex < T > const &sc) +{ + return kyosu::to_complex(sc.real(), sc.imag()); +} + +TTS_CASE_WITH( "Check behavior of sinh on scalar" + , tts::bunch + , tts::generate( tts::randoms(-10, 10), tts::randoms(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = typename T::value_type; + using c_t = std::complex; + using kc_t = kyosu::as_complex_t; + for(size_t i = 0; i < a0.size(); ++i) + { + auto e = a0[i]; + auto f = a1[i]; + + TTS_RELATIVE_EQUAL(kyosu::sinh(kc_t(e, f)), cv(std::sinh(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of sinh on wide" + , kyosu::simd_real_types + , tts::generate( tts::between(-10, 10) + , tts::between(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = T; + using ke_t = kyosu::as_complex_t; + using c_t = std::complex>; + ke_t e([&](auto i, auto){return cv(std::sinh(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::sinh(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/sinhcosh.cpp b/test/unit/complex/sinhcosh.cpp new file mode 100644 index 00000000..aff4cf2e --- /dev/null +++ b/test/unit/complex/sinhcosh.cpp @@ -0,0 +1,43 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include +#include + + +TTS_CASE_WITH( "Check behavior of sinhcosh on scalar" + , tts::bunch + , tts::generate( tts::randoms(-10, 10), tts::randoms(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = typename T::value_type; + using kc_t = kyosu::as_complex_t; + for(size_t i = 0; i < a0.size(); ++i) + { + auto e = kc_t(a0[i], a1[i]); + auto [s, c] = kyosu::sinhcosh(e); + TTS_RELATIVE_EQUAL(c, kyosu::cosh(e), 1.0e-6); + TTS_RELATIVE_EQUAL(s, kyosu::sinh(e), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of sinhcosh on wide" + , kyosu::simd_real_types + , tts::generate( tts::between(-10, 10) + , tts::between(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = T; + using ke_t = kyosu::as_complex_t; + auto e = ke_t(a0, a1); + auto [s, c] = kyosu::sinhcosh(e); + TTS_RELATIVE_EQUAL(c, kyosu::cosh(e), 1.0e-6); + TTS_RELATIVE_EQUAL(s, kyosu::sinh(e), 1.0e-6); +}; diff --git a/test/unit/complex/tanh.cpp b/test/unit/complex/tanh.cpp new file mode 100644 index 00000000..85456aa5 --- /dev/null +++ b/test/unit/complex/tanh.cpp @@ -0,0 +1,48 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include +#include + +template < typename T > +auto cv(std::complex < T > const &sc) +{ + return kyosu::to_complex(sc.real(), sc.imag()); +} + +TTS_CASE_WITH( "Check behavior of tanh on scalar" + , tts::bunch + , tts::generate( tts::randoms(-10, 10), tts::randoms(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = typename T::value_type; + using c_t = std::complex; + using kc_t = kyosu::as_complex_t; + for(size_t i = 0; i < a0.size(); ++i) + { + auto e = a0[i]; + auto f = a1[i]; + + TTS_RELATIVE_EQUAL(kyosu::tanh(kc_t(e, f)), cv(std::tanh(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of tanh on wide" + , kyosu::simd_real_types + , tts::generate( tts::between(-10, 10) + , tts::between(-10, 10)) + ) + (T const& a0, T const& a1 ) +{ + using e_t = T; + using ke_t = kyosu::as_complex_t; + using c_t = std::complex>; + ke_t e([&](auto i, auto){return cv(std::tanh(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::tanh(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/function/cosh.cpp b/test/unit/function/cosh.cpp new file mode 100644 index 00000000..586328b0 --- /dev/null +++ b/test/unit/function/cosh.cpp @@ -0,0 +1,49 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +# if __has_include () +# include +# define HAS_BOOST +# endif + +TTS_CASE_WITH ( "Check kyosu::cosh over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::cosh(data), eve::cosh(data), 0.5); +}; + +#ifdef HAS_BOOST + +template < typename T > +auto cv(boost::math::quaternion const &bq) +{ + return kyosu::quaternion(bq.R_component_1(), bq.R_component_2(), + bq.R_component_3(), bq.R_component_4()); +} + +TTS_CASE_WITH ( "Check kyosu::cosh over quaternion" + , kyosu::simd_real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r, T i, T j, T k) +{ + using ke_t = kyosu::as_quaternion_t; + using bq_t = boost::math::quaternion>; + auto boost_cosh = [](auto x, auto y, auto z, auto t){return cv(boost::math::cosh(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_cosh(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::cosh(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/coth.cpp b/test/unit/function/coth.cpp new file mode 100644 index 00000000..23800aa8 --- /dev/null +++ b/test/unit/function/coth.cpp @@ -0,0 +1,49 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +# if __has_include () +# include +# define HAS_BOOST +# endif + +TTS_CASE_WITH ( "Check kyosu::coth over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::coth(data), eve::coth(data), 0.5); +}; + +#ifdef HAS_BOOST + +template < typename T > +auto cv(boost::math::quaternion const &bq) +{ + return kyosu::quaternion(bq.R_component_1(), bq.R_component_2(), + bq.R_component_3(), bq.R_component_4()); +} + +TTS_CASE_WITH ( "Check kyosu::coth over quaternion" + , kyosu::simd_real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r, T i, T j, T k) +{ + using ke_t = kyosu::as_quaternion_t; + using bq_t = boost::math::quaternion>; + auto boost_coth = [](auto x, auto y, auto z, auto t){return kyosu::rec(cv(boost::math::tanh(bq_t(x, y, z, t)))); }; + ke_t e([&](auto n, auto){return boost_coth(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::coth(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/rec.cpp b/test/unit/function/rec.cpp new file mode 100644 index 00000000..5a987c1d --- /dev/null +++ b/test/unit/function/rec.cpp @@ -0,0 +1,33 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::rec over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::rec(data), eve::rec(data), 0.5); +}; + + +TTS_CASE_WITH ( "Check kyosu::rec over quaternion" + , kyosu::simd_real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r, T i, T j, T k) +{ + auto o = eve::one(eve::as(eve::underlying_type_t())); + using ke_t = kyosu::as_quaternion_t; + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::rec(q), o/q, 1e-5); +}; diff --git a/test/unit/function/sinh.cpp b/test/unit/function/sinh.cpp new file mode 100644 index 00000000..a896146e --- /dev/null +++ b/test/unit/function/sinh.cpp @@ -0,0 +1,49 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +# if __has_include () +# include +# define HAS_BOOST +# endif + +TTS_CASE_WITH ( "Check kyosu::sinh over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::sinh(data), eve::sinh(data), 0.5); +}; + +#ifdef HAS_BOOST + +template < typename T > +auto cv(boost::math::quaternion const &bq) +{ + return kyosu::quaternion(bq.R_component_1(), bq.R_component_2(), + bq.R_component_3(), bq.R_component_4()); +} + +TTS_CASE_WITH ( "Check kyosu::sinh over quaternion" + , kyosu::simd_real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r, T i, T j, T k) +{ + using ke_t = kyosu::as_quaternion_t; + using bq_t = boost::math::quaternion>; + auto boost_sinh = [](auto x, auto y, auto z, auto t){return cv(boost::math::sinh(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_sinh(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::sinh(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/sinhcosh.cpp b/test/unit/function/sinhcosh.cpp new file mode 100644 index 00000000..435fef3b --- /dev/null +++ b/test/unit/function/sinhcosh.cpp @@ -0,0 +1,38 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::sinh over quaternion" + , kyosu::simd_real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r, T i, T j, T k) +{ + { + auto [s, c] = kyosu::sinhcosh(r); + TTS_RELATIVE_EQUAL(s, kyosu::sinh(r), 1e-5); + TTS_RELATIVE_EQUAL(c, kyosu::cosh(r), 1e-5); + } + { + using ke_t = kyosu::as_complex_t; + auto cq= ke_t(r,i); + auto [s, c] = kyosu::sinhcosh(cq); + TTS_RELATIVE_EQUAL(s, kyosu::sinh(cq), 1e-5); + TTS_RELATIVE_EQUAL(c, kyosu::cosh(cq), 1e-5); + } + { + using ke_t = kyosu::as_quaternion_t; + auto q = ke_t(r,i,j,k); + auto [s, c] = kyosu::sinhcosh(q); + TTS_RELATIVE_EQUAL(s, kyosu::sinh(q), 1e-5); + TTS_RELATIVE_EQUAL(c, kyosu::cosh(q), 1e-5); + } +}; diff --git a/test/unit/function/tanh.cpp b/test/unit/function/tanh.cpp new file mode 100644 index 00000000..586328b0 --- /dev/null +++ b/test/unit/function/tanh.cpp @@ -0,0 +1,49 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +# if __has_include () +# include +# define HAS_BOOST +# endif + +TTS_CASE_WITH ( "Check kyosu::cosh over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::cosh(data), eve::cosh(data), 0.5); +}; + +#ifdef HAS_BOOST + +template < typename T > +auto cv(boost::math::quaternion const &bq) +{ + return kyosu::quaternion(bq.R_component_1(), bq.R_component_2(), + bq.R_component_3(), bq.R_component_4()); +} + +TTS_CASE_WITH ( "Check kyosu::cosh over quaternion" + , kyosu::simd_real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r, T i, T j, T k) +{ + using ke_t = kyosu::as_quaternion_t; + using bq_t = boost::math::quaternion>; + auto boost_cosh = [](auto x, auto y, auto z, auto t){return cv(boost::math::cosh(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_cosh(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::cosh(q), e, 1e-5); +}; +# endif