From 8c700d5977ce329fb128206a0a1040f2729347eb Mon Sep 17 00:00:00 2001 From: jtlap Date: Thu, 31 Aug 2023 11:49:46 +0200 Subject: [PATCH] [FEATURE] log familly, circular trigonometrics and co-trigo functions --- include/kyosu/functions.hpp | 15 ++ include/kyosu/functions/cos.hpp | 74 ++++++++++ include/kyosu/functions/cot.hpp | 74 ++++++++++ include/kyosu/functions/csc.hpp | 74 ++++++++++ include/kyosu/functions/csch.hpp | 74 ++++++++++ include/kyosu/functions/log.hpp | 79 ++++++++++ include/kyosu/functions/log10.hpp | 79 ++++++++++ include/kyosu/functions/log1p.hpp | 79 ++++++++++ include/kyosu/functions/log2.hpp | 79 ++++++++++ include/kyosu/functions/sec.hpp | 74 ++++++++++ include/kyosu/functions/sech.hpp | 74 ++++++++++ include/kyosu/functions/sign.hpp | 76 ++++++++++ include/kyosu/functions/sin.hpp | 74 ++++++++++ include/kyosu/functions/sincos.hpp | 74 ++++++++++ include/kyosu/functions/sqrt.hpp | 80 ++++++++++ include/kyosu/functions/tan.hpp | 74 ++++++++++ include/kyosu/types/impl/arithmetic.hpp | 8 + include/kyosu/types/impl/math.hpp | 188 ++++++++++++++++++++++++ include/kyosu/types/impl/predicates.hpp | 2 +- include/kyosu/types/impl/trigo.hpp | 123 ++++++++++++++++ test/doc/if_else.cpp | 18 +++ test/unit/complex/cos.cpp | 48 ++++++ test/unit/complex/cot.cpp | 47 ++++++ test/unit/complex/csc.cpp | 47 ++++++ test/unit/complex/log.cpp | 118 +++++++++++++++ test/unit/complex/log10.cpp | 48 ++++++ test/unit/complex/log1p.cpp | 48 ++++++ test/unit/complex/log2.cpp | 50 +++++++ test/unit/complex/sec.cpp | 47 ++++++ test/unit/complex/sin.cpp | 48 ++++++ test/unit/complex/sincos.cpp | 43 ++++++ test/unit/complex/sqrt.cpp | 106 +++++++++++++ test/unit/complex/tan.cpp | 48 ++++++ test/unit/function/cos.cpp | 49 ++++++ test/unit/function/cot.cpp | 49 ++++++ test/unit/function/csc.cpp | 49 ++++++ test/unit/function/log.cpp | 32 ++++ test/unit/function/log10.cpp | 32 ++++ test/unit/function/log1p.cpp | 37 +++++ test/unit/function/log2.cpp | 32 ++++ test/unit/function/sec.cpp | 49 ++++++ test/unit/function/sin.cpp | 49 ++++++ test/unit/function/sincos.cpp | 38 +++++ test/unit/function/tan.cpp | 49 ++++++ test/unit/function/tanh.cpp | 12 +- 45 files changed, 2660 insertions(+), 7 deletions(-) create mode 100644 include/kyosu/functions/cos.hpp create mode 100644 include/kyosu/functions/cot.hpp create mode 100644 include/kyosu/functions/csc.hpp create mode 100644 include/kyosu/functions/csch.hpp create mode 100644 include/kyosu/functions/log.hpp create mode 100644 include/kyosu/functions/log10.hpp create mode 100644 include/kyosu/functions/log1p.hpp create mode 100644 include/kyosu/functions/log2.hpp create mode 100644 include/kyosu/functions/sec.hpp create mode 100644 include/kyosu/functions/sech.hpp create mode 100644 include/kyosu/functions/sign.hpp create mode 100644 include/kyosu/functions/sin.hpp create mode 100644 include/kyosu/functions/sincos.hpp create mode 100644 include/kyosu/functions/sqrt.hpp create mode 100644 include/kyosu/functions/tan.hpp create mode 100644 test/doc/if_else.cpp create mode 100644 test/unit/complex/cos.cpp create mode 100644 test/unit/complex/cot.cpp create mode 100644 test/unit/complex/csc.cpp create mode 100644 test/unit/complex/log.cpp create mode 100644 test/unit/complex/log10.cpp create mode 100644 test/unit/complex/log1p.cpp create mode 100644 test/unit/complex/log2.cpp create mode 100644 test/unit/complex/sec.cpp create mode 100644 test/unit/complex/sin.cpp create mode 100644 test/unit/complex/sincos.cpp create mode 100644 test/unit/complex/sqrt.cpp create mode 100644 test/unit/complex/tan.cpp create mode 100644 test/unit/function/cos.cpp create mode 100644 test/unit/function/cot.cpp create mode 100644 test/unit/function/csc.cpp create mode 100644 test/unit/function/log.cpp create mode 100644 test/unit/function/log10.cpp create mode 100644 test/unit/function/log1p.cpp create mode 100644 test/unit/function/log2.cpp create mode 100644 test/unit/function/sec.cpp create mode 100644 test/unit/function/sin.cpp create mode 100644 test/unit/function/sincos.cpp create mode 100644 test/unit/function/tan.cpp diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index eef42653..b5072b0c 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -14,9 +14,13 @@ #include #include #include +#include #include +#include #include #include +#include +#include #include #include #include @@ -49,6 +53,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -57,9 +65,16 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include #include #include diff --git a/include/kyosu/functions/cos.hpp b/include/kyosu/functions/cos.hpp new file mode 100644 index 00000000..c0dba1df --- /dev/null +++ b/include/kyosu/functions/cos.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_cos : eve::elementwise + { + using callable_tag_type = callable_cos; + + KYOSU_DEFERS_CALLABLE(cos_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::cos(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 cos +//! @brief Computes the cosine of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T cos(T z) noexcept; +//! template constexpr T cos(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the cosine of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/cos.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_cos cos = {}; +} diff --git a/include/kyosu/functions/cot.hpp b/include/kyosu/functions/cot.hpp new file mode 100644 index 00000000..fad74592 --- /dev/null +++ b/include/kyosu/functions/cot.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_cot : eve::elementwise + { + using callable_tag_type = callable_cot; + + KYOSU_DEFERS_CALLABLE(cot_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::cot(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 cot +//! @brief Computes the cotangent of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T cot(T z) noexcept; +//! template constexpr T cot(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the cotangent of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/cot.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_cot cot = {}; +} diff --git a/include/kyosu/functions/csc.hpp b/include/kyosu/functions/csc.hpp new file mode 100644 index 00000000..3d5378fd --- /dev/null +++ b/include/kyosu/functions/csc.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_csc : eve::elementwise + { + using callable_tag_type = callable_csc; + + KYOSU_DEFERS_CALLABLE(csc_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::csc(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 csc +//! @brief Computes the cosecant of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T csc(T z) noexcept; +//! template constexpr T csc(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the cosecant of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/csc.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_csc csc = {}; +} diff --git a/include/kyosu/functions/csch.hpp b/include/kyosu/functions/csch.hpp new file mode 100644 index 00000000..9ccb225f --- /dev/null +++ b/include/kyosu/functions/csch.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_csch : eve::elementwise + { + using callable_tag_type = callable_csch; + + KYOSU_DEFERS_CALLABLE(csch_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::csch(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 csch +//! @brief Computes the hyperbolic cscant of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T csch(T z) noexcept; +//! template constexpr T csch(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the hyperbolic cscant of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/csch.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_csch csch = {}; +} diff --git a/include/kyosu/functions/log.hpp b/include/kyosu/functions/log.hpp new file mode 100644 index 00000000..56149962 --- /dev/null +++ b/include/kyosu/functions/log.hpp @@ -0,0 +1,79 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include +#include + +namespace kyosu::tags +{ + struct callable_log : eve::elementwise + { + using callable_tag_type = callable_log; + + KYOSU_DEFERS_CALLABLE(log_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + auto fn = callable_log{}; + return fn( kyosu::to_complex(v, T(0))); + } + + 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 log +//! @brief Computes the natural logarithm of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constlogr T log(T z) noexcept; +//! template constlogr T log(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the `log(z)`. If z is an ordered value log returns a complex typed value. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/log.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_log log = {}; +} diff --git a/include/kyosu/functions/log10.hpp b/include/kyosu/functions/log10.hpp new file mode 100644 index 00000000..c1bb477d --- /dev/null +++ b/include/kyosu/functions/log10.hpp @@ -0,0 +1,79 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include +#include + +namespace kyosu::tags +{ + struct callable_log10 : eve::elementwise + { + using callable_tag_type = callable_log10; + + KYOSU_DEFERS_CALLABLE(log10_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + auto fn = callable_log10{}; + return fn( kyosu::to_complex(v, T(0))); + } + + 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 log10 +//! @brief Computes the base 10 logarithm of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T log10(T z) noexcept; +//! template constexpr as_complex_t log10(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the `log10(z)`. If z is an ordered value log10 returns a complex typed value. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/log10.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_log10 log10 = {}; +} diff --git a/include/kyosu/functions/log1p.hpp b/include/kyosu/functions/log1p.hpp new file mode 100644 index 00000000..e7dbf404 --- /dev/null +++ b/include/kyosu/functions/log1p.hpp @@ -0,0 +1,79 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include +#include + +namespace kyosu::tags +{ + struct callable_log1p : eve::elementwise + { + using callable_tag_type = callable_log1p; + + KYOSU_DEFERS_CALLABLE(log1p_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + auto fn = callable_log1p{}; + return fn( kyosu::to_complex(v, T(0))); + } + + 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 log1p +//! @brief Computes the natural logarithm of the argument plus 1. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T log1p(T z) noexcept; +//! template constexpr as_complex_t log1p(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the `log1p(1+z)`. If z is an ordered value log1p returns a complex typed value. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/log1p.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_log1p log1p = {}; +} diff --git a/include/kyosu/functions/log2.hpp b/include/kyosu/functions/log2.hpp new file mode 100644 index 00000000..e8b3a5de --- /dev/null +++ b/include/kyosu/functions/log2.hpp @@ -0,0 +1,79 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include +#include + +namespace kyosu::tags +{ + struct callable_log2 : eve::elementwise + { + using callable_tag_type = callable_log2; + + KYOSU_DEFERS_CALLABLE(log2_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + auto fn = callable_log2{}; + return fn( kyosu::to_complex(v, T(0))); + } + + 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 log2 +//! @brief Computes the base 2 logarithm of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T log2(T z) noexcept; +//! template constexpr as_complex_t log2(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the `log2(z)`. If z is an ordered value log2 returns a complex typed value. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/log2.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_log2 log2 = {}; +} diff --git a/include/kyosu/functions/sec.hpp b/include/kyosu/functions/sec.hpp new file mode 100644 index 00000000..a0450308 --- /dev/null +++ b/include/kyosu/functions/sec.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_sec : eve::elementwise + { + using callable_tag_type = callable_sec; + + KYOSU_DEFERS_CALLABLE(sec_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::sec(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 sec +//! @brief Computes the secant of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T sec(T z) noexcept; +//! template constexpr T sec(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the secant of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sec.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sec sec = {}; +} diff --git a/include/kyosu/functions/sech.hpp b/include/kyosu/functions/sech.hpp new file mode 100644 index 00000000..15d48fa9 --- /dev/null +++ b/include/kyosu/functions/sech.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_sech : eve::elementwise + { + using callable_tag_type = callable_sech; + + KYOSU_DEFERS_CALLABLE(sech_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::sech(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 sech +//! @brief Computes the hyperbolic secant of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T sech(T z) noexcept; +//! template constexpr T sech(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the hyperbolic secant of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sech.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sech sech = {}; +} diff --git a/include/kyosu/functions/sign.hpp b/include/kyosu/functions/sign.hpp new file mode 100644 index 00000000..9fdb17d0 --- /dev/null +++ b/include/kyosu/functions/sign.hpp @@ -0,0 +1,76 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_sign : eve::elementwise + { + using callable_tag_type = callable_sign; + + KYOSU_DEFERS_CALLABLE(sign_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + return eve::sign(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 sign +//! @brief Computes tne normalized value z/abs(z) if z is not zero else 0. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T sign(T z) noexcept; +//! template constexpr T sign(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to for which square root is computed. +//! +//! **Return value** +//! +//! Returns the "sign" of the argument i.e. its normalized value. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sign.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sign sign = {}; +} diff --git a/include/kyosu/functions/sin.hpp b/include/kyosu/functions/sin.hpp new file mode 100644 index 00000000..0d43f0f2 --- /dev/null +++ b/include/kyosu/functions/sin.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_sin : eve::elementwise + { + using callable_tag_type = callable_sin; + + KYOSU_DEFERS_CALLABLE(sin_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::sin(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 sin +//! @brief Computes the sine of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T sin(T z) noexcept; +//! template constexpr T sin(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the sine of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sin.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sin sin = {}; +} diff --git a/include/kyosu/functions/sincos.hpp b/include/kyosu/functions/sincos.hpp new file mode 100644 index 00000000..ef8f09bd --- /dev/null +++ b/include/kyosu/functions/sincos.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_sincos : eve::elementwise + { + using callable_tag_type = callable_sincos; + + KYOSU_DEFERS_CALLABLE(sincos_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::sincos(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 sincos +//! @brief Computes simultaneously the sine and cosine of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto sincos(T z) noexcept; +//! template constexpr auto sincos(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns simultaneously the sine and cosine of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sincos.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sincos sincos = {}; +} diff --git a/include/kyosu/functions/sqrt.hpp b/include/kyosu/functions/sqrt.hpp new file mode 100644 index 00000000..129ec8f2 --- /dev/null +++ b/include/kyosu/functions/sqrt.hpp @@ -0,0 +1,80 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include +#include + +namespace kyosu::tags +{ + struct callable_sqrt : eve::elementwise + { + using callable_tag_type = callable_sqrt; + + KYOSU_DEFERS_CALLABLE(sqrt_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + auto fn = callable_log{}; + return fn(kyosu::to_complex(v, T(0))); + + } + + 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 sqrt +//! @brief Computes a square root value. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T sqrt(T z) noexcept; +//! template constexpr T sqrt(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to for which square root is computed. +//! +//! **Return value** +//! +//! Returns a square root of its argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/sqrt.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_sqrt sqrt = {}; +} diff --git a/include/kyosu/functions/tan.hpp b/include/kyosu/functions/tan.hpp new file mode 100644 index 00000000..e604dc7a --- /dev/null +++ b/include/kyosu/functions/tan.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_tan : eve::elementwise + { + using callable_tag_type = callable_tan; + + KYOSU_DEFERS_CALLABLE(tan_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::tan(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 tan +//! @brief Computes the tangent of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T tan(T z) noexcept; +//! template constexpr T tan(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the tangent of the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/tan.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_tan tan = {}; +} diff --git a/include/kyosu/types/impl/arithmetic.hpp b/include/kyosu/types/impl/arithmetic.hpp index dc064d57..58914280 100644 --- a/include/kyosu/types/impl/arithmetic.hpp +++ b/include/kyosu/types/impl/arithmetic.hpp @@ -178,6 +178,7 @@ namespace kyosu::_ { return conj(c)/sqr_abs(c); } + template requires(dimension_v <= dimension_v) KYOSU_FORCEINLINE constexpr @@ -193,4 +194,11 @@ namespace kyosu::_ return kumi::apply([](auto const&... e) { return type{kyosu::convert(e, eve::as{})...}; }, c); } } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C c) noexcept + { + return kyosu::if_else(kyosu::is_nez(c), c/abs(c), C(0)); + } } diff --git a/include/kyosu/types/impl/math.hpp b/include/kyosu/types/impl/math.hpp index 7bae6923..e61a0c4c 100644 --- a/include/kyosu/types/impl/math.hpp +++ b/include/kyosu/types/impl/math.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace kyosu::_ { @@ -126,4 +127,191 @@ namespace kyosu::_ } } + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + using c_t = as_cayley_dickson_n_t<2,eve::underlying_type_t>; + if constexpr(kyosu::concepts::complex) + { + auto arg = [](auto z){ return eve::pedantic(eve::atan2)(kyosu::imag(z), kyosu::real(z));}; + auto [rz, iz] = z; + auto infty = eve::inf(eve::as(rz)); + auto argz = arg(z); + auto absz = eve::if_else(eve::is_nan(rz) && eve::is_infinite(iz), infty, kyosu::abs(z)); + auto la = eve::log(absz); + auto r = kyosu::if_else(kyosu::is_real(z) && eve::is_positive(rz), to_complex(la, eve::zero(eve::as(rz))), to_complex(la, argz)); + if(eve::any(kyosu::is_not_finite(z))) + { + r = kyosu::if_else(eve::is_infinite(rz) && eve::is_nan(iz), to_complex(infty, iz), r); + } + return r; + } + else + { + auto az = kyosu::abs(z); + auto v = kyosu::pure(z); + auto s = kyosu::real(z); + auto z1 = (eve::acos(s/az)/abs(v))*v+eve::log(az); + auto tmp = kyosu::if_else( kyosu::is_real(z) + , kyosu::log(kyosu::real(z)) + , z1 + ); + return kyosu::if_else( kyosu::is_eqz(z) + , eve::minf(eve::as(az)) + , tmp + ); + + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + using c_t = as_cayley_dickson_n_t<2,eve::underlying_type_t>; + if constexpr(kyosu::concepts::complex) + { + auto [rz, iz] = z; + auto infty = eve::inf(eve::as(rz)); + auto arg = [](auto z){ return eve::pedantic(eve::atan2)(kyosu::imag(z), kyosu::real(z));}; + auto argz = arg(z)*eve::invlog_10(eve::as(rz)); + auto absz = eve::if_else(eve::is_nan(rz) && eve::is_infinite(iz), infty, kyosu::abs(z)); + auto la = eve::log10(absz); + auto r = kyosu::if_else(kyosu::is_real(z) && eve::is_positive(rz), to_complex(la, eve::zero(eve::as(rz))), to_complex(la, argz)); + if(eve::any(kyosu::is_not_finite(z))) + { + r = kyosu::if_else(eve::is_infinite(rz) && eve::is_nan(iz), to_complex(infty, iz), r); + } + return r; + } + else + { + using e_t = eve::underlying_type_t; + return log(z)*eve::invlog_10(eve::as()); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + using c_t = as_cayley_dickson_n_t<2,eve::underlying_type_t>; + if constexpr(kyosu::concepts::complex) + { + auto [rz, iz] = z; + auto infty = eve::inf(eve::as(rz)); + auto arg = [](auto z){ return eve::pedantic(eve::atan2)(kyosu::imag(z), kyosu::real(z));}; + auto argz = arg(z)*eve::invlog_2(eve::as(rz)); + auto absz = eve::if_else(eve::is_nan(rz) && eve::is_infinite(iz), infty, kyosu::abs(z)); + auto la = eve::log2(absz); + auto r = kyosu::if_else(kyosu::is_real(z) && eve::is_positive(rz), to_complex(la, eve::zero(eve::as(rz))), to_complex(la, argz)); + if(eve::any(kyosu::is_not_finite(z))) + { + r = kyosu::if_else(eve::is_infinite(rz) && eve::is_nan(iz), to_complex(infty, iz), r); + } + return r; + } + else + { + using e_t = eve::underlying_type_t; + return log(z)*eve::invlog_2(eve::as()); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + using c_t = as_cayley_dickson_n_t<2,eve::underlying_type_t>; + using e_t = eve::underlying_type_t; + if constexpr(kyosu::concepts::complex) + { + auto m = kyosu::inc(z); + auto arg = [](auto z){ return eve::pedantic(eve::atan2)(kyosu::imag(z), kyosu::real(z));}; + auto theta = eve::if_else((kyosu::is_real(m) && eve::is_nltz(kyosu::real(m))), eve::zero, arg(m)) ; + auto rz = kyosu::real(z); + auto iz2 = eve::sqr(kyosu::imag(z)); + return to_complex(eve::half(eve::as())*eve::log1p(rz*(rz+e_t(2))+iz2), theta); + } + else + { + auto incz = inc(z); + auto az = kyosu::abs(incz); + auto az2 = kyosu::sqr_abs(z) + 2*real(z); + auto v = kyosu::pure(z); + auto s = kyosu::real(incz); + auto z1 = (eve::acos(s/az)/abs(v))*v+ eve::half(eve::as())*eve::log1p(az2); + auto tmp = kyosu::if_else( kyosu::is_real(z) + , kyosu::log(kyosu::real(z)) + , z1 + ); + return kyosu::if_else( kyosu::is_eqz(z) + , eve::minf(eve::as(az)) + , tmp + ); + + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(kyosu::concepts::complex) + { + //always compute the sqrt of the complex with positive imaginary part + //then conjugate if necessary + auto [rz, iz] = z; + auto negimag = eve::is_negative(iz); + auto x = eve::abs(rz); + auto y = eve::abs(iz); + auto iaz = eve::if_else(negimag, -iz, iz); // always >= 0 or -Nan + auto gtxy = (x > y); + auto gezrz = eve::is_gez(rz); + auto r = eve::if_else(gtxy, y/x, x/y); + auto rr= eve::sqrt(eve::inc(eve::sqr(r))); + auto sqrtx = eve::sqrt(x); + auto w = eve::if_else(gtxy, + sqrtx*eve::sqrt(eve::half(eve::as(r))*eve::inc(rr)), + eve::sqrt(y)*eve::sqrt(eve::half(eve::as(r))*(r+rr))); + auto is_real_z = kyosu::is_real(z); + C res; + auto rr1 = eve::if_else(is_real_z, sqrtx, w); + auto ii1 = eve::if_else(is_real_z, eve::zero, iaz*eve::half(eve::as(r))/w); +// auto res = kyosu::to_complex(rr1, ii1); + res = kyosu::if_else(gezrz + , to_complex(rr1, ii1) + , to_complex(ii1, rr1) + ); + if (eve::any(is_not_finite(z))) [[unlikely]] + { + res = kyosu::if_else(rz == eve::minf(eve::as(rz)) + , kyosu::if_else( eve::is_nan(iz), to_complex(iz, eve::minf(eve::as(rz))) + , to_complex(eve::zero(eve::as(rz)), eve::inf(eve::as(rz)))) + , res + ); + res = kyosu::if_else(rz == eve::inf(eve::as(rz)) + , if_else( eve::is_nan(iz), to_complex(eve::inf(eve::as(rz)), iz) + , to_complex( eve::inf(eve::as(rz)), eve::zero(eve::as(rz)) )) + , res + ); + res = kyosu::if_else(eve::is_nan(rz), to_complex(rz, rz), res); + auto infty = eve::inf(eve::as(iaz)); + res = kyosu::if_else(iaz == infty, to_complex(infty, infty), res); + } + return if_else(negimag, kyosu::conj(res), res); + } + else + { + auto r = kyosu::abs(z); + auto theta = eve::acos(real(z)/r); + auto u = kyosu::sign(kyosu::pure(z)); + auto [s, c] = eve::sincos(theta*eve::half(eve::as(theta))); + auto res = u*s; + kyosu::real(res) = c; + return kyosu::if_else(eve::is_eqz(r), eve::zero(eve::as(z)), res*eve::sqrt(r)); + } + } + } diff --git a/include/kyosu/types/impl/predicates.hpp b/include/kyosu/types/impl/predicates.hpp index 8027d650..28edc0f8 100644 --- a/include/kyosu/types/impl/predicates.hpp +++ b/include/kyosu/types/impl/predicates.hpp @@ -79,7 +79,7 @@ namespace kyosu::_ KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& c) noexcept { - return kumi::all_of(c, [](auto const& e) { return eve::is_not_finite(e); }); + return kumi::any_of(c, [](auto const& e) { return eve::is_not_finite(e); }); } } diff --git a/include/kyosu/types/impl/trigo.hpp b/include/kyosu/types/impl/trigo.hpp index ccca98e0..60ac6b15 100644 --- a/include/kyosu/types/impl/trigo.hpp +++ b/include/kyosu/types/impl/trigo.hpp @@ -39,6 +39,13 @@ namespace kyosu::_ } } + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + return kyosu::rec(kyosu::cosh(z)); + } + template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& z) noexcept @@ -71,6 +78,13 @@ namespace kyosu::_ } } + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + return kyosu::rec(kyosu::sinh(z)); + } + template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& z) noexcept @@ -151,4 +165,113 @@ namespace kyosu::_ } } + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + return cosh(to_complex(-kyosu::imag(z), kyosu::real(z))); + } + else + { + auto p = kyosu::pure(z); + auto az = kyosu::abs(p); + auto [s, c] = eve::sincos(real(z)); + auto w = -s*eve::sinhc(az); + return c*cosh(az)+w*pure(z); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + return kyosu::rec(kyosu::cos(z)); + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto s = kyosu::sinh(to_complex(-kyosu::imag(z), kyosu::real(z))); + return to_complex(kyosu::imag(s), -kyosu::real(s)); + } + else + { + auto p = kyosu::pure(z); + auto az = kyosu::abs(p); + auto [s, c] = eve::sincos(real(z)); + auto w = c*eve::sinhc(az); + return s*cosh(az)+w*pure(z); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + return kyosu::rec(kyosu::sin(z)); + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto [sh, ch] = sinhcosh(to_complex(-kyosu::imag(z), kyosu::real(z))); + return kumi::tuple{to_complex(kyosu::imag(sh), -kyosu::real(sh)), ch}; + + } + else + { + auto p = kyosu::pure(z); + auto az = kyosu::abs(p); + auto [s, c] = eve::sincos(kyosu::real(z)); + auto shc = eve::sinhc(az); + auto ch = eve::cosh(az); + auto wc = c*shc; + auto ws =-s*shc; + auto sq = s*ch + wc*p; + auto cq = c*ch + ws*p; + return kumi::tuple{sq, cq}; + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto t = kyosu::tanh(kyosu::to_complex(-kyosu::imag(z), kyosu::real(z))); + return kyosu::to_complex(kyosu::imag(t), -kyosu::real(t)); + } + else + { + auto [s, c] = sincos(z); + return s/c; + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + if constexpr(concepts::complex ) + { + auto r = kyosu::tan(z); + return kyosu::if_else(kyosu::is_infinite(r), kyosu::to_complex(eve::zero(eve::as(eve::underlying_type_t()))), kyosu::rec(r)); + } + else + { + auto [s, c] = sincos(z); + return c/s; + } + } + + } diff --git a/test/doc/if_else.cpp b/test/doc/if_else.cpp new file mode 100644 index 00000000..7727c18e --- /dev/null +++ b/test/doc/if_else.cpp @@ -0,0 +1,18 @@ +#include +#include +#include + +int main() +{ + using kyosu::complex; + using kyosu::quaternion; + + + auto c = complex(3.5f,-2.9f); + auto q = quaternion(1.f,2.f,3.f,4.f); + auto t = 1.0f; + auto r = kyosu::if_else(t > 2.0f, q, c); + std::cout << r << std::endl; + + return 0; +} diff --git a/test/unit/complex/cos.cpp b/test/unit/complex/cos.cpp new file mode 100644 index 00000000..38ce06f9 --- /dev/null +++ b/test/unit/complex/cos.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 cos 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::cos(kc_t(e, f)), cv(std::cos(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of cos 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::cos(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::cos(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/cot.cpp b/test/unit/complex/cot.cpp new file mode 100644 index 00000000..39329e86 --- /dev/null +++ b/test/unit/complex/cot.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 cot 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::cot(kc_t(e, f)), kyosu::rec(cv(std::tan(c_t(e, f)))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of cot 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::tan(c_t(a0.get(i), a1.get(i))))); }); + TTS_RELATIVE_EQUAL(kyosu::cot(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/csc.cpp b/test/unit/complex/csc.cpp new file mode 100644 index 00000000..a97ac299 --- /dev/null +++ b/test/unit/complex/csc.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 csc 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::csc(kc_t(e, f)), kyosu::rec(cv(std::sin(c_t(e, f)))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of csc 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::sin(c_t(a0.get(i), a1.get(i))))); }); + TTS_RELATIVE_EQUAL(kyosu::csc(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/log.cpp b/test/unit/complex/log.cpp new file mode 100644 index 00000000..dbd65dab --- /dev/null +++ b/test/unit/complex/log.cpp @@ -0,0 +1,118 @@ +//====================================================================================================================== +/* + 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 log 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::log(kc_t(e, f)), cv(std::log(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of log 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>; + auto std_log = [](auto x, auto y){return cv(std::log(c_t(x, y))); }; + ke_t e([&](auto i, auto){return std_log(a0.get(i), a1.get(i)); }); + TTS_RELATIVE_EQUAL(kyosu::log(ke_t{a0,a1}), e, 1.0e-6); +}; + +TTS_CASE_TPL( "Check corner cases of log", kyosu::scalar_real_types) + (tts::type) +{ + using c_t = kyosu::complex; + using eve::as; + const int N = 14; + auto zer = eve::zero(as()); + auto mzer = eve::mzero(as()); + auto inf = eve::inf(as()); + auto minf = eve::minf(as()); + auto nan = eve::nan(as()); + auto one = eve::one(as()); + auto pi = eve::pi(as()); + auto pio_2 = eve::pio_2(as()); + auto pio_4 = eve::pio_4(as()); + std::array inputs = + { + c_t(mzer,zer), //0 + c_t(zer,zer), //1 + c_t(one,inf), //2 + c_t(one,nan), //3 + c_t(minf,one), //4 + c_t(minf,zer), //5 + c_t(inf,one), //6 + c_t(inf,zer), //7 + c_t(inf,inf), //8 + c_t(inf, nan), //9 + c_t(minf,nan), //10 + c_t(nan,one), //11 + c_t(nan,inf), //12 + c_t(nan,nan) //13 + }; + + std::array results = + { + c_t(minf,pi), //0 + c_t(minf,zer), //1 + c_t(inf,pio_2), //2 + c_t(nan,nan), //3 + c_t(inf,pi), //4 + c_t(inf,pi), //5 + c_t(inf,zer), //6 + c_t(inf,zer), //7 + c_t(inf,pio_4), //8 + c_t(inf, nan), //9 + c_t(inf,nan), //10 + c_t(nan,nan), //11 + c_t(inf,nan), //12 + c_t(nan,nan) //13 + }; + + using kyosu::conj; + using kyosu::log; + for(int i=0; i < N; ++i) + { + std::cout << "i " << i << " input " << inputs[i] << " ->" << log(inputs[i]) << std::endl; + TTS_IEEE_EQUAL(log(inputs[i]), results[i]) << "i " << i << " -> " << inputs[i] << "\n"; + TTS_IEEE_EQUAL(log(conj(inputs[i])), conj(log(inputs[i]))); + } + + using wc_t = eve::wide>; + wc_t wci0([inputs](auto i, auto){return inputs[i]; }); + wc_t wco0([results](auto i, auto){return results[i]; }); + wc_t wci1([inputs](auto i, auto c){return inputs[c-i-1]; }); + wc_t wco1([results](auto i, auto c){return results[c-i-1]; }); + TTS_IEEE_EQUAL(log(wci0), wco0); + TTS_IEEE_EQUAL(log(wci1), wco1); + +}; diff --git a/test/unit/complex/log10.cpp b/test/unit/complex/log10.cpp new file mode 100644 index 00000000..953e8169 --- /dev/null +++ b/test/unit/complex/log10.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 log10 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::log10(kc_t(e, f)), cv(std::log10(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of log10 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>; + auto std_log10 = [](auto x, auto y){return cv(std::log10(c_t(x, y))); }; + ke_t e([&](auto i, auto){return std_log10(a0.get(i), a1.get(i)); }); + TTS_RELATIVE_EQUAL(kyosu::log10(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/log1p.cpp b/test/unit/complex/log1p.cpp new file mode 100644 index 00000000..16fa3f8a --- /dev/null +++ b/test/unit/complex/log1p.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 log1p 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::log1p(kc_t(e, f)), cv(std::log(c_t(e+1, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of log1p 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::log(c_t(eve::inc(a0.get(i)), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::log1p(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/log2.cpp b/test/unit/complex/log2.cpp new file mode 100644 index 00000000..5790511c --- /dev/null +++ b/test/unit/complex/log2.cpp @@ -0,0 +1,50 @@ +//====================================================================================================================== +/* + 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 log2 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]; + auto std_log2 = [](auto x){return std::log(x)*eve::invlog_2(eve::as()); }; + + TTS_RELATIVE_EQUAL(kyosu::log2(kc_t(e, f)), cv(std_log2(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of log2 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>; + auto std_log2 = [](auto x, auto y){return cv(std::log(c_t(x, y)))*eve::invlog_2(eve::as(x)); }; + ke_t e([&](auto i, auto){return std_log2(a0.get(i), a1.get(i)); }); + TTS_RELATIVE_EQUAL(kyosu::log2(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/sec.cpp b/test/unit/complex/sec.cpp new file mode 100644 index 00000000..5bffe82d --- /dev/null +++ b/test/unit/complex/sec.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 sec 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::sec(kc_t(e, f)), kyosu::rec(cv(std::cos(c_t(e, f)))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of sec 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::cos(c_t(a0.get(i), a1.get(i))))); }); + TTS_RELATIVE_EQUAL(kyosu::sec(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/sin.cpp b/test/unit/complex/sin.cpp new file mode 100644 index 00000000..d33469ba --- /dev/null +++ b/test/unit/complex/sin.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 sin 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::sin(kc_t(e, f)), cv(std::sin(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of sin 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::sin(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::sin(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/complex/sincos.cpp b/test/unit/complex/sincos.cpp new file mode 100644 index 00000000..a11ad21f --- /dev/null +++ b/test/unit/complex/sincos.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 sincos 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::sincos(e); + TTS_RELATIVE_EQUAL(c, kyosu::cos(e), 1.0e-6); + TTS_RELATIVE_EQUAL(s, kyosu::sin(e), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of sincos 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::sincos(e); + TTS_RELATIVE_EQUAL(c, kyosu::cos(e), 1.0e-6); + TTS_RELATIVE_EQUAL(s, kyosu::sin(e), 1.0e-6); +}; diff --git a/test/unit/complex/sqrt.cpp b/test/unit/complex/sqrt.cpp new file mode 100644 index 00000000..563d8b5c --- /dev/null +++ b/test/unit/complex/sqrt.cpp @@ -0,0 +1,106 @@ +//====================================================================================================================== +/* + 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 sqrt 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::sqrt(kc_t(e, f)), cv(std::sqrt(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of sqrt 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::sqrt(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::sqrt(ke_t{a0,a1}), e, 1.0e-6); +}; + +TTS_CASE_TPL( "Check corner cases of sqrt", kyosu::scalar_real_types) + (tts::type) +{ + using c_t = kyosu::complex; + using eve::as; + const int N = 14; + auto zer = eve::zero(as()); + auto mzer = eve::mzero(as()); + auto inf = eve::inf(as()); + auto minf = eve::minf(as()); + auto mone = eve::mone(as()); + auto nan = eve::nan(as()); + auto one = eve::one(as()); + std::array inputs = + { + c_t(zer,zer), //0 + c_t(mzer,zer),//1 + c_t(one,inf), //2 + c_t(mone,inf),//3 + c_t(nan,inf), //4 + c_t(one,nan), //5 + c_t(minf,one), //6 + c_t(inf,one), //7 + c_t(minf,-nan),//8 + c_t(inf,nan), //9 + c_t(nan,one), //10 + c_t(nan,nan), //11 + c_t(T(4), zer), //12 + c_t(nan,zer) //13 + }; + + std::array results = + { + c_t(zer,zer), //0 + c_t(zer,zer),//1 + c_t(inf,inf), //2 + c_t(inf,inf),//3 + c_t(inf,inf), //4 + c_t(nan,nan), //5 + c_t(zer,inf), //6 + c_t(inf,zer), //7 + c_t(nan,minf),//8 + c_t(inf,nan), //9 + c_t(nan,nan), //10 + c_t(nan,nan), //11 + c_t(T(2), zer), //12 + c_t(nan,nan) //13 + }; + + using kyosu::conj; + using kyosu::sqrt; + for(int i=0; i < N; ++i) + { + TTS_IEEE_EQUAL(sqrt(inputs[i]), results[i]); +// TTS_IEEE_EQUAL(sqrt(conj(inputs[i])), conj(sqrt(inputs[i]))); + } +}; diff --git a/test/unit/complex/tan.cpp b/test/unit/complex/tan.cpp new file mode 100644 index 00000000..989e3e98 --- /dev/null +++ b/test/unit/complex/tan.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 tan 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::tan(kc_t(e, f)), cv(std::tan(c_t(e, f))), 1.0e-6); + } +}; + +TTS_CASE_WITH( "Check behavior of tan 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::tan(c_t(a0.get(i), a1.get(i)))); }); + TTS_RELATIVE_EQUAL(kyosu::tan(ke_t{a0,a1}), e, 1.0e-6); +}; diff --git a/test/unit/function/cos.cpp b/test/unit/function/cos.cpp new file mode 100644 index 00000000..f52d5ee2 --- /dev/null +++ b/test/unit/function/cos.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::cos over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::cos(data), eve::cos(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::cos 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_cos = [](auto x, auto y, auto z, auto t){return cv(boost::math::cos(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_cos(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::cos(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/cot.cpp b/test/unit/function/cot.cpp new file mode 100644 index 00000000..6b24e591 --- /dev/null +++ b/test/unit/function/cot.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::cot over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::cot(data), eve::cot(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::cot 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_cot = [](auto x, auto y, auto z, auto t){return kyosu::rec(cv(boost::math::tan(bq_t(x, y, z, t)))); }; + ke_t e([&](auto n, auto){return boost_cot(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::cot(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/csc.cpp b/test/unit/function/csc.cpp new file mode 100644 index 00000000..043a4789 --- /dev/null +++ b/test/unit/function/csc.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::csc over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::csc(data), eve::csc(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::csc 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_csc = [](auto x, auto y, auto z, auto t){return kyosu::rec(cv(boost::math::sin(bq_t(x, y, z, t)))); }; + ke_t e([&](auto n, auto){return boost_csc(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::csc(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/log.cpp b/test/unit/function/log.cpp new file mode 100644 index 00000000..8cbc345b --- /dev/null +++ b/test/unit/function/log.cpp @@ -0,0 +1,32 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::exp 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 a0, T a1, T a2, T a3) +{ + using ce_t = kyosu::as_complex_t; + using qe_t = kyosu::as_quaternion_t; + + auto r = T(a0); + auto c = ce_t(a0,a1); + auto q = qe_t(a0,a1,a2,a3); + + auto lr = kyosu::log(r); + auto lc = kyosu::log(c); + auto lq = kyosu::log(q); + TTS_RELATIVE_EQUAL(kyosu::exp(lr), kyosu::to_complex(r), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::exp(lc), c, 1e-5); + TTS_RELATIVE_EQUAL(kyosu::exp(lq), q, 1e-5); +}; diff --git a/test/unit/function/log10.cpp b/test/unit/function/log10.cpp new file mode 100644 index 00000000..4680fb5e --- /dev/null +++ b/test/unit/function/log10.cpp @@ -0,0 +1,32 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::exp 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 a0, T a1, T a2, T a3) +{ + using ce_t = kyosu::as_complex_t; + using qe_t = kyosu::as_quaternion_t; + + auto r = T(a0); + auto c = ce_t(a0,a1); + auto q = qe_t(a0,a1,a2,a3); + + auto lr = kyosu::log10(r); + auto lc = kyosu::log10(c); + auto lq = kyosu::log10(q); + TTS_RELATIVE_EQUAL(kyosu::exp10(lr), kyosu::to_complex(r), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::exp10(lc), c, 1e-5); + TTS_RELATIVE_EQUAL(kyosu::exp10(lq), q, 1e-5); +}; diff --git a/test/unit/function/log1p.cpp b/test/unit/function/log1p.cpp new file mode 100644 index 00000000..5a80a623 --- /dev/null +++ b/test/unit/function/log1p.cpp @@ -0,0 +1,37 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::exp 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 a0, T a1, T a2, T a3) +{ + using ce_t = kyosu::as_complex_t; + using qe_t = kyosu::as_quaternion_t; + + auto r = T(a0); + auto c = ce_t(a0,a1); + auto q = qe_t(a0,a1,a2,a3); + +// auto lr = kyosu::log1p(r); +// auto lc = kyosu::log1p(c); +// auto lq = kyosu::log1p(q); + +// TTS_RELATIVE_EQUAL(kyosu::expm1(lr), kyosu::to_complex(r), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::expm1(lc), c, 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::expm1(lq), q, 1e-5); + + TTS_RELATIVE_EQUAL( kyosu::log1p(r), kyosu::log(kyosu::inc(r)), 1.0e-6); + TTS_RELATIVE_EQUAL( kyosu::log1p(c), kyosu::log(kyosu::inc(c)), 1.0e-6); + TTS_RELATIVE_EQUAL( kyosu::log1p(q), kyosu::log(kyosu::inc(q)), 1.0e-6); +}; diff --git a/test/unit/function/log2.cpp b/test/unit/function/log2.cpp new file mode 100644 index 00000000..35039e41 --- /dev/null +++ b/test/unit/function/log2.cpp @@ -0,0 +1,32 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::exp 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 a0, T a1, T a2, T a3) +{ + using ce_t = kyosu::as_complex_t; + using qe_t = kyosu::as_quaternion_t; + + auto r = T(a0); + auto c = ce_t(a0,a1); + auto q = qe_t(a0,a1,a2,a3); + + auto lr = kyosu::log2(r); + auto lc = kyosu::log2(c); + auto lq = kyosu::log2(q); + TTS_RELATIVE_EQUAL(kyosu::exp2(lr), kyosu::to_complex(r), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::exp2(lc), c, 1e-5); + TTS_RELATIVE_EQUAL(kyosu::exp2(lq), q, 1e-5); +}; diff --git a/test/unit/function/sec.cpp b/test/unit/function/sec.cpp new file mode 100644 index 00000000..ec45bc64 --- /dev/null +++ b/test/unit/function/sec.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::sec over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::sec(data), eve::sec(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::sec 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_sec = [](auto x, auto y, auto z, auto t){return kyosu::rec(cv(boost::math::cos(bq_t(x, y, z, t)))); }; + ke_t e([&](auto n, auto){return boost_sec(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::sec(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/sin.cpp b/test/unit/function/sin.cpp new file mode 100644 index 00000000..8ff12201 --- /dev/null +++ b/test/unit/function/sin.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::sin over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::sin(data), eve::sin(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::sin 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_sin = [](auto x, auto y, auto z, auto t){return cv(boost::math::sin(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_sin(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::sin(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/sincos.cpp b/test/unit/function/sincos.cpp new file mode 100644 index 00000000..1192fdc3 --- /dev/null +++ b/test/unit/function/sincos.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::sin 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::sincos(r); + TTS_RELATIVE_EQUAL(s, kyosu::sin(r), 1e-5); + TTS_RELATIVE_EQUAL(c, kyosu::cos(r), 1e-5); + } + { + using ke_t = kyosu::as_complex_t; + auto cq= ke_t(r,i); + auto [s, c] = kyosu::sincos(cq); + TTS_RELATIVE_EQUAL(s, kyosu::sin(cq), 1e-5); + TTS_RELATIVE_EQUAL(c, kyosu::cos(cq), 1e-5); + } + { + using ke_t = kyosu::as_quaternion_t; + auto q = ke_t(r,i,j,k); + auto [s, c] = kyosu::sincos(q); + TTS_RELATIVE_EQUAL(s, kyosu::sin(q), 1e-5); + TTS_RELATIVE_EQUAL(c, kyosu::cos(q), 1e-5); + } +}; diff --git a/test/unit/function/tan.cpp b/test/unit/function/tan.cpp new file mode 100644 index 00000000..33249a75 --- /dev/null +++ b/test/unit/function/tan.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::tan over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_ULP_EQUAL(kyosu::tan(data), eve::tan(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::tan 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_tan = [](auto x, auto y, auto z, auto t){return cv(boost::math::tan(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_tan(r.get(n), i.get(n), j.get(n), k.get(n)); }); + auto q = ke_t(r,i,j,k); + TTS_RELATIVE_EQUAL(kyosu::tan(q), e, 1e-5); +}; +# endif diff --git a/test/unit/function/tanh.cpp b/test/unit/function/tanh.cpp index 586328b0..207d0fd3 100644 --- a/test/unit/function/tanh.cpp +++ b/test/unit/function/tanh.cpp @@ -13,13 +13,13 @@ # define HAS_BOOST # endif -TTS_CASE_WITH ( "Check kyosu::cosh over real" +TTS_CASE_WITH ( "Check kyosu::tanh over real" , kyosu::real_types , tts::generate(tts::between(-10,10)) ) (auto data) { - TTS_ULP_EQUAL(kyosu::cosh(data), eve::cosh(data), 0.5); + TTS_ULP_EQUAL(kyosu::tanh(data), eve::tanh(data), 0.5); }; #ifdef HAS_BOOST @@ -31,7 +31,7 @@ auto cv(boost::math::quaternion const &bq) bq.R_component_3(), bq.R_component_4()); } -TTS_CASE_WITH ( "Check kyosu::cosh over quaternion" +TTS_CASE_WITH ( "Check kyosu::tanh over quaternion" , kyosu::simd_real_types , tts::generate ( tts::between(-10,10), tts::between(-10,10) , tts::between(-10,10), tts::between(-10,10) @@ -41,9 +41,9 @@ TTS_CASE_WITH ( "Check kyosu::cosh over quaternion" { 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 boost_tanh = [](auto x, auto y, auto z, auto t){return cv(boost::math::tanh(bq_t(x, y, z, t))); }; + ke_t e([&](auto n, auto){return boost_tanh(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); + TTS_RELATIVE_EQUAL(kyosu::tanh(q), e, 1e-5); }; # endif