From d33aa4edffaaacff4683f137e6899e97200eca60 Mon Sep 17 00:00:00 2001 From: jtlap Date: Sun, 19 Nov 2023 15:01:16 +0100 Subject: [PATCH] Add cayley-dickson specific constants --- doc/index.md | 8 ++ include/kyosu/constants.hpp | 18 +++++ include/kyosu/constants/cinf.hpp | 79 ++++++++++++++++++++ include/kyosu/constants/i.hpp | 78 +++++++++++++++++++ include/kyosu/constants/j.hpp | 78 +++++++++++++++++++ include/kyosu/constants/k.hpp | 78 +++++++++++++++++++ include/kyosu/constants/mi.hpp | 78 +++++++++++++++++++ include/kyosu/functions.hpp | 2 + include/kyosu/functions/muli.hpp | 75 +++++++++++++++++++ include/kyosu/functions/mulmi.hpp | 75 +++++++++++++++++++ include/kyosu/kyosu.hpp | 1 + include/kyosu/types/cayley_dickson.hpp | 1 + include/kyosu/types/impl/arithmetic.hpp | 34 ++++++++- include/kyosu/types/impl/compounds.hpp | 11 ++- include/kyosu/types/impl/detail/bessel_h.hpp | 4 +- include/kyosu/types/impl/detail/bessel_i.hpp | 11 ++- include/kyosu/types/impl/invtrig.hpp | 4 +- include/kyosu/types/impl/math.hpp | 2 +- include/kyosu/types/impl/special.hpp | 4 +- test/doc/cinf.cpp | 36 +++++++++ test/doc/i.cpp | 30 ++++++++ test/doc/j.cpp | 30 ++++++++ test/doc/k.cpp | 30 ++++++++ test/doc/mi.cpp | 30 ++++++++ test/doc/muli.cpp | 24 ++++++ test/unit/complex/log_gamma.cpp | 4 +- test/unit/function/i.cpp | 25 +++++++ test/unit/function/j.cpp | 25 +++++++ test/unit/function/k.cpp | 25 +++++++ test/unit/function/muli.cpp | 54 +++++++++++++ test/unit/function/mulmi.cpp | 54 +++++++++++++ test/unit/function/sqr_abs.cpp | 6 ++ 32 files changed, 992 insertions(+), 22 deletions(-) create mode 100644 include/kyosu/constants.hpp create mode 100644 include/kyosu/constants/cinf.hpp create mode 100644 include/kyosu/constants/i.hpp create mode 100644 include/kyosu/constants/j.hpp create mode 100644 include/kyosu/constants/k.hpp create mode 100644 include/kyosu/constants/mi.hpp create mode 100644 include/kyosu/functions/muli.hpp create mode 100644 include/kyosu/functions/mulmi.hpp create mode 100644 test/doc/cinf.cpp create mode 100644 test/doc/i.cpp create mode 100644 test/doc/j.cpp create mode 100644 test/doc/k.cpp create mode 100644 test/doc/mi.cpp create mode 100644 test/doc/muli.cpp create mode 100644 test/unit/function/i.cpp create mode 100644 test/unit/function/j.cpp create mode 100644 test/unit/function/k.cpp create mode 100644 test/unit/function/muli.cpp create mode 100644 test/unit/function/mulmi.cpp diff --git a/doc/index.md b/doc/index.md index 66a05526..12f79083 100644 --- a/doc/index.md +++ b/doc/index.md @@ -112,6 +112,8 @@ Prefix forms are also provided as `add`, `sub`, `multiply` and `div`. Also plus The left division sometimes necessary if the dimensionality is greater than 2 is given as `ldiv`. +The left multiplication to the left by i or -i (i*i=-1) can be done calling respectively muli and mulmi + Functions --------- @@ -176,3 +178,9 @@ Most **KYOSU** callables are usable with all cayley_dickson types. The exception | | | | |-----------|------------|------------| | [rot_angle](@ref kyosu::rot_angle) | [rot_axis](@ref kyosu::rot_axis) | [rotate_vec](@ref kyosu::rotate_vec) | + + * Constant i, j, k and cinf are defined. + + * i(as()) returns a complex of the same underlying type as Z; + * j(as()) and k(as()) return a quaternion of the same underlying type as Z; + * cinf(as()) returns a complex with nan real part and inf imaginary part, that can be roughly taken as a complex-infinity, in the sense that abs is infinite and arg is undefinite (nan). diff --git a/include/kyosu/constants.hpp b/include/kyosu/constants.hpp new file mode 100644 index 00000000..03d1297a --- /dev/null +++ b/include/kyosu/constants.hpp @@ -0,0 +1,18 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +//====================================================================================================================== +//! @defgroup functions Cayley-Dickson constants +//! @brief non real constants +//====================================================================================================================== +#include +#include +#include +#include +#include diff --git a/include/kyosu/constants/cinf.hpp b/include/kyosu/constants/cinf.hpp new file mode 100644 index 00000000..84c42175 --- /dev/null +++ b/include/kyosu/constants/cinf.hpp @@ -0,0 +1,79 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_cinf : eve::elementwise + { + using callable_tag_type = callable_cinf; + + KYOSU_DEFERS_CALLABLE(i_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, as const& ) noexcept + requires(concepts::cayley_dickson || eve::floating_ordered_value) + { + using u_t = eve::underlying_type_t; + return kyosu::complex(eve::nan(as()),eve::inf(as())); + } + + 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 i +//! @brief Computes the complex number cinf i.e. complex(nan, inf) in the chosen type. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr as_complex_t> cinf(as z) noexcept; +//! template constexpr és_complex_t> cinf(as z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * always returns a complex scalar value cinf such that real(cinf) is a Nan and imag(cinf) is Inf. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/i.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_cinf cinf = {}; +} diff --git a/include/kyosu/constants/i.hpp b/include/kyosu/constants/i.hpp new file mode 100644 index 00000000..08a32a7b --- /dev/null +++ b/include/kyosu/constants/i.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_i : eve::elementwise + { + using callable_tag_type = callable_i; + + KYOSU_DEFERS_CALLABLE(i_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, as const& ) noexcept + requires(concepts::cayley_dickson || eve::floating_ordered_value) + { + using u_t = eve::underlying_type_t; + return kyosu::complex(u_t(0),u_t(1)); } + + 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 i +//! @brief Computes the complex number i i.e. complex(0, 1) in the chosen type. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr as_complex_t> i(as z) noexcept; +//! template constexpr és_complex_t> i(as z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * always returns a complex scalar value i such that real(i) is null and imag(i) is one. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/i.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_i i = {}; +} diff --git a/include/kyosu/constants/j.hpp b/include/kyosu/constants/j.hpp new file mode 100644 index 00000000..525ee6ef --- /dev/null +++ b/include/kyosu/constants/j.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_j : eve::elementwise + { + using callable_tag_type = callable_j; + + KYOSU_DEFERS_CALLABLE(j_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, as const& ) noexcept + requires(concepts::cayley_dickson || eve::floating_ordered_value) + { + using u_t = eve::underlying_type_t; + return kyosu::quaternion(u_t(0), u_t(0), u_t(1), u_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 i +//! @brief Computes the complex number j i.e. quaternion(0, 0, 1, 0) in the chosen type. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr as_complex_t> j(as z) noexcept; +//! template constexpr és_complex_t> j(as z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * always returns a quaternion scalar value j such that all parts are null except the jpart whose value is one. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/i.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_j j = {}; +} diff --git a/include/kyosu/constants/k.hpp b/include/kyosu/constants/k.hpp new file mode 100644 index 00000000..f97e0cb5 --- /dev/null +++ b/include/kyosu/constants/k.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_k : eve::elementwise + { + using callable_tag_type = callable_k; + + KYOSU_DEFERS_CALLABLE(k_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, as const& ) noexcept + requires(concepts::cayley_dickson || eve::floating_ordered_value) + { + using u_t = eve::underlying_type_t; + return kyosu::quaternion(u_t(0),u_t(0), u_t(0), u_t(1)); } + + 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 i +//! @brief Computes the complex number k i.e. quaternion(0, 0, 0, 1) in the chosen type. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr as_complex_t> k(as z) noexcept; +//! template constexpr és_complex_t> k(as z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * always returns a quaternion scalar value k such that all parts are null exceptthe k part whose value is one. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/i.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_k k = {}; +} diff --git a/include/kyosu/constants/mi.hpp b/include/kyosu/constants/mi.hpp new file mode 100644 index 00000000..9fa1f9fc --- /dev/null +++ b/include/kyosu/constants/mi.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include + +namespace kyosu::tags +{ + struct callable_mi : eve::elementwise + { + using callable_tag_type = callable_mi; + + KYOSU_DEFERS_CALLABLE(mi_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, as const& ) noexcept + requires(concepts::cayley_dickson || eve::floating_ordered_value) + { + using u_t = eve::underlying_type_t; + return kyosu::complex(u_t(0),u_t(-1)); } + + 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 i +//! @brief Computes the complex number mi i.e. complex(0, -1) in the chosen type, the conjugate of i. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr as_complex_t> mi(as z) noexcept; +//! template constexpr és_complex_t> mi(as z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * always returns a complex scalar value mi such that real(i) is null and imag(i) is minus one. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/i.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_mi mi = {}; +} diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index e0b5f199..2502e6ba 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -136,6 +136,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/kyosu/functions/muli.hpp b/include/kyosu/functions/muli.hpp new file mode 100644 index 00000000..2d7f6270 --- /dev/null +++ b/include/kyosu/functions/muli.hpp @@ -0,0 +1,75 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_muli: eve::elementwise + { + using callable_tag_type = callable_muli; + + KYOSU_DEFERS_CALLABLE(muli_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return complex(T(0), 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 muli +//! @brief Computes the value of the parameter multiplied by i on the left side. +//! For real complex and quaternion the computation is an optimization over the call to * operator. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto muli(T z) noexcept; +//! template constexpr auto muli(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * Returns i(as(z))*z; If z is floating point a complex is returned. +//! In the other cases the returned value as the same type as the input. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/muli.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_muli muli = {}; +} diff --git a/include/kyosu/functions/mulmi.hpp b/include/kyosu/functions/mulmi.hpp new file mode 100644 index 00000000..6e18e864 --- /dev/null +++ b/include/kyosu/functions/mulmi.hpp @@ -0,0 +1,75 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright: KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_mulmi: eve::elementwise + { + using callable_tag_type = callable_mulmi; + + KYOSU_DEFERS_CALLABLE(mulmi_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return complex(T(0), -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 mulmi +//! @brief Computes the value of the parameter multiplied by i on the left side. +//! For real complex and quaternion the computation is an optimization over the call to * operator. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto mulmi(T z) noexcept; +//! template constexpr auto mulmi(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z`: Value to process. +//! +//! **Return value** +//! +//! * Returns -i(as(z))*z; If z is floating point a complex is returned. +//! In the other cases the returned value as the same type as the input. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/mulmi.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_mulmi mulmi = {}; +} diff --git a/include/kyosu/kyosu.hpp b/include/kyosu/kyosu.hpp index cbcb92b2..d0bedcec 100644 --- a/include/kyosu/kyosu.hpp +++ b/include/kyosu/kyosu.hpp @@ -12,3 +12,4 @@ namespace kyosu {} #include #include +#include diff --git a/include/kyosu/types/cayley_dickson.hpp b/include/kyosu/types/cayley_dickson.hpp index e38db55f..3630a4be 100644 --- a/include/kyosu/types/cayley_dickson.hpp +++ b/include/kyosu/types/cayley_dickson.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/include/kyosu/types/impl/arithmetic.hpp b/include/kyosu/types/impl/arithmetic.hpp index b0a4d4f6..fce999ce 100644 --- a/include/kyosu/types/impl/arithmetic.hpp +++ b/include/kyosu/types/impl/arithmetic.hpp @@ -12,6 +12,31 @@ namespace kyosu::_ { + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + if constexpr(kyosu::concepts::complex) + return complex(-ipart(c), real(c)); + else if constexpr(kyosu::concepts::quaternion) + return quaternion(-ipart(c), real(c), -kpart(c), jpart(c)); + else + return i(as(c))*c; + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + if constexpr(kyosu::concepts::complex) + return complex(ipart(c), -real(c)); + else if constexpr(kyosu::concepts::quaternion) + return quaternion(ipart(c), -real(c), kpart(c), -jpart(c)); + else + return mi(as(c))*c; + } + template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& c) noexcept @@ -22,7 +47,7 @@ namespace kyosu::_ template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& c) noexcept { - return kumi::apply(eve::hypot, c); + return kumi::apply(eve::pedantic(eve::hypot), c); } template @@ -39,8 +64,10 @@ namespace kyosu::_ KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& c) noexcept { + auto anyinf = kumi::any_of(c, eve::is_infinite); auto squares = kumi::map([](auto const& e) { return e*e; }, c); - return kumi::sum( kumi::extract(squares,kumi::index<1>), get<0>(squares)); + auto r = kumi::sum( kumi::extract(squares,kumi::index<1>), get<0>(squares)); + return if_else(anyinf, eve::inf(as(r)), r); } template @@ -186,7 +213,7 @@ namespace kyosu::_ KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C c) noexcept { - return conj(c)/sqr_abs(c); + return if_else(is_infinite(c), eve::zero, if_else(is_eqz(c), rec(real(c)), conj(c)/sqr_abs(c))); } template @@ -546,4 +573,5 @@ namespace kyosu::_ return (c0+ (c1+ ... + cs)) / (sizeof...(cs) + 2); } } + } diff --git a/include/kyosu/types/impl/compounds.hpp b/include/kyosu/types/impl/compounds.hpp index 5586d9e1..64ef3576 100644 --- a/include/kyosu/types/impl/compounds.hpp +++ b/include/kyosu/types/impl/compounds.hpp @@ -112,7 +112,16 @@ namespace kyosu requires(dimension_v <= dimension_v) constexpr Self& operator/=(Self& self, Other const& other) noexcept { - self = (self * conj(other))/sqr_abs(other); + auto r1 = (self * if_else(is_infinite(other), eve::zero, conj(other)/sqr_abs(other))); + auto eqzother = is_eqz(other); + if(eve::none(eqzother)) + { + self = r1; + } + else + { + self = if_else(is_eqz(other), self/real(other), r1); + } return self; } diff --git a/include/kyosu/types/impl/detail/bessel_h.hpp b/include/kyosu/types/impl/detail/bessel_h.hpp index 0f3173aa..40df8594 100644 --- a/include/kyosu/types/impl/detail/bessel_h.hpp +++ b/include/kyosu/types/impl/detail/bessel_h.hpp @@ -26,7 +26,6 @@ namespace kyosu::_ { if constexpr(concepts::complex) { - auto muli = [](auto z){ auto [r, i] = z; return complex(-i, r); }; return cyl_bessel_jn(n, z)+muli(cyl_bessel_yn(n, z)); } else @@ -40,7 +39,6 @@ namespace kyosu::_ { if constexpr(concepts::complex) { - auto muli = [](auto z){ auto [r, i] = z; return complex(-i, r); }; return cyl_bessel_jn(n, z)-muli(cyl_bessel_yn(n, z)); } else @@ -111,7 +109,7 @@ namespace kyosu::_ using u_t = eve::underlying_type_t; auto i = complex(u_t(0), u_t(1)); auto rz = rec(z); - auto miz = complex(ipart(z), -real(z)); + auto miz = mulmi(z); auto h0 = if_else(imzlt0, i*exp(miz), -i*exp(-miz))*rz; if(n == 0) return h0; auto h1 = if_else(imzlt0, (rz+i),(rz-i))*h0 ; diff --git a/include/kyosu/types/impl/detail/bessel_i.hpp b/include/kyosu/types/impl/detail/bessel_i.hpp index e431ccdd..5b116e01 100644 --- a/include/kyosu/types/impl/detail/bessel_i.hpp +++ b/include/kyosu/types/impl/detail/bessel_i.hpp @@ -16,7 +16,7 @@ namespace kyosu::_ template auto dispatch(eve::tag_of, Z z) noexcept { - return cyl_bessel_j0(complex(-ipart(z), real(z))); + return cyl_bessel_j0(muli(z)); } //===------------------------------------------------------------------------------------------- @@ -27,8 +27,7 @@ namespace kyosu::_ { if constexpr(concepts::complex ) { - auto [r, i] = cyl_bessel_j1(complex(-ipart(z), real(z))); - return complex(i, -r); + return mulmi(cyl_bessel_j1(muli(z))); } else { @@ -52,7 +51,7 @@ namespace kyosu::_ else return complex(eve::zero(eve::as()), eve::one(eve::as())); }; auto an = eve::abs(n); - return miton(an)*cyl_bessel_jn(an,complex(-ipart(z), real(z))); + return miton(an)*cyl_bessel_jn(an,muli(z)); } else { @@ -115,7 +114,7 @@ namespace kyosu::_ else if (n%4 == 2) return complex(eve::mone(eve::as())); else return complex(eve::zero(eve::as()), eve::mone(eve::as())); }; - return iton(-n)*sph_bessel_jn(n,complex(-ipart(z), real(z))); + return iton(-n)*sph_bessel_jn(n,muli(z)); } else { @@ -172,7 +171,7 @@ namespace kyosu::_ else if (n%4 == 2) return complex(eve::mone(eve::as())); else return complex(eve::zero(eve::as()), eve::mone(eve::as())); }; - return iton(-n-1)*sph_bessel_yn(n,complex(-ipart(z), real(z))); + return iton(-n-1)*sph_bessel_yn(n,muli(z)); } else { diff --git a/include/kyosu/types/impl/invtrig.hpp b/include/kyosu/types/impl/invtrig.hpp index e846d2be..41c604de 100644 --- a/include/kyosu/types/impl/invtrig.hpp +++ b/include/kyosu/types/impl/invtrig.hpp @@ -348,9 +348,7 @@ namespace kyosu::_ { if constexpr(concepts::complex ) { - auto [r, i] = a0; - auto [r1, i1] = kyosu::asin(complex(-i, r)); - return complex(i1, -r1); // -(eve::i*asin(eve::i*a0)); + return mulmi( kyosu::asin(muli(a0))); } else { diff --git a/include/kyosu/types/impl/math.hpp b/include/kyosu/types/impl/math.hpp index b31d6e93..30c730ee 100644 --- a/include/kyosu/types/impl/math.hpp +++ b/include/kyosu/types/impl/math.hpp @@ -261,7 +261,7 @@ namespace kyosu::_ , complex(ii1, rr1) ); res = if_else(is_pure(z), eve::sqrt_2(eve::as(r))*complex( eve::half(eve::as(r)), eve::half(eve::as(r)))*eve::sqrt(iz), res); - if (eve::any(is_not_finite(z))) [[unlikely]] + if (eve::any(is_not_finite(z))) { res = kyosu::if_else(rz == eve::minf(eve::as(rz)) , kyosu::if_else( eve::is_nan(iz), complex(iz, eve::minf(eve::as(rz))) diff --git a/include/kyosu/types/impl/special.hpp b/include/kyosu/types/impl/special.hpp index c1b24774..798aa136 100644 --- a/include/kyosu/types/impl/special.hpp +++ b/include/kyosu/types/impl/special.hpp @@ -464,9 +464,7 @@ namespace kyosu::_ } else { - auto [rz, iz] = z; - auto tmp = erf(complex(-iz, rz)); - return complex(imag(tmp), -real(tmp)); + return mulmi(erf(muli(z))); } } else diff --git a/test/doc/cinf.cpp b/test/doc/cinf.cpp new file mode 100644 index 00000000..9b23a1a4 --- /dev/null +++ b/test/doc/cinf.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() +{ + using kyosu::as; + using kyosu::complex_t; + using kyosu::quaternion_t; + + std::cout << "Real: \n"; + auto cinf = kyosu::cinf(kyosu::as(72.9f)); + std::cout << "cinf = " << cinf << "\n"; + std::cout << "rec(cinf) = " << kyosu::rec(cinf) << std::endl; + std::cout << "1.0f/cinf = " << 1.0/cinf << std::endl; + std::cout << 1.0f/kyosu::complex_t(0.0, 0.0) << std::endl; + std::cout << "kyosu::abs(cinf) " << kyosu::abs(cinf) << std::endl; + std::cout << "kyosu::arg(cinf) " << kyosu::arg(cinf) << std::endl; + std::cout << "Complex: \n"; + auto c = kyosu::complex_t(3.5f,-2.9f); + std::cout << "c = " << c << std::endl; + std::cout << "cinf(as(c)) " << " -> " << kyosu::cinf(as(c)) << "\n"; + std::cout << c/kyosu::complex_t(0.0, 0.0) << std::endl; + std::cout << c/0.0f << std::endl; + + std::cout << "Quaternion: \n"; + auto z = kyosu::quaternion_t(1.,2.,3.,4.); + std::cout << "cinf(as(z)) " << " -> " << kyosu::cinf(as(z)) << "\n"; + + std::cout << "SIMD: "; + using wc_t = eve::wide, eve::fixed<2>>; + auto wz = wc_t(complex_t(1.3,-3.7)); + std::cout << "cinf(as(wz)) " << " -> " << kyosu::cinf(as(wz)) << "\n"; + + return 0; +} diff --git a/test/doc/i.cpp b/test/doc/i.cpp new file mode 100644 index 00000000..562c45a3 --- /dev/null +++ b/test/doc/i.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +int main() +{ + using kyosu::i; + using kyosu::as; + using kyosu::complex_t; + using kyosu::quaternion_t; + + std::cout << "Real: \n"; + std::cout << "i(kyosu::as(72.9f))" << " -> " << i(as(72.9f)) << "\n"; + + std::cout << "Complex: \n"; + auto c = kyosu::complex_t(3.5f,-2.9f); + std::cout << "c = " << c << std::endl; + std::cout << "i(as(c) " << " -> " << i(as(c)) << "\n"; + + std::cout << "Quaternion: \n"; + auto z = kyosu::quaternion_t(1.,2.,3.,4.); + std::cout << "i(as(z) " << " -> " << i(as(z)) << "\n"; + + std::cout << "SIMD: "; + using wc_t = eve::wide, eve::fixed<2>>; + auto wz = wc_t(complex_t(1.3,-3.7)); + std::cout << "i(as(wz)) " << " -> " << i(as(wz)) << "\n"; + + return 0; +} diff --git a/test/doc/j.cpp b/test/doc/j.cpp new file mode 100644 index 00000000..d5b58447 --- /dev/null +++ b/test/doc/j.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +int main() +{ + using kyosu::j; + using kyosu::as; + using kyosu::complex_t; + using kyosu::quaternion_t; + + std::cout << "Real: \n"; + std::cout << "j(kyosu::as(72.9f))" << " -> " << j(as(72.9f)) << "\n"; + + std::cout << "Complex: \n"; + auto c = kyosu::complex_t(3.5f,-2.9f); + std::cout << "c = " << c << std::endl; + std::cout << "j(as(c) " << " -> " << j(as(c)) << "\n"; + + std::cout << "Quaternion: \n"; + auto z = kyosu::quaternion_t(1.,2.,3.,4.); + std::cout << "j(as(z) " << " -> " << j(as(z)) << "\n"; + + std::cout << "SIMD: "; + using wc_t = eve::wide, eve::fixed<2>>; + auto wz = wc_t(complex_t(1.3,-3.7)); + std::cout << "j(as(wz)) " << " -> " << j(as(wz)) << "\n"; + + return 0; +} diff --git a/test/doc/k.cpp b/test/doc/k.cpp new file mode 100644 index 00000000..71340803 --- /dev/null +++ b/test/doc/k.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +int main() +{ + using kyosu::k; + using kyosu::as; + using kyosu::complex_t; + using kyosu::quaternion_t; + + std::cout << "Real: \n"; + std::cout << "k(kyosu::as(72.9f))" << " -> " << k(as(72.9f)) << "\n"; + + std::cout << "Complex: \n"; + auto c = kyosu::complex_t(3.5f,-2.9f); + std::cout << "c = " << c << std::endl; + std::cout << "k(as(c) " << " -> " << k(as(c)) << "\n"; + + std::cout << "Quaternion: \n"; + auto z = kyosu::quaternion_t(1.,2.,3.,4.); + std::cout << "k(as(z) " << " -> " << k(as(z)) << "\n"; + + std::cout << "SIMD: "; + using wc_t = eve::wide, eve::fixed<2>>; + auto wz = wc_t(complex_t(1.3,-3.7)); + std::cout << "k(as(wz)) " << " -> " << k(as(wz)) << "\n"; + + return 0; +} diff --git a/test/doc/mi.cpp b/test/doc/mi.cpp new file mode 100644 index 00000000..bea546a9 --- /dev/null +++ b/test/doc/mi.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +int main() +{ + using kyosu::mi; + using kyosu::as; + using kyosu::complex_t; + using kyosu::quaternion_t; + + std::cout << "Real: \n"; + std::cout << "mi(kyosu::as(72.9f))" << " -> " << mi(as(72.9f)) << "\n"; + + std::cout << "Complex: \n"; + auto c = kyosu::complex_t(3.5f,-2.9f); + std::cout << "c = " << c << std::endl; + std::cout << "mi(as(c) " << " -> " << mi(as(c)) << "\n"; + + std::cout << "Quaternion: \n"; + auto z = kyosu::quaternion_t(1.,2.,3.,4.); + std::cout << "mi(as(z) " << " -> " << mi(as(z)) << "\n"; + + std::cout << "SIMD: "; + using wc_t = eve::wide, eve::fixed<2>>; + auto wz = wc_t(complex_t(1.3,-3.7)); + std::cout << "mi(as(wz)) " << " -> " << mi(as(wz)) << "\n"; + + return 0; +} diff --git a/test/doc/muli.cpp b/test/doc/muli.cpp new file mode 100644 index 00000000..ef77b1dd --- /dev/null +++ b/test/doc/muli.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +int main() +{ + + using wide_ft = eve::wide >; + wide_ft r = { 3.0f, 2.0f, 1.0f, 0.5f}; + wide_ft i = { 2.0f , -1.0, -5.0, 0.0}; + auto zc = kyosu::complex_t(r, i); + auto zq = kyosu::quaternion(1.0f, 2.0f, 3.0f, 4.0f); + + std::cout + << "---- simd" << std::endl + << "<- r = " << r << std::endl + << "-> muli(r) = " << kyosu::muli(r)<< std::endl + << "<- zc = " << zc << std::endl + << "-> muli(zc) = " << kyosu::muli(zc)<< std::endl + << "<- zq = " << zq << std::endl + << "-> muli(zq) = " << kyosu::muli(zq) << std::endl; + + return 0; +} diff --git a/test/unit/complex/log_gamma.cpp b/test/unit/complex/log_gamma.cpp index 52e6423c..a5bd8a18 100644 --- a/test/unit/complex/log_gamma.cpp +++ b/test/unit/complex/log_gamma.cpp @@ -12,15 +12,15 @@ TTS_CASE_TPL( "Check log_abs_gamma", kyosu::real_types) (tts::type) { + using kyosu::as; using z_t = kyosu::complex_t; using e_t = T; auto tcx = [](auto r, auto i){return kyosu::complex(T(r), T(i)); }; - T nan(eve::nan(eve::as())); z_t one = tcx(1, 0); z_t zer = tcx(0, 0); z_t two = tcx(2, 0); z_t three = tcx(3, 0); - TTS_IEEE_EQUAL( kyosu::log_gamma(zer), kyosu::complex(nan, nan) ); + TTS_IEEE_EQUAL( kyosu::log_gamma(zer), kyosu::complex(eve::inf(as()), eve::zero(as())) ); TTS_EQUAL( kyosu::log_gamma(one), zer ); TTS_EQUAL( kyosu::log_gamma(two), zer); TTS_RELATIVE_EQUAL( kyosu::log_gamma(three), kyosu::log(two), 1.0e-5); diff --git a/test/unit/function/i.cpp b/test/unit/function/i.cpp new file mode 100644 index 00000000..18020b4f --- /dev/null +++ b/test/unit/function/i.cpp @@ -0,0 +1,25 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::i" + , kyosu::scalar_real_types + , tts::generate(tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10)) + ) +(T r, T i, T j, T k) +{ + using kyosu::as; + using u_t = eve::underlying_type_t; + TTS_EQUAL(kyosu::i(as(r)), kyosu::complex_t(0, 1)); + auto c = kyosu::complex_t(r, i); + auto z = kyosu::quaternion_t(r, i, j, k); + TTS_EQUAL(kyosu::i(as(c)), kyosu::complex_t(0, 1)); + TTS_EQUAL(kyosu::i(as(z)), kyosu::complex_t(0, 1)); +}; diff --git a/test/unit/function/j.cpp b/test/unit/function/j.cpp new file mode 100644 index 00000000..e0256c34 --- /dev/null +++ b/test/unit/function/j.cpp @@ -0,0 +1,25 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::j" + , kyosu::scalar_real_types + , tts::generate(tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10)) + ) +(T r, T i, T j, T k) +{ + using kyosu::as; + using u_t = eve::underlying_type_t; + TTS_EQUAL(kyosu::j(as(r)), kyosu::quaternion_t(0, 0, 1, 0)); + auto c = kyosu::complex_t(r, i); + auto z = kyosu::quaternion_t(r, i, j, k); + TTS_EQUAL(kyosu::j(as(c)), kyosu::quaternion_t(0, 0, 1, 0)); + TTS_EQUAL(kyosu::j(as(z)), kyosu::quaternion_t(0, 0, 1, 0)); +}; diff --git a/test/unit/function/k.cpp b/test/unit/function/k.cpp new file mode 100644 index 00000000..1433d926 --- /dev/null +++ b/test/unit/function/k.cpp @@ -0,0 +1,25 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::k" + , kyosu::scalar_real_types + , tts::generate(tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10)) + ) +(T r, T i, T j, T k) +{ + using kyosu::as; + using u_t = eve::underlying_type_t; + TTS_EQUAL(kyosu::k(as(r)), kyosu::quaternion_t(0, 0, 0, 1)); + auto c = kyosu::complex_t(r, i); + auto z = kyosu::quaternion_t(r, i, j, k); + TTS_EQUAL(kyosu::k(as(c)), kyosu::quaternion_t(0, 0, 0, 1)); + TTS_EQUAL(kyosu::k(as(z)), kyosu::quaternion_t(0, 0, 0, 1)); +}; diff --git a/test/unit/function/muli.cpp b/test/unit/function/muli.cpp new file mode 100644 index 00000000..8ab88f13 --- /dev/null +++ b/test/unit/function/muli.cpp @@ -0,0 +1,54 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::muli over real" + , kyosu::real_types + , tts::generate(tts::randoms(-10,10)) + ) +(T data) +{ + TTS_EQUAL(kyosu::muli(data), kyosu::i(kyosu::as())*data); +}; + +TTS_CASE_WITH ( "Check kyosu::muli over complex" + , kyosu::real_types + , tts::generate(tts::randoms(-10,10), tts::randoms(-10,10)) + ) +(T r, T i) +{ + TTS_EQUAL(kyosu::muli(kyosu::complex(r,i)), kyosu::i(kyosu::as())*kyosu::complex(r,i)); +}; + +TTS_CASE_WITH ( "Check kyosu::muli over quaternion" + , kyosu::real_types + , tts::generate ( tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + ) + ) + (T r, T i, T j, T k) +{ + using type = kyosu::quaternion_t; + TTS_EQUAL(kyosu::muli(type(r,i,j,k)), kyosu::i(kyosu::as())*type(r,i,j,k)); +}; + + +TTS_CASE_WITH ( "Check kyosu::muli over octonion" + , kyosu::real_types + , tts::generate ( tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + ) + ) + (T r, T i, T j, T k, T l, T li, T lj, T lk) +{ + using type = kyosu::octonion_t; + TTS_EQUAL(kyosu::muli(type(r,i,j,k,l,li,lj,lk)), kyosu::i(kyosu::as())*type(r,i,j,k,l,li,lj,lk)); +}; diff --git a/test/unit/function/mulmi.cpp b/test/unit/function/mulmi.cpp new file mode 100644 index 00000000..56e29e1e --- /dev/null +++ b/test/unit/function/mulmi.cpp @@ -0,0 +1,54 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::mulmi over real" + , kyosu::real_types + , tts::generate(tts::randoms(-10,10)) + ) +(T data) +{ + TTS_EQUAL(kyosu::mulmi(data), kyosu::mi(kyosu::as())*data); +}; + +TTS_CASE_WITH ( "Check kyosu::mulmi over complex" + , kyosu::real_types + , tts::generate(tts::randoms(-10,10), tts::randoms(-10,10)) + ) +(T r, T i) +{ + TTS_EQUAL(kyosu::mulmi(kyosu::complex(r,i)), kyosu::mi(kyosu::as())*kyosu::complex(r,i)); +}; + +TTS_CASE_WITH ( "Check kyosu::mulmi over quaternion" + , kyosu::real_types + , tts::generate ( tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + ) + ) + (T r, T i, T j, T k) +{ + using type = kyosu::quaternion_t; + TTS_EQUAL(kyosu::mulmi(type(r,i,j,k)), kyosu::mi(kyosu::as())*type(r,i,j,k)); +}; + + +TTS_CASE_WITH ( "Check kyosu::mulmi over octonion" + , kyosu::real_types + , tts::generate ( tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + , tts::randoms(-10,10), tts::randoms(-10,10) + ) + ) + (T r, T i, T j, T k, T l, T li, T lj, T lk) +{ + using type = kyosu::octonion_t; + TTS_EQUAL(kyosu::mulmi(type(r,i,j,k,l,li,lj,lk)), kyosu::mi(kyosu::as())*type(r,i,j,k,l,li,lj,lk)); +}; diff --git a/test/unit/function/sqr_abs.cpp b/test/unit/function/sqr_abs.cpp index 286324ea..1b11c34f 100644 --- a/test/unit/function/sqr_abs.cpp +++ b/test/unit/function/sqr_abs.cpp @@ -24,6 +24,9 @@ TTS_CASE_WITH ( "Check kyosu::sqr_abs over complex" (auto r, auto i) { TTS_ULP_EQUAL(kyosu::sqr_abs(kyosu::complex(r,i)), r*r+i*i, 0.5); + auto inf = eve::inf(kyosu::as(r)); + auto nan = eve::nan(kyosu::as(r)); + TTS_IEEE_EQUAL(kyosu::sqr_abs(kyosu::complex(inf, nan)), inf); }; TTS_CASE_WITH ( "Check kyosu::sqr_abs over quaternion" @@ -36,4 +39,7 @@ TTS_CASE_WITH ( "Check kyosu::sqr_abs over quaternion" { using type = kyosu::quaternion_t; TTS_ULP_EQUAL(kyosu::sqr_abs(type(r,i,j,k)), r*r+i*i+j*j+k*k, 2.0); + auto inf = eve::inf(kyosu::as(r)); + auto nan = eve::nan(kyosu::as(r)); + TTS_IEEE_EQUAL(kyosu::sqr_abs(type(r,inf,j,nan)), inf); };