mirror of
https://github.com/bolero-MURAKAMI/Sprout.git
synced 2024-12-23 21:25:49 +00:00
add sprout/rational.hpp
add sprout/math/common_factor.hpp
This commit is contained in:
parent
dc8cb3d14e
commit
5a9b2e4f7d
8 changed files with 1153 additions and 119 deletions
|
@ -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
|
||||
// <http://www.boost.org/LICENSE_1_0.txt>
|
||||
//
|
||||
#include <sprout/string.hpp>
|
||||
|
||||
//
|
||||
// C style string to Sprout.String
|
||||
//
|
||||
int
|
||||
main(){
|
||||
|
||||
constexpr char const* c_str = "homu";
|
||||
|
||||
//
|
||||
// String length is required
|
||||
//
|
||||
constexpr auto length = sprout::char_traits<char>::length(c_str);
|
||||
static_assert(length == 4, "");
|
||||
|
||||
//
|
||||
// To Sprout.String
|
||||
//
|
||||
constexpr auto str = sprout::string_from_c_str<length>( c_str );
|
||||
static_assert(std::is_same<sprout::string<4> const, decltype(str)>{}, "");
|
||||
static_assert(str == "homu", "");
|
||||
|
||||
constexpr auto str2 = sprout::string_from_c_str<length>( c_str, 2 );
|
||||
static_assert(std::is_same<sprout::string<4> 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
|
||||
// <http://www.boost.org/LICENSE_1_0.txt>
|
||||
//
|
||||
#include <sprout/string.hpp>
|
||||
|
||||
//
|
||||
// C style string to Sprout.String
|
||||
//
|
||||
int
|
||||
main(){
|
||||
|
||||
constexpr char const* c_str = "homu";
|
||||
|
||||
//
|
||||
// String length is required
|
||||
//
|
||||
constexpr auto length = sprout::char_traits<char>::length(c_str);
|
||||
static_assert(length == 4, "");
|
||||
|
||||
//
|
||||
// To Sprout.String
|
||||
//
|
||||
constexpr auto str = sprout::string_from_c_str<length>( c_str );
|
||||
static_assert(std::is_same<sprout::string<4> const, decltype(str)>{}, "");
|
||||
static_assert(str == "homu", "");
|
||||
|
||||
constexpr auto str2 = sprout::string_from_c_str<length>( c_str, 2 );
|
||||
static_assert(std::is_same<sprout::string<4> const, decltype(str2)>{}, "");
|
||||
static_assert(str2 == "ho", "");
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// <http://www.boost.org/LICENSE_1_0.txt>
|
||||
//
|
||||
#include <sprout/weed.hpp>
|
||||
|
||||
|
||||
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>, 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
|
||||
// <http://www.boost.org/LICENSE_1_0.txt>
|
||||
//
|
||||
#include <sprout/weed.hpp>
|
||||
|
||||
|
||||
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>, sprout::string<4>> const,
|
||||
decltype(attr)
|
||||
>::value, "");
|
||||
static_assert(sprout::get<0>(attr) == "homu", "");
|
||||
static_assert(sprout::get<1>(attr) == "mado", "");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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<std::is_same<T, std::intmax_t>::value>::type = sprout::enabler
|
||||
>
|
||||
SPROUT_CONSTEXPR T abs(T j) {
|
||||
return sprout::imaxabs(j);
|
||||
}
|
||||
} // namespace sprout
|
||||
|
||||
#endif // #ifndef SPROUT_CINTTYPES_ABS_HPP
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#ifndef SPROUT_CSTDLIB_ABS_HPP
|
||||
#define SPROUT_CSTDLIB_ABS_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <sprout/config.hpp>
|
||||
#include <sprout/utility/enabler_if.hpp>
|
||||
|
||||
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<IntType>::value && std::is_signed<IntType>::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<IntType>::value && std::is_unsigned<IntType>::value
|
||||
>::type = sprout::enabler
|
||||
>
|
||||
SPROUT_CONSTEXPR IntType abs(IntType j) {
|
||||
return j;
|
||||
}
|
||||
} // namespace sprout
|
||||
|
||||
#endif // #ifndef SPROUT_CSTDLIB_ABS_HPP
|
||||
|
|
7
sprout/math/common_factor.hpp
Normal file
7
sprout/math/common_factor.hpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef SPROUT_MATH_COMMON_FACTOR_HPP
|
||||
#define SPROUT_MATH_COMMON_FACTOR_HPP
|
||||
|
||||
#include <sprout/math/gcd.hpp>
|
||||
#include <sprout/math/lcm.hpp>
|
||||
|
||||
#endif // SPROUT_MATH_COMMON_FACTOR_HPP
|
188
sprout/math/gcd.hpp
Normal file
188
sprout/math/gcd.hpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
#ifndef SPROUT_MATH_GCD_HPP
|
||||
#define SPROUT_MATH_GCD_HPP
|
||||
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <sprout/config.hpp>
|
||||
#include <sprout/array.hpp>
|
||||
#include <sprout/cstdlib/abs.hpp>
|
||||
|
||||
namespace sprout {
|
||||
namespace math {
|
||||
namespace detail {
|
||||
template<typename RingType>
|
||||
inline SPROUT_CONSTEXPR RingType
|
||||
gcd_euclidean(RingType a, RingType b) {
|
||||
return a == static_cast<RingType>(0) ? b
|
||||
: b % a == static_cast<RingType>(0) ? a
|
||||
: sprout::math::detail::gcd_euclidean(a % (b % a), b % a)
|
||||
;
|
||||
}
|
||||
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR IntType
|
||||
gcd_integer_impl(IntType result) {
|
||||
return result < static_cast<IntType>(0) ? -result : result;
|
||||
}
|
||||
template<typename IntType>
|
||||
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<typename BuiltInUnsigned>
|
||||
inline SPROUT_CONSTEXPR BuiltInUnsigned
|
||||
gcd_binary_2_1(unsigned shifts, sprout::array<BuiltInUnsigned, 2> const& r, unsigned which);
|
||||
template<typename BuiltInUnsigned>
|
||||
inline SPROUT_CONSTEXPR BuiltInUnsigned
|
||||
gcd_binary_2_2(unsigned shifts, sprout::array<BuiltInUnsigned, 2> const& r, unsigned which) {
|
||||
return !(r[ which ] & 1u) ? sprout::math::detail::gcd_binary_2_2(
|
||||
shifts,
|
||||
which ? sprout::array<BuiltInUnsigned, 2>{{r[0], BuiltInUnsigned(r[1] >> 1)}}
|
||||
: sprout::array<BuiltInUnsigned, 2>{{BuiltInUnsigned(r[0] >> 1), r[1]}}
|
||||
,
|
||||
which
|
||||
)
|
||||
: r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_1(
|
||||
shifts,
|
||||
which ^ 1u ? sprout::array<BuiltInUnsigned, 2>{{r[0], BuiltInUnsigned(r[1] - r[0])}}
|
||||
: sprout::array<BuiltInUnsigned, 2>{{BuiltInUnsigned(r[0] - r[1]), r[1]}}
|
||||
,
|
||||
which ^ 1u
|
||||
)
|
||||
: sprout::math::detail::gcd_binary_2_1(
|
||||
shifts,
|
||||
which ? sprout::array<BuiltInUnsigned, 2>{{r[0], BuiltInUnsigned(r[1] - r[0])}}
|
||||
: sprout::array<BuiltInUnsigned, 2>{{BuiltInUnsigned(r[0] - r[1]), r[1]}}
|
||||
,
|
||||
which
|
||||
)
|
||||
;
|
||||
}
|
||||
template<typename BuiltInUnsigned>
|
||||
inline SPROUT_CONSTEXPR BuiltInUnsigned
|
||||
gcd_binary_2_1(unsigned shifts, sprout::array<BuiltInUnsigned, 2> const& r, unsigned which) {
|
||||
return r[which] ? sprout::math::detail::gcd_binary_2_2(shifts, r, which)
|
||||
: r[!which] << shifts
|
||||
;
|
||||
}
|
||||
template<typename BuiltInUnsigned>
|
||||
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<BuiltInUnsigned, 2>{{u, v}}, static_cast<bool>(u & 1u)
|
||||
)
|
||||
;
|
||||
}
|
||||
template<typename BuiltInUnsigned>
|
||||
inline SPROUT_CONSTEXPR BuiltInUnsigned
|
||||
gcd_binary(BuiltInUnsigned u, BuiltInUnsigned v) {
|
||||
return u && v ? sprout::math::detail::gcd_binary_1(u, v)
|
||||
: u + v
|
||||
;
|
||||
}
|
||||
|
||||
template<typename T, bool IsSpecialized, bool IsSigned>
|
||||
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<typename T>
|
||||
struct gcd_optimal_evaluator_helper_t<T, true, true> {
|
||||
public:
|
||||
SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const {
|
||||
return sprout::math::detail::gcd_integer(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct gcd_optimal_evaluator {
|
||||
public:
|
||||
SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const {
|
||||
typedef std::numeric_limits<T> 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<Ut> { \
|
||||
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<St> { \
|
||||
public: \
|
||||
SPROUT_CONSTEXPR St operator()(St a, St b) const { \
|
||||
using sprout::abs; \
|
||||
return static_cast<St>(sprout::math::detail::gcd_optimal_evaluator<Ut>().operator()( \
|
||||
static_cast<Ut>(abs(a)), static_cast<Ut>(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<typename T>
|
||||
inline SPROUT_CONSTEXPR T
|
||||
gcd_optimal(T const& a, T const& b) {
|
||||
return sprout::math::detail::gcd_optimal_evaluator<T>().operator()(a, b);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
//
|
||||
// gcd_evaluator
|
||||
//
|
||||
template<typename IntType>
|
||||
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<typename IntType>
|
||||
inline SPROUT_CONSTEXPR IntType
|
||||
gcd(IntType const& a, IntType const& b) {
|
||||
return sprout::math::gcd_evaluator<IntType>().operator()(a, b);
|
||||
}
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // SPROUT_MATH_GCD_HPP
|
101
sprout/math/lcm.hpp
Normal file
101
sprout/math/lcm.hpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
#ifndef SPROUT_MATH_LCM_HPP
|
||||
#define SPROUT_MATH_LCM_HPP
|
||||
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include <sprout/config.hpp>
|
||||
#include <sprout/math/gcd.hpp>
|
||||
|
||||
namespace sprout {
|
||||
namespace math {
|
||||
namespace detail {
|
||||
template<typename RingType>
|
||||
inline SPROUT_CONSTEXPR RingType
|
||||
lcm_euclidean_impl(RingType a, RingType b, RingType temp) {
|
||||
return temp != static_cast<RingType>(0) ? (a / temp * b)
|
||||
: static_cast<RingType>(0)
|
||||
;
|
||||
}
|
||||
template<typename RingType>
|
||||
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<typename IntType>
|
||||
inline SPROUT_CONSTEXPR IntType
|
||||
lcm_integer_impl(IntType result) {
|
||||
return result < static_cast<IntType>(0) ? -result : result;
|
||||
}
|
||||
template<typename IntType>
|
||||
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<typename T, bool IsSpecialized, bool IsSigned>
|
||||
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<typename T>
|
||||
struct lcm_optimal_evaluator_helper_t<T, true, true> {
|
||||
public:
|
||||
SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const {
|
||||
return sprout::math::detail::lcm_integer(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct lcm_optimal_evaluator {
|
||||
public:
|
||||
SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const {
|
||||
typedef std::numeric_limits<T> 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<typename T>
|
||||
inline SPROUT_CONSTEXPR T
|
||||
lcm_optimal(T const& a, T const& b) {
|
||||
return sprout::math::detail::lcm_optimal_evaluator<T>().operator()(a, b);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
//
|
||||
// lcm_evaluator
|
||||
//
|
||||
template<typename IntType>
|
||||
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<typename IntType>
|
||||
inline SPROUT_CONSTEXPR IntType
|
||||
lcm(IntType const& a, IntType const& b) {
|
||||
return sprout::math::lcm_evaluator<IntType>().operator()(a, b);
|
||||
}
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // SPROUT_MATH_LCM_HPP
|
725
sprout/rational.hpp
Normal file
725
sprout/rational.hpp
Normal file
|
@ -0,0 +1,725 @@
|
|||
#ifndef SPROUT_RATIONAL_HPP
|
||||
#define SPROUT_RATIONAL_HPP
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <sprout/config.hpp>
|
||||
#include <sprout/cstdlib/abs.hpp>
|
||||
#include <sprout/math/gcd.hpp>
|
||||
#include <sprout/detail/call_traits.hpp>
|
||||
#include <sprout/detail/io/ios_state.hpp>
|
||||
|
||||
namespace sprout {
|
||||
//
|
||||
// bad_rational
|
||||
//
|
||||
class bad_rational
|
||||
: public std::domain_error
|
||||
{
|
||||
public:
|
||||
explicit bad_rational()
|
||||
: std::domain_error("bad rational: zero denominator")
|
||||
{}
|
||||
};
|
||||
|
||||
template<typename IntType>
|
||||
class rational;
|
||||
|
||||
namespace detail {
|
||||
struct rational_private_constructor_tag {};
|
||||
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR sprout::rational<IntType> make_rational(
|
||||
typename sprout::detail::call_traits<IntType>::param_type n,
|
||||
typename sprout::detail::call_traits<IntType>::param_type d,
|
||||
sprout::detail::rational_private_constructor_tag
|
||||
);
|
||||
} // 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()
|
||||
: 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<typename IntType>
|
||||
class rational
|
||||
: private sprout::detail::rational_impl<IntType>
|
||||
{
|
||||
static_assert(std::numeric_limits<IntType>::is_specialized, "std::numeric_limits<IntType>::is_specialized");
|
||||
public:
|
||||
typedef IntType int_type;
|
||||
typedef typename sprout::detail::call_traits<IntType>::param_type param_type;
|
||||
private:
|
||||
struct private_constructor_tag {};
|
||||
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
|
||||
: 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<IntType> sprout::detail::make_rational<IntType>(
|
||||
typename sprout::detail::call_traits<IntType>::param_type n,
|
||||
typename sprout::detail::call_traits<IntType>::param_type d,
|
||||
sprout::detail::rational_private_constructor_tag
|
||||
);
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR sprout::rational<IntType> make_rational(
|
||||
typename sprout::detail::call_traits<IntType>::param_type n,
|
||||
typename sprout::detail::call_traits<IntType>::param_type d,
|
||||
sprout::detail::rational_private_constructor_tag
|
||||
)
|
||||
{
|
||||
return sprout::rational<IntType>(
|
||||
n, d,
|
||||
typename sprout::rational<IntType>::private_constructor_tag()
|
||||
);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
//
|
||||
// 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) {
|
||||
return sprout::detail::make_rational<IntType>(
|
||||
-r.numerator(), r.denominator(),
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
)
|
||||
{
|
||||
return sprout::detail::make_rational<IntType>(
|
||||
num / g, den * (rhs.denominator() / g),
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
);
|
||||
}
|
||||
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,
|
||||
sprout::math::gcd(num, g), den, num
|
||||
);
|
||||
}
|
||||
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,
|
||||
sprout::math::gcd(lhs.denominator(), rhs.denominator())
|
||||
);
|
||||
}
|
||||
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
|
||||
)
|
||||
{
|
||||
return sprout::detail::make_rational<IntType>(
|
||||
num / g, den * (rhs.denominator() / g),
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
);
|
||||
}
|
||||
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,
|
||||
sprout::math::gcd(num, g), den, num
|
||||
);
|
||||
}
|
||||
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,
|
||||
sprout::math::gcd(lhs.denominator(), rhs.denominator())
|
||||
);
|
||||
}
|
||||
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
|
||||
)
|
||||
{
|
||||
return sprout::detail::make_rational<IntType>(
|
||||
(lhs.numerator() / gcd1) * (rhs.numerator() / gcd2),
|
||||
(lhs.denominator() / gcd2) * (rhs.denominator() / gcd1),
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
);
|
||||
}
|
||||
} // 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,
|
||||
sprout::math::gcd(lhs.numerator(), rhs.denominator()),
|
||||
sprout::math::gcd(rhs.numerator(), lhs.denominator())
|
||||
);
|
||||
}
|
||||
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) {
|
||||
return den < IntType(0) ? sprout::detail::make_rational<IntType>(
|
||||
-num, -den,
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
)
|
||||
: sprout::detail::make_rational<IntType>(
|
||||
num, den,
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
)
|
||||
;
|
||||
}
|
||||
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,
|
||||
sprout::math::gcd(lhs.numerator(), rhs.numerator()),
|
||||
sprout::math::gcd(rhs.denominator(), lhs.denominator())
|
||||
)
|
||||
;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// operator==
|
||||
// operator!=
|
||||
//
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator==(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return lhs.numerator() == rhs.numerator() && lhs.denominator() == rhs.denominator();
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator==(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
|
||||
return lhs.denominator() == IntType(1) && lhs.numerator() == rhs;
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator==(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
|
||||
return rhs == lhs;
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator!=(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator!=(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator!=(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
//
|
||||
// operator<
|
||||
// operator>
|
||||
// operator<=
|
||||
// operator>=
|
||||
//
|
||||
namespace detail {
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
rational_less_impl_2(
|
||||
sprout::rational<IntType> const& lhs, sprout::rational<IntType> 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<bool>(reverse ^ 1)
|
||||
: sprout::detail::rational_less_impl_2(
|
||||
lhs, rhs,
|
||||
r1, d1 / r1, d1 % r1,
|
||||
r2, d2 / r2, d2 % r2,
|
||||
reverse ^ 1
|
||||
)
|
||||
;
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
rational_less_impl_1(
|
||||
sprout::rational<IntType> const& lhs, sprout::rational<IntType> 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<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
rational_less_impl(
|
||||
sprout::rational<IntType> const& lhs, sprout::rational<IntType> 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<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
rational_less_impl(
|
||||
sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::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<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator<(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return sprout::detail::rational_less_impl(
|
||||
lhs, rhs,
|
||||
lhs.denominator(), lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator()
|
||||
);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator<(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
|
||||
return sprout::detail::rational_less_impl(
|
||||
lhs, rhs,
|
||||
lhs.numerator() / lhs.denominator(), lhs.numerator() % lhs.denominator()
|
||||
);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator<(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
|
||||
return lhs != rhs && !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator>(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator>(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator>(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator<=(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator<=(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator<=(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator>=(sprout::rational<IntType> const& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator>=(sprout::rational<IntType> const& lhs, typename sprout::rational<IntType>::param_type rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR bool
|
||||
operator>=(typename sprout::rational<IntType>::param_type lhs, sprout::rational<IntType> const& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
//
|
||||
// operator>>
|
||||
// operator<<
|
||||
//
|
||||
template<typename Elem, typename Traits, typename IntType>
|
||||
inline std::basic_istream<Elem, Traits>&
|
||||
operator>>(std::basic_istream<Elem, Traits>& lhs, sprout::rational<IntType>& 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<typename Elem, typename Traits, typename IntType>
|
||||
inline std::basic_ostream<Elem, Traits>&
|
||||
operator<<(std::basic_ostream<Elem, Traits>& lhs, sprout::rational<IntType> const& rhs) {
|
||||
return lhs << rhs.numerator() << Elem('/') << rhs.denominator();
|
||||
}
|
||||
|
||||
//
|
||||
// rational_cast
|
||||
//
|
||||
template<typename T, typename IntType>
|
||||
inline SPROUT_CONSTEXPR T
|
||||
rational_cast(sprout::rational<IntType> const& src) {
|
||||
return static_cast<T>(src.numerator()) / static_cast<T>(src.denominator());
|
||||
}
|
||||
|
||||
//
|
||||
// abs
|
||||
//
|
||||
template<typename IntType>
|
||||
inline SPROUT_CONSTEXPR sprout::rational<IntType>
|
||||
abs(sprout::rational<IntType> const& x) {
|
||||
return x.numerator() >= IntType(0) ? x
|
||||
: sprout::detail::make_rational<IntType>(
|
||||
-x.numerator(), x.denominator(),
|
||||
sprout::detail::rational_private_constructor_tag()
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace sprout
|
||||
|
||||
#endif // SPROUT_RATIONAL_HPP
|
Loading…
Reference in a new issue