/*============================================================================= Copyright (c) 2011-2017 Bolero MURAKAMI https://github.com/bolero-MURAKAMI/Sprout 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 SPROUT_RATIONAL_ARITHMETIC_HPP #define SPROUT_RATIONAL_ARITHMETIC_HPP #include #include #include #include namespace sprout { // // 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::rational_construct_access::raw_construct( -r.numerator(), r.denominator() ); } // // 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::rational_construct_access::raw_construct( num / g, den * (rhs.denominator() / g) ); } 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::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::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::rational_construct_access::raw_construct( num / g, den * (rhs.denominator() / g) ); } 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::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::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::rational_construct_access::raw_construct( (lhs.numerator() / gcd1) * (rhs.numerator() / gcd2), (lhs.denominator() / gcd2) * (rhs.denominator() / gcd1) ); } } // 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::gcd(lhs.numerator(), rhs.denominator()), sprout::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::rational_construct_access::raw_construct(-num, -den) : sprout::detail::rational_construct_access::raw_construct(num, den) ; } 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::gcd(lhs.numerator(), rhs.numerator()), sprout::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; } } // namespace sprout #endif // SPROUT_RATIONAL_ARITHMETIC_HPP