/*============================================================================= Copyright (c) 2011-2019 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_MATH_GCD_HPP #define SPROUT_MATH_GCD_HPP #include #include #include #include #include #ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE # include #endif namespace sprout { namespace math { namespace detail { template inline SPROUT_CONSTEXPR RingType gcd_euclidean(RingType a, RingType b) { return a == static_cast(0) ? b : b % a == static_cast(0) ? a : sprout::math::detail::gcd_euclidean(a % (b % a), b % a) ; } template inline SPROUT_CONSTEXPR IntType gcd_integer_impl(IntType result) { return result < static_cast(0) ? -result : result; } template 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) ); } #ifdef SPROUT_WORKAROUND_NOT_TERMINATE_RECURSIVE_CONSTEXPR_FUNCTION_TEMPLATE template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_2(unsigned shifts, sprout::array const& r, unsigned which) { return r[which] ? sprout::math::detail::gcd_binary_2_1(shifts, r, which) : r[!which] << shifts ; } template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_2(unsigned, sprout::array const&, unsigned) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which) { return !(r[which] & 1u) ? sprout::math::detail::gcd_binary_2_1( shifts, which ? sprout::array{{r[0], BuiltInUnsigned(r[1] >> 1)}} : sprout::array{{BuiltInUnsigned(r[0] >> 1), r[1]}} , which ) : r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_2( shifts, which ^ 1u ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} , which ^ 1u ) : sprout::math::detail::gcd_binary_2_2( shifts, which ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} , which ) ; } template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned, sprout::array const&, unsigned) { return sprout::throw_recursive_function_template_instantiation_exeeded(); } #else template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which); template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_2(unsigned shifts, sprout::array const& r, unsigned which) { return r[which] ? sprout::math::detail::gcd_binary_2_1(shifts, r, which) : r[!which] << shifts ; } template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary_2_1(unsigned shifts, sprout::array const& r, unsigned which) { return !(r[which] & 1u) ? sprout::math::detail::gcd_binary_2_1( shifts, which ? sprout::array{{r[0], BuiltInUnsigned(r[1] >> 1)}} : sprout::array{{BuiltInUnsigned(r[0] >> 1), r[1]}} , which ) : r[!which] > r[which] ? sprout::math::detail::gcd_binary_2_2( shifts, which ^ 1u ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} , which ^ 1u ) : sprout::math::detail::gcd_binary_2_2( shifts, which ? sprout::array{{r[0], BuiltInUnsigned(r[1] - r[0])}} : sprout::array{{BuiltInUnsigned(r[0] - r[1]), r[1]}} , which ) ; } #endif template 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_1( shifts, sprout::array{{u, v}}, static_cast(u & 1u) ) ; } template inline SPROUT_CONSTEXPR BuiltInUnsigned gcd_binary(BuiltInUnsigned u, BuiltInUnsigned v) { return u && v ? sprout::math::detail::gcd_binary_1(u, v) : u + v ; } template 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 struct gcd_optimal_evaluator_helper_t { public: SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { return sprout::math::detail::gcd_integer(a, b); } }; template struct gcd_optimal_evaluator { public: SPROUT_CONSTEXPR T operator()(T const& a, T const& b) const { typedef sprout::numeric_limits 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 { \ 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 { \ public: \ SPROUT_CONSTEXPR St operator()(St a, St b) const { \ using sprout::abs; \ return static_cast(sprout::math::detail::gcd_optimal_evaluator().operator()( \ static_cast(abs(a)), static_cast(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 inline SPROUT_CONSTEXPR T gcd_optimal(T const& a, T const& b) { return sprout::math::detail::gcd_optimal_evaluator().operator()(a, b); } } // namespace detail // // gcd_evaluator // template class gcd_evaluator { public: typedef IntType result_type; typedef IntType first_argument_type; typedef IntType second_argument_type; public: SPROUT_CONSTEXPR IntType operator()(IntType const& a, IntType const& b) const { return sprout::math::detail::gcd_optimal(a, b); } }; template<> class gcd_evaluator { public: template SPROUT_CONSTEXPR IntType operator()(IntType const& a, IntType const& b) const { return sprout::math::detail::gcd_optimal(a, b); } }; // // gcd // template inline SPROUT_CONSTEXPR IntType gcd(IntType const& a, IntType const& b) { return sprout::math::gcd_evaluator().operator()(a, b); } } // namespace math using sprout::math::gcd; } // namespace sprout #endif // #ifndef SPROUT_MATH_GCD_HPP