diff --git a/include/kyosu/functions.hpp b/include/kyosu/functions.hpp index a4a3f217..863f711f 100644 --- a/include/kyosu/functions.hpp +++ b/include/kyosu/functions.hpp @@ -14,13 +14,17 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include +#include #include #include #include diff --git a/include/kyosu/functions/dec.hpp b/include/kyosu/functions/dec.hpp new file mode 100644 index 00000000..a64259f8 --- /dev/null +++ b/include/kyosu/functions/dec.hpp @@ -0,0 +1,73 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_dec : eve::elementwise + { + using callable_tag_type = callable_dec; + + KYOSU_DEFERS_CALLABLE(dec_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::dec(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 dec +//! @brief decrements the argument by 1. +//! +//! **Defined in Header** +//! +//! @code +//! #declude +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T dec(T z) noexcept; +//! template constexpr T dec(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to decrement. +//! +//! **Return value** +//! +//! Returns its argument minus 1. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/dec.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_dec dec = {}; +} diff --git a/include/kyosu/functions/inc.hpp b/include/kyosu/functions/inc.hpp new file mode 100644 index 00000000..b493af8b --- /dev/null +++ b/include/kyosu/functions/inc.hpp @@ -0,0 +1,73 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_inc : eve::elementwise + { + using callable_tag_type = callable_inc; + + KYOSU_DEFERS_CALLABLE(inc_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::inc(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 inc +//! @brief Increments the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T inc(T z) noexcept; +//! template constexpr T inc(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to increment. +//! +//! **Return value** +//! +//! Returns its argument plus 1. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/inc.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_inc inc = {}; +} diff --git a/include/kyosu/functions/minus.hpp b/include/kyosu/functions/minus.hpp new file mode 100644 index 00000000..b596b1f4 --- /dev/null +++ b/include/kyosu/functions/minus.hpp @@ -0,0 +1,73 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_minus : eve::elementwise + { + using callable_tag_type = callable_minus; + + KYOSU_DEFERS_CALLABLE(minus_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return -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 minus +//! @brief Computes the opposite value. +//! +//! **Defined in Header** +//! +//! @code +//! #include +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T minus(T z) noexcept; +//! template constexpr T minus(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : Value to minusugate. +//! +//! **Return value** +//! +//! Returns the opposite of its argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/minus.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_minus minus = {}; +} diff --git a/include/kyosu/functions/oneminus.hpp b/include/kyosu/functions/oneminus.hpp new file mode 100644 index 00000000..0e6ae8f3 --- /dev/null +++ b/include/kyosu/functions/oneminus.hpp @@ -0,0 +1,73 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include + +namespace kyosu::tags +{ + struct callable_oneminus : eve::elementwise + { + using callable_tag_type = callable_oneminus; + + KYOSU_DEFERS_CALLABLE(oneminus_); + + template + static KYOSU_FORCEINLINE auto deferred_call(auto, T const& v) noexcept { return eve::oneminus(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 oneminus +//! @brief Computes the value 1 minus the argument. +//! +//! **Defined in Header** +//! +//! @code +//! #oneminuslude +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace kyosu +//! { +//! template constexpr T oneminus(T z) noexcept; +//! template constexpr T oneminus(T z) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `z` : argument. +//! +//! **Return value** +//! +//! Returns 1 minus the argument. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/oneminus.cpp} +//! @} +//====================================================================================================================== +inline constexpr tags::callable_oneminus oneminus = {}; +} diff --git a/include/kyosu/types/impl/arithmetic.hpp b/include/kyosu/types/impl/arithmetic.hpp index 3417553a..e8985472 100644 --- a/include/kyosu/types/impl/arithmetic.hpp +++ b/include/kyosu/types/impl/arithmetic.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace kyosu::_ { @@ -95,4 +96,35 @@ namespace kyosu::_ { return C{kumi::map([](auto const& e) { return eve::frac(e); }, c)}; } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C const& c) noexcept + { + return -c; + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C c) noexcept + { + real(c) = eve::inc(real(c)); + return c; + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C c) noexcept + { + real(c) = eve::dec(real(c)); + return c; + } + + template + KYOSU_FORCEINLINE constexpr + auto dispatch(eve::tag_of const&, C c) noexcept + { + return kyosu::inc(kyosu::minus(c)); + } + } diff --git a/test/doc/dec.cpp b/test/doc/dec.cpp new file mode 100644 index 00000000..3278b095 --- /dev/null +++ b/test/doc/dec.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() +{ + using kyosu::dec; + using kyosu::complex; + using kyosu::quaternion; + using e_t = float; + using c_t = complex; + using q_t = quaternion; + using we_t = eve::wide>; + using wc_t = eve::wide>; + using wq_t = eve::wide>; + + std::cout << "Real: \n"; + e_t e(72.9f); + we_t we = we_t(e); + std::cout << e << " -> " << dec(e) << "\n"; + std::cout << we << " -> " << dec(we) << "\n"; + + std::cout << "Complex: \n"; + c_t c(3.5f,-2.9f); + wc_t wc = wc_t(c); + std::cout << c << " -> " << dec(c) << "\n"; + std::cout << wc << " -> " << dec(wc) << "\n"; + + std::cout << "Quaternion: \n"; + q_t q(3.5f,-2.9f, 2.1f, 3.2f); + wq_t wq = wq_t(q); + std::cout << q << " -> " << dec(q) << "\n"; + std::cout << wq << " -> " << dec(wq) << "\n"; + + return 0; +} diff --git a/test/doc/inc.cpp b/test/doc/inc.cpp new file mode 100644 index 00000000..fdfac122 --- /dev/null +++ b/test/doc/inc.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() +{ + using kyosu::inc; + using kyosu::complex; + using kyosu::quaternion; + using e_t = float; + using c_t = complex; + using q_t = quaternion; + using we_t = eve::wide>; + using wc_t = eve::wide>; + using wq_t = eve::wide>; + + std::cout << "Real: \n"; + e_t e(72.9f); + we_t we = we_t(e); + std::cout << e << " -> " << inc(e) << "\n"; + std::cout << we << " -> " << inc(we) << "\n"; + + std::cout << "Complex: \n"; + c_t c(3.5f,-2.9f); + wc_t wc = wc_t(c); + std::cout << c << " -> " << inc(c) << "\n"; + std::cout << wc << " -> " << inc(wc) << "\n"; + + std::cout << "Quaternion: \n"; + q_t q(3.5f,-2.9f, 2.1f, 3.2f); + wq_t wq = wq_t(q); + std::cout << q << " -> " << inc(q) << "\n"; + std::cout << wq << " -> " << inc(wq) << "\n"; + + return 0; +} diff --git a/test/doc/minus.cpp b/test/doc/minus.cpp new file mode 100644 index 00000000..ddbec677 --- /dev/null +++ b/test/doc/minus.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() +{ + using kyosu::minus; + using kyosu::complex; + using kyosu::quaternion; + using e_t = float; + using c_t = complex; + using q_t = quaternion; + using we_t = eve::wide>; + using wc_t = eve::wide>; + using wq_t = eve::wide>; + + std::cout << "Real: \n"; + e_t e(72.9f); + we_t we = we_t(e); + std::cout << e << " -> " << minus(e) << "\n"; + std::cout << we << " -> " << minus(we) << "\n"; + + std::cout << "Complex: \n"; + c_t c(3.5f,-2.9f); + wc_t wc = wc_t(c); + std::cout << c << " -> " << minus(c) << "\n"; + std::cout << wc << " -> " << minus(wc) << "\n"; + + std::cout << "Quaternion: \n"; + q_t q(3.5f,-2.9f, 2.1f, 3.2f); + wq_t wq = wq_t(q); + std::cout << q << " -> " << minus(q) << "\n"; + std::cout << wq << " -> " << minus(wq) << "\n"; + + return 0; +} diff --git a/test/doc/oneminus.cpp b/test/doc/oneminus.cpp new file mode 100644 index 00000000..b9ec4394 --- /dev/null +++ b/test/doc/oneminus.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() +{ + using kyosu::oneminus; + using kyosu::complex; + using kyosu::quaternion; + using e_t = float; + using c_t = complex; + using q_t = quaternion; + using we_t = eve::wide>; + using wc_t = eve::wide>; + using wq_t = eve::wide>; + + std::cout << "Real: \n"; + e_t e(72.9f); + we_t we = we_t(e); + std::cout << e << " -> " << oneminus(e) << "\n"; + std::cout << we << " -> " << oneminus(we) << "\n"; + + std::cout << "Complex: \n"; + c_t c(3.5f,-2.9f); + wc_t wc = wc_t(c); + std::cout << c << " -> " << oneminus(c) << "\n"; + std::cout << wc << " -> " << oneminus(wc) << "\n"; + + std::cout << "Quaternion: \n"; + q_t q(3.5f,-2.9f, 2.1f, 3.2f); + wq_t wq = wq_t(q); + std::cout << q << " -> " << oneminus(q) << "\n"; + std::cout << wq << " -> " << oneminus(wq) << "\n"; + + return 0; +} diff --git a/test/unit/function/dec.cpp b/test/unit/function/dec.cpp new file mode 100644 index 00000000..5acac332 --- /dev/null +++ b/test/unit/function/dec.cpp @@ -0,0 +1,40 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::dec over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_EQUAL(kyosu::dec(data), eve::dec(data)); +}; + +TTS_CASE_WITH ( "Check kyosu::dec over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10)) + ) +(T r, T i) +{ + using type = kyosu::as_complex_t; + TTS_EQUAL(kyosu::dec(type(r,i)), type(r-1,i)); +}; + +TTS_CASE_WITH ( "Check kyosu::dec over quaternion" + , kyosu::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 type = kyosu::as_quaternion_t; + TTS_EQUAL(kyosu::dec(type(r,i,j,k)), type(r-1,i,j,k)); +}; diff --git a/test/unit/function/inc.cpp b/test/unit/function/inc.cpp new file mode 100644 index 00000000..74f1b905 --- /dev/null +++ b/test/unit/function/inc.cpp @@ -0,0 +1,40 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::inc over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_EQUAL(kyosu::inc(data), eve::inc(data)); +}; + +TTS_CASE_WITH ( "Check kyosu::inc over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10)) + ) +(T r, T i) +{ + using type = kyosu::as_complex_t; + TTS_EQUAL(kyosu::inc(type(r,i)), type(r+1,i)); +}; + +TTS_CASE_WITH ( "Check kyosu::inc over quaternion" + , kyosu::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 type = kyosu::as_quaternion_t; + TTS_EQUAL(kyosu::inc(type(r,i,j,k)), type(r+1,i,j,k)); +}; diff --git a/test/unit/function/minus.cpp b/test/unit/function/minus.cpp new file mode 100644 index 00000000..46c5ee01 --- /dev/null +++ b/test/unit/function/minus.cpp @@ -0,0 +1,39 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::minus over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_EQUAL(kyosu::minus(data), -data); +}; + +TTS_CASE_WITH ( "Check kyosu::minus over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10)) + ) +(auto r, auto i) +{ + TTS_EQUAL(kyosu::minus(kyosu::to_complex(r,i)), kyosu::to_complex(-r,-i)); +}; + +TTS_CASE_WITH ( "Check kyosu::minus over quaternion" + , kyosu::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 type = kyosu::as_quaternion_t; + TTS_EQUAL(kyosu::minus(type(r,i,j,k)), type(-r,-i,-j,-k)); +}; diff --git a/test/unit/function/oneminus.cpp b/test/unit/function/oneminus.cpp new file mode 100644 index 00000000..e537aa34 --- /dev/null +++ b/test/unit/function/oneminus.cpp @@ -0,0 +1,42 @@ +//====================================================================================================================== +/* + Kyosu - Complex Without Complexes + Copyright : KYOSU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#include +#include + +TTS_CASE_WITH ( "Check kyosu::oneminus over real" + , kyosu::real_types + , tts::generate(tts::between(-10,10)) + ) +(auto data) +{ + TTS_EQUAL(kyosu::oneminus(data), eve::oneminus(data)); +}; + +TTS_CASE_WITH ( "Check kyosu::oneminus over complex" + , kyosu::real_types + , tts::generate(tts::between(-10,10), tts::between(-10,10)) + ) +(T r, T i) +{ + using type = kyosu::as_complex_t; + auto o = type(1); + TTS_EQUAL(kyosu::oneminus(type(r,i)), o-type(r,i)); +}; + +TTS_CASE_WITH ( "Check kyosu::oneminus over quaternion" + , kyosu::real_types + , tts::generate ( tts::between(-5,5), tts::between(-5,5) + , tts::between(-5,5), tts::between(-5,5) + ) + ) +(T r, T i, T j, T k) +{ + using type = kyosu::as_quaternion_t; + auto o = type(T(1)); + TTS_EQUAL(kyosu::oneminus(type(r,i,j,k)), o-type(r,i,j,k)); +};