Sprout/sprout/rational/arithmetic.hpp

256 lines
8.3 KiB
C++
Raw Normal View History

2013-08-08 09:54:33 +00:00
/*=============================================================================
2015-01-10 10:13:57 +00:00
Copyright (c) 2011-2015 Bolero MURAKAMI
2013-08-08 09:54:33 +00:00
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)
=============================================================================*/
2012-08-28 16:16:12 +00:00
#ifndef SPROUT_RATIONAL_ARITHMETIC_HPP
#define SPROUT_RATIONAL_ARITHMETIC_HPP
#include <sprout/config.hpp>
#include <sprout/rational/rational.hpp>
#include <sprout/rational/exceptions.hpp>
#include <sprout/math/gcd.hpp>
namespace sprout {
//
// operator+
// operator-
//
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator+(rational<IntType> const& r) {
return r;
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator-(rational<IntType> const& r) {
2013-08-09 13:14:43 +00:00
return sprout::detail::rational_construct_access<IntType>::raw_construct(
-r.numerator(), r.denominator()
2012-08-28 16:16:12 +00:00
);
}
//
// operator+
// operator-
// operator*
// operator/
//
namespace detail {
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_add_impl_3(
sprout::rational<IntType> const& rhs,
IntType g, IntType den, IntType num
)
{
2013-08-09 13:14:43 +00:00
return sprout::detail::rational_construct_access<IntType>::raw_construct(
num / g, den * (rhs.denominator() / g)
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_add_impl_2(
sprout::rational<IntType> const& rhs,
IntType g, IntType den, IntType num
)
{
return rational_add_impl_3(
rhs,
2013-04-23 10:03:03 +00:00
sprout::gcd(num, g), den, num
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_add_impl_1(
sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs,
IntType g, IntType den
)
{
return rational_add_impl_2(
rhs,
g, den, lhs.numerator() * (rhs.denominator() / g) + rhs.numerator() * den
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_add_impl(
sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs,
IntType g
)
{
return rational_add_impl_1(
lhs, rhs,
g, lhs.denominator() / g
);
}
} // namespace detail
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator+(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
return sprout::detail::rational_add_impl(
lhs, rhs,
2013-04-23 10:03:03 +00:00
sprout::gcd(lhs.denominator(), rhs.denominator())
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator+(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
return lhs + sprout::rational<IntType>(rhs);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator+(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
return sprout::rational<IntType>(lhs) + rhs;
}
namespace detail {
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_sub_impl_3(
sprout::rational<IntType> const& rhs,
IntType g, IntType den, IntType num
)
{
2013-08-09 13:14:43 +00:00
return sprout::detail::rational_construct_access<IntType>::raw_construct(
num / g, den * (rhs.denominator() / g)
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_sub_impl_2(
sprout::rational<IntType> const& rhs,
IntType g, IntType den, IntType num
)
{
return rational_sub_impl_3(
rhs,
2013-04-23 10:03:03 +00:00
sprout::gcd(num, g), den, num
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_sub_impl_1(
sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs,
IntType g, IntType den
)
{
return rational_sub_impl_2(
rhs,
g, den, lhs.numerator() * (rhs.denominator() / g) - rhs.numerator() * den
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_sub_impl(
sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs,
IntType g
)
{
return rational_sub_impl_1(
lhs, rhs,
g, lhs.denominator() / g
);
}
} // namespace detail
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator-(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
return sprout::detail::rational_sub_impl(
lhs, rhs,
2013-04-23 10:03:03 +00:00
sprout::gcd(lhs.denominator(), rhs.denominator())
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator-(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
return lhs - sprout::rational<IntType>(rhs);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator-(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
return sprout::rational<IntType>(lhs) - rhs;
}
namespace detail {
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_mul_impl(
sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs,
IntType gcd1, IntType gcd2
)
{
2013-08-09 13:14:43 +00:00
return sprout::detail::rational_construct_access<IntType>::raw_construct(
2012-08-28 16:16:12 +00:00
(lhs.numerator() / gcd1) * (rhs.numerator() / gcd2),
2013-08-09 13:14:43 +00:00
(lhs.denominator() / gcd2) * (rhs.denominator() / gcd1)
2012-08-28 16:16:12 +00:00
);
}
} // namespace detail
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator*(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
return sprout::detail::rational_mul_impl(
lhs, rhs,
2013-04-23 10:03:03 +00:00
sprout::gcd(lhs.numerator(), rhs.denominator()),
sprout::gcd(rhs.numerator(), lhs.denominator())
2012-08-28 16:16:12 +00:00
);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator*(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
return lhs * sprout::rational<IntType>(rhs);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator*(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
return sprout::rational<IntType>(lhs) * rhs;
}
namespace detail {
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_div_impl_1(IntType num, IntType den) {
2013-08-09 13:14:43 +00:00
return den < IntType(0) ? sprout::detail::rational_construct_access<IntType>::raw_construct(-num, -den)
: sprout::detail::rational_construct_access<IntType>::raw_construct(num, den)
2012-08-28 16:16:12 +00:00
;
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
rational_div_impl(
sprout::rational<IntType> const& lhs, sprout::rational<IntType> 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<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator/(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
return rhs.numerator() == IntType(0) ? throw sprout::bad_rational()
: lhs.numerator() == IntType(0) ? lhs
: sprout::detail::rational_div_impl(
lhs, rhs,
2013-04-23 10:03:03 +00:00
sprout::gcd(lhs.numerator(), rhs.numerator()),
sprout::gcd(rhs.denominator(), lhs.denominator())
2012-08-28 16:16:12 +00:00
)
;
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator/(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
return lhs / sprout::rational<IntType>(rhs);
}
template<typename IntType>
inline SPROUT_CONSTEXPR sprout::rational<IntType>
operator/(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
return sprout::rational<IntType>(lhs) / rhs;
}
2013-03-22 05:24:19 +00:00
} // namespace sprout
2012-08-28 16:16:12 +00:00
#endif // SPROUT_RATIONAL_ARITHMETIC_HPP