Sprout/sprout/rational/rational.hpp

222 lines
6.4 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_RATIONAL_HPP
#define SPROUT_RATIONAL_RATIONAL_HPP
#include <utility>
#include <sprout/config.hpp>
2013-08-06 15:15:09 +00:00
#include <sprout/limits.hpp>
2012-08-28 16:16:12 +00:00
#include <sprout/rational/exceptions.hpp>
#include <sprout/math/gcd.hpp>
2012-10-05 15:58:56 +00:00
#include <sprout/utility/swap.hpp>
2012-08-28 16:16:12 +00:00
#include <sprout/detail/call_traits.hpp>
namespace sprout {
template<typename IntType>
class rational;
namespace detail {
2013-08-09 13:14:43 +00:00
struct rational_private_construct_t {};
2012-08-28 16:16:12 +00:00
template<typename IntType>
2013-08-09 13:14:43 +00:00
class rational_construct_access;
2012-08-28 16:16:12 +00:00
} // namespace detail
namespace detail {
template<typename IntType>
class rational_impl {
protected:
typedef IntType int_type;
typedef typename sprout::detail::call_traits<IntType>::param_type param_type;
protected:
IntType num_;
IntType den_;
protected:
SPROUT_CONSTEXPR rational_impl()
2013-02-26 01:43:27 +00:00
: num_(0), den_(1)
2012-08-28 16:16:12 +00:00
{}
rational_impl(rational_impl const&) = default;
SPROUT_CONSTEXPR rational_impl(param_type n)
2013-02-26 01:43:27 +00:00
: num_(n), den_(1)
2012-08-28 16:16:12 +00:00
{}
SPROUT_CONSTEXPR rational_impl(param_type n, param_type d)
2013-02-26 01:43:27 +00:00
: num_(n), den_(d)
2012-08-28 16:16:12 +00:00
{}
SPROUT_CONSTEXPR rational_impl(param_type n, param_type d, param_type g)
2013-02-26 01:43:27 +00:00
: num_(n / g), den_(d / g)
2012-08-28 16:16:12 +00:00
{}
};
} // namespace detail
//
// rational
//
template<typename IntType>
class rational
: private sprout::detail::rational_impl<IntType>
{
2013-08-06 15:15:09 +00:00
static_assert(sprout::numeric_limits<IntType>::is_specialized, "sprout::numeric_limits<IntType>::is_specialized");
2013-08-09 13:14:43 +00:00
friend class sprout::detail::rational_construct_access<IntType>;
2012-08-28 16:16:12 +00:00
public:
typedef IntType int_type;
typedef typename sprout::detail::call_traits<IntType>::param_type param_type;
private:
typedef sprout::detail::rational_impl<IntType> 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
2013-04-23 10:03:03 +00:00
: normalize_g_1(den, sprout::gcd(num, den))
2012-08-28 16:16:12 +00:00
;
}
private:
using base_type::num_;
using base_type::den_;
private:
2013-08-09 13:14:43 +00:00
SPROUT_CONSTEXPR rational(sprout::detail::rational_private_construct_t, param_type n, param_type d)
2012-08-28 16:16:12 +00:00
: base_type(n, d)
{}
public:
2012-11-18 14:32:36 +00:00
SPROUT_CONSTEXPR rational() SPROUT_NOEXCEPT
2012-08-28 16:16:12 +00:00
: base_type()
{}
rational(rational const&) = default;
2012-11-18 14:32:36 +00:00
SPROUT_CONSTEXPR rational(param_type n) SPROUT_NOEXCEPT
2012-08-28 16:16:12 +00:00
: base_type(n)
{}
SPROUT_CONSTEXPR rational(param_type n, param_type d)
: base_type(n, d, normalize_g(n, d))
{}
SPROUT_CXX14_CONSTEXPR rational& operator=(rational const& rhs) SPROUT_NOEXCEPT {
rational temp(rhs);
sprout::swap(temp, *this);
return *this;
}
SPROUT_CXX14_CONSTEXPR rational& operator=(param_type n) SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
return assign(n, 1);
}
SPROUT_CXX14_CONSTEXPR rational& assign(param_type n, param_type d) {
2012-08-28 16:16:12 +00:00
rational temp(n, d);
2012-10-05 15:58:56 +00:00
sprout::swap(temp, *this);
2012-08-28 16:16:12 +00:00
return *this;
}
2012-11-18 14:32:36 +00:00
SPROUT_CONSTEXPR IntType numerator() const SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
return num_;
}
2012-11-18 14:32:36 +00:00
SPROUT_CONSTEXPR IntType denominator() const SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
return den_;
}
SPROUT_CXX14_CONSTEXPR rational& operator+=(rational const& rhs) {
2013-04-23 10:03:03 +00:00
IntType g = sprout::gcd(den_, rhs.den_);
2012-08-28 16:16:12 +00:00
den_ /= g;
num_ = num_ * (rhs.den_ / g) + rhs.num_ * den_;
2013-04-23 10:03:03 +00:00
g = sprout::gcd(num_, g);
2012-08-28 16:16:12 +00:00
num_ /= g;
den_ *= rhs.den_ / g;
return *this;
}
SPROUT_CXX14_CONSTEXPR rational& operator-=(rational const& rhs) {
2013-04-23 10:03:03 +00:00
IntType g = sprout::gcd(den_, rhs.den_);
2012-08-28 16:16:12 +00:00
den_ /= g;
num_ = num_ * (rhs.den_ / g) - rhs.num_ * den_;
2013-04-23 10:03:03 +00:00
g = sprout::gcd(num_, g);
2012-08-28 16:16:12 +00:00
num_ /= g;
den_ *= rhs.den_ / g;
return *this;
}
SPROUT_CXX14_CONSTEXPR rational& operator*=(rational const& rhs) {
2013-04-23 10:03:03 +00:00
IntType gcd1 = sprout::gcd(num_, rhs.den_);
IntType gcd2 = sprout::gcd(rhs.num_, den_);
2012-08-28 16:16:12 +00:00
num_ =(num_ / gcd1) * (rhs.num_ / gcd2);
den_ =(den_ / gcd2) * (rhs.den_ / gcd1);
return *this;
}
SPROUT_CXX14_CONSTEXPR rational& operator/=(rational const& rhs) {
2012-08-28 16:16:12 +00:00
if (rhs.num_ == IntType(0)) {
2013-03-18 10:12:21 +00:00
throw sprout::bad_rational();
2012-08-28 16:16:12 +00:00
}
if (num_ == IntType(0)) {
return *this;
}
2013-04-23 10:03:03 +00:00
IntType gcd1 = sprout::gcd(num_, rhs.num_);
IntType gcd2 = sprout::gcd(rhs.den_, den_);
2012-08-28 16:16:12 +00:00
num_ =(num_ / gcd1) * (rhs.den_ / gcd2);
den_ =(den_ / gcd2) * (rhs.num_ / gcd1);
if (den_ < IntType(0)) {
num_ = -num_;
den_ = -den_;
}
return *this;
}
SPROUT_CXX14_CONSTEXPR rational& operator+=(param_type rhs) {
2012-08-28 16:16:12 +00:00
return *this += rational(rhs);
}
SPROUT_CXX14_CONSTEXPR rational& operator-=(param_type rhs) {
2012-08-28 16:16:12 +00:00
return *this -= rational(rhs);
}
SPROUT_CXX14_CONSTEXPR rational& operator*=(param_type rhs) {
2012-08-28 16:16:12 +00:00
return *this *= rational(rhs);
}
SPROUT_CXX14_CONSTEXPR rational& operator/=(param_type rhs) {
2012-08-28 16:16:12 +00:00
return *this /= rational(rhs);
}
SPROUT_CXX14_CONSTEXPR rational& operator++() SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
num_ += den_;
return *this;
}
SPROUT_CXX14_CONSTEXPR rational& operator--() SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
num_ -= den_;
return *this;
}
SPROUT_CXX14_CONSTEXPR rational operator++(int) SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
rational result(*this);
++*this;
return result;
}
SPROUT_CXX14_CONSTEXPR rational operator--(int) SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
rational result(*this);
--*this;
return result;
}
2012-11-18 14:32:36 +00:00
SPROUT_CONSTEXPR bool operator!() const SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
return !num_;
}
2012-11-18 14:32:36 +00:00
SPROUT_CONSTEXPR operator bool() const SPROUT_NOEXCEPT {
2012-08-28 16:16:12 +00:00
return num_ != 0;
}
};
namespace detail {
template<typename IntType>
2013-08-09 13:14:43 +00:00
class rational_construct_access {
public:
static SPROUT_CONSTEXPR sprout::rational<IntType>
raw_construct(
typename sprout::detail::call_traits<IntType>::param_type n,
typename sprout::detail::call_traits<IntType>::param_type d
)
{
return sprout::rational<IntType>(
sprout::detail::rational_private_construct_t(),
n, d
);
}
};
2012-08-28 16:16:12 +00:00
} // namespace detail
2013-03-22 05:24:19 +00:00
} // namespace sprout
2012-08-28 16:16:12 +00:00
#endif // SPROUT_RATIONAL_RATIONAL_HPP