diff --git a/include/kyosu/functions/is_imag.hpp b/include/kyosu/complex/arg.hpp similarity index 68% rename from include/kyosu/functions/is_imag.hpp rename to include/kyosu/complex/arg.hpp index 33190eaf..1e0d2df1 100644 --- a/include/kyosu/functions/is_imag.hpp +++ b/include/kyosu/complex/arg.hpp @@ -11,14 +11,16 @@ namespace kyosu::tags { - struct callable_is_imag : eve::elementwise + struct callable_arg : eve::elementwise { - using callable_tag_type = callable_is_imag; + using callable_tag_type = callable_arg; - KYOSU_DEFERS_CALLABLE(is_imag_); + KYOSU_DEFERS_CALLABLE(arg_); template - static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::is_eqz(v); } + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { + return eve::if_else(eve::is_positive(v), eve::zero, eve::pi(eve::as(v))); + } template KYOSU_FORCEINLINE auto operator()(T const& target) const noexcept -> decltype(eve::tag_invoke(*this, target)) @@ -27,7 +29,7 @@ namespace kyosu::tags } template - eve::unsupported_call operator()(T&&... x) const + eve::unsupported_call operator()(T&&... x) const requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; }; } @@ -37,8 +39,8 @@ namespace kyosu //====================================================================================================================== //! @addtogroup functions //! @{ -//! @var is_imag -//! @brief test if the complex parameter is pure imaginary. +//! @var arg +//! @brief complex number argument. //! //! **Defined in Header** //! @@ -51,8 +53,8 @@ namespace kyosu //! @code //! namespace kyosu //! { -//! template constexpr auto is_imag(T z) noexcept; -//! template constexpr auto is_imag(T z) noexcept; +//! template constexpr auto arg(T z) noexcept; +//! template constexpr auto arg(T z) noexcept; //! } //! @endcode //! @@ -62,12 +64,12 @@ namespace kyosu //! //! **Return value** //! -//! Returns the value of real(z) == 0. +//! Returns elementwise true the argument of the complex number i.e. `atan2(imag(z), real(z))`. //! //! @groupheader{Example} //! -//! @godbolt{doc/is_imag.cpp} +//! @godbolt{doc/arg.cpp} //! @} //====================================================================================================================== -inline constexpr tags::callable_is_imag is_imag = {}; +inline constexpr tags::callable_arg arg = {}; } diff --git a/include/kyosu/complex/impl/arithmetic.hpp b/include/kyosu/complex/impl/arithmetic.hpp new file mode 100644 index 00000000..c070dfd9 --- /dev/null +++ b/include/kyosu/complex/impl/arithmetic.hpp @@ -0,0 +1,19 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once +#include + +namespace kyosu::_ +{ + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + return eve::pedantic(eve::atan2(kyosu::imag(c), kyosu::real(c)); + } +} diff --git a/include/kyosu/complex/polar.hpp b/include/kyosu/complex/polar.hpp new file mode 100644 index 00000000..09252844 --- /dev/null +++ b/include/kyosu/complex/polar.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_polar : eve::elementwise + { + using callable_tag_type = callable_polar; + + KYOSU_DEFERS_CALLABLE(polar_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T0 const& rho, T1 const & theta) noexcept + { + auto [s, c] = eve::sincos(theta); + return kyosu::to_complex(rho*c, eve::if_else(eve::is_eqz(s), eve::zero, rho*s)); + } + + template + KYOSU_FORCEINLINE auto operator()(T0 const& target0, T1 const& target1) const noexcept + -> decltype(eve::tag_invoke(*this, target0, target1)) + { + return eve::tag_invoke(*this, target0, target1); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var polar +//! @brief complex number from modulus and argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto polar(T0 rho, T1 theta) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `rho` : modulus. +//! * `theta` : argument. +//! +//! **Return value** +//! +//! Returns elementwise true the polarument of the complex number i.e. \f$\rho e^{i\theta}\f$. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/polar.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_polar polar = {}; +} diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index 49d915b8..45e663a5 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -8,8 +8,8 @@ #pragma once //====================================================================================================================== -//! @defgroup functions Functions -//! @brief Functions performing computations over complex, quaternions and octonions. +//! @defgroup functions Cayley-Dickson Functions +//! @brief Functions performing computations over all caylet-dickson types complex, quaternions, octonions... //====================================================================================================================== #include #include @@ -42,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -57,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +65,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -83,3 +87,11 @@ #include #include #include + +//====================================================================================================================== +//! @brief Functions performing computations over complex or real elements only. +//====================================================================================================================== + +#include +#include +#include diff --git a/include/kyosu/functions/log_abs.hpp b/include/kyosu/functions/log_abs.hpp new file mode 100644 index 00000000..dcae6ed0 --- /dev/null +++ b/include/kyosu/functions/log_abs.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_abs : eve::elementwise + { + using callable_tag_type = callable_log_abs; + + KYOSU_DEFERS_CALLABLE(log_abs_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept + { + auto fn = callable_log_abs{}; + 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_abs +//! @brief Computes the natural logarithm of the absolute value of the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constlog_absr T log_abs(T z) noexcept; +//! template constlog_absr T log_abs(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to process. +//! +//! **Return value** +//! +//! Returns the `log(abs(z))`. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/log_abs.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_log_abs log_abs = {}; +} diff --git a/include/kyosu/functions/pow.hpp b/include/kyosu/functions/pow.hpp new file mode 100644 index 00000000..ff96d63e --- /dev/null +++ b/include/kyosu/functions/pow.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +namespace kyosu::tags +{ + struct callable_pow : eve::elementwise + { + using callable_tag_type = callable_pow; + + KYOSU_DEFERS_CALLABLE(pow_); + + static KYOSU_FORCEINLINE auto deferred_call(auto + , eve::ordered_value auto const& v0 + , eve::ordered_value auto const& v1) noexcept + { + return eve::pow(v0, v1); + } + + KYOSU_FORCEINLINE auto operator()(auto const& target0, auto const& target1) const noexcept + -> decltype(eve::tag_invoke(*this, target0, target1)) + { + return eve::tag_invoke(*this, target0, target1); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var pow +//! @brief Computes the computing the pow operation \f$x^y\f$. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto pow(T0 z0, T1, z1) noexcept; +//! template > constexpr auto pow(T0 z0, T1, z1) noexcept; +//! template constexpr auto pow(T0 z0, T1, z1) noexcept; +//! template > constexpr auto pow(T0 z0, T1, z1) noexcept; +///! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z0, z1` : Values to process. +//! +//! **Return value** +//! +//! the call is semantically equivalent to `eve::exp(z1*eve::log(z0))` +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/pow.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_pow pow = {}; +} diff --git a/include/kyosu/functions/pow1p.hpp b/include/kyosu/functions/pow1p.hpp new file mode 100644 index 00000000..9bdf03bd --- /dev/null +++ b/include/kyosu/functions/pow1p.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +namespace kyosu::tags +{ + struct callable_pow1p : eve::elementwise + { + using callable_tag_type = callable_pow1p; + + KYOSU_DEFERS_CALLABLE(pow1p_); + + static KYOSU_FORCEINLINE auto deferred_call(auto + , eve::ordered_value auto const& v0 + , eve::ordered_value auto const& v1) noexcept + { + return eve::pow1p(v0, v1); + } + + KYOSU_FORCEINLINE auto operator()(auto const& target0, auto const& target1) const noexcept + -> decltype(eve::tag_invoke(*this, target0, target1)) + { + return eve::tag_invoke(*this, target0, target1); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var pow1p +//! @brief Computes the computing the pow1p operation \f$(x+1)^y\f$. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto pow1p(T0 z0, T1, z1) noexcept; +//! template > constexpr auto pow1p(T0 z0, T1, z1) noexcept; +//! template constexpr auto pow1p(T0 z0, T1, z1) noexcept; +//! template > constexpr auto pow1p(T0 z0, T1, z1) noexcept; +///! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z0, z1` : Values to process. +//! +//! **Return value** +//! +//! the call is semantically equivalent to `eve::exp(z1*eve::log1p(z0))` +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/pow1p.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_pow1p pow1p = {}; +} diff --git a/include/kyosu/functions/pow_abs.hpp b/include/kyosu/functions/pow_abs.hpp new file mode 100644 index 00000000..bdd661e9 --- /dev/null +++ b/include/kyosu/functions/pow_abs.hpp @@ -0,0 +1,78 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +namespace kyosu::tags +{ + struct callable_pow_abs : eve::elementwise + { + using callable_tag_type = callable_pow_abs; + + KYOSU_DEFERS_CALLABLE(pow_abs_); + + static KYOSU_FORCEINLINE auto deferred_call(auto + , eve::ordered_value auto const& v0 + , eve::ordered_value auto const& v1) noexcept + { + return eve::pow(eve::abs(v0), v1); + } + + KYOSU_FORCEINLINE auto operator()(auto const& target0, auto const& target1) const noexcept + -> decltype(eve::tag_invoke(*this, target0, target1)) + { + return eve::tag_invoke(*this, target0, target1); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var pow_abs +//! @brief Computes the computing the pow_abs operation \f$(|x|)^y\f$. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto pow_abs(T0 z0, T1, z1) noexcept; +//! template > constexpr auto pow_abs(T0 z0, T1, z1) noexcept; +//! template constexpr auto pow_abs(T0 z0, T1, z1) noexcept; +//! template > constexpr auto pow_abs(T0 z0, T1, z1) noexcept; +///! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z0, z1` : Values to process. +//! +//! **Return value** +//! +//! the call is semantically equivalent to `eve::exp(abs(z1)*log(z0))` +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/pow_abs.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_pow_abs pow_abs = {}; +} diff --git a/include/kyosu/functions/powm1.hpp b/include/kyosu/functions/powm1.hpp new file mode 100644 index 00000000..4b0ce9e8 --- /dev/null +++ b/include/kyosu/functions/powm1.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_powm1 : eve::elementwise + { + using callable_tag_type = callable_powm1; + + KYOSU_DEFERS_CALLABLE(powm1_); + + static KYOSU_FORCEINLINE auto deferred_call(auto + , eve::ordered_value auto const& v0 + , eve::ordered_value auto const& v1) noexcept + { + return eve::powm1(v0, v1); //dec(eve::pow(v0, v1)); + } + + KYOSU_FORCEINLINE auto operator()(auto const& target0, auto const& target1) const noexcept + -> decltype(eve::tag_invoke(*this, target0, target1)) + { + return eve::tag_invoke(*this, target0, target1); + } + + template + eve::unsupported_call operator()(T&&... x) const + requires(!requires { eve::tag_invoke(*this, KYOSU_FWD(x)...); }) = delete; + }; +} + +namespace kyosu +{ +//====================================================================================================================== +//! @addtogroup functions +//! @{ +//! @var powm1 +//! @brief Computes the computing the powm1 operation \f$x^y-1\f$. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr auto powm1(T0 z0, T1, z1) noexcept; +//! template > constexpr auto powm1(T0 z0, T1, z1) noexcept; +//! template constexpr auto powm1(T0 z0, T1, z1) noexcept; +//! template > constexpr auto powm1(T0 z0, T1, z1) noexcept; +///! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z0, z1` : Values to process. +//! +//! **Return value** +//! +//! the call is semantically equivalent to `eve::exp(z1*eve::log(z0))-1` +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/powm1.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_powm1 powm1 = {}; +} diff --git a/include/kyosu/types/cayley_dickson.hpp b/include/kyosu/types/cayley_dickson.hpp index 6ab99347..c392fae3 100644 --- a/include/kyosu/types/cayley_dickson.hpp +++ b/include/kyosu/types/cayley_dickson.hpp @@ -16,6 +16,8 @@ #include #include #include +#include + #include namespace kyosu diff --git a/include/kyosu/types/impl/complex/arithmetic.hpp b/include/kyosu/types/impl/complex/arithmetic.hpp new file mode 100644 index 00000000..78348889 --- /dev/null +++ b/include/kyosu/types/impl/complex/arithmetic.hpp @@ -0,0 +1,21 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::_ +{ + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + return /*eve::pedantic*/(eve::atan2(kyosu::imag(c), kyosu::real(c))); + } + +} diff --git a/include/kyosu/types/impl/math.hpp b/include/kyosu/types/impl/math.hpp index 2efac083..38d2127a 100644 --- a/include/kyosu/types/impl/math.hpp +++ b/include/kyosu/types/impl/math.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace kyosu::_ { @@ -127,6 +128,14 @@ namespace kyosu::_ } } + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& z) noexcept + { + using u_t = eve::underlying_type_t; + return eve::half(eve::as())*eve::log(kyosu::sqr_abs(z)); + } + template KYOSU_FORCEINLINE constexpr auto dispatch(eve::tag_of const&, C const& z) noexcept @@ -338,4 +347,124 @@ namespace kyosu::_ if constexpr(sizeof...(zs) == 0) return 0.0f; else return eve::manhattan(kumi::flatten(kumi::cat(zs...))); } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept + { + using r_t = kyosu::as_cayley_dickson_t; + using er_t = eve::element_type_t; + using u_t = eve::underlying_type_t; + if constexpr(eve::integral_value) + { + if constexpr( eve::unsigned_value ) + { + C0 base = c0; + C1 expo = c1; + auto const o = eve::one(eve::as()); + r_t result(o); + std::cout << "result " << result << std::endl; + while(true) + { + if (eve::all(eve::is_eqz(expo))) break; + std::cout << "expo " << expo << " base " << base << "result " << result << std::endl; + result = kyosu::if_else(eve::is_odd(expo), result*base, o); + std::cout << "expo " << expo << " base " << base << "result " << result << std::endl; + expo = (expo >> 1); + base = kyosu::sqr(base); + } + return result; + } + else + { + using ic1_t = eve::as_integer_t; + auto tmp = kyosu::pow(c0, eve::bit_cast(eve::abs(c1), eve::as())); + return kyosu::if_else(eve::is_ltz(c1), kyosu::rec(tmp), tmp); + } + } + else if constexpr(kyosu::concepts::complex && kyosu::concepts::complex) + { + r_t r; + if constexpr(eve::floating_value && kyosu::concepts::complex) // c1 is complex c0 is real + { + auto [rc1, ic1] = c1; + auto lgac0 = eve::log_abs(c0); + auto ang = eve::if_else(kyosu::is_real(c1), eve::zero, ic1*lgac0); + auto mod = eve::pow(c0, rc1); + auto r1 = kyosu::polar(mod, ang); + auto isposc0 = eve::is_positive(c0); + if (eve::all(isposc0)) + { + r = r1; + } + else + { + auto rho = eve::exp(eve::diff_of_prod(lgac0, rc1, ic1, eve::pi(eve::as(rc1)))); + auto theta = eve::pedantic(eve::sum_of_prod)(eve::pi(eve::as(rc1)), rc1, ic1, lgac0); + auto r2 = rho*kyosu::exp_i(theta); + r = kyosu::if_else(isposc0, r1, r2); + } + } + else if constexpr(eve::floating_value ) // c0 is complex c1 is real + { + auto lc0 = kyosu::log_abs(c0); + auto argc0 = kyosu::arg(c0); + auto rho = eve::exp(lc0*c1); + auto theta = argc0*c1; + return rho*kyosu::exp_i(theta); + } + else if constexpr( kyosu::concepts::complex)// c0 and c1 are complex + { + auto [rc1, ic1] = c1; + auto lc0 = kyosu::log_abs(c0); + auto argc0 = kyosu::arg(c0); + auto rho = eve::exp(eve::pedantic(eve::diff_of_prod)(lc0, rc1, ic1, argc0)); + auto theta = eve::pedantic(eve::sum_of_prod)(argc0, rc1, ic1, lc0); + r = rho*exp_i(theta); + auto realc0 = is_real(c0); + if(eve::any(realc0)) + { + auto rr = to_complex(kyosu::pow(real(c0), c1)); + r = kyosu::if_else(realc0, rr, r); + } + } + r = kyosu::if_else(kyosu::is_eqz(c1), eve::one(eve::as()), r); + return r; + } + else + { + auto cc0 = kyosu::convert(c0, eve::as()); + auto cc1 = kyosu::convert(c1, eve::as()); + + auto r = kyosu::exp(kyosu::log(cc0)*cc1); + return kyosu::if_else (kyosu::is_eqz(cc0) + , eve::if_else(kyosu::is_eqz(cc1) + , eve::one(eve::as()) + , eve::zero(eve::as())) + , r + ); + } + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept + { + auto ac0 = kyosu::sqr_abs(c0); + return kyosu::pow(ac0, c1*eve::half(eve::as(kyosu::real(c0)))); + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept + { + return kyosu::dec(kyosu::pow(c0, c1)); + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C0 const & c0, C1 const & c1) noexcept + { + return kyosu::pow(kyosu::inc(c0), c1); + } } diff --git a/test/unit/function/pow.cpp b/test/unit/function/pow.cpp new file mode 100644 index 00000000..8dfda5b0 --- /dev/null +++ b/test/unit/function/pow.cpp @@ -0,0 +1,62 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::pow over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10) + ,tts::between(-10,10) + ) + ) +(auto r0, auto r1) +{ + TTS_EQUAL(kyosu::pow(r0, r1), eve::pow(r0, r1)); + TTS_RELATIVE_EQUAL(kyosu::pow(r0, 4), kyosu::sqr(kyosu::sqr(r0)), 1.0e-5); +}; + +TTS_CASE_WITH ( "Check kyosu::pow over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10) + ,tts::between(-10,10), tts::between(-10,10) + ) + ) +(auto r0, auto i0, auto r1, auto i1) +{ + auto c0 = kyosu::to_complex(r0,i0); + auto c1 = kyosu::to_complex(r1,i1); + TTS_RELATIVE_EQUAL(kyosu::pow(c0, c1), kyosu::exp(c1*kyosu::log(c0)), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::pow(r0, c1), kyosu::exp(c1*kyosu::log(r0)), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::pow(c0, r1), kyosu::exp(r1*kyosu::log(c0)), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::pow(c0, 4u), c0*kyosu::sqr(kyosu::sqr(c0)), 1.0e-5); + + auto o = 1.0f; + auto oo = kyosu::to_complex(o+o, o); + auto z = kyosu::if_else(4 < 2, o*oo, o); + std::cout << "o " << o << std::endl; + std::cout << "oo " << oo << std::endl; + std::cout << "o*oo " << o*oo << std::endl; + std::cout << "z " << z << std::endl; +}; + +TTS_CASE_WITH ( "Check kyosu::pow over quaternion" + , kyosu::real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r0, T i0, T j0, T k0, T r1, T i1, T j1, T k1) +{ + using type = kyosu::as_quaternion_t; + auto q0 = type(r0,i0,j0,k0); + auto q1 = type(r1,i1,j1,k1); + TTS_RELATIVE_EQUAL(kyosu::pow(q0, q1), kyosu::exp(q1*kyosu::log(q0)), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::pow(q0, 4), kyosu::sqr(kyosu::sqr(q0)), 1.0e-5); +}; diff --git a/test/unit/function/pow1p.cpp b/test/unit/function/pow1p.cpp new file mode 100644 index 00000000..83e87c27 --- /dev/null +++ b/test/unit/function/pow1p.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::pow1p over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10) + ,tts::between(-10,10) + ) + ) +(auto r0, auto r1) +{ + TTS_EQUAL(kyosu::pow1p(r0, r1), eve::pow1p(r0, r1)); +// TTS_RELATIVE_EQUAL(kyosu::pow1p(r0, 4), kyosu::sqr(kyosu::sqr(eve::inc(r0))), 1.0e-5); +}; + +TTS_CASE_WITH ( "Check kyosu::pow1p over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10) + ,tts::between(-10,10), tts::between(-10,10) + ) + ) +(auto r0, auto i0, auto r1, auto i1) +{ + auto c0 = kyosu::to_complex(r0,i0); + auto c1 = kyosu::to_complex(r1,i1); + TTS_RELATIVE_EQUAL(kyosu::pow1p(c0, c1), kyosu::exp(c1*kyosu::log(kyosu::inc(c0))), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::pow1p(r0, c1), kyosu::exp(c1*kyosu::log(kyosu::inc(r0))), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::pow1p(c0, r1), kyosu::exp(r1*kyosu::log(kyosu::inc(c0))), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::pow1p(c0, 4u), kyosu::dec(c0*kyosu::sqr(kyosu::sqr(c0)), 1.0e-5); +}; + +TTS_CASE_WITH ( "Check kyosu::pow1p over quaternion" + , kyosu::real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r0, T i0, T j0, T k0, T r1, T i1, T j1, T k1) +{ + using type = kyosu::as_quaternion_t; + auto q0 = type(r0,i0,j0,k0); + auto q1 = type(r1,i1,j1,k1); + TTS_RELATIVE_EQUAL(kyosu::pow1p(q0, q1), kyosu::exp(q1*kyosu::log(kyosu::inc(q0))), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::pow1p(q0, 4), kyosu::sqr(kyosu::sqr(q0)), 1.0e-5); +}; diff --git a/test/unit/function/pow_abs.cpp b/test/unit/function/pow_abs.cpp new file mode 100644 index 00000000..5ad4dbb0 --- /dev/null +++ b/test/unit/function/pow_abs.cpp @@ -0,0 +1,64 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::pow_abs over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10) + ,tts::between(-10,10) + ) + ) +(auto r0, auto r1) +{ + TTS_EQUAL(kyosu::pow_abs(r0, r1), eve::pow_abs(r0, r1)); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(r0, 4), kyosu::sqr(kyosu::sqr(r0)), 1.0e-5); +}; + +TTS_CASE_WITH ( "Check kyosu::pow_abs over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10) + ,tts::between(-10,10), tts::between(-10,10) + ) + ) +(auto r0, auto i0, auto r1, auto i1) +{ + auto c0 = kyosu::to_complex(r0,i0); + auto c1 = kyosu::to_complex(r1,i1); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(c0, c1), kyosu::exp(c1*kyosu::log_abs(c0)), 1e-4); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(r0, c1), kyosu::exp(c1*kyosu::log_abs(r0)), 1e-4); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(c0, r1), kyosu::exp(r1*kyosu::log_abs(c0)), 2e-4); +// TTS_RELATIVE_EQUAL(kyosu::pow_abs(c0, 4u), c0*kyosu::sqr(kyosu::sqr(c0)), 1.0e-4); + + auto o = 1.0f; + auto oo = kyosu::to_complex(o+o, o); + auto z = kyosu::if_else(4 < 2, o*oo, o); + std::cout << "o " << o << std::endl; + std::cout << "oo " << oo << std::endl; + std::cout << "o*oo " << o*oo << std::endl; + std::cout << "z " << z << std::endl; +}; + +TTS_CASE_WITH ( "Check kyosu::pow_abs over quaternion" + , kyosu::real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r0, T i0, T j0, T k0, T r1, T i1, T j1, T k1) +{ + using type = kyosu::as_quaternion_t; + auto q0 = type(r0,i0,j0,k0); + auto q1 = type(r1,i1,j1,k1); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(q0, q1), kyosu::exp(q1*kyosu::log_abs(q0)), 1e-4); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(r0, q1), kyosu::exp(q1*kyosu::log_abs(r0)), 1e-4); + TTS_RELATIVE_EQUAL(kyosu::pow_abs(q0, r1), kyosu::exp(r1*kyosu::log_abs(q0)), 1e-4); +// TTS_RELATIVE_EQUAL(kyosu::pow_abs(q0, 4), kyosu::sqr(kyosu::sqr(q0)), 1.0e-4); +}; diff --git a/test/unit/function/powm1.cpp b/test/unit/function/powm1.cpp new file mode 100644 index 00000000..5ab0f780 --- /dev/null +++ b/test/unit/function/powm1.cpp @@ -0,0 +1,62 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::powm1 over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10) + ,tts::between(-10,10) + ) + ) +(auto r0, auto r1) +{ + TTS_EQUAL(kyosu::powm1(r0, r1), eve::powm1(r0, r1)); +// TTS_RELATIVE_EQUAL(kyosu::powm1(r0, 4), kyosu::sqr(kyosu::sqr(r0)), 1.0e-5); +}; + +TTS_CASE_WITH ( "Check kyosu::powm1 over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10) + ,tts::between(-10,10), tts::between(-10,10) + ) + ) +(auto r0, auto i0, auto r1, auto i1) +{ + auto c0 = kyosu::to_complex(r0,i0); + auto c1 = kyosu::to_complex(r1,i1); + TTS_RELATIVE_EQUAL(kyosu::powm1(c0, c1), kyosu::dec(kyosu::exp(c1*kyosu::log(c0))), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::powm1(r0, c1), kyosu::dec(kyosu::exp(c1*kyosu::log(r0))), 1e-5); + TTS_RELATIVE_EQUAL(kyosu::powm1(c0, r1), kyosu::dec(kyosu::exp(r1*kyosu::log(c0))), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::powm1(c0, 4u), kyosu::dec(c0*kyosu::sqr(kyosu::sqr(c0))), 1.0e-5); + + auto o = 1.0f; + auto oo = kyosu::to_complex(o+o, o); + auto z = kyosu::if_else(4 < 2, o*oo, o); + std::cout << "o " << o << std::endl; + std::cout << "oo " << oo << std::endl; + std::cout << "o*oo " << o*oo << std::endl; + std::cout << "z " << z << std::endl; +}; + +TTS_CASE_WITH ( "Check kyosu::powm1 over quaternion" + , kyosu::real_types + , tts::generate ( tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + , tts::between(-10,10), tts::between(-10,10) + ) + ) +(T r0, T i0, T j0, T k0, T r1, T i1, T j1, T k1) +{ + using type = kyosu::as_quaternion_t; + auto q0 = type(r0,i0,j0,k0); + auto q1 = type(r1,i1,j1,k1); + TTS_RELATIVE_EQUAL(kyosu::powm1(q0, q1), kyosu::dec(kyosu::exp(q1*kyosu::log((q0)))), 1e-5); +// TTS_RELATIVE_EQUAL(kyosu::powm1(q0, 4), kyosu::dec(kyosu::sqr(kyosu::sqr(q0))), 1.0e-5); +};