From 5073b381459c4fc47dd1d5291e23387556b4a180 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 May 2024 09:15:50 +0200 Subject: [PATCH 01/39] Add better cmake support --- CMakeLists.txt | 6 ++++++ test/CMakeLists.txt | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 test/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index d6cdd2861..d7d7dee25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,12 @@ else() endif() +if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + + add_subdirectory(test) + +endif() + # Only enable tests when we're the root project if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..8bf4ccf66 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright 2018, 2019 Peter Dimov +# Copyright 2024 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) + +if(HAVE_BOOST_TEST) + + boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::multiprecision Boost::assert Boost::config Boost::core Boost::integer Boost::lexical_cast Boost::math Boost::random) + +endif() From 1f98503b50fd6c00167892a287085bc5054fb2e4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 May 2024 10:29:54 +0200 Subject: [PATCH 02/39] Add test set --- test/CMakeLists.txt | 11 ++++------- test/Jamfile.v2 | 2 ++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8bf4ccf66..a9ff2f412 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,10 +3,7 @@ # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt -include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) - -if(HAVE_BOOST_TEST) - - boost_test_jamfile(FILE Jamfile.v2 LINK_LIBRARIES Boost::multiprecision Boost::assert Boost::config Boost::core Boost::integer Boost::lexical_cast Boost::math Boost::random) - -endif() +file(GLOB SOURCES "*.cpp") +add_library(boost_mp_tests STATIC ${SOURCES}) +target_compile_features(boost_mp_tests PRIVATE cxx_std_17) +target_link_libraries(boost_mp_tests PUBLIC Boost::multiprecision Boost::assert Boost::config Boost::core Boost::integer Boost::lexical_cast Boost::math Boost::random) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 3e490a13c..66f2f6f3d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -223,6 +223,8 @@ test-suite arithmetic_tests : [ run test_complex_signed_zero.cpp : : : TEST_CPP_BIN_FLOAT [ requires cxx17_if_constexpr ] : test_complex_signed_zero_cpp_bin_float ] [ run test_complex_signed_zero.cpp mpc mpfr gmp : : : TEST_MPC [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpc : : no ] : test_complex_signed_zero_mpc ] + [ run test_complex_class.cpp ] + [ run test_preserve_source_precision.cpp gmp : : : [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_gmp : : no ] TEST_MPF : test_preserve_source_precision_gmp ] [ run test_preserve_source_precision.cpp gmp mpfr : : : [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpfr : : no ] TEST_MPFR : test_preserve_source_precision_mpfr ] [ run test_preserve_source_precision.cpp gmp mpfr mpc : : : [ requires cxx17_if_constexpr ] [ check-target-builds ../config//has_mpc : : no ] TEST_MPC : test_preserve_source_precision_mpc ] From 8e82bbb6ddb343fc3ae5d2cb3a2b70df0b87756d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 May 2024 10:30:07 +0200 Subject: [PATCH 03/39] Add class basis --- include/boost/multiprecision/complex.hpp | 105 +++++++++++++++++++++++ test/test_complex_class.cpp | 29 +++++++ 2 files changed, 134 insertions(+) create mode 100644 include/boost/multiprecision/complex.hpp create mode 100644 test/test_complex_class.cpp diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp new file mode 100644 index 000000000..cb21b2570 --- /dev/null +++ b/include/boost/multiprecision/complex.hpp @@ -0,0 +1,105 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2024 Matt Borland. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MP_COMPLEX_HPP +#define BOOST_MP_COMPLEX_HPP + +#include +#include +#include + +namespace boost { +namespace multiprecision { + +template +class complex +{ +private: + T real_; + T imag_; + +public: + constexpr complex() noexcept = default; + explicit constexpr complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} + constexpr complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} + constexpr complex& operator=(const complex& rhs) = default; + + constexpr T real() noexcept { return real_; } + constexpr T imag() noexcept { return imag_; } + + friend constexpr complex operator+(const complex& lhs, const complex& rhs) noexcept; + friend constexpr complex operator-(const complex& lhs, const complex& rhs) noexcept; + friend constexpr complex operator*(const complex& lhs, const complex& rhs) noexcept; + friend constexpr complex operator/(const complex& lhs, const complex& rhs) noexcept; + + constexpr complex& operator+=(const complex& rhs) noexcept + { + *this = *this + rhs; + return *this; + } + + constexpr complex& operator-=(const complex& rhs) noexcept + { + *this = *this - rhs; + return *this; + } + + constexpr complex& operator*=(const complex& rhs) noexcept + { + *this = *this * rhs; + return *this; + } + + constexpr complex& operator/=(const complex& rhs) noexcept + { + *this = *this / rhs; + return *this; + } + + friend inline complex polar(const T& rho, const T& theta) noexcept; +}; + +template +constexpr complex operator+(const complex& lhs, const complex& rhs) noexcept +{ + return {lhs.real_ + rhs.real_, lhs.imag_ + rhs.imag_}; +} + +template +constexpr complex operator-(const complex& lhs, const complex& rhs) noexcept +{ + return {lhs.real_ - rhs.real_, lhs.imag_ - rhs.imag_}; +} + +template +constexpr complex operator*(const complex& lhs, const complex& rhs) noexcept +{ + return {lhs.real_ * rhs.real_ - lhs.imag_ * rhs.imag_, lhs.imag_ * rhs.real_ + lhs.real_ * rhs.imag_}; +} + +template +constexpr complex operator/(const complex& lhs, const complex& rhs) noexcept +{ + const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; + const T real_part = (lhs.real_ * rhs.real_ + lhs.imag_ * rhs.imag_) / divisor; + const T imag_part = (lhs.imag_ * rhs.real_ - lhs.real_ * rhs.imag_) / divisor; + return {real_part, imag_part}; +} + +template +inline complex polar(const T& rho, const T& theta) noexcept +{ + using std::sin; + using std::cos; + + BOOST_MP_ASSERT_MSG(rho >= T{0}, "Rho must be positive"); + + return {rho * cos(theta), rho * sin(theta)}; +} + +} // Namespace multiprecision +} // Namespace boost + +#endif //BOOST_MP_COMPLEX_HPP diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp new file mode 100644 index 000000000..6b788b4b0 --- /dev/null +++ b/test/test_complex_class.cpp @@ -0,0 +1,29 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2024 Matt Borland. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +using namespace boost::multiprecision; + +template +void test_construction() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); +} + +int main() +{ + test_construction(); + test_construction(); + test_construction(); + + return boost::report_errors(); +} From 2a688a5fa001b423890c76c51102db290a774b8c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 May 2024 10:38:31 +0200 Subject: [PATCH 04/39] Restrict to boost.mp types --- include/boost/multiprecision/complex.hpp | 5 +++-- test/test_complex_class.cpp | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index cb21b2570..87247ec9e 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -7,13 +7,14 @@ #define BOOST_MP_COMPLEX_HPP #include +#include #include #include namespace boost { namespace multiprecision { -template +template ::value, bool> = true> class complex { private: @@ -88,7 +89,7 @@ constexpr complex operator/(const complex& lhs, const complex& rhs) noe return {real_part, imag_part}; } -template +template ::value, bool> = true> inline complex polar(const T& rho, const T& theta) noexcept { using std::sin; diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 6b788b4b0..c4c369261 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -17,6 +17,18 @@ void test_construction() using std::complex; using std::polar; using complex_scalar = decltype(polar(T(), T())); + + complex_scalar v {}; + BOOST_TEST_EQ(v.real(), T{0}); + BOOST_TEST_EQ(v.imag(), T{0}); + + complex_scalar v1 {T{1}}; + BOOST_TEST_EQ(v1.real(), T{1}); + BOOST_TEST_EQ(v1.imag(), T{0}); + + complex_scalar v2 {T{2}, T{2}}; + BOOST_TEST_EQ(v2.real(), T{2}); + BOOST_TEST_EQ(v2.imag(), T{2}); } int main() From 564ce7784738f46d309833511103b3f177adab6e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 May 2024 10:59:08 +0200 Subject: [PATCH 05/39] Add unary operators --- include/boost/multiprecision/complex.hpp | 3 ++ test/test_complex_class.cpp | 64 ++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 87247ec9e..798c883e6 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -30,6 +30,9 @@ class complex constexpr T real() noexcept { return real_; } constexpr T imag() noexcept { return imag_; } + constexpr complex operator+() { return *this; } + constexpr complex operator-() { return {-real_, -imag_}; } + friend constexpr complex operator+(const complex& lhs, const complex& rhs) noexcept; friend constexpr complex operator-(const complex& lhs, const complex& rhs) noexcept; friend constexpr complex operator*(const complex& lhs, const complex& rhs) noexcept; diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index c4c369261..ab77fb90d 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -31,11 +32,74 @@ void test_construction() BOOST_TEST_EQ(v2.imag(), T{2}); } +template +void test_unary_operators() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + const complex_scalar val {T{2}, T{-2}}; + complex_scalar pos_val = +val; + BOOST_TEST_EQ(val.real(), pos_val.real()); + BOOST_TEST_EQ(val.imag(), pos_val.imag()); + + complex_scalar neg_val = -val; + BOOST_TEST_EQ(neg_val.real(), T{-2}); + BOOST_TEST_EQ(neg_val.imag(), T{2}); +} + +template +void test_addition() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{1}, T{1}}; + complex_scalar rhs_1 {T{2}, T{2}}; + complex_scalar res_1 = lhs_1 + rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{3}); + BOOST_TEST_EQ(res_1.real(), T{3}); +} + +template +void test_subtraction() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{1}, T{1}}; + complex_scalar rhs_1 {T{2}, T{2}}; + complex_scalar res_1 = lhs_1 - rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{-1}); + BOOST_TEST_EQ(res_1.real(), T{-1}); +} + int main() { test_construction(); test_construction(); test_construction(); + test_construction(); + + test_unary_operators(); + test_unary_operators(); + test_unary_operators(); + test_unary_operators(); + + test_addition(); + test_addition(); + test_addition(); + test_addition(); + + test_subtraction(); + test_subtraction(); + test_subtraction(); + test_subtraction(); return boost::report_errors(); } From 2df271ff394c2b74934118a8480bca333133d22e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 6 May 2024 12:19:38 +0200 Subject: [PATCH 06/39] Specialize class --- include/boost/multiprecision/complex.hpp | 136 ++++++++++++++++++----- test/test_complex_class.cpp | 30 ++++- 2 files changed, 137 insertions(+), 29 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 798c883e6..99cb44a51 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -8,13 +8,14 @@ #include #include +#include #include #include namespace boost { namespace multiprecision { - -template ::value, bool> = true> +/* +template class complex { private: @@ -22,69 +23,71 @@ class complex T imag_; public: - constexpr complex() noexcept = default; - explicit constexpr complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} - constexpr complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} - constexpr complex& operator=(const complex& rhs) = default; + complex() noexcept = default; + complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} + complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} + complex& operator=(const complex& rhs) + { + real_ = rhs.real_; + imag_ = rhs.imag_; + } - constexpr T real() noexcept { return real_; } - constexpr T imag() noexcept { return imag_; } + T real() noexcept { return real_; } + T imag() noexcept { return imag_; } - constexpr complex operator+() { return *this; } - constexpr complex operator-() { return {-real_, -imag_}; } + complex operator+() { return *this; } + complex operator-() { return {-real_, -imag_}; } - friend constexpr complex operator+(const complex& lhs, const complex& rhs) noexcept; - friend constexpr complex operator-(const complex& lhs, const complex& rhs) noexcept; - friend constexpr complex operator*(const complex& lhs, const complex& rhs) noexcept; - friend constexpr complex operator/(const complex& lhs, const complex& rhs) noexcept; + friend complex operator+(const complex& lhs, const complex& rhs) noexcept; + friend complex operator-(const complex& lhs, const complex& rhs) noexcept; + friend complex operator*(const complex& lhs, const complex& rhs) noexcept; + friend complex operator/(const complex& lhs, const complex& rhs) noexcept; - constexpr complex& operator+=(const complex& rhs) noexcept + complex& operator+=(const complex& rhs) noexcept { *this = *this + rhs; return *this; } - constexpr complex& operator-=(const complex& rhs) noexcept + complex& operator-=(const complex& rhs) noexcept { *this = *this - rhs; return *this; } - constexpr complex& operator*=(const complex& rhs) noexcept + complex& operator*=(const complex& rhs) noexcept { *this = *this * rhs; return *this; } - constexpr complex& operator/=(const complex& rhs) noexcept + complex& operator/=(const complex& rhs) noexcept { *this = *this / rhs; return *this; } - - friend inline complex polar(const T& rho, const T& theta) noexcept; }; template -constexpr complex operator+(const complex& lhs, const complex& rhs) noexcept +complex operator+(const complex& lhs, const complex& rhs) noexcept { return {lhs.real_ + rhs.real_, lhs.imag_ + rhs.imag_}; } template -constexpr complex operator-(const complex& lhs, const complex& rhs) noexcept +complex operator-(const complex& lhs, const complex& rhs) noexcept { return {lhs.real_ - rhs.real_, lhs.imag_ - rhs.imag_}; } template -constexpr complex operator*(const complex& lhs, const complex& rhs) noexcept +complex operator*(const complex& lhs, const complex& rhs) noexcept { return {lhs.real_ * rhs.real_ - lhs.imag_ * rhs.imag_, lhs.imag_ * rhs.real_ + lhs.real_ * rhs.imag_}; } template -constexpr complex operator/(const complex& lhs, const complex& rhs) noexcept +complex operator/(const complex& lhs, const complex& rhs) noexcept { const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; const T real_part = (lhs.real_ * rhs.real_ + lhs.imag_ * rhs.imag_) / divisor; @@ -102,8 +105,91 @@ inline complex polar(const T& rho, const T& theta) noexcept return {rho * cos(theta), rho * sin(theta)}; } - +*/ } // Namespace multiprecision } // Namespace boost +namespace std { + +template <> +class complex +{ +private: + using T = boost::multiprecision::cpp_bin_float_50; + + T real_; + T imag_; + +public: + complex() noexcept = default; + complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} + complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} + complex& operator=(const complex& rhs) = default; + + T real() const noexcept { return real_; } + T imag() const noexcept { return imag_; } + + complex operator+() { return *this; } + complex operator-() { return {-real_, -imag_}; } + + complex operator+(const complex& rhs) noexcept + { + return {real_ + rhs.real_, imag_ + rhs.imag_}; + } + + complex operator-(const complex& rhs) noexcept + { + return {real_ - rhs.real_, imag_ - rhs.imag_}; + } + + complex operator*(const complex& rhs) noexcept + { + return {real_ * rhs.real_ - imag_ * rhs.imag_, imag_ * rhs.real_ + real_ * rhs.imag_}; + } + + complex operator/(const complex& rhs) noexcept + { + const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; + const T real_part = (real_ * rhs.real_ + imag_ * rhs.imag_) / divisor; + const T imag_part = (imag_ * rhs.real_ - real_ * rhs.imag_) / divisor; + return {real_part, imag_part}; + } + + complex& operator+=(const complex& rhs) noexcept + { + *this = *this + rhs; + return *this; + } + + complex& operator-=(const complex& rhs) noexcept + { + *this = *this - rhs; + return *this; + } + + complex& operator*=(const complex& rhs) noexcept + { + *this = *this * rhs; + return *this; + } + + complex& operator/=(const complex& rhs) noexcept + { + *this = *this / rhs; + return *this; + } +}; + +inline complex polar(const boost::multiprecision::cpp_bin_float_50& rho, const boost::multiprecision::cpp_bin_float_50& theta) noexcept +{ + using std::sin; + using std::cos; + + BOOST_MP_ASSERT_MSG(rho >= boost::multiprecision::cpp_bin_float_50{0}, "Rho must be positive"); + + return {rho * cos(theta), rho * sin(theta)}; +} + +} + #endif //BOOST_MP_COMPLEX_HPP diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index ab77fb90d..acc7456d2 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include using namespace boost::multiprecision; @@ -18,6 +19,7 @@ void test_construction() using std::complex; using std::polar; using complex_scalar = decltype(polar(T(), T())); + std::cerr << typeid(complex_scalar).name() << std::endl; complex_scalar v {}; BOOST_TEST_EQ(v.real(), T{0}); @@ -79,27 +81,47 @@ void test_subtraction() BOOST_TEST_EQ(res_1.real(), T{-1}); } +template +void test_multiplication() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{-3}, T{3}}; + complex_scalar rhs_1 {T{2}, T{2}}; + complex_scalar res_1 = lhs_1 * rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{-12}); + BOOST_TEST_EQ(res_1.imag(), T{0}); +} + int main() { test_construction(); test_construction(); test_construction(); - test_construction(); + //test_construction(); test_unary_operators(); test_unary_operators(); test_unary_operators(); - test_unary_operators(); + //test_unary_operators(); test_addition(); test_addition(); test_addition(); - test_addition(); + //test_addition(); test_subtraction(); test_subtraction(); test_subtraction(); - test_subtraction(); + //test_subtraction(); + + test_multiplication(); + test_multiplication(); + test_multiplication(); + //test_multiplication(); return boost::report_errors(); } From f61a9e1a976d21da39e689144e3491a818b615a1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 09:55:33 +0200 Subject: [PATCH 07/39] Have std::complex inherit from multiprecision number class --- include/boost/multiprecision/complex.hpp | 137 +++++------------------ test/test_complex_class.cpp | 10 +- 2 files changed, 30 insertions(+), 117 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 99cb44a51..ed36065a2 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -9,12 +9,13 @@ #include #include #include +#include #include #include namespace boost { namespace multiprecision { -/* + template class complex { @@ -26,128 +27,34 @@ class complex complex() noexcept = default; complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} - complex& operator=(const complex& rhs) + complex& operator=(const complex& rhs) { real_ = rhs.real_; imag_ = rhs.imag_; } - T real() noexcept { return real_; } - T imag() noexcept { return imag_; } - - complex operator+() { return *this; } - complex operator-() { return {-real_, -imag_}; } - - friend complex operator+(const complex& lhs, const complex& rhs) noexcept; - friend complex operator-(const complex& lhs, const complex& rhs) noexcept; - friend complex operator*(const complex& lhs, const complex& rhs) noexcept; - friend complex operator/(const complex& lhs, const complex& rhs) noexcept; - - complex& operator+=(const complex& rhs) noexcept - { - *this = *this + rhs; - return *this; - } - - complex& operator-=(const complex& rhs) noexcept - { - *this = *this - rhs; - return *this; - } - - complex& operator*=(const complex& rhs) noexcept - { - *this = *this * rhs; - return *this; - } - - complex& operator/=(const complex& rhs) noexcept - { - *this = *this / rhs; - return *this; - } -}; - -template -complex operator+(const complex& lhs, const complex& rhs) noexcept -{ - return {lhs.real_ + rhs.real_, lhs.imag_ + rhs.imag_}; -} - -template -complex operator-(const complex& lhs, const complex& rhs) noexcept -{ - return {lhs.real_ - rhs.real_, lhs.imag_ - rhs.imag_}; -} - -template -complex operator*(const complex& lhs, const complex& rhs) noexcept -{ - return {lhs.real_ * rhs.real_ - lhs.imag_ * rhs.imag_, lhs.imag_ * rhs.real_ + lhs.real_ * rhs.imag_}; -} - -template -complex operator/(const complex& lhs, const complex& rhs) noexcept -{ - const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; - const T real_part = (lhs.real_ * rhs.real_ + lhs.imag_ * rhs.imag_) / divisor; - const T imag_part = (lhs.imag_ * rhs.real_ - lhs.real_ * rhs.imag_) / divisor; - return {real_part, imag_part}; -} - -template ::value, bool> = true> -inline complex polar(const T& rho, const T& theta) noexcept -{ - using std::sin; - using std::cos; - - BOOST_MP_ASSERT_MSG(rho >= T{0}, "Rho must be positive"); - - return {rho * cos(theta), rho * sin(theta)}; -} -*/ -} // Namespace multiprecision -} // Namespace boost - -namespace std { - -template <> -class complex -{ -private: - using T = boost::multiprecision::cpp_bin_float_50; - - T real_; - T imag_; - -public: - complex() noexcept = default; - complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} - complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} - complex& operator=(const complex& rhs) = default; - T real() const noexcept { return real_; } T imag() const noexcept { return imag_; } - complex operator+() { return *this; } - complex operator-() { return {-real_, -imag_}; } + complex operator+() const { return *this; } + complex operator-() const { return {-real_, -imag_}; } - complex operator+(const complex& rhs) noexcept + complex operator+(const complex& rhs) noexcept { return {real_ + rhs.real_, imag_ + rhs.imag_}; } - complex operator-(const complex& rhs) noexcept + complex operator-(const complex& rhs) noexcept { return {real_ - rhs.real_, imag_ - rhs.imag_}; } - complex operator*(const complex& rhs) noexcept + complex operator*(const complex& rhs) noexcept { return {real_ * rhs.real_ - imag_ * rhs.imag_, imag_ * rhs.real_ + real_ * rhs.imag_}; } - complex operator/(const complex& rhs) noexcept + complex operator/(const complex& rhs) noexcept { const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; const T real_part = (real_ * rhs.real_ + imag_ * rhs.imag_) / divisor; @@ -155,41 +62,47 @@ class complex return {real_part, imag_part}; } - complex& operator+=(const complex& rhs) noexcept + complex& operator+=(const complex& rhs) noexcept { *this = *this + rhs; return *this; } - complex& operator-=(const complex& rhs) noexcept + complex& operator-=(const complex& rhs) noexcept { *this = *this - rhs; return *this; } - complex& operator*=(const complex& rhs) noexcept + complex& operator*=(const complex& rhs) noexcept { *this = *this * rhs; return *this; } - complex& operator/=(const complex& rhs) noexcept + complex& operator/=(const complex& rhs) noexcept { *this = *this / rhs; return *this; } }; -inline complex polar(const boost::multiprecision::cpp_bin_float_50& rho, const boost::multiprecision::cpp_bin_float_50& theta) noexcept +template +inline complex> polar(const boost::multiprecision::number& rho, + const boost::multiprecision::number& theta) noexcept { - using std::sin; - using std::cos; - - BOOST_MP_ASSERT_MSG(rho >= boost::multiprecision::cpp_bin_float_50{0}, "Rho must be positive"); - + BOOST_MP_ASSERT_MSG(rho >= T{0}, "Rho must be positive"); return {rho * cos(theta), rho * sin(theta)}; } +} // Namespace multiprecision +} // Namespace boost + +namespace std { + +template +class complex> : public boost::multiprecision::complex> {}; + } #endif //BOOST_MP_COMPLEX_HPP diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index acc7456d2..92b0a14f3 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -101,27 +101,27 @@ int main() test_construction(); test_construction(); test_construction(); - //test_construction(); + test_construction(); test_unary_operators(); test_unary_operators(); test_unary_operators(); - //test_unary_operators(); + test_unary_operators(); test_addition(); test_addition(); test_addition(); - //test_addition(); + test_addition(); test_subtraction(); test_subtraction(); test_subtraction(); - //test_subtraction(); + test_subtraction(); test_multiplication(); test_multiplication(); test_multiplication(); - //test_multiplication(); + test_multiplication(); return boost::report_errors(); } From b714bb29bbcae0386c62a38b638df5f78939a767 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 10:13:35 +0200 Subject: [PATCH 08/39] Add equality --- include/boost/multiprecision/complex.hpp | 21 ++++++++++++++++++ test/test_complex_class.cpp | 28 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index ed36065a2..b9b96b18d 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -31,6 +31,7 @@ class complex { real_ = rhs.real_; imag_ = rhs.imag_; + return *this; } T real() const noexcept { return real_; } @@ -85,6 +86,26 @@ class complex *this = *this / rhs; return *this; } + + bool operator==(const complex& rhs) noexcept + { + return real_ == rhs.real_ && imag_ == rhs.imag_; + } + + bool operator!=(const complex& rhs) noexcept + { + return !(*this == rhs); + } + + bool operator==(const T& rhs) noexcept + { + return real_ == rhs && imag_ == T{0}; + } + + bool operator!=(const T& rhs) noexcept + { + return !(*this == rhs); + } }; template diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 92b0a14f3..31085ec8e 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -96,6 +96,29 @@ void test_multiplication() BOOST_TEST_EQ(res_1.imag(), T{0}); } +template +void test_equality() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{2}, T{-1}}; + complex_scalar rhs {T{2}, T{1}}; + + BOOST_TEST(lhs != rhs); + BOOST_TEST(!(lhs == rhs)); + + T scalar_rhs {T{2}}; + + BOOST_TEST(lhs != scalar_rhs); + BOOST_TEST(!(lhs == scalar_rhs)); + + lhs = complex_scalar{T{2}, T{0}}; + BOOST_TEST(lhs == scalar_rhs); + BOOST_TEST(!(lhs != scalar_rhs)); +} + int main() { test_construction(); @@ -123,5 +146,10 @@ int main() test_multiplication(); test_multiplication(); + test_equality(); + test_equality(); + test_equality(); + test_equality(); + return boost::report_errors(); } From dbbc9412935c207f53f7d9074810f0ab8305bdd2 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 10:21:24 +0200 Subject: [PATCH 09/39] Add the ostream operator --- include/boost/multiprecision/complex.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index b9b96b18d..54ea4c3ea 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,19 @@ class complex { return !(*this == rhs); } + + // Writes in the form (real, imag) + template + std::basic_ostream& operator<<(std::basic_ostream& os) + { + std::basic_ostringstream s; + s.flags(os.flags()); + s.imbue(os.getloc()); + s.precision(os.precision()); + s << '(' << real_ << ',' << imag_ << ')'; + + return os << s.str(); + } }; template From 0b5bd14993446a0f473cff4d2b211dbeb6a7725d Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 10:29:28 +0200 Subject: [PATCH 10/39] Add the istream operator --- include/boost/multiprecision/complex.hpp | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 54ea4c3ea..25458f660 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -120,6 +121,54 @@ class complex return os << s.str(); } + + // Supported formats: + // 1) real + // 2) (real) + // 3) (real, imag) + template + std::basic_istream& operator>>(std::basic_ostream& is) + { + CharT ch {}; + T real = T{0}; + T imag = T{0}; + + is >> std::ws; + is.get(ch); + + if (ch == '(') + { + // Expecting a format like 2 or 3 + is >> std::ws >> real; + is.get(ch); + if (ch == ',') + { + // A comma indicates it's 3 + is >> std::ws >> imag; + is.get(ch); // Should be ')' + } + else if (ch != ')') + { + // Syntax error: unexpected character + is.setstate(std::ios_base::failbit); + return is; + } + } + else + { + // No parentheses, just a real number from format 1 + is.putback(ch); + is >> real; + } + + if (!is.fail()) + { + real_ = real; + imag_ = imag; + } + + return is; + } }; template From f50f134d6884c3b9fee997641950828ef70a8ace Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 10:51:54 +0200 Subject: [PATCH 11/39] Add overloads for non-member real and imag --- include/boost/multiprecision/complex.hpp | 12 ++++++++++++ test/test_complex_class.cpp | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 25458f660..afc36c66b 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -179,6 +179,18 @@ inline complex> polar(const boost::multipre return {rho * cos(theta), rho * sin(theta)}; } +template +inline boost::multiprecision::number real(const complex>& c) noexcept +{ + return c.real(); +} + +template +inline boost::multiprecision::number imag(const complex>& c) noexcept +{ + return c.imag(); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 31085ec8e..5cbadd570 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -119,6 +119,21 @@ void test_equality() BOOST_TEST(!(lhs != scalar_rhs)); } +template +void test_non_member_real_imag() +{ + using std::complex; + using std::polar; + using std::real; + using std::complex; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{2}, T{-1}}; + + BOOST_TEST_EQ(real(lhs), lhs.real()); + BOOST_TEST_EQ(imag(lhs), lhs.imag()); +} + int main() { test_construction(); @@ -151,5 +166,10 @@ int main() test_equality(); test_equality(); + test_non_member_real_imag(); + test_non_member_real_imag(); + test_non_member_real_imag(); + test_non_member_real_imag(); + return boost::report_errors(); } From 612f4fe2dfbfd314bf734d212320631b83786b48 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 12:16:21 +0200 Subject: [PATCH 12/39] Replace polar impl with the one from default ops --- include/boost/multiprecision/complex.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index afc36c66b..4d6797a4a 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -176,7 +176,7 @@ inline complex> polar(const boost::multipre const boost::multiprecision::number& theta) noexcept { BOOST_MP_ASSERT_MSG(rho >= T{0}, "Rho must be positive"); - return {rho * cos(theta), rho * sin(theta)}; + return polar(rho, theta); } template From 21d9b25780df426fbbd48d0eca7e6f463a1589eb Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 12:17:55 +0200 Subject: [PATCH 13/39] Add abs overload --- include/boost/multiprecision/complex.hpp | 14 ++++++++++---- test/test_complex_class.cpp | 20 +++++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 4d6797a4a..df4c70280 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -180,15 +180,21 @@ inline complex> polar(const boost::multipre } template -inline boost::multiprecision::number real(const complex>& c) noexcept +inline boost::multiprecision::number real(const complex>& z) noexcept { - return c.real(); + return z.real(); } template -inline boost::multiprecision::number imag(const complex>& c) noexcept +inline boost::multiprecision::number imag(const complex>& z) noexcept { - return c.imag(); + return z.imag(); +} + +template +inline boost::multiprecision::number abs(const complex>& z) noexcept +{ + return hypot(z.real(), z.imag()); } } // Namespace multiprecision diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 5cbadd570..4a0ff9e85 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -125,7 +125,6 @@ void test_non_member_real_imag() using std::complex; using std::polar; using std::real; - using std::complex; using complex_scalar = decltype(polar(T(), T())); complex_scalar lhs {T{2}, T{-1}}; @@ -134,6 +133,20 @@ void test_non_member_real_imag() BOOST_TEST_EQ(imag(lhs), lhs.imag()); } +template +void test_abs() +{ + using std::complex; + using std::polar; + using std::abs; + using std::sqrt; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{1}}; + + BOOST_TEST_EQ(abs(lhs), sqrt(T{2})); +} + int main() { test_construction(); @@ -171,5 +184,10 @@ int main() test_non_member_real_imag(); test_non_member_real_imag(); + test_abs(); + test_abs(); + test_abs(); + test_abs(); + return boost::report_errors(); } From d76f19bbe3245b2c6f414276267b67ec5d8f23b1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 12:20:19 +0200 Subject: [PATCH 14/39] Add constexpr annotations --- include/boost/multiprecision/complex.hpp | 52 ++++++++++++------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index df4c70280..a62b1639c 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -26,38 +26,38 @@ class complex T imag_; public: - complex() noexcept = default; - complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} - complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} - complex& operator=(const complex& rhs) + BOOST_MP_CXX14_CONSTEXPR complex() noexcept = default; + BOOST_MP_CXX14_CONSTEXPR complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} + BOOST_MP_CXX14_CONSTEXPR complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} + BOOST_MP_CXX14_CONSTEXPR complex& operator=(const complex& rhs) { real_ = rhs.real_; imag_ = rhs.imag_; return *this; } - T real() const noexcept { return real_; } - T imag() const noexcept { return imag_; } + BOOST_MP_CXX14_CONSTEXPR T real() const noexcept { return real_; } + BOOST_MP_CXX14_CONSTEXPR T imag() const noexcept { return imag_; } - complex operator+() const { return *this; } - complex operator-() const { return {-real_, -imag_}; } + BOOST_MP_CXX14_CONSTEXPR complex operator+() const { return *this; } + BOOST_MP_CXX14_CONSTEXPR complex operator-() const { return {-real_, -imag_}; } - complex operator+(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex operator+(const complex& rhs) noexcept { return {real_ + rhs.real_, imag_ + rhs.imag_}; } - complex operator-(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& rhs) noexcept { return {real_ - rhs.real_, imag_ - rhs.imag_}; } - complex operator*(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& rhs) noexcept { return {real_ * rhs.real_ - imag_ * rhs.imag_, imag_ * rhs.real_ + real_ * rhs.imag_}; } - complex operator/(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& rhs) noexcept { const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; const T real_part = (real_ * rhs.real_ + imag_ * rhs.imag_) / divisor; @@ -65,46 +65,46 @@ class complex return {real_part, imag_part}; } - complex& operator+=(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex& operator+=(const complex& rhs) noexcept { *this = *this + rhs; return *this; } - complex& operator-=(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex& operator-=(const complex& rhs) noexcept { *this = *this - rhs; return *this; } - complex& operator*=(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex& operator*=(const complex& rhs) noexcept { *this = *this * rhs; return *this; } - complex& operator/=(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR complex& operator/=(const complex& rhs) noexcept { *this = *this / rhs; return *this; } - bool operator==(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator==(const complex& rhs) noexcept { return real_ == rhs.real_ && imag_ == rhs.imag_; } - bool operator!=(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator!=(const complex& rhs) noexcept { return !(*this == rhs); } - bool operator==(const T& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator==(const T& rhs) noexcept { return real_ == rhs && imag_ == T{0}; } - bool operator!=(const T& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator!=(const T& rhs) noexcept { return !(*this == rhs); } @@ -172,27 +172,27 @@ class complex }; template -inline complex> polar(const boost::multiprecision::number& rho, - const boost::multiprecision::number& theta) noexcept +inline BOOST_MP_CXX14_CONSTEXPR complex> polar(const boost::multiprecision::number& rho, + const boost::multiprecision::number& theta) noexcept { BOOST_MP_ASSERT_MSG(rho >= T{0}, "Rho must be positive"); return polar(rho, theta); } template -inline boost::multiprecision::number real(const complex>& z) noexcept +inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number real(const complex>& z) noexcept { return z.real(); } template -inline boost::multiprecision::number imag(const complex>& z) noexcept +inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number imag(const complex>& z) noexcept { return z.imag(); } template -inline boost::multiprecision::number abs(const complex>& z) noexcept +inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number abs(const complex>& z) noexcept { return hypot(z.real(), z.imag()); } @@ -205,6 +205,6 @@ namespace std { template class complex> : public boost::multiprecision::complex> {}; -} +} // namespace std #endif //BOOST_MP_COMPLEX_HPP From e46424d495c3faa1cdae8edc23b7b728010cdae9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 12:35:16 +0200 Subject: [PATCH 15/39] Add arg --- include/boost/multiprecision/complex.hpp | 6 +++++ test/test_complex_class.cpp | 31 +++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index a62b1639c..a5e3a7557 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -197,6 +197,12 @@ inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number abs(const c return hypot(z.real(), z.imag()); } +template +inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number arg(const complex>& z) noexcept +{ + return atan2(z.imag(), z.real()); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 4a0ff9e85..353a4cb83 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -139,7 +141,6 @@ void test_abs() using std::complex; using std::polar; using std::abs; - using std::sqrt; using complex_scalar = decltype(polar(T(), T())); complex_scalar lhs {T{1}, T{1}}; @@ -147,6 +148,29 @@ void test_abs() BOOST_TEST_EQ(abs(lhs), sqrt(T{2})); } +template +bool test_equal(T lhs, T rhs, int tol = 10) noexcept +{ + using std::fabs; + return fabs(lhs - rhs) < static_cast(tol) * std::numeric_limits::epsilon(); +} + +template +void test_arg() +{ + using std::complex; + using std::polar; + using std::arg; + using boost::math::constants::pi; + using boost::math::constants::half_pi; + using complex_scalar = decltype(polar(T(), T())); + + BOOST_TEST(test_equal(arg(complex_scalar{T{1}, T{0}}), T{0})); + BOOST_TEST(test_equal(arg(complex_scalar{T{0}, T{0}}), T{0})); + BOOST_TEST(test_equal(arg(complex_scalar{T{0}, T{1}}), half_pi())); + BOOST_TEST(test_equal(arg(complex_scalar{T{-1}, T{0}}), pi())); +} + int main() { test_construction(); @@ -189,5 +213,10 @@ int main() test_abs(); test_abs(); + test_arg(); + test_arg(); + test_arg(); + test_arg(); + return boost::report_errors(); } From 20faba1051cd0b57f3a7a96a7ec1a180b6e94d6c Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 12:39:11 +0200 Subject: [PATCH 16/39] Add norm --- include/boost/multiprecision/complex.hpp | 6 +++++ test/test_complex_class.cpp | 34 ++++++++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index a5e3a7557..575205181 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -203,6 +203,12 @@ inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number arg(const c return atan2(z.imag(), z.real()); } +template +inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number norm(const complex>& z) noexcept +{ + return z.real() * z.real() + z.imag() * z.imag(); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 353a4cb83..d56580aa7 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -15,6 +15,13 @@ using namespace boost::multiprecision; +template +bool test_equal(T lhs, T rhs, int tol = 10) noexcept +{ + using std::fabs; + return fabs(lhs - rhs) < static_cast(tol) * std::numeric_limits::epsilon(); +} + template void test_construction() { @@ -145,14 +152,7 @@ void test_abs() complex_scalar lhs {T{1}, T{1}}; - BOOST_TEST_EQ(abs(lhs), sqrt(T{2})); -} - -template -bool test_equal(T lhs, T rhs, int tol = 10) noexcept -{ - using std::fabs; - return fabs(lhs - rhs) < static_cast(tol) * std::numeric_limits::epsilon(); + BOOST_TEST(test_equal(abs(lhs), sqrt(T{2}))); } template @@ -171,6 +171,19 @@ void test_arg() BOOST_TEST(test_equal(arg(complex_scalar{T{-1}, T{0}}), pi())); } +template +void test_norm() +{ + using std::complex; + using std::polar; + using std::norm; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{3}, T{4}}; + + BOOST_TEST(test_equal(norm(lhs), T{25})); +} + int main() { test_construction(); @@ -218,5 +231,10 @@ int main() test_arg(); test_arg(); + test_norm(); + test_norm(); + test_norm(); + test_norm(); + return boost::report_errors(); } From 8ee77ce758f0ec3236651120daac7bfe1047311b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 12:49:04 +0200 Subject: [PATCH 17/39] Add conj overload --- include/boost/multiprecision/complex.hpp | 6 ++++++ test/test_complex_class.cpp | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 575205181..2abe3ae2e 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -209,6 +209,12 @@ inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number norm(const return z.real() * z.real() + z.imag() * z.imag(); } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> conj(const complex>& z) noexcept +{ + return {z.real(), -z.imag()}; +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index d56580aa7..e959d7793 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -184,6 +184,20 @@ void test_norm() BOOST_TEST(test_equal(norm(lhs), T{25})); } +template +void test_conj() +{ + using std::complex; + using std::polar; + using std::conj; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{1}}; + complex_scalar rhs {T{1}, T{-1}}; + + BOOST_TEST(conj(lhs) == rhs); +} + int main() { test_construction(); @@ -236,5 +250,10 @@ int main() test_norm(); test_norm(); + test_conj(); + test_conj(); + test_conj(); + test_conj(); + return boost::report_errors(); } From a5faa8df736d582ced3375779dda07e2b4744f48 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 13:09:37 +0200 Subject: [PATCH 18/39] Add proj overload and fix const correctness --- include/boost/multiprecision/complex.hpp | 30 ++++++++++++++++-------- test/test_complex_class.cpp | 27 ++++++++++++++++++++- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 2abe3ae2e..16eff987d 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -89,35 +89,34 @@ class complex return *this; } - BOOST_MP_CXX14_CONSTEXPR bool operator==(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator==(const complex& rhs) const noexcept { return real_ == rhs.real_ && imag_ == rhs.imag_; } - BOOST_MP_CXX14_CONSTEXPR bool operator!=(const complex& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator!=(const complex& rhs) const noexcept { return !(*this == rhs); } - BOOST_MP_CXX14_CONSTEXPR bool operator==(const T& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator==(const T& rhs) const noexcept { return real_ == rhs && imag_ == T{0}; } - BOOST_MP_CXX14_CONSTEXPR bool operator!=(const T& rhs) noexcept + BOOST_MP_CXX14_CONSTEXPR bool operator!=(const T& rhs) const noexcept { return !(*this == rhs); } - // Writes in the form (real, imag) template - std::basic_ostream& operator<<(std::basic_ostream& os) + friend std::basic_ostream& operator<<(std::basic_ostream& os, const complex& z) { std::basic_ostringstream s; s.flags(os.flags()); s.imbue(os.getloc()); s.precision(os.precision()); - s << '(' << real_ << ',' << imag_ << ')'; + s << '(' << z.real_ << ',' << z.imag_ << ')'; return os << s.str(); } @@ -127,7 +126,7 @@ class complex // 2) (real) // 3) (real, imag) template - std::basic_istream& operator>>(std::basic_ostream& is) + friend std::basic_istream& operator>>(std::basic_istream& is, complex& z) { CharT ch {}; T real = T{0}; @@ -163,8 +162,8 @@ class complex if (!is.fail()) { - real_ = real; - imag_ = imag; + z.real_ = real; + z.imag_ = imag; } return is; @@ -215,6 +214,17 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> co return {z.real(), -z.imag()}; } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> proj(const complex>& z) noexcept +{ + if (isinf(z.real()) || isinf(z.imag())) + { + return {std::numeric_limits>::infinity(), copysign(boost::multiprecision::number{0}, z.imag())}; + } + + return z; +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index e959d7793..9799cbc01 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -195,7 +195,27 @@ void test_conj() complex_scalar lhs {T{1}, T{1}}; complex_scalar rhs {T{1}, T{-1}}; - BOOST_TEST(conj(lhs) == rhs); + BOOST_TEST_EQ(conj(lhs), rhs); +} + +template +void test_proj() +{ + using std::complex; + using std::polar; + using std::proj; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{1}}; + BOOST_TEST_EQ(lhs, proj(lhs)); + + lhs = complex_scalar{T{std::numeric_limits::infinity()}, T{1}}; + complex_scalar rhs = complex_scalar{T{std::numeric_limits::infinity()}, T{0}}; + BOOST_TEST_EQ(proj(lhs), rhs); + + lhs = complex_scalar{T{std::numeric_limits::infinity()}, T{-1}}; + rhs = complex_scalar{T{std::numeric_limits::infinity()}, T{-0}}; + BOOST_TEST_EQ(proj(lhs), rhs); } int main() @@ -255,5 +275,10 @@ int main() test_conj(); test_conj(); + test_proj(); + test_proj(); + test_proj(); + test_proj(); + return boost::report_errors(); } From 618bdf387e2f428413f8b94730d738b6e6056bec Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 7 May 2024 15:25:31 +0200 Subject: [PATCH 19/39] Fix test for std::sqrt promoting float result to double --- test/test_complex_class.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 9799cbc01..72438a338 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -152,7 +152,7 @@ void test_abs() complex_scalar lhs {T{1}, T{1}}; - BOOST_TEST(test_equal(abs(lhs), sqrt(T{2}))); + BOOST_TEST(test_equal(static_cast(abs(lhs)), static_cast(sqrt(T{2})))); } template From 861c6bd8bce1e1f82e178fd293dd6c41373df489 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 09:11:36 +0200 Subject: [PATCH 20/39] Add exp overload --- include/boost/multiprecision/complex.hpp | 10 ++++++++-- test/test_complex_class.cpp | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 16eff987d..9e875d1af 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -174,8 +174,8 @@ template inline BOOST_MP_CXX14_CONSTEXPR complex> polar(const boost::multiprecision::number& rho, const boost::multiprecision::number& theta) noexcept { - BOOST_MP_ASSERT_MSG(rho >= T{0}, "Rho must be positive"); - return polar(rho, theta); + BOOST_MP_ASSERT_MSG(rho >= 0, "Rho must be positive"); + return {rho * cos(theta), rho * sin(theta)}; } template @@ -225,6 +225,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> pr return z; } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> exp(const complex>& z) noexcept +{ + return polar(exp(z.real()), z.imag()); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 72438a338..1f797cb98 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -218,6 +218,22 @@ void test_proj() BOOST_TEST_EQ(proj(lhs), rhs); } +template +void test_exp() +{ + using std::complex; + using std::polar; + using std::exp; + using boost::math::constants::pi; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{0}, pi()}; + lhs = exp(lhs); + complex_scalar rhs {T{-1}, T{0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); +} + int main() { test_construction(); @@ -280,5 +296,10 @@ int main() test_proj(); test_proj(); + test_exp(); + test_exp(); + test_exp(); + test_exp(); + return boost::report_errors(); } From 1c95d3a97de6463784aadcfed3fdc401ec3f6b63 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 09:29:11 +0200 Subject: [PATCH 21/39] Add overload for log --- include/boost/multiprecision/complex.hpp | 6 ++++ test/test_complex_class.cpp | 38 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 9e875d1af..d4da0874d 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -231,6 +231,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> ex return polar(exp(z.real()), z.imag()); } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> log(const complex>& z) noexcept +{ + return {log(abs(z)), arg(z)}; +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 1f797cb98..7b12f483e 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -234,6 +234,39 @@ void test_exp() BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); } +template +void test_log() +{ + using std::complex; + using std::polar; + using std::log; + using boost::math::constants::half_pi; + using boost::math::constants::pi; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{0}, T{1}}; + lhs = log(lhs); + complex_scalar rhs {T{0}, half_pi()}; + + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + lhs = {T{-1}, T{0}}; + lhs = log(lhs); + rhs = {T{0}, pi()}; + + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + // Other side of the cut line + lhs = {T{-1}, T{-0}}; + lhs = log(lhs); + rhs = {T{0}, -pi()}; + + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); +} + int main() { test_construction(); @@ -301,5 +334,10 @@ int main() test_exp(); test_exp(); + test_log(); + test_log(); + test_log(); + test_log(); + return boost::report_errors(); } From 4abb2717667af858f78c7f375d56a95756eb7317 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 09:56:34 +0200 Subject: [PATCH 22/39] Add complex and scalar basic operations --- include/boost/multiprecision/complex.hpp | 47 +++++++++ test/test_complex_class.cpp | 119 +++++++++++++++++++++-- 2 files changed, 158 insertions(+), 8 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index d4da0874d..40d27808d 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -47,16 +47,31 @@ class complex return {real_ + rhs.real_, imag_ + rhs.imag_}; } + BOOST_MP_CXX14_CONSTEXPR complex operator+(const T& rhs) noexcept + { + return {real_ + rhs, imag_}; + } + BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& rhs) noexcept { return {real_ - rhs.real_, imag_ - rhs.imag_}; } + BOOST_MP_CXX14_CONSTEXPR complex operator-(const T& rhs) noexcept + { + return {real_ - rhs, imag_}; + } + BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& rhs) noexcept { return {real_ * rhs.real_ - imag_ * rhs.imag_, imag_ * rhs.real_ + real_ * rhs.imag_}; } + BOOST_MP_CXX14_CONSTEXPR complex operator*(const T& rhs) noexcept + { + return {real_ * rhs, imag_ * rhs}; + } + BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& rhs) noexcept { const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; @@ -65,30 +80,62 @@ class complex return {real_part, imag_part}; } + BOOST_MP_CXX14_CONSTEXPR complex operator/(const T& rhs) noexcept + { + const T divisor = rhs * rhs; + const T real_part = (real_ * rhs) / divisor; + const T imag_part = (imag_ * rhs) / divisor; + return {real_part, imag_part}; + } + BOOST_MP_CXX14_CONSTEXPR complex& operator+=(const complex& rhs) noexcept { *this = *this + rhs; return *this; } + BOOST_MP_CXX14_CONSTEXPR complex& operator+=(const T& rhs) noexcept + { + *this = *this + rhs; + return *this; + } + BOOST_MP_CXX14_CONSTEXPR complex& operator-=(const complex& rhs) noexcept { *this = *this - rhs; return *this; } + BOOST_MP_CXX14_CONSTEXPR complex& operator-=(const T& rhs) noexcept + { + *this = *this - rhs; + return *this; + } + BOOST_MP_CXX14_CONSTEXPR complex& operator*=(const complex& rhs) noexcept { *this = *this * rhs; return *this; } + BOOST_MP_CXX14_CONSTEXPR complex& operator*=(const T& rhs) noexcept + { + *this = *this * rhs; + return *this; + } + BOOST_MP_CXX14_CONSTEXPR complex& operator/=(const complex& rhs) noexcept { *this = *this / rhs; return *this; } + BOOST_MP_CXX14_CONSTEXPR complex& operator/=(const T& rhs) noexcept + { + *this = *this / rhs; + return *this; + } + BOOST_MP_CXX14_CONSTEXPR bool operator==(const complex& rhs) const noexcept { return real_ == rhs.real_ && imag_ == rhs.imag_; diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 7b12f483e..225979ac8 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -72,7 +72,7 @@ void test_addition() complex_scalar res_1 = lhs_1 + rhs_1; BOOST_TEST_EQ(res_1.real(), T{3}); - BOOST_TEST_EQ(res_1.real(), T{3}); + BOOST_TEST_EQ(res_1.imag(), T{3}); } template @@ -87,7 +87,7 @@ void test_subtraction() complex_scalar res_1 = lhs_1 - rhs_1; BOOST_TEST_EQ(res_1.real(), T{-1}); - BOOST_TEST_EQ(res_1.real(), T{-1}); + BOOST_TEST_EQ(res_1.imag(), T{-1}); } template @@ -105,6 +105,21 @@ void test_multiplication() BOOST_TEST_EQ(res_1.imag(), T{0}); } +template +void test_division() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{6}, T{2}}; + complex_scalar rhs_1 {T{2}, T{2}}; + complex_scalar res_1 = lhs_1 / rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{2}); + BOOST_TEST_EQ(res_1.imag(), T{-1}); +} + template void test_equality() { @@ -258,13 +273,76 @@ void test_log() BOOST_TEST(test_equal(lhs.real(), rhs.real())); BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); - // Other side of the cut line - lhs = {T{-1}, T{-0}}; - lhs = log(lhs); - rhs = {T{0}, -pi()}; + BOOST_IF_CONSTEXPR (!std::is_same::value) + { + // Other side of the cut line + lhs = {T {-1}, -T {0}}; + lhs = log(lhs); + rhs = {T {0}, -pi()}; - BOOST_TEST(test_equal(lhs.real(), rhs.real())); - BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + } +} + +template +void test_scalar_addition() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{1}, T{1}}; + T rhs_1 {T{2}}; + complex_scalar res_1 = lhs_1 + rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{3}); + BOOST_TEST_EQ(res_1.imag(), T{1}); +} + +template +void test_scalar_subtraction() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{1}, T{1}}; + T rhs_1 {T{2}}; + complex_scalar res_1 = lhs_1 - rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{-1}); + BOOST_TEST_EQ(res_1.imag(), T{1}); +} + +template +void test_scalar_multiplication() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{3}, T{2}}; + T rhs_1 {T{2}}; + complex_scalar res_1 = lhs_1 * rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{6}); + BOOST_TEST_EQ(res_1.imag(), T{4}); +} + +template +void test_scalar_division() +{ + using std::complex; + using std::polar; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs_1 {T{4}, T{2}}; + T rhs_1 {T{2}}; + complex_scalar res_1 = lhs_1 / rhs_1; + + BOOST_TEST_EQ(res_1.real(), T{2}); + BOOST_TEST_EQ(res_1.imag(), T{1}); } int main() @@ -294,6 +372,11 @@ int main() test_multiplication(); test_multiplication(); + test_division(); + test_division(); + test_division(); + test_division(); + test_equality(); test_equality(); test_equality(); @@ -339,5 +422,25 @@ int main() test_log(); test_log(); + test_scalar_addition(); + test_scalar_addition(); + test_scalar_addition(); + test_scalar_addition(); + + test_scalar_subtraction(); + test_scalar_subtraction(); + test_scalar_subtraction(); + test_scalar_subtraction(); + + test_scalar_multiplication(); + test_scalar_multiplication(); + test_scalar_multiplication(); + test_scalar_multiplication(); + + test_scalar_division(); + test_scalar_division(); + test_scalar_division(); + test_scalar_division(); + return boost::report_errors(); } From 4a35b0d229041e3afa1262093d1e41f40601ecae Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 10:32:07 +0200 Subject: [PATCH 23/39] Add log10 overload --- include/boost/multiprecision/complex.hpp | 6 ++++++ test/test_complex_class.cpp | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 40d27808d..80cc75193 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -284,6 +284,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> lo return {log(abs(z)), arg(z)}; } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> log10(const complex>& z) noexcept +{ + return log(z) / log(boost::multiprecision::number{10}); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 225979ac8..d9d5ce6e5 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -345,6 +345,20 @@ void test_scalar_division() BOOST_TEST_EQ(res_1.imag(), T{1}); } +template +void test_log10() +{ + using std::complex; + using std::polar; + using std::log10; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{-100}, T{0}}; + lhs = log10(lhs); + complex_scalar rhs {T{2}, static_cast(1.36438)}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); +} + int main() { test_construction(); @@ -442,5 +456,10 @@ int main() test_scalar_division(); test_scalar_division(); + test_log10(); + test_log10(); + test_log10(); + test_log10(); + return boost::report_errors(); } From aa019973cd49a69d19767d55829100c8253605dc Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 10:58:50 +0200 Subject: [PATCH 24/39] Make basic operations non-member functions --- include/boost/multiprecision/complex.hpp | 59 ++++++++++++++++-------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 80cc75193..e1a1cfbcf 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -42,49 +42,72 @@ class complex BOOST_MP_CXX14_CONSTEXPR complex operator+() const { return *this; } BOOST_MP_CXX14_CONSTEXPR complex operator-() const { return {-real_, -imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator+(const complex& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator+(const complex& lhs, const complex& rhs) noexcept { - return {real_ + rhs.real_, imag_ + rhs.imag_}; + return {lhs.real_ + rhs.real_, lhs.imag_ + rhs.imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator+(const T& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator+(const complex& lhs, const T& rhs) noexcept { - return {real_ + rhs, imag_}; + return {lhs.real_ + rhs, lhs.imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator+(const T& lhs, const complex& rhs) noexcept { - return {real_ - rhs.real_, imag_ - rhs.imag_}; + return {lhs + rhs.real_, rhs.imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator-(const T& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& lhs, const complex& rhs) noexcept { - return {real_ - rhs, imag_}; + return {lhs.real_ - rhs.real_, lhs.imag_ - rhs.imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& lhs, const T& rhs) noexcept { - return {real_ * rhs.real_ - imag_ * rhs.imag_, imag_ * rhs.real_ + real_ * rhs.imag_}; + return {lhs.real_ - rhs, lhs.imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator*(const T& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator-(const T& lhs, const complex& rhs) noexcept { - return {real_ * rhs, imag_ * rhs}; + return {lhs - rhs.real_, -rhs.imag_}; } - BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& lhs, const complex& rhs) noexcept + { + return {lhs.real_ * rhs.real_ - lhs.imag_ * rhs.imag_, lhs.imag_ * rhs.real_ + lhs.real_ * rhs.imag_}; + } + + friend BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& lhs, const T& rhs) noexcept + { + return {lhs.real_ * rhs, lhs.imag_ * rhs}; + } + + friend BOOST_MP_CXX14_CONSTEXPR complex operator*(const T& lhs, const complex& rhs) noexcept + { + return {lhs * rhs.real_, lhs * rhs.imag_}; + } + + friend BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& lhs, const complex& rhs) noexcept { const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; - const T real_part = (real_ * rhs.real_ + imag_ * rhs.imag_) / divisor; - const T imag_part = (imag_ * rhs.real_ - real_ * rhs.imag_) / divisor; + const T real_part = (lhs.real_ * rhs.real_ + lhs.imag_ * rhs.imag_) / divisor; + const T imag_part = (lhs.imag_ * rhs.real_ - lhs.real_ * rhs.imag_) / divisor; return {real_part, imag_part}; } - BOOST_MP_CXX14_CONSTEXPR complex operator/(const T& rhs) noexcept + friend BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& lhs, const T& rhs) noexcept { const T divisor = rhs * rhs; - const T real_part = (real_ * rhs) / divisor; - const T imag_part = (imag_ * rhs) / divisor; + const T real_part = (lhs.real_ * rhs) / divisor; + const T imag_part = (lhs.imag_ * rhs) / divisor; + return {real_part, imag_part}; + } + + friend BOOST_MP_CXX14_CONSTEXPR complex operator/(const T& lhs, const complex& rhs) noexcept + { + const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; + const T real_part = (lhs * rhs.real_) / divisor; + const T imag_part = -(lhs.real_ * rhs.imag_) / divisor; return {real_part, imag_part}; } From 2a5d7bb05d72989372102936a0b19ef68057c307 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 11:06:14 +0200 Subject: [PATCH 25/39] Add pow overload --- include/boost/multiprecision/complex.hpp | 23 +++++++++++ test/test_complex_class.cpp | 49 +++++++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index e1a1cfbcf..7954ebb87 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -313,6 +313,29 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> lo return log(z) / log(boost::multiprecision::number{10}); } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> pow(const complex>& x, + const complex>& y) noexcept +{ + return exp(y * log(x)); +} + +template +inline BOOST_MP_CXX14_CONSTEXPR complex> pow(const boost::multiprecision::number& x, + const complex>& y) noexcept +{ + const complex> new_x {x}; + return exp(y * log(new_x)); +} + +template +inline BOOST_MP_CXX14_CONSTEXPR complex> pow(const complex>& x, + const boost::multiprecision::number& y) noexcept +{ + const complex> new_y {y}; + return exp(new_y * log(x)); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index d9d5ce6e5..2927d19cc 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -19,7 +19,18 @@ template bool test_equal(T lhs, T rhs, int tol = 10) noexcept { using std::fabs; - return fabs(lhs - rhs) < static_cast(tol) * std::numeric_limits::epsilon(); + const bool res = fabs(lhs - rhs) < static_cast(tol) * std::numeric_limits::epsilon(); + + if (!res) + { + // LCOV_EXCL_START + std::cerr << "LHS: " << lhs + << "\nRHS: " << rhs + << "\nDist: " << fabs(lhs - rhs) / std::numeric_limits::epsilon() << std::endl; + // LCOV_EXCL_STOP + } + + return res; } template @@ -359,6 +370,37 @@ void test_log10() BOOST_TEST(test_equal(lhs.real(), rhs.real())); } +template +void test_pow() +{ + using std::complex; + using std::polar; + using std::pow; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{2}}; + lhs = pow(lhs, T{2}); + complex_scalar rhs {T{-3}, T{4}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag(), 100)); + + lhs = {T{-1}, T{0}}; + lhs = pow(lhs, T{1}/2); + rhs = {T{0}, T{1}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + // Check other side of the cut + BOOST_IF_CONSTEXPR (!std::is_same::value) + { + lhs = {T {-1}, -T {0}}; + lhs = pow(lhs, T {1} / 2); + rhs = {T {0}, T {-1}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + } +} + int main() { test_construction(); @@ -461,5 +503,10 @@ int main() test_log10(); test_log10(); + test_pow(); + test_pow(); + test_pow(); + test_pow(); + return boost::report_errors(); } From c560957850f21adf95c1d92f8af3aa96be88eb4a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 11:24:25 +0200 Subject: [PATCH 26/39] Add sqrt overload --- include/boost/multiprecision/complex.hpp | 6 +++++ test/test_complex_class.cpp | 30 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 7954ebb87..92c1266dc 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -336,6 +336,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> po return exp(new_y * log(x)); } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> sqrt(const complex>& z) noexcept +{ + return polar(sqrt(abs(z)), arg(z) / 2); +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 2927d19cc..45bd6a875 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -401,6 +401,31 @@ void test_pow() } } +template +void test_sqrt() +{ + using std::complex; + using std::polar; + using std::sqrt; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{4}, T{0}}; + lhs = sqrt(lhs); + complex_scalar rhs {T{2}, T{0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + // Check other side of the cut + BOOST_IF_CONSTEXPR (!std::is_same::value) + { + lhs = {T {4}, -T {0}}; + lhs = sqrt(lhs); + rhs = {T {2}, -T {0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + } +} + int main() { test_construction(); @@ -508,5 +533,10 @@ int main() test_pow(); test_pow(); + test_sqrt(); + test_sqrt(); + test_sqrt(); + test_sqrt(); + return boost::report_errors(); } From f1b88eaf5c0f68e676f752e4d3f472a29af12ae8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 11:40:02 +0200 Subject: [PATCH 27/39] Add sinh overload --- include/boost/multiprecision/complex.hpp | 6 ++++++ test/test_complex_class.cpp | 26 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 92c1266dc..56558c307 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -342,6 +342,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> sq return polar(sqrt(abs(z)), arg(z) / 2); } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> sinh(const complex>& z) noexcept +{ + return {sinh(z.real()) * cos(z.imag()), cosh(z.real()) * sin(z.imag())}; +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 45bd6a875..30cd54693 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -426,6 +426,27 @@ void test_sqrt() } } +template +void test_sinh() +{ + using std::complex; + using std::polar; + using std::sinh; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{0}}; + lhs = sinh(lhs); + complex_scalar rhs {sinh(T{1}), T{0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + lhs = {T{0}, T{1}}; + lhs = sinh(lhs); + rhs = {T{0}, sin(T{1})}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); +} + int main() { test_construction(); @@ -538,5 +559,10 @@ int main() test_sqrt(); test_sqrt(); + test_sinh(); + test_sinh(); + test_sinh(); + test_sinh(); + return boost::report_errors(); } From caf7058268665600f64ec1ff1928fc06ef3a9497 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 11:46:49 +0200 Subject: [PATCH 28/39] Add cosh overload --- include/boost/multiprecision/complex.hpp | 6 ++++++ test/test_complex_class.cpp | 26 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 56558c307..f208cb867 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -348,6 +348,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> si return {sinh(z.real()) * cos(z.imag()), cosh(z.real()) * sin(z.imag())}; } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> cosh(const complex>& z) noexcept +{ + return {cosh(z.real()) * cos(z.imag()), sinh(z.real()) * sin(z.imag())}; +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 30cd54693..1e460a627 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -447,6 +447,27 @@ void test_sinh() BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); } +template +void test_cosh() +{ + using std::complex; + using std::polar; + using std::sinh; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{0}}; + lhs = cosh(lhs); + complex_scalar rhs {cosh(T{1}), T{0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + lhs = {T{0}, T{1}}; + lhs = cosh(lhs); + rhs = {cos(T{1}), T{0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); +} + int main() { test_construction(); @@ -564,5 +585,10 @@ int main() test_sinh(); test_sinh(); + test_cosh(); + test_cosh(); + test_cosh(); + test_cosh(); + return boost::report_errors(); } From 17b815dc2e0b1cfc33c483ca77640ac9b6da25b8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 11:49:34 +0200 Subject: [PATCH 29/39] Add tanh overload --- include/boost/multiprecision/complex.hpp | 6 ++++++ test/test_complex_class.cpp | 26 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index f208cb867..3cc9b0cdf 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -354,6 +354,12 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> co return {cosh(z.real()) * cos(z.imag()), sinh(z.real()) * sin(z.imag())}; } +template +inline BOOST_MP_CXX14_CONSTEXPR complex> tanh(const complex>& z) noexcept +{ + return {sinh(z) / cosh(z)}; +} + } // Namespace multiprecision } // Namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 1e460a627..4c4c6d946 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -468,6 +468,27 @@ void test_cosh() BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); } +template +void test_tanh() +{ + using std::complex; + using std::polar; + using std::sinh; + using complex_scalar = decltype(polar(T(), T())); + + complex_scalar lhs {T{1}, T{0}}; + lhs = tanh(lhs); + complex_scalar rhs {tanh(T{1}), T{0}}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); + + lhs = {T{0}, T{1}}; + lhs = tanh(lhs); + rhs = {T{0}, tan(T{1})}; + BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); +} + int main() { test_construction(); @@ -590,5 +611,10 @@ int main() test_cosh(); test_cosh(); + test_tanh(); + test_tanh(); + test_tanh(); + test_tanh(); + return boost::report_errors(); } From f9b9071a9d5a8c1099af3fd8c3bcdbce63ce96ec Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 8 May 2024 12:01:33 +0200 Subject: [PATCH 30/39] Add MSVC workaround for test failure --- test/test_complex_class.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 4c4c6d946..e9a6728b5 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -391,6 +391,8 @@ void test_pow() BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); // Check other side of the cut + // MSVC 14.0 gets this wrong with float and double + #if !defined(_MSC_VER) || (_MSC_VER > 1900) BOOST_IF_CONSTEXPR (!std::is_same::value) { lhs = {T {-1}, -T {0}}; @@ -399,6 +401,7 @@ void test_pow() BOOST_TEST(test_equal(lhs.real(), rhs.real())); BOOST_TEST(test_equal(lhs.imag(), rhs.imag())); } + #endif } template From 9b3575b34522281283d6df3499e458fb02ae210e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 9 May 2024 10:55:34 +0200 Subject: [PATCH 31/39] Bootstrap from existing complex class --- include/boost/multiprecision/complex.hpp | 267 ++++++++++++++++++++++- test/test_complex_class.cpp | 104 ++++----- 2 files changed, 316 insertions(+), 55 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 3cc9b0cdf..4fc05f250 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -8,8 +8,9 @@ #include #include -#include +#include #include +#include #include #include #include @@ -18,6 +19,7 @@ namespace boost { namespace multiprecision { +/* template class complex { @@ -359,15 +361,274 @@ inline BOOST_MP_CXX14_CONSTEXPR complex> ta { return {sinh(z) / cosh(z)}; } - +*/ } // Namespace multiprecision } // Namespace boost namespace std { template -class complex> : public boost::multiprecision::complex> {}; +class complex> +{ +private: + using float_type = boost::multiprecision::number; + using self_type = complex>; + using complex_type = decltype(polar(std::declval>(), std::declval>())); + + complex_type m_data_; + +public: + complex() = default; + explicit complex(float_type real) : m_data_ {real} {} + complex(float_type real, float_type imag) : m_data_ {real, imag} {} + complex(const complex_type& data) : m_data_ {data} {} + complex(complex_type&& data) : m_data_ {data} {} + + complex_type& data() { return m_data_; } + const complex_type& data() const { return m_data_; } + + float_type real() const { return m_data_.real(); } + float_type imag() const { return m_data_.imag(); } + + self_type operator+() const { return *this; } + self_type operator-() const { return {-m_data_.real(), -m_data_.imag()}; } + + friend self_type operator+(const self_type& lhs, const self_type& rhs) + { + return {lhs.m_data_ + rhs.m_data_}; + } + + friend self_type operator+(const self_type& lhs, const float_type& rhs) + { + return {lhs.m_data_ + rhs}; + } + + friend self_type operator+(const float_type& lhs, const self_type& rhs) + { + return {lhs + rhs.m_data_}; + } + + friend self_type operator-(const self_type& lhs, const self_type& rhs) + { + return {lhs.m_data_ - rhs.m_data_}; + } + + friend self_type operator-(const self_type& lhs, const float_type& rhs) + { + return {lhs.m_data_ - rhs}; + } + + friend self_type operator-(const float_type& lhs, const self_type& rhs) + { + return {lhs - rhs.m_data_}; + } + + friend self_type operator*(const self_type& lhs, const self_type& rhs) + { + return {lhs.m_data_ * rhs.m_data_}; + } + + friend self_type operator*(const self_type& lhs, const float_type& rhs) + { + return {lhs.m_data_ * rhs}; + } + + friend self_type operator*(const float_type& lhs, const self_type& rhs) + { + return {lhs * rhs.m_data_}; + } + + friend self_type operator/(const self_type& lhs, const self_type& rhs) + { + return {lhs.m_data_ / rhs.m_data_}; + } + + friend self_type operator/(const self_type& lhs, const float_type& rhs) + { + return {lhs.m_data_ / rhs}; + } + + friend self_type operator/(const float_type& lhs, const self_type& rhs) + { + return {lhs / rhs.m_data_}; + } + + self_type& operator+=(const self_type& rhs) + { + *this = *this + rhs; + return *this; + } + + self_type& operator+=(const float_type& rhs) + { + *this = *this + rhs; + return *this; + } + + self_type& operator-=(const self_type& rhs) + { + *this = *this - rhs; + return *this; + } + + self_type& operator-=(const float_type& rhs) + { + *this = *this - rhs; + return *this; + } + + self_type& operator*=(const self_type& rhs) + { + *this = *this * rhs; + return *this; + } + + self_type& operator*=(const float_type& rhs) + { + *this = *this * rhs; + return *this; + } + + self_type& operator/=(const self_type& rhs) + { + *this = *this / rhs; + return *this; + } + + self_type& operator/=(const float_type& rhs) + { + *this = *this / rhs; + return *this; + } + + bool operator==(const self_type& rhs) const + { + return this->m_data_ == rhs.m_data_; + } + + bool operator!=(const self_type& rhs) const + { + return !(*this == rhs); + } + + bool operator==(const float_type& rhs) const + { + return this->real() == rhs && this->imag() == float_type{0}; + } + + bool operator!=(const float_type& rhs) const + { + return !(*this == rhs); + } + + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const self_type& z) + { + std::basic_ostringstream s; + s.flags(os.flags()); + s.imbue(os.getloc()); + s.precision(os.precision()); + s << '(' << z.real() << ',' << z.imag() << ')'; + + return os << s.str(); + } + + // Supported formats: + // 1) real + // 2) (real) + // 3) (real, imag) + template + friend std::basic_istream& operator>>(std::basic_istream& is, self_type& z) + { + CharT ch {}; + float_type real {}; + float_type imag {}; + + is >> std::ws; + is.get(ch); + + if (ch == '(') + { + // Expecting a format like 2 or 3 + is >> std::ws >> real; + is.get(ch); + if (ch == ',') + { + // A comma indicates it's 3 + is >> std::ws >> imag; + is.get(ch); // Should be ')' + } + else if (ch != ')') + { + // Syntax error: unexpected character + is.setstate(std::ios_base::failbit); + return is; + } + } + else + { + // No parentheses, just a real number from format 1 + is.putback(ch); + is >> real; + } + + if (!is.fail()) + { + z = self_type{real, imag}; + } + + return is; + } +}; } // namespace std +namespace boost { +namespace multiprecision { + +template +inline boost::multiprecision::number real(const std::complex>& z) +{ + return z.real(); +} + +template +inline boost::multiprecision::number imag(const std::complex>& z) +{ + return z.imag(); +} + +template +inline boost::multiprecision::number abs(const std::complex>& z) +{ + return abs(z.data()); +} + +template +inline boost::multiprecision::number arg(const std::complex>& z) +{ + return arg(z.data()); +} + +template +inline boost::multiprecision::number norm(const std::complex>& z) +{ + return norm(z.data()); +} + +template +inline std::complex> conj(const std::complex>& z) +{ + return {conj(z.data())}; +} + +template +inline std::complex> proj(const std::complex>& z) +{ + return {proj(z.data())}; +} + +} // namespace MP +} // namespace boost + #endif //BOOST_MP_COMPLEX_HPP diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index e9a6728b5..48167e065 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -38,7 +37,7 @@ void test_construction() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; std::cerr << typeid(complex_scalar).name() << std::endl; complex_scalar v {}; @@ -59,7 +58,7 @@ void test_unary_operators() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; const complex_scalar val {T{2}, T{-2}}; complex_scalar pos_val = +val; @@ -76,7 +75,7 @@ void test_addition() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; complex_scalar rhs_1 {T{2}, T{2}}; @@ -91,7 +90,7 @@ void test_subtraction() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; complex_scalar rhs_1 {T{2}, T{2}}; @@ -106,7 +105,7 @@ void test_multiplication() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{-3}, T{3}}; complex_scalar rhs_1 {T{2}, T{2}}; @@ -121,7 +120,7 @@ void test_division() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{6}, T{2}}; complex_scalar rhs_1 {T{2}, T{2}}; @@ -136,7 +135,7 @@ void test_equality() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{2}, T{-1}}; complex_scalar rhs {T{2}, T{1}}; @@ -160,7 +159,7 @@ void test_non_member_real_imag() using std::complex; using std::polar; using std::real; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{2}, T{-1}}; @@ -174,7 +173,7 @@ void test_abs() using std::complex; using std::polar; using std::abs; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{1}}; @@ -189,7 +188,7 @@ void test_arg() using std::arg; using boost::math::constants::pi; using boost::math::constants::half_pi; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; BOOST_TEST(test_equal(arg(complex_scalar{T{1}, T{0}}), T{0})); BOOST_TEST(test_equal(arg(complex_scalar{T{0}, T{0}}), T{0})); @@ -203,7 +202,7 @@ void test_norm() using std::complex; using std::polar; using std::norm; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{3}, T{4}}; @@ -216,7 +215,7 @@ void test_conj() using std::complex; using std::polar; using std::conj; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{1}}; complex_scalar rhs {T{1}, T{-1}}; @@ -230,7 +229,7 @@ void test_proj() using std::complex; using std::polar; using std::proj; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{1}}; BOOST_TEST_EQ(lhs, proj(lhs)); @@ -251,7 +250,7 @@ void test_exp() using std::polar; using std::exp; using boost::math::constants::pi; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{0}, pi()}; lhs = exp(lhs); @@ -268,7 +267,7 @@ void test_log() using std::log; using boost::math::constants::half_pi; using boost::math::constants::pi; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{0}, T{1}}; lhs = log(lhs); @@ -301,7 +300,7 @@ void test_scalar_addition() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; T rhs_1 {T{2}}; @@ -316,7 +315,7 @@ void test_scalar_subtraction() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; T rhs_1 {T{2}}; @@ -331,7 +330,7 @@ void test_scalar_multiplication() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{3}, T{2}}; T rhs_1 {T{2}}; @@ -346,7 +345,7 @@ void test_scalar_division() { using std::complex; using std::polar; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs_1 {T{4}, T{2}}; T rhs_1 {T{2}}; @@ -362,7 +361,7 @@ void test_log10() using std::complex; using std::polar; using std::log10; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{-100}, T{0}}; lhs = log10(lhs); @@ -376,7 +375,7 @@ void test_pow() using std::complex; using std::polar; using std::pow; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{2}}; lhs = pow(lhs, T{2}); @@ -410,7 +409,7 @@ void test_sqrt() using std::complex; using std::polar; using std::sqrt; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{4}, T{0}}; lhs = sqrt(lhs); @@ -435,7 +434,7 @@ void test_sinh() using std::complex; using std::polar; using std::sinh; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{0}}; lhs = sinh(lhs); @@ -456,7 +455,7 @@ void test_cosh() using std::complex; using std::polar; using std::sinh; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{0}}; lhs = cosh(lhs); @@ -477,7 +476,7 @@ void test_tanh() using std::complex; using std::polar; using std::sinh; - using complex_scalar = decltype(polar(T(), T())); + using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{0}}; lhs = tanh(lhs); @@ -497,127 +496,128 @@ int main() test_construction(); test_construction(); test_construction(); - test_construction(); + test_construction(); test_unary_operators(); test_unary_operators(); test_unary_operators(); - test_unary_operators(); + test_unary_operators(); test_addition(); test_addition(); test_addition(); - test_addition(); + test_addition(); test_subtraction(); test_subtraction(); test_subtraction(); - test_subtraction(); + test_subtraction(); test_multiplication(); test_multiplication(); test_multiplication(); - test_multiplication(); + test_multiplication(); test_division(); test_division(); test_division(); - test_division(); + test_division(); test_equality(); test_equality(); test_equality(); - test_equality(); + test_equality(); test_non_member_real_imag(); test_non_member_real_imag(); test_non_member_real_imag(); - test_non_member_real_imag(); + test_non_member_real_imag(); test_abs(); test_abs(); test_abs(); - test_abs(); + test_abs(); test_arg(); test_arg(); test_arg(); - test_arg(); + test_arg(); test_norm(); test_norm(); test_norm(); - test_norm(); + test_norm(); test_conj(); test_conj(); test_conj(); - test_conj(); + test_conj(); test_proj(); test_proj(); test_proj(); - test_proj(); - + test_proj(); +/* test_exp(); test_exp(); test_exp(); - test_exp(); + test_exp(); test_log(); test_log(); test_log(); - test_log(); + test_log(); test_scalar_addition(); test_scalar_addition(); test_scalar_addition(); - test_scalar_addition(); + test_scalar_addition(); test_scalar_subtraction(); test_scalar_subtraction(); test_scalar_subtraction(); - test_scalar_subtraction(); + test_scalar_subtraction(); test_scalar_multiplication(); test_scalar_multiplication(); test_scalar_multiplication(); - test_scalar_multiplication(); + test_scalar_multiplication(); test_scalar_division(); test_scalar_division(); test_scalar_division(); - test_scalar_division(); + test_scalar_division(); test_log10(); test_log10(); test_log10(); - test_log10(); + test_log10(); test_pow(); test_pow(); test_pow(); - test_pow(); + test_pow(); test_sqrt(); test_sqrt(); test_sqrt(); - test_sqrt(); + test_sqrt(); test_sinh(); test_sinh(); test_sinh(); - test_sinh(); + test_sinh(); test_cosh(); test_cosh(); test_cosh(); - test_cosh(); + test_cosh(); test_tanh(); test_tanh(); test_tanh(); - test_tanh(); + test_tanh(); +*/ return boost::report_errors(); } From 214a2d23674e60803c1366cd2753f61e33649519 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 9 May 2024 11:11:32 +0200 Subject: [PATCH 32/39] Add remaining special functions --- include/boost/multiprecision/complex.hpp | 117 +++++++++++++++++++++++ test/test_complex_class.cpp | 5 +- 2 files changed, 119 insertions(+), 3 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 4fc05f250..98d350edb 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -628,6 +628,123 @@ inline std::complex> proj(const std::comple return {proj(z.data())}; } +template +inline std::complex> exp(const std::complex>& z) +{ + return {exp(z.data())}; +} + +template +inline std::complex> log(const std::complex>& z) +{ + return {log(z.data())}; +} + +template +inline std::complex> log10(const std::complex>& z) +{ + return {log10(z.data())}; +} + +template +inline std::complex> pow(const std::complex>& x, + const std::complex>& y) +{ + return {pow(x.data(), y.data())}; +} + +template +inline std::complex> pow(const boost::multiprecision::number& x, + const std::complex>& y) +{ + return {pow(x, y.data())}; +} + +template +inline std::complex> pow(const std::complex>& x, + const boost::multiprecision::number& y) +{ + return {pow(x.data(), y)}; +} + +template +inline std::complex> sqrt(const std::complex>& z) +{ + return {sqrt(z.data())}; +} + +template +inline std::complex> sin(const std::complex>& z) +{ + return {sin(z.data())}; +} + +template +inline std::complex> cos(const std::complex>& z) +{ + return {cos(z.data())}; +} + +template +inline std::complex> tan(const std::complex>& z) +{ + return {tan(z.data())}; +} + +template +inline std::complex> asin(const std::complex>& z) +{ + return {asin(z.data())}; +} + +template +inline std::complex> acos(const std::complex>& z) +{ + return {acos(z.data())}; +} + +template +inline std::complex> atan(const std::complex>& z) +{ + return {atan(z.data())}; +} + +template +inline std::complex> sinh(const std::complex>& z) +{ + return {sinh(z.data())}; +} + +template +inline std::complex> cosh(const std::complex>& z) +{ + return {cosh(z.data())}; +} + +template +inline std::complex> tanh(const std::complex>& z) +{ + return {tanh(z.data())}; +} + +template +inline std::complex> asinh(const std::complex>& z) +{ + return {asinh(z.data())}; +} + +template +inline std::complex> acosh(const std::complex>& z) +{ + return {acosh(z.data())}; +} + +template +inline std::complex> atanh(const std::complex>& z) +{ + return {atanh(z.data())}; +} + } // namespace MP } // namespace boost diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 48167e065..bb406195a 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -380,7 +380,7 @@ void test_pow() complex_scalar lhs {T{1}, T{2}}; lhs = pow(lhs, T{2}); complex_scalar rhs {T{-3}, T{4}}; - BOOST_TEST(test_equal(lhs.real(), rhs.real())); + BOOST_TEST(test_equal(lhs.real(), rhs.real(), 100)); BOOST_TEST(test_equal(lhs.imag(), rhs.imag(), 100)); lhs = {T{-1}, T{0}}; @@ -557,7 +557,7 @@ int main() test_proj(); test_proj(); test_proj(); -/* + test_exp(); test_exp(); test_exp(); @@ -617,7 +617,6 @@ int main() test_tanh(); test_tanh(); test_tanh(); -*/ return boost::report_errors(); } From 7ec2760223a670f6edb629ba6e7e8c80874f2dca Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Tue, 14 May 2024 19:08:04 +0100 Subject: [PATCH 33/39] Add tentative polar() support and tests. Fix a few missing using declarations. Remove unneeded using std::polar. --- include/boost/multiprecision/complex.hpp | 8 ++++- test/test_complex_class.cpp | 40 ++++++++---------------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index 98d350edb..a89e4adc9 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -373,7 +373,7 @@ class complex> private: using float_type = boost::multiprecision::number; using self_type = complex>; - using complex_type = decltype(polar(std::declval>(), std::declval>())); + using complex_type = decltype(boost::multiprecision::polar(std::declval>(), std::declval>())); complex_type m_data_; @@ -581,6 +581,12 @@ class complex> } }; +template +inline std::complex> polar(const boost::multiprecision::number& a, const boost::multiprecision::number& b) +{ + return { boost::multiprecision::polar(a, b) }; +} + } // namespace std namespace boost { diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index bb406195a..0d7f349e7 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -36,7 +36,6 @@ template void test_construction() { using std::complex; - using std::polar; using complex_scalar = std::complex; std::cerr << typeid(complex_scalar).name() << std::endl; @@ -51,13 +50,20 @@ void test_construction() complex_scalar v2 {T{2}, T{2}}; BOOST_TEST_EQ(v2.real(), T{2}); BOOST_TEST_EQ(v2.imag(), T{2}); + + if constexpr(boost::multiprecision::is_number::value) + { + complex_scalar v3 = std::polar(T(1), T(2)); + complex_scalar v4 = boost::multiprecision::polar(T(1), T(2)); + BOOST_TEST_EQ(v3.real(), v4.real()); + BOOST_TEST_EQ(v3.imag(), v4.imag()); + } } template void test_unary_operators() { using std::complex; - using std::polar; using complex_scalar = std::complex; const complex_scalar val {T{2}, T{-2}}; @@ -74,7 +80,6 @@ template void test_addition() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; @@ -89,7 +94,6 @@ template void test_subtraction() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; @@ -104,7 +108,6 @@ template void test_multiplication() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{-3}, T{3}}; @@ -119,7 +122,6 @@ template void test_division() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{6}, T{2}}; @@ -134,7 +136,6 @@ template void test_equality() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs {T{2}, T{-1}}; @@ -157,7 +158,6 @@ template void test_non_member_real_imag() { using std::complex; - using std::polar; using std::real; using complex_scalar = std::complex; @@ -171,7 +171,6 @@ template void test_abs() { using std::complex; - using std::polar; using std::abs; using complex_scalar = std::complex; @@ -184,7 +183,6 @@ template void test_arg() { using std::complex; - using std::polar; using std::arg; using boost::math::constants::pi; using boost::math::constants::half_pi; @@ -200,7 +198,6 @@ template void test_norm() { using std::complex; - using std::polar; using std::norm; using complex_scalar = std::complex; @@ -213,7 +210,6 @@ template void test_conj() { using std::complex; - using std::polar; using std::conj; using complex_scalar = std::complex; @@ -227,7 +223,6 @@ template void test_proj() { using std::complex; - using std::polar; using std::proj; using complex_scalar = std::complex; @@ -247,7 +242,6 @@ template void test_exp() { using std::complex; - using std::polar; using std::exp; using boost::math::constants::pi; using complex_scalar = std::complex; @@ -263,7 +257,6 @@ template void test_log() { using std::complex; - using std::polar; using std::log; using boost::math::constants::half_pi; using boost::math::constants::pi; @@ -299,7 +292,6 @@ template void test_scalar_addition() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; @@ -314,7 +306,6 @@ template void test_scalar_subtraction() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{1}, T{1}}; @@ -329,7 +320,6 @@ template void test_scalar_multiplication() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{3}, T{2}}; @@ -344,7 +334,6 @@ template void test_scalar_division() { using std::complex; - using std::polar; using complex_scalar = std::complex; complex_scalar lhs_1 {T{4}, T{2}}; @@ -359,7 +348,6 @@ template void test_log10() { using std::complex; - using std::polar; using std::log10; using complex_scalar = std::complex; @@ -373,7 +361,6 @@ template void test_pow() { using std::complex; - using std::polar; using std::pow; using complex_scalar = std::complex; @@ -407,7 +394,6 @@ template void test_sqrt() { using std::complex; - using std::polar; using std::sqrt; using complex_scalar = std::complex; @@ -432,8 +418,8 @@ template void test_sinh() { using std::complex; - using std::polar; using std::sinh; + using std::sin; using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{0}}; @@ -453,8 +439,8 @@ template void test_cosh() { using std::complex; - using std::polar; - using std::sinh; + using std::cosh; + using std::cos; using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{0}}; @@ -474,8 +460,8 @@ template void test_tanh() { using std::complex; - using std::polar; - using std::sinh; + using std::tanh; + using std::tan; using complex_scalar = std::complex; complex_scalar lhs {T{1}, T{0}}; From 411d9ea274c02218856d9c4b3fd293e5e0b3e27f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 15 May 2024 10:27:09 +0200 Subject: [PATCH 34/39] Remove MSVC 14.0 for boost 1.86 --- .github/workflows/multiprecision.yml | 43 ---------------------------- 1 file changed, 43 deletions(-) diff --git a/.github/workflows/multiprecision.yml b/.github/workflows/multiprecision.yml index 8e2e7726f..b316d9278 100644 --- a/.github/workflows/multiprecision.yml +++ b/.github/workflows/multiprecision.yml @@ -435,49 +435,6 @@ jobs: - name: b2 config run: cat bin.v2/config.log working-directory: ../boost-root/ - windows_msvc_14_0: - runs-on: windows-2019 - defaults: - run: - shell: cmd - env: - ARGS: toolset=${{ matrix.toolset }} address-model=64 cxxstd=${{ matrix.standard }} - strategy: - fail-fast: false - matrix: - toolset: [ msvc-14.0 ] - standard: [ 14, latest ] - suite: [ github_ci_block_1, github_ci_block_2 ] - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: '0' - - name: Checkout main boost - run: git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root - - name: Update tools/boostdep - run: git submodule update --init tools/boostdep - working-directory: ../boost-root - - name: Copy files - run: xcopy /s /e /q %GITHUB_WORKSPACE% libs\multiprecision - working-directory: ../boost-root - - name: Install deps - run: python tools/boostdep/depinst/depinst.py multiprecision - working-directory: ../boost-root - - name: Bootstrap - run: bootstrap - working-directory: ../boost-root - - name: Generate headers - run: b2 headers - working-directory: ../boost-root - - name: Config Info - run: ..\..\..\b2 print_config_info print_math_info %ARGS% - working-directory: ../boost-root/libs/config/test - - name: Test - run: ..\..\..\b2 -j2 --hash %ARGS% define=CI_SUPPRESS_KNOWN_ISSUES ${{ matrix.suite }} - working-directory: ../boost-root/libs/multiprecision/test - - name: b2 config - run: cat bin.v2/config.log - working-directory: ../boost-root/ windows_msvc_14_2: runs-on: windows-2019 defaults: From 4b0d1e53c2c3990bdd678b60dbc6f3cc2ff01ef5 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 15 May 2024 10:28:34 +0200 Subject: [PATCH 35/39] Fix usage of if constexpr --- test/test_complex_class.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 0d7f349e7..973f34dd5 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -51,7 +51,7 @@ void test_construction() BOOST_TEST_EQ(v2.real(), T{2}); BOOST_TEST_EQ(v2.imag(), T{2}); - if constexpr(boost::multiprecision::is_number::value) + BOOST_IF_CONSTEXPR (boost::multiprecision::is_number::value) { complex_scalar v3 = std::polar(T(1), T(2)); complex_scalar v4 = boost::multiprecision::polar(T(1), T(2)); From b437d605a92a5655101250cf67573749555dfe22 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 16 May 2024 08:43:11 +0200 Subject: [PATCH 36/39] Use SFINAE to fix C++14 build errors --- test/test_complex_class.cpp | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/test/test_complex_class.cpp b/test/test_complex_class.cpp index 973f34dd5..cdfe5bcfe 100644 --- a/test/test_complex_class.cpp +++ b/test/test_complex_class.cpp @@ -32,7 +32,7 @@ bool test_equal(T lhs, T rhs, int tol = 10) noexcept return res; } -template +template ::value, bool> = true> void test_construction() { using std::complex; @@ -50,14 +50,31 @@ void test_construction() complex_scalar v2 {T{2}, T{2}}; BOOST_TEST_EQ(v2.real(), T{2}); BOOST_TEST_EQ(v2.imag(), T{2}); +} - BOOST_IF_CONSTEXPR (boost::multiprecision::is_number::value) - { - complex_scalar v3 = std::polar(T(1), T(2)); - complex_scalar v4 = boost::multiprecision::polar(T(1), T(2)); - BOOST_TEST_EQ(v3.real(), v4.real()); - BOOST_TEST_EQ(v3.imag(), v4.imag()); - } +template ::value, bool> = true> +void test_construction() +{ + using std::complex; + using complex_scalar = std::complex; + std::cerr << typeid(complex_scalar).name() << std::endl; + + complex_scalar v {}; + BOOST_TEST_EQ(v.real(), T{0}); + BOOST_TEST_EQ(v.imag(), T{0}); + + complex_scalar v1 {T{1}}; + BOOST_TEST_EQ(v1.real(), T{1}); + BOOST_TEST_EQ(v1.imag(), T{0}); + + complex_scalar v2 {T{2}, T{2}}; + BOOST_TEST_EQ(v2.real(), T{2}); + BOOST_TEST_EQ(v2.imag(), T{2}); + + complex_scalar v3 = std::polar(T(1), T(2)); + complex_scalar v4 = boost::multiprecision::polar(T(1), T(2)); + BOOST_TEST_EQ(v3.real(), v4.real()); + BOOST_TEST_EQ(v3.imag(), v4.imag()); } template From b885279d90489569ba64c76b09f81170c18746ea Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 17 May 2024 14:06:42 +0200 Subject: [PATCH 37/39] Delete cruft --- include/boost/multiprecision/complex.hpp | 349 ----------------------- 1 file changed, 349 deletions(-) diff --git a/include/boost/multiprecision/complex.hpp b/include/boost/multiprecision/complex.hpp index a89e4adc9..cadf53d9b 100644 --- a/include/boost/multiprecision/complex.hpp +++ b/include/boost/multiprecision/complex.hpp @@ -16,355 +16,6 @@ #include #include -namespace boost { -namespace multiprecision { - -/* -template -class complex -{ -private: - T real_; - T imag_; - -public: - BOOST_MP_CXX14_CONSTEXPR complex() noexcept = default; - BOOST_MP_CXX14_CONSTEXPR complex(T real) noexcept : real_ {real}, imag_ {T{0}} {} - BOOST_MP_CXX14_CONSTEXPR complex(T real, T imag) noexcept : real_ {real}, imag_ {imag} {} - BOOST_MP_CXX14_CONSTEXPR complex& operator=(const complex& rhs) - { - real_ = rhs.real_; - imag_ = rhs.imag_; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR T real() const noexcept { return real_; } - BOOST_MP_CXX14_CONSTEXPR T imag() const noexcept { return imag_; } - - BOOST_MP_CXX14_CONSTEXPR complex operator+() const { return *this; } - BOOST_MP_CXX14_CONSTEXPR complex operator-() const { return {-real_, -imag_}; } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator+(const complex& lhs, const complex& rhs) noexcept - { - return {lhs.real_ + rhs.real_, lhs.imag_ + rhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator+(const complex& lhs, const T& rhs) noexcept - { - return {lhs.real_ + rhs, lhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator+(const T& lhs, const complex& rhs) noexcept - { - return {lhs + rhs.real_, rhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& lhs, const complex& rhs) noexcept - { - return {lhs.real_ - rhs.real_, lhs.imag_ - rhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator-(const complex& lhs, const T& rhs) noexcept - { - return {lhs.real_ - rhs, lhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator-(const T& lhs, const complex& rhs) noexcept - { - return {lhs - rhs.real_, -rhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& lhs, const complex& rhs) noexcept - { - return {lhs.real_ * rhs.real_ - lhs.imag_ * rhs.imag_, lhs.imag_ * rhs.real_ + lhs.real_ * rhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator*(const complex& lhs, const T& rhs) noexcept - { - return {lhs.real_ * rhs, lhs.imag_ * rhs}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator*(const T& lhs, const complex& rhs) noexcept - { - return {lhs * rhs.real_, lhs * rhs.imag_}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& lhs, const complex& rhs) noexcept - { - const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; - const T real_part = (lhs.real_ * rhs.real_ + lhs.imag_ * rhs.imag_) / divisor; - const T imag_part = (lhs.imag_ * rhs.real_ - lhs.real_ * rhs.imag_) / divisor; - return {real_part, imag_part}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator/(const complex& lhs, const T& rhs) noexcept - { - const T divisor = rhs * rhs; - const T real_part = (lhs.real_ * rhs) / divisor; - const T imag_part = (lhs.imag_ * rhs) / divisor; - return {real_part, imag_part}; - } - - friend BOOST_MP_CXX14_CONSTEXPR complex operator/(const T& lhs, const complex& rhs) noexcept - { - const T divisor = rhs.real_ * rhs.real_ + rhs.imag_ * rhs.imag_; - const T real_part = (lhs * rhs.real_) / divisor; - const T imag_part = -(lhs.real_ * rhs.imag_) / divisor; - return {real_part, imag_part}; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator+=(const complex& rhs) noexcept - { - *this = *this + rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator+=(const T& rhs) noexcept - { - *this = *this + rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator-=(const complex& rhs) noexcept - { - *this = *this - rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator-=(const T& rhs) noexcept - { - *this = *this - rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator*=(const complex& rhs) noexcept - { - *this = *this * rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator*=(const T& rhs) noexcept - { - *this = *this * rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator/=(const complex& rhs) noexcept - { - *this = *this / rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR complex& operator/=(const T& rhs) noexcept - { - *this = *this / rhs; - return *this; - } - - BOOST_MP_CXX14_CONSTEXPR bool operator==(const complex& rhs) const noexcept - { - return real_ == rhs.real_ && imag_ == rhs.imag_; - } - - BOOST_MP_CXX14_CONSTEXPR bool operator!=(const complex& rhs) const noexcept - { - return !(*this == rhs); - } - - BOOST_MP_CXX14_CONSTEXPR bool operator==(const T& rhs) const noexcept - { - return real_ == rhs && imag_ == T{0}; - } - - BOOST_MP_CXX14_CONSTEXPR bool operator!=(const T& rhs) const noexcept - { - return !(*this == rhs); - } - - template - friend std::basic_ostream& operator<<(std::basic_ostream& os, const complex& z) - { - std::basic_ostringstream s; - s.flags(os.flags()); - s.imbue(os.getloc()); - s.precision(os.precision()); - s << '(' << z.real_ << ',' << z.imag_ << ')'; - - return os << s.str(); - } - - // Supported formats: - // 1) real - // 2) (real) - // 3) (real, imag) - template - friend std::basic_istream& operator>>(std::basic_istream& is, complex& z) - { - CharT ch {}; - T real = T{0}; - T imag = T{0}; - - is >> std::ws; - is.get(ch); - - if (ch == '(') - { - // Expecting a format like 2 or 3 - is >> std::ws >> real; - is.get(ch); - if (ch == ',') - { - // A comma indicates it's 3 - is >> std::ws >> imag; - is.get(ch); // Should be ')' - } - else if (ch != ')') - { - // Syntax error: unexpected character - is.setstate(std::ios_base::failbit); - return is; - } - } - else - { - // No parentheses, just a real number from format 1 - is.putback(ch); - is >> real; - } - - if (!is.fail()) - { - z.real_ = real; - z.imag_ = imag; - } - - return is; - } -}; - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> polar(const boost::multiprecision::number& rho, - const boost::multiprecision::number& theta) noexcept -{ - BOOST_MP_ASSERT_MSG(rho >= 0, "Rho must be positive"); - return {rho * cos(theta), rho * sin(theta)}; -} - -template -inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number real(const complex>& z) noexcept -{ - return z.real(); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number imag(const complex>& z) noexcept -{ - return z.imag(); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number abs(const complex>& z) noexcept -{ - return hypot(z.real(), z.imag()); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number arg(const complex>& z) noexcept -{ - return atan2(z.imag(), z.real()); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR boost::multiprecision::number norm(const complex>& z) noexcept -{ - return z.real() * z.real() + z.imag() * z.imag(); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> conj(const complex>& z) noexcept -{ - return {z.real(), -z.imag()}; -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> proj(const complex>& z) noexcept -{ - if (isinf(z.real()) || isinf(z.imag())) - { - return {std::numeric_limits>::infinity(), copysign(boost::multiprecision::number{0}, z.imag())}; - } - - return z; -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> exp(const complex>& z) noexcept -{ - return polar(exp(z.real()), z.imag()); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> log(const complex>& z) noexcept -{ - return {log(abs(z)), arg(z)}; -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> log10(const complex>& z) noexcept -{ - return log(z) / log(boost::multiprecision::number{10}); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> pow(const complex>& x, - const complex>& y) noexcept -{ - return exp(y * log(x)); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> pow(const boost::multiprecision::number& x, - const complex>& y) noexcept -{ - const complex> new_x {x}; - return exp(y * log(new_x)); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> pow(const complex>& x, - const boost::multiprecision::number& y) noexcept -{ - const complex> new_y {y}; - return exp(new_y * log(x)); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> sqrt(const complex>& z) noexcept -{ - return polar(sqrt(abs(z)), arg(z) / 2); -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> sinh(const complex>& z) noexcept -{ - return {sinh(z.real()) * cos(z.imag()), cosh(z.real()) * sin(z.imag())}; -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> cosh(const complex>& z) noexcept -{ - return {cosh(z.real()) * cos(z.imag()), sinh(z.real()) * sin(z.imag())}; -} - -template -inline BOOST_MP_CXX14_CONSTEXPR complex> tanh(const complex>& z) noexcept -{ - return {sinh(z) / cosh(z)}; -} -*/ -} // Namespace multiprecision -} // Namespace boost - namespace std { template From ded45c0c5ce91d82045b3dee658a5242f9548182 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 17 May 2024 14:57:00 +0200 Subject: [PATCH 38/39] Add nick's test set --- test/Jamfile.v2 | 1 + test/boost_math_issue_1131.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 test/boost_math_issue_1131.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 66f2f6f3d..e4d5b0893 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1266,6 +1266,7 @@ test-suite misc : # Eigen interoperability: # [ run test_eigen_interop_cpp_int.cpp : : : release [ check-target-builds ../config//has_eigen : : no ] ] + [ run boost_math_issue_1131.cpp : : : release [ check-target-builds ../config//has_eigen : : no ] ] [ run test_eigen_interop_cpp_dec_float.cpp : : : release [ check-target-builds ../config//has_eigen : : no ] ] [ run test_eigen_interop_cpp_dec_float_2.cpp : : : release [ check-target-builds ../config//has_eigen : : no ] ] [ run test_eigen_interop_cpp_dec_float_3.cpp : : : release [ check-target-builds ../config//has_eigen : : no ] ] diff --git a/test/boost_math_issue_1131.cpp b/test/boost_math_issue_1131.cpp new file mode 100644 index 000000000..7cc11f8a0 --- /dev/null +++ b/test/boost_math_issue_1131.cpp @@ -0,0 +1,24 @@ +// Copyright 2024 Nick Thompson +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +using boost::multiprecision::cpp_bin_float_100; + +int main() { + + Eigen::Matrix A = Eigen::Matrix::Identity(3,3); + Eigen::EigenSolver es; + es.compute(A, /*computeEigenvectors=*/ false); + + auto eigs = es.eigenvalues(); + for (auto eig : eigs) { + std::cout << eig << "\n"; + } + + return 0; +} From 903d23cbfbee812406685dcf760db4ae89c7083e Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 17 May 2024 16:21:13 +0200 Subject: [PATCH 39/39] Eigen matrix doesn't support iterators --- test/boost_math_issue_1131.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/boost_math_issue_1131.cpp b/test/boost_math_issue_1131.cpp index 7cc11f8a0..57d0eb9d0 100644 --- a/test/boost_math_issue_1131.cpp +++ b/test/boost_math_issue_1131.cpp @@ -6,18 +6,18 @@ #include #include #include +#include using boost::multiprecision::cpp_bin_float_100; int main() { - Eigen::Matrix A = Eigen::Matrix::Identity(3,3); Eigen::EigenSolver es; es.compute(A, /*computeEigenvectors=*/ false); auto eigs = es.eigenvalues(); - for (auto eig : eigs) { - std::cout << eig << "\n"; + for (std::size_t i = 0; i < eigs.size(); ++i) { + std::cout << eigs[i] << "\n"; } return 0;