From 5a9b2e4f7db621a05e40a2ec0e0fc9007ee33ce2 Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Fri, 25 May 2012 22:21:16 +0900 Subject: [PATCH] add sprout/rational.hpp add sprout/math/common_factor.hpp --- .../string/example/c_str_to_sprout_string.cpp | 88 +-- libs/weed/example/as_tuple.cpp | 134 ++-- sprout/cinttypes/abs.hpp | 8 - sprout/cstdlib/abs.hpp | 21 + sprout/math/common_factor.hpp | 7 + sprout/math/gcd.hpp | 188 +++++ sprout/math/lcm.hpp | 101 +++ sprout/rational.hpp | 725 ++++++++++++++++++ 8 files changed, 1153 insertions(+), 119 deletions(-) create mode 100644 sprout/math/common_factor.hpp create mode 100644 sprout/math/gcd.hpp create mode 100644 sprout/math/lcm.hpp create mode 100644 sprout/rational.hpp diff --git a/libs/string/example/c_str_to_sprout_string.cpp b/libs/string/example/c_str_to_sprout_string.cpp index 43187bdb..4fdea513 100644 --- a/libs/string/example/c_str_to_sprout_string.cpp +++ b/libs/string/example/c_str_to_sprout_string.cpp @@ -1,44 +1,44 @@ -// -// Sprout C++ Library -// -// Copyright (c) 2012 -// bolero-MURAKAMI : http://d.hatena.ne.jp/boleros/ -// osyo-manga : http://d.hatena.ne.jp/osyo-manga/ -// -// Readme: -// https://github.com/bolero-MURAKAMI/Sprout/blob/master/README -// -// License: -// Boost Software License - Version 1.0 -// -// -#include - -// -// C style string to Sprout.String -// -int -main(){ - - constexpr char const* c_str = "homu"; - - // - // String length is required - // - constexpr auto length = sprout::char_traits::length(c_str); - static_assert(length == 4, ""); - - // - // To Sprout.String - // - constexpr auto str = sprout::string_from_c_str( c_str ); - static_assert(std::is_same const, decltype(str)>{}, ""); - static_assert(str == "homu", ""); - - constexpr auto str2 = sprout::string_from_c_str( c_str, 2 ); - static_assert(std::is_same const, decltype(str2)>{}, ""); - static_assert(str2 == "ho", ""); - - - return 0; -} +// +// Sprout C++ Library +// +// Copyright (c) 2012 +// bolero-MURAKAMI : http://d.hatena.ne.jp/boleros/ +// osyo-manga : http://d.hatena.ne.jp/osyo-manga/ +// +// Readme: +// https://github.com/bolero-MURAKAMI/Sprout/blob/master/README +// +// License: +// Boost Software License - Version 1.0 +// +// +#include + +// +// C style string to Sprout.String +// +int +main(){ + + constexpr char const* c_str = "homu"; + + // + // String length is required + // + constexpr auto length = sprout::char_traits::length(c_str); + static_assert(length == 4, ""); + + // + // To Sprout.String + // + constexpr auto str = sprout::string_from_c_str( c_str ); + static_assert(std::is_same const, decltype(str)>{}, ""); + static_assert(str == "homu", ""); + + constexpr auto str2 = sprout::string_from_c_str( c_str, 2 ); + static_assert(std::is_same const, decltype(str2)>{}, ""); + static_assert(str2 == "ho", ""); + + + return 0; +} diff --git a/libs/weed/example/as_tuple.cpp b/libs/weed/example/as_tuple.cpp index 75b93582..96ecbd18 100644 --- a/libs/weed/example/as_tuple.cpp +++ b/libs/weed/example/as_tuple.cpp @@ -1,67 +1,67 @@ -// -// Sprout C++ Library -// -// Copyright (c) 2012 -// bolero-MURAKAMI : http://d.hatena.ne.jp/boleros/ -// osyo-manga : http://d.hatena.ne.jp/osyo-manga/ -// -// Readme: -// https://github.com/bolero-MURAKAMI/Sprout/blob/master/README -// -// License: -// Boost Software License - Version 1.0 -// -// -#include - - -int -main(){ - namespace w = sprout::weed; - - static constexpr auto source = sprout::to_string("homu:mado"); - - // String parser - static constexpr auto item = *w::lim<4>(w::char_ - ':'); - - - // - // If you do not want to use the as_tuple - // - { - static constexpr auto parser = item >> ':' >> item; - - static constexpr auto result = w::parse( - sprout::begin(source), sprout::end(source), parser - ); - static_assert(result.success(), ""); - - // !!!! - static_assert(result.attr() == "homumado", ""); - } - - - // - // You need to use the as_tuple - // - { - static constexpr auto parser = w::as_tuple[item] >> ':' >> w::as_tuple[item]; - - static constexpr auto result = w::parse( - sprout::begin(source), sprout::end(source), parser - ); - static_assert(result.success(), ""); - - static constexpr auto attr = result.attr(); - - // OK - static_assert(std::is_same< - sprout::tuple, sprout::string<4>> const, - decltype(attr) - >::value, ""); - static_assert(sprout::get<0>(attr) == "homu", ""); - static_assert(sprout::get<1>(attr) == "mado", ""); - } - - return 0; -} +// +// Sprout C++ Library +// +// Copyright (c) 2012 +// bolero-MURAKAMI : http://d.hatena.ne.jp/boleros/ +// osyo-manga : http://d.hatena.ne.jp/osyo-manga/ +// +// Readme: +// https://github.com/bolero-MURAKAMI/Sprout/blob/master/README +// +// License: +// Boost Software License - Version 1.0 +// +// +#include + + +int +main(){ + namespace w = sprout::weed; + + static constexpr auto source = sprout::to_string("homu:mado"); + + // String parser + static constexpr auto item = *w::lim<4>(w::char_ - ':'); + + + // + // If you do not want to use the as_tuple + // + { + static constexpr auto parser = item >> ':' >> item; + + static constexpr auto result = w::parse( + sprout::begin(source), sprout::end(source), parser + ); + static_assert(result.success(), ""); + + // !!!! + static_assert(result.attr() == "homumado", ""); + } + + + // + // You need to use the as_tuple + // + { + static constexpr auto parser = w::as_tuple[item] >> ':' >> w::as_tuple[item]; + + static constexpr auto result = w::parse( + sprout::begin(source), sprout::end(source), parser + ); + static_assert(result.success(), ""); + + static constexpr auto attr = result.attr(); + + // OK + static_assert(std::is_same< + sprout::tuple, sprout::string<4>> const, + decltype(attr) + >::value, ""); + static_assert(sprout::get<0>(attr) == "homu", ""); + static_assert(sprout::get<1>(attr) == "mado", ""); + } + + return 0; +} diff --git a/sprout/cinttypes/abs.hpp b/sprout/cinttypes/abs.hpp index 4abb84d6..f8d9d13d 100644 --- a/sprout/cinttypes/abs.hpp +++ b/sprout/cinttypes/abs.hpp @@ -10,14 +10,6 @@ namespace sprout { SPROUT_CONSTEXPR std::intmax_t imaxabs(std::intmax_t j) { return j < 0 ? -j : j; } - - template< - typename T, - typename sprout::enabler_if::value>::type = sprout::enabler - > - SPROUT_CONSTEXPR T abs(T j) { - return sprout::imaxabs(j); - } } // namespace sprout #endif // #ifndef SPROUT_CINTTYPES_ABS_HPP diff --git a/sprout/cstdlib/abs.hpp b/sprout/cstdlib/abs.hpp index 26666c5e..a40cf775 100644 --- a/sprout/cstdlib/abs.hpp +++ b/sprout/cstdlib/abs.hpp @@ -1,7 +1,9 @@ #ifndef SPROUT_CSTDLIB_ABS_HPP #define SPROUT_CSTDLIB_ABS_HPP +#include #include +#include namespace sprout { // Copyright (C) 2011 RiSK (sscrisk) @@ -26,6 +28,25 @@ namespace sprout { SPROUT_CONSTEXPR long long abs(long long j) { return sprout::llabs(j); } + + template< + typename IntType, + typename sprout::enabler_if< + std::is_integral::value && std::is_signed::value + >::type = sprout::enabler + > + SPROUT_CONSTEXPR IntType abs(IntType j) { + return j < 0 ? -j : j; + } + template< + typename IntType, + typename sprout::enabler_if< + std::is_integral::value && std::is_unsigned::value + >::type = sprout::enabler + > + SPROUT_CONSTEXPR IntType abs(IntType j) { + return j; + } } // namespace sprout #endif // #ifndef SPROUT_CSTDLIB_ABS_HPP diff --git a/sprout/math/common_factor.hpp b/sprout/math/common_factor.hpp new file mode 100644 index 00000000..70d3c494 --- /dev/null +++ b/sprout/math/common_factor.hpp @@ -0,0 +1,7 @@ +#ifndef SPROUT_MATH_COMMON_FACTOR_HPP +#define SPROUT_MATH_COMMON_FACTOR_HPP + +#include +#include + +#endif // SPROUT_MATH_COMMON_FACTOR_HPP diff --git a/sprout/math/gcd.hpp b/sprout/math/gcd.hpp new file mode 100644 index 00000000..ef970698 --- /dev/null +++ b/sprout/math/gcd.hpp @@ -0,0 +1,188 @@ +#ifndef SPROUT_MATH_GCD_HPP +#define SPROUT_MATH_GCD_HPP + +#include +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template + inline SPROUT_CONSTEXPR RingType + gcd_euclidean(RingType a, RingType b) { + return a == static_cast(0) ? b + : b % a == static_cast(0) ? a + : sprout::math::detail::gcd_euclidean(a % (b % a), b % a) + ; + } + + template + inline SPROUT_CONSTEXPR IntType + gcd_integer_impl(IntType result) { + return result < static_cast(0) ? -result : result; + } + template + inline SPROUT_CONSTEXPR IntType + gcd_integer(IntType const& a, IntType const& b) { + return sprout::math::detail::gcd_integer_impl( + sprout::math::detail::gcd_euclidean(a, b) + ); + } + + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_2(unsigned shifts, sprout::array const& r, unsigned which) { + return !(r[ which ] & 1u) ? sprout::math::detail::gcd_binary_2_2( + shifts, + which ? sprout::array{{r[0], BuiltInUnsigned(r[1] >> 1)}} + : sprout::array{{BuiltInUnsigned(r[0] >> 1), r[1]}} + , + which + ) + : r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_1( + shifts, + which ^ 1u ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} + : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} + , + which ^ 1u + ) + : sprout::math::detail::gcd_binary_2_1( + shifts, + which ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} + : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} + , + which + ) + ; + } + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which) { + return r[which] ? sprout::math::detail::gcd_binary_2_2(shifts, r, which) + : r[!which] << shifts + ; + } + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary_1(BuiltInUnsigned u, BuiltInUnsigned v, unsigned shifts = 0) { + return (!(u & 1u) && !(v & 1u)) ? sprout::math::detail::gcd_binary_1(u >> 1, v >> 1, shifts + 1) + : sprout::math::detail::gcd_binary_2_2( + shifts, sprout::array{{u, v}}, static_cast(u & 1u) + ) + ; + } + template + inline SPROUT_CONSTEXPR BuiltInUnsigned + gcd_binary(BuiltInUnsigned u, BuiltInUnsigned v) { + return u && v ? sprout::math::detail::gcd_binary_1(u, v) + : u + v + ; + } + + template + struct gcd_optimal_evaluator_helper_t { + public: + SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { + return sprout::math::detail::gcd_euclidean(a, b); + } + }; + template + struct gcd_optimal_evaluator_helper_t { + public: + SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { + return sprout::math::detail::gcd_integer(a, b); + } + }; + + template + struct gcd_optimal_evaluator { + public: + SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { + typedef std::numeric_limits limits_type; + typedef sprout::math::detail::gcd_optimal_evaluator_helper_t< + T, limits_type::is_specialized, limits_type::is_signed + > helper_type; + return helper_type().operator()(a, b); + } + }; + +# define SPROUT_PRIVATE_GCD_UF(Ut) \ + template<> \ + struct gcd_optimal_evaluator { \ + public: \ + SPROUT_CONSTEXPR Ut operator()(Ut a, Ut b) const { \ + return sprout::math::detail::gcd_binary(a, b); \ + } \ + } + SPROUT_PRIVATE_GCD_UF(unsigned char); + SPROUT_PRIVATE_GCD_UF(unsigned short); + SPROUT_PRIVATE_GCD_UF(unsigned); + SPROUT_PRIVATE_GCD_UF(unsigned long); + SPROUT_PRIVATE_GCD_UF(unsigned long long); +# if CHAR_MIN == 0 + SPROUT_PRIVATE_GCD_UF(char); +# endif + #undef SPROUT_PRIVATE_GCD_UF + +# define SPROUT_PRIVATE_GCD_SF(St, Ut) \ + template<> \ + struct gcd_optimal_evaluator { \ + public: \ + SPROUT_CONSTEXPR St operator()(St a, St b) const { \ + using sprout::abs; \ + return static_cast(sprout::math::detail::gcd_optimal_evaluator().operator()( \ + static_cast(abs(a)), static_cast(abs(b)) \ + )); \ + } \ + } + SPROUT_PRIVATE_GCD_SF(signed char, unsigned char); + SPROUT_PRIVATE_GCD_SF(short, unsigned short); + SPROUT_PRIVATE_GCD_SF(int, unsigned); + SPROUT_PRIVATE_GCD_SF(long, unsigned long); +# if CHAR_MIN < 0 + SPROUT_PRIVATE_GCD_SF(char, unsigned char); +# endif + SPROUT_PRIVATE_GCD_SF(long long, unsigned long long); + #undef SPROUT_PRIVATE_GCD_SF + + template + inline SPROUT_CONSTEXPR T + gcd_optimal(T const& a, T const& b) { + return sprout::math::detail::gcd_optimal_evaluator().operator()(a, b); + } + } // namespace detail + + // + // gcd_evaluator + // + template + class gcd_evaluator { + public: + typedef IntType result_type; + typedef IntType first_argument_type; + typedef IntType second_argument_type; + public: + SPROUT_CONSTEXPR result_type + operator()(first_argument_type const& a, second_argument_type const& b) const { + return sprout::math::detail::gcd_optimal(a, b); + } + }; + + // + // gcd + // + template + inline SPROUT_CONSTEXPR IntType + gcd(IntType const& a, IntType const& b) { + return sprout::math::gcd_evaluator().operator()(a, b); + } + } // namespace math +} // namespace boost + +#endif // SPROUT_MATH_GCD_HPP diff --git a/sprout/math/lcm.hpp b/sprout/math/lcm.hpp new file mode 100644 index 00000000..16efdb11 --- /dev/null +++ b/sprout/math/lcm.hpp @@ -0,0 +1,101 @@ +#ifndef SPROUT_MATH_LCM_HPP +#define SPROUT_MATH_LCM_HPP + +#include +#include +#include +#include + +namespace sprout { + namespace math { + namespace detail { + template + inline SPROUT_CONSTEXPR RingType + lcm_euclidean_impl(RingType a, RingType b, RingType temp) { + return temp != static_cast(0) ? (a / temp * b) + : static_cast(0) + ; + } + template + inline SPROUT_CONSTEXPR RingType + lcm_euclidean(RingType a, RingType b) { + return sprout::math::detail::lcm_euclidean_impl( + a, b, sprout::math::detail::gcd_euclidean(a, b) + ); + } + + template + inline SPROUT_CONSTEXPR IntType + lcm_integer_impl(IntType result) { + return result < static_cast(0) ? -result : result; + } + template + inline SPROUT_CONSTEXPR IntType + lcm_integer(IntType const& a, IntType const& b) { + return sprout::math::detail::lcm_integer_impl( + sprout::math::detail::lcm_euclidean(a, b) + ); + } + + template + struct lcm_optimal_evaluator_helper_t { + public: + SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { + return sprout::math::detail::lcm_euclidean(a, b); + } + }; + template + struct lcm_optimal_evaluator_helper_t { + public: + SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { + return sprout::math::detail::lcm_integer(a, b); + } + }; + + template + struct lcm_optimal_evaluator { + public: + SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { + typedef std::numeric_limits limits_type; + typedef sprout::math::detail::lcm_optimal_evaluator_helper_t< + T, limits_type::is_specialized, limits_type::is_signed + > helper_type; + return helper_type().operator()(a, b); + } + }; + + template + inline SPROUT_CONSTEXPR T + lcm_optimal(T const& a, T const& b) { + return sprout::math::detail::lcm_optimal_evaluator().operator()(a, b); + } + } // namespace detail + + // + // lcm_evaluator + // + template + class lcm_evaluator { + public: + typedef IntType result_type; + typedef IntType first_argument_type; + typedef IntType second_argument_type; + public: + SPROUT_CONSTEXPR result_type + operator()(first_argument_type const& a, second_argument_type const& b) const { + return sprout::math::detail::lcm_optimal(a, b); + } + }; + + // + // lcm + // + template + inline SPROUT_CONSTEXPR IntType + lcm(IntType const& a, IntType const& b) { + return sprout::math::lcm_evaluator().operator()(a, b); + } + } // namespace math +} // namespace boost + +#endif // SPROUT_MATH_LCM_HPP diff --git a/sprout/rational.hpp b/sprout/rational.hpp new file mode 100644 index 00000000..df1da97c --- /dev/null +++ b/sprout/rational.hpp @@ -0,0 +1,725 @@ +#ifndef SPROUT_RATIONAL_HPP +#define SPROUT_RATIONAL_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + // + // bad_rational + // + class bad_rational + : public std::domain_error + { + public: + explicit bad_rational() + : std::domain_error("bad rational: zero denominator") + {} + }; + + template + class rational; + + namespace detail { + struct rational_private_constructor_tag {}; + + template + inline SPROUT_CONSTEXPR sprout::rational make_rational( + typename sprout::detail::call_traits::param_type n, + typename sprout::detail::call_traits::param_type d, + sprout::detail::rational_private_constructor_tag + ); + } // namespace detail + + namespace detail { + template + class rational_impl { + protected: + typedef IntType int_type; + typedef typename sprout::detail::call_traits::param_type param_type; + protected: + IntType num_; + IntType den_; + protected: + SPROUT_CONSTEXPR rational_impl() + : num_(0) + , den_(1) + {} + rational_impl(rational_impl const&) = default; + SPROUT_CONSTEXPR rational_impl(param_type n) + : num_(n) + , den_(1) + {} + SPROUT_CONSTEXPR rational_impl(param_type n, param_type d) + : num_(n) + , den_(d) + {} + SPROUT_CONSTEXPR rational_impl(param_type n, param_type d, param_type g) + : num_(n / g) + , den_(d / g) + {} + }; + } // namespace detail + + // + // rational + // + template + class rational + : private sprout::detail::rational_impl + { + static_assert(std::numeric_limits::is_specialized, "std::numeric_limits::is_specialized"); + public: + typedef IntType int_type; + typedef typename sprout::detail::call_traits::param_type param_type; + private: + struct private_constructor_tag {}; + typedef sprout::detail::rational_impl base_type; + private: + static SPROUT_CONSTEXPR IntType normalize_g_1(IntType den, IntType g) { + return den / g < 0 ? -g : g; + } + static SPROUT_CONSTEXPR IntType normalize_g(IntType num, IntType den) { + return den == 0 ? throw sprout::bad_rational() + : num == 0 ? den + : normalize_g_1(den, sprout::math::gcd(num, den)) + ; + } + private: + using base_type::num_; + using base_type::den_; + private: + SPROUT_CONSTEXPR rational(param_type n, param_type d, private_constructor_tag) + : base_type(n, d) + {} + public: + SPROUT_CONSTEXPR rational() + : base_type() + {} + rational(rational const&) = default; + SPROUT_CONSTEXPR rational(param_type n) + : base_type(n) + {} + SPROUT_CONSTEXPR rational(param_type n, param_type d) + : base_type(n, d, normalize_g(n, d)) + {} + + rational& operator=(rational const&) = default; + rational& operator=(param_type n) { + return assign(n, 1); + } + rational& assign(param_type n, param_type d) { + using std::swap; + rational temp(n, d); + swap(temp, *this); + return *this; + } + + SPROUT_CONSTEXPR IntType numerator() const { + return num_; + } + SPROUT_CONSTEXPR IntType denominator() const { + return den_; + } + + rational& operator+=(rational const& rhs) { + IntType g = sprout::math::gcd(den_, rhs.den_); + den_ /= g; + num_ = num_ * (rhs.den_ / g) + rhs.num_ * den_; + g = sprout::math::gcd(num_, g); + num_ /= g; + den_ *= rhs.den_ / g; + return *this; + } + rational& operator-=(rational const& rhs) { + IntType g = sprout::math::gcd(den_, rhs.den_); + den_ /= g; + num_ = num_ * (rhs.den_ / g) - rhs.num_ * den_; + g = sprout::math::gcd(num_, g); + num_ /= g; + den_ *= rhs.den_ / g; + return *this; + } + rational& operator*=(rational const& rhs) { + IntType gcd1 = sprout::math::gcd(num_, rhs.den_); + IntType gcd2 = sprout::math::gcd(rhs.num_, den_); + num_ =(num_ / gcd1) * (rhs.num_ / gcd2); + den_ =(den_ / gcd2) * (rhs.den_ / gcd1); + return *this; + } + rational& operator/=(rational const& rhs) { + if (rhs.num_ == IntType(0)) { + throw bad_rational(); + } + if (num_ == IntType(0)) { + return *this; + } + IntType gcd1 = sprout::math::gcd(num_, rhs.num_); + IntType gcd2 = sprout::math::gcd(rhs.den_, den_); + num_ =(num_ / gcd1) * (rhs.den_ / gcd2); + den_ =(den_ / gcd2) * (rhs.num_ / gcd1); + if (den_ < IntType(0)) { + num_ = -num_; + den_ = -den_; + } + return *this; + } + rational& operator+=(param_type rhs) { + return *this += rational(rhs); + } + rational& operator-=(param_type rhs) { + return *this -= rational(rhs); + } + rational& operator*=(param_type rhs) { + return *this *= rational(rhs); + } + rational& operator/=(param_type rhs) { + return *this /= rational(rhs); + } + + rational& operator++() { + num_ += den_; + return *this; + } + rational& operator--() { + num_ -= den_; + return *this; + } + rational operator++(int) { + rational result(*this); + ++*this; + return result; + } + rational operator--(int) { + rational result(*this); + --*this; + return result; + } + + SPROUT_CONSTEXPR bool operator!() const { + return !num_; + } + SPROUT_CONSTEXPR operator bool() const { + return num_ != 0; + } + + public: + friend sprout::rational sprout::detail::make_rational( + typename sprout::detail::call_traits::param_type n, + typename sprout::detail::call_traits::param_type d, + sprout::detail::rational_private_constructor_tag + ); + }; + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational make_rational( + typename sprout::detail::call_traits::param_type n, + typename sprout::detail::call_traits::param_type d, + sprout::detail::rational_private_constructor_tag + ) + { + return sprout::rational( + n, d, + typename sprout::rational::private_constructor_tag() + ); + } + } // namespace detail + + // + // operator+ + // operator- + // + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(rational const& r) { + return r; + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(rational const& r) { + return sprout::detail::make_rational( + -r.numerator(), r.denominator(), + sprout::detail::rational_private_constructor_tag() + ); + } + + // + // operator+ + // operator- + // operator* + // operator/ + // + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl_3( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return sprout::detail::make_rational( + num / g, den * (rhs.denominator() / g), + sprout::detail::rational_private_constructor_tag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl_2( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return rational_add_impl_3( + rhs, + sprout::math::gcd(num, g), den, num + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl_1( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g, IntType den + ) + { + return rational_add_impl_2( + rhs, + g, den, lhs.numerator() * (rhs.denominator() / g) + rhs.numerator() * den + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_add_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g + ) + { + return rational_add_impl_1( + lhs, rhs, + g, lhs.denominator() / g + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_add_impl( + lhs, rhs, + sprout::math::gcd(lhs.denominator(), rhs.denominator()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs + sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator+(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) + rhs; + } + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl_3( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return sprout::detail::make_rational( + num / g, den * (rhs.denominator() / g), + sprout::detail::rational_private_constructor_tag() + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl_2( + sprout::rational const& rhs, + IntType g, IntType den, IntType num + ) + { + return rational_sub_impl_3( + rhs, + sprout::math::gcd(num, g), den, num + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl_1( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g, IntType den + ) + { + return rational_sub_impl_2( + rhs, + g, den, lhs.numerator() * (rhs.denominator() / g) - rhs.numerator() * den + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_sub_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType g + ) + { + return rational_sub_impl_1( + lhs, rhs, + g, lhs.denominator() / g + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_sub_impl( + lhs, rhs, + sprout::math::gcd(lhs.denominator(), rhs.denominator()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs - sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator-(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) - rhs; + } + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_mul_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType gcd1, IntType gcd2 + ) + { + return sprout::detail::make_rational( + (lhs.numerator() / gcd1) * (rhs.numerator() / gcd2), + (lhs.denominator() / gcd2) * (rhs.denominator() / gcd1), + sprout::detail::rational_private_constructor_tag() + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator*(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_mul_impl( + lhs, rhs, + sprout::math::gcd(lhs.numerator(), rhs.denominator()), + sprout::math::gcd(rhs.numerator(), lhs.denominator()) + ); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator*(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs * sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator*(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) * rhs; + } + + namespace detail { + template + inline SPROUT_CONSTEXPR sprout::rational + rational_div_impl_1(IntType num, IntType den) { + return den < IntType(0) ? sprout::detail::make_rational( + -num, -den, + sprout::detail::rational_private_constructor_tag() + ) + : sprout::detail::make_rational( + num, den, + sprout::detail::rational_private_constructor_tag() + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::rational + rational_div_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType gcd1, IntType gcd2 + ) + { + return sprout::detail::rational_div_impl_1( + (lhs.numerator() / gcd1) * (rhs.denominator() / gcd2), + (lhs.denominator() / gcd2) * (rhs.numerator() / gcd1) + ); + } + } // namespace detail + template + inline SPROUT_CONSTEXPR sprout::rational + operator/(sprout::rational const& lhs, sprout::rational const& rhs) { + return rhs.numerator() == IntType(0) ? throw sprout::bad_rational() + : lhs.numerator() == IntType(0) ? lhs + : sprout::detail::rational_div_impl( + lhs, rhs, + sprout::math::gcd(lhs.numerator(), rhs.numerator()), + sprout::math::gcd(rhs.denominator(), lhs.denominator()) + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator/(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs / sprout::rational(rhs); + } + template + inline SPROUT_CONSTEXPR sprout::rational + operator/(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return sprout::rational(lhs) / rhs; + } + + // + // operator== + // operator!= + // + template + inline SPROUT_CONSTEXPR bool + operator==(sprout::rational const& lhs, sprout::rational const& rhs) { + return lhs.numerator() == rhs.numerator() && lhs.denominator() == rhs.denominator(); + } + template + inline SPROUT_CONSTEXPR bool + operator==(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return lhs.denominator() == IntType(1) && lhs.numerator() == rhs; + } + template + inline SPROUT_CONSTEXPR bool + operator==(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return rhs == lhs; + } + template + inline SPROUT_CONSTEXPR bool + operator!=(sprout::rational const& lhs, sprout::rational const& rhs) { + return !(lhs == rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator!=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return !(lhs == rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator!=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return !(lhs == rhs); + } + + // + // operator< + // operator> + // operator<= + // operator>= + // + namespace detail { + template + inline SPROUT_CONSTEXPR bool + rational_less_impl_2( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType d1, IntType q1, IntType r1, + IntType d2, IntType q2, IntType r2, + unsigned reverse = 0 + ) + { + return q1 != q2 ? reverse ? q1 > q2 : q1 < q2 + : r1 == IntType(0) || r2 == IntType(0) + ? r1 == r2 ? false + : (r1 != IntType(0)) != static_cast(reverse ^ 1) + : sprout::detail::rational_less_impl_2( + lhs, rhs, + r1, d1 / r1, d1 % r1, + r2, d2 / r2, d2 % r2, + reverse ^ 1 + ) + ; + } + template + inline SPROUT_CONSTEXPR bool + rational_less_impl_1( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType d1, IntType q1, IntType r1, + IntType d2, IntType q2, IntType r2 + ) + { + return r2 < IntType(0) ? sprout::detail::rational_less_impl_1( + lhs, rhs, + d1, q1, r1, + d2, q2 - 1, r2 + d2 + ) + : sprout::detail::rational_less_impl_2( + lhs, rhs, + d1, q1, r1, + d2, q2, r2 + ) + ; + } + template + inline SPROUT_CONSTEXPR bool + rational_less_impl( + sprout::rational const& lhs, sprout::rational const& rhs, + IntType d1, IntType q1, IntType r1 + ) + { + return r1 < IntType(0) ? sprout::detail::rational_less_impl( + lhs, rhs, + d1, q1 - 1, r1 + d1 + ) + : sprout::detail::rational_less_impl_1( + lhs, rhs, + d1, q1, r1, + rhs.denominator(), rhs.numerator() / rhs.denominator(), rhs.numerator() % rhs.denominator() + ) + ; + } + + template + inline SPROUT_CONSTEXPR bool + rational_less_impl( + sprout::rational const& lhs, typename sprout::rational::param_type rhs, + IntType q, IntType r + ) + { + return r < IntType(0) ? sprout::detail::rational_less_impl( + lhs, rhs, + r + lhs.denominator(), q - 1 + ) + : q < rhs + ; + } + } // namespace detail + template + inline SPROUT_CONSTEXPR bool + operator<(sprout::rational const& lhs, sprout::rational const& rhs) { + return sprout::detail::rational_less_impl( + lhs, rhs, + lhs.denominator(), lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator() + ); + } + template + inline SPROUT_CONSTEXPR bool + operator<(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return sprout::detail::rational_less_impl( + lhs, rhs, + lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator() + ); + } + template + inline SPROUT_CONSTEXPR bool + operator<(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return lhs != rhs && !(rhs < lhs); + } + + template + inline SPROUT_CONSTEXPR bool + operator>(sprout::rational const& lhs, sprout::rational const& rhs) { + return rhs < lhs; + } + template + inline SPROUT_CONSTEXPR bool + operator>(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return rhs < lhs; + } + template + inline SPROUT_CONSTEXPR bool + operator>(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return rhs < lhs; + } + + template + inline SPROUT_CONSTEXPR bool + operator<=(sprout::rational const& lhs, sprout::rational const& rhs) { + return !(rhs < lhs); + } + template + inline SPROUT_CONSTEXPR bool + operator<=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return !(rhs < lhs); + } + template + inline SPROUT_CONSTEXPR bool + operator<=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return !(rhs < lhs); + } + + template + inline SPROUT_CONSTEXPR bool + operator>=(sprout::rational const& lhs, sprout::rational const& rhs) { + return !(lhs < rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator>=(sprout::rational const& lhs, typename sprout::rational::param_type rhs) { + return !(lhs < rhs); + } + template + inline SPROUT_CONSTEXPR bool + operator>=(typename sprout::rational::param_type lhs, sprout::rational const& rhs) { + return !(lhs < rhs); + } + + // + // operator>> + // operator<< + // + template + inline std::basic_istream& + operator>>(std::basic_istream& lhs, sprout::rational& rhs) { + IntType n = IntType(0); + IntType d = IntType(1); + Elem c = 0; + sprout::detail::io::ios_flags_saver saver(lhs); + lhs >> n; + c = lhs.get(); + if (c != Elem('/')) { + lhs.clear(std::istream::badbit); + } + lhs >> std::noskipws; + lhs >> d; + if (lhs) { + rhs.assign(n, d); + } + return lhs; + } + template + inline std::basic_ostream& + operator<<(std::basic_ostream& lhs, sprout::rational const& rhs) { + return lhs << rhs.numerator() << Elem('/') << rhs.denominator(); + } + + // + // rational_cast + // + template + inline SPROUT_CONSTEXPR T + rational_cast(sprout::rational const& src) { + return static_cast(src.numerator()) / static_cast(src.denominator()); + } + + // + // abs + // + template + inline SPROUT_CONSTEXPR sprout::rational + abs(sprout::rational const& x) { + return x.numerator() >= IntType(0) ? x + : sprout::detail::make_rational( + -x.numerator(), x.denominator(), + sprout::detail::rational_private_constructor_tag() + ) + ; + } + +} // namespace sprout + +#endif // SPROUT_RATIONAL_HPP