2012-05-25 13:21:16 +00:00
|
|
|
#ifndef SPROUT_MATH_LCM_HPP
|
|
|
|
#define SPROUT_MATH_LCM_HPP
|
|
|
|
|
|
|
|
#include <climits>
|
|
|
|
#include <sprout/config.hpp>
|
2013-08-06 15:15:09 +00:00
|
|
|
#include <sprout/limits.hpp>
|
2012-05-25 13:21:16 +00:00
|
|
|
#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 {
|
2013-08-06 15:15:09 +00:00
|
|
|
typedef sprout::numeric_limits<T> limits_type;
|
2012-05-25 13:21:16 +00:00
|
|
|
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);
|
|
|
|
}
|
2013-03-22 05:24:19 +00:00
|
|
|
} // namespace detail
|
2012-05-25 13:21:16 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// lcm_evaluator
|
|
|
|
//
|
2013-02-07 16:14:42 +00:00
|
|
|
template<typename IntType = void>
|
2012-05-25 13:21:16 +00:00
|
|
|
class lcm_evaluator {
|
|
|
|
public:
|
|
|
|
typedef IntType result_type;
|
|
|
|
typedef IntType first_argument_type;
|
|
|
|
typedef IntType second_argument_type;
|
|
|
|
public:
|
2013-02-07 16:14:42 +00:00
|
|
|
SPROUT_CONSTEXPR IntType
|
|
|
|
operator()(IntType const& a, IntType const& b) const {
|
|
|
|
return sprout::math::detail::lcm_optimal(a, b);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
template<>
|
|
|
|
class lcm_evaluator<void> {
|
|
|
|
public:
|
|
|
|
template<typename IntType>
|
|
|
|
SPROUT_CONSTEXPR IntType
|
|
|
|
operator()(IntType const& a, IntType const& b) const {
|
2012-05-25 13:21:16 +00:00
|
|
|
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);
|
|
|
|
}
|
2013-03-22 05:24:19 +00:00
|
|
|
} // namespace math
|
2013-04-23 10:03:03 +00:00
|
|
|
|
|
|
|
using sprout::math::lcm;
|
|
|
|
} // namespace sprout
|
2012-05-25 13:21:16 +00:00
|
|
|
|
2013-03-22 05:24:19 +00:00
|
|
|
#endif // #ifndef SPROUT_MATH_LCM_HPP
|