mirror of
https://github.com/boostorg/math.git
synced 2026-01-19 04:22:09 +00:00
Switch to using Boost.Integer gcd/lcm.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// Boost common_factor_ct.hpp header file ----------------------------------//
|
||||
|
||||
// (C) Copyright Daryle Walker and Stephen Cleary 2001-2002.
|
||||
// (C) Copyright John Maddock 2017.
|
||||
// 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)
|
||||
@@ -10,85 +10,16 @@
|
||||
#ifndef BOOST_MATH_COMMON_FACTOR_CT_HPP
|
||||
#define BOOST_MATH_COMMON_FACTOR_CT_HPP
|
||||
|
||||
#include <boost/math_fwd.hpp> // self include
|
||||
#include <boost/config.hpp> // for BOOST_STATIC_CONSTANT, etc.
|
||||
#include <boost/mpl/integral_c.hpp>
|
||||
#include <boost/integer/common_factor_ct.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
// Implementation details --------------------------------------------------//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Build GCD with Euclid's recursive algorithm
|
||||
template < static_gcd_type Value1, static_gcd_type Value2 >
|
||||
struct static_gcd_helper_t
|
||||
{
|
||||
private:
|
||||
BOOST_STATIC_CONSTANT( static_gcd_type, new_value1 = Value2 );
|
||||
BOOST_STATIC_CONSTANT( static_gcd_type, new_value2 = Value1 % Value2 );
|
||||
|
||||
#ifndef __BORLANDC__
|
||||
#define BOOST_DETAIL_GCD_HELPER_VAL(Value) static_cast<static_gcd_type>(Value)
|
||||
#else
|
||||
typedef static_gcd_helper_t self_type;
|
||||
#define BOOST_DETAIL_GCD_HELPER_VAL(Value) (self_type:: Value )
|
||||
#endif
|
||||
|
||||
typedef static_gcd_helper_t< BOOST_DETAIL_GCD_HELPER_VAL(new_value1),
|
||||
BOOST_DETAIL_GCD_HELPER_VAL(new_value2) > next_step_type;
|
||||
|
||||
#undef BOOST_DETAIL_GCD_HELPER_VAL
|
||||
|
||||
public:
|
||||
BOOST_STATIC_CONSTANT( static_gcd_type, value = next_step_type::value );
|
||||
};
|
||||
|
||||
// Non-recursive case
|
||||
template < static_gcd_type Value1 >
|
||||
struct static_gcd_helper_t< Value1, 0UL >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT( static_gcd_type, value = Value1 );
|
||||
};
|
||||
|
||||
// Build the LCM from the GCD
|
||||
template < static_gcd_type Value1, static_gcd_type Value2 >
|
||||
struct static_lcm_helper_t
|
||||
{
|
||||
typedef static_gcd_helper_t<Value1, Value2> gcd_type;
|
||||
|
||||
BOOST_STATIC_CONSTANT( static_gcd_type, value = Value1 / gcd_type::value
|
||||
* Value2 );
|
||||
};
|
||||
|
||||
// Special case for zero-GCD values
|
||||
template < >
|
||||
struct static_lcm_helper_t< 0UL, 0UL >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT( static_gcd_type, value = 0UL );
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
// Compile-time greatest common divisor evaluator class declaration --------//
|
||||
|
||||
template < static_gcd_type Value1, static_gcd_type Value2 >
|
||||
struct static_gcd : public mpl::integral_c<static_gcd_type, (detail::static_gcd_helper_t<Value1, Value2>::value) >
|
||||
{
|
||||
}; // boost::math::static_gcd
|
||||
|
||||
|
||||
// Compile-time least common multiple evaluator class declaration ----------//
|
||||
|
||||
template < static_gcd_type Value1, static_gcd_type Value2 >
|
||||
struct static_lcm : public mpl::integral_c<static_gcd_type, (detail::static_lcm_helper_t<Value1, Value2>::value) >
|
||||
{
|
||||
}; // boost::math::static_lcm
|
||||
|
||||
using boost::integer::static_gcd;
|
||||
using boost::integer::static_lcm;
|
||||
using boost::integer::static_gcd_type;
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// (C) Copyright Jeremy William Murphy 2016.
|
||||
// (C) Copyright John Maddock 2017.
|
||||
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
@@ -7,538 +7,19 @@
|
||||
#ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP
|
||||
#define BOOST_MATH_COMMON_FACTOR_RT_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
|
||||
#include <boost/config.hpp> // for BOOST_NESTED_TEMPLATE, etc.
|
||||
#include <boost/limits.hpp> // for std::numeric_limits
|
||||
#include <climits> // for CHAR_MIN
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127 4244) // Conditional expression is constant
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) && !defined(BOOST_NO_CXX11_NOEXCEPT)
|
||||
#define BOOST_GCD_NOEXCEPT(T) noexcept(std::is_arithmetic<T>::value)
|
||||
#else
|
||||
#define BOOST_GCD_NOEXCEPT(T)
|
||||
#endif
|
||||
#include <boost/integer/common_factor_rt.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <class I>
|
||||
class rational;
|
||||
|
||||
namespace math {
|
||||
|
||||
namespace gcd_detail{
|
||||
using boost::integer::gcd;
|
||||
using boost::integer::lcm;
|
||||
using boost::integer::gcd_range;
|
||||
using boost::integer::lcm_range;
|
||||
using boost::integer::gcd_evaluator;
|
||||
using boost::integer::lcm_evaluator;
|
||||
|
||||
//
|
||||
// some helper functions which really should be constexpr already, but sadly aren't:
|
||||
//
|
||||
#ifndef BOOST_NO_CXX14_CONSTEXPR
|
||||
template <class T>
|
||||
inline constexpr T constexpr_min(T const& a, T const& b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
template <class T>
|
||||
inline constexpr auto constexpr_swap(T&a, T& b) BOOST_GCD_NOEXCEPT(T) -> decltype(a.swap(b))
|
||||
{
|
||||
return a.swap(b);
|
||||
}
|
||||
template <class T, class U>
|
||||
inline constexpr void constexpr_swap(T&a, U& b...) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
T t(static_cast<T&&>(a));
|
||||
a = static_cast<T&&>(b);
|
||||
b = static_cast<T&&>(t);
|
||||
}
|
||||
#else
|
||||
template <class T>
|
||||
inline T constexpr_min(T const& a, T const& b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
template <class T>
|
||||
inline void constexpr_swap(T&a, T& b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T, bool a =
|
||||
#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS
|
||||
std::is_unsigned<T>::value ||
|
||||
#endif
|
||||
(std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_signed)>
|
||||
struct gcd_traits_abs_defaults
|
||||
{
|
||||
inline static BOOST_CXX14_CONSTEXPR const T& abs(const T& val) BOOST_GCD_NOEXCEPT(T) { return val; }
|
||||
};
|
||||
template <class T>
|
||||
struct gcd_traits_abs_defaults<T, false>
|
||||
{
|
||||
inline static T BOOST_CXX14_CONSTEXPR abs(const T& val) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
// This sucks, but std::abs is not constexpr :(
|
||||
return val < 0 ? -val : val;
|
||||
}
|
||||
};
|
||||
|
||||
enum method_type
|
||||
{
|
||||
method_euclid = 0,
|
||||
method_binary = 1,
|
||||
method_mixed = 2,
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
struct gcd_traits_defaults : public gcd_traits_abs_defaults<T>
|
||||
{
|
||||
BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(T& val) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
unsigned r = 0;
|
||||
while(0 == (val & 1u))
|
||||
{
|
||||
#ifdef _MSC_VER // VC++ can't handle operator >>= in constexpr code for some reason
|
||||
val = val >> 1;
|
||||
#else
|
||||
val >>= 1;
|
||||
#endif
|
||||
++r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
inline static BOOST_CXX14_CONSTEXPR bool less(const T& a, const T& b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
return a < b;
|
||||
}
|
||||
static const method_type method = std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer ? method_mixed : method_euclid;
|
||||
};
|
||||
//
|
||||
// Default gcd_traits just inherits from defaults:
|
||||
//
|
||||
template <class T>
|
||||
struct gcd_traits : public gcd_traits_defaults<T> {};
|
||||
|
||||
#ifdef BOOST_NO_CXX14_CONSTEXPR
|
||||
//
|
||||
// Some platforms have fast bitscan operations, that allow us to implement
|
||||
// make_odd much more efficiently, unfortunately we can't use these if we want
|
||||
// the functions to be constexpr as the compiler intrinsics aren't constexpr.
|
||||
//
|
||||
#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#pragma intrinsic(_BitScanForward,)
|
||||
template <>
|
||||
struct gcd_traits<unsigned long> : public gcd_traits_defaults<unsigned long>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned find_lsb(unsigned long val) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanForward(&result, val);
|
||||
return result;
|
||||
}
|
||||
BOOST_FORCEINLINE static unsigned make_odd(unsigned long& val) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned result = find_lsb(val);
|
||||
val >>= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef _M_X64
|
||||
#pragma intrinsic(_BitScanForward64)
|
||||
template <>
|
||||
struct gcd_traits<unsigned __int64> : public gcd_traits_defaults<unsigned __int64>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned find_lsb(unsigned __int64 mask) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned long result;
|
||||
_BitScanForward64(&result, mask);
|
||||
return result;
|
||||
}
|
||||
BOOST_FORCEINLINE static unsigned make_odd(unsigned __int64& val) BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned result = find_lsb(val);
|
||||
val >>= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
//
|
||||
// Other integer type are trivial adaptations of the above,
|
||||
// this works for signed types too, as by the time these functions
|
||||
// are called, all values are > 0.
|
||||
//
|
||||
template <> struct gcd_traits<long> : public gcd_traits_defaults<long>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(long& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<unsigned int> : public gcd_traits_defaults<unsigned int>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(unsigned int& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<int> : public gcd_traits_defaults<int>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(int& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<unsigned short> : public gcd_traits_defaults<unsigned short>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(unsigned short& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<short> : public gcd_traits_defaults<short>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(short& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<unsigned char> : public gcd_traits_defaults<unsigned char>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(unsigned char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<signed char> : public gcd_traits_defaults<signed char>
|
||||
{ BOOST_FORCEINLINE static signed make_odd(signed char& val)BOOST_NOEXCEPT{ signed result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
template <> struct gcd_traits<char> : public gcd_traits_defaults<char>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
|
||||
template <> struct gcd_traits<wchar_t> : public gcd_traits_defaults<wchar_t>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
|
||||
#endif
|
||||
#ifdef _M_X64
|
||||
template <> struct gcd_traits<__int64> : public gcd_traits_defaults<__int64>
|
||||
{ BOOST_FORCEINLINE static unsigned make_odd(__int64& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits<unsigned __int64>::find_lsb(val); val >>= result; return result; } };
|
||||
#endif
|
||||
|
||||
#elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
|
||||
|
||||
template <>
|
||||
struct gcd_traits<unsigned> : public gcd_traits_defaults<unsigned>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned find_lsb(unsigned mask)BOOST_NOEXCEPT
|
||||
{
|
||||
return __builtin_ctz(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE static unsigned make_odd(unsigned& val)BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned result = find_lsb(val);
|
||||
val >>= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct gcd_traits<unsigned long> : public gcd_traits_defaults<unsigned long>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned find_lsb(unsigned long mask)BOOST_NOEXCEPT
|
||||
{
|
||||
return __builtin_ctzl(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE static unsigned make_odd(unsigned long& val)BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned result = find_lsb(val);
|
||||
val >>= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct gcd_traits<boost::ulong_long_type> : public gcd_traits_defaults<boost::ulong_long_type>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned find_lsb(boost::ulong_long_type mask)BOOST_NOEXCEPT
|
||||
{
|
||||
return __builtin_ctzll(mask);
|
||||
}
|
||||
BOOST_FORCEINLINE static unsigned make_odd(boost::ulong_long_type& val)BOOST_NOEXCEPT
|
||||
{
|
||||
unsigned result = find_lsb(val);
|
||||
val >>= result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
//
|
||||
// Other integer type are trivial adaptations of the above,
|
||||
// this works for signed types too, as by the time these functions
|
||||
// are called, all values are > 0.
|
||||
//
|
||||
template <> struct gcd_traits<boost::long_long_type> : public gcd_traits_defaults<boost::long_long_type>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(boost::long_long_type& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<boost::ulong_long_type>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<long> : public gcd_traits_defaults<long>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(long& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<int> : public gcd_traits_defaults<int>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(int& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<unsigned short> : public gcd_traits_defaults<unsigned short>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(unsigned short& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<short> : public gcd_traits_defaults<short>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(short& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<unsigned char> : public gcd_traits_defaults<unsigned char>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(unsigned char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<signed char> : public gcd_traits_defaults<signed char>
|
||||
{
|
||||
BOOST_FORCEINLINE static signed make_odd(signed char& val)BOOST_NOEXCEPT { signed result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
template <> struct gcd_traits<char> : public gcd_traits_defaults<char>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
|
||||
template <> struct gcd_traits<wchar_t> : public gcd_traits_defaults<wchar_t>
|
||||
{
|
||||
BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
#endif // BOOST_NO_CXX14_CONSTEXPR
|
||||
//
|
||||
// The Mixed Binary Euclid Algorithm
|
||||
// Sidi Mohamed Sedjelmaci
|
||||
// Electronic Notes in Discrete Mathematics 35 (2009) 169-176
|
||||
//
|
||||
template <class T>
|
||||
BOOST_CXX14_CONSTEXPR T mixed_binary_gcd(T u, T v) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
if(gcd_traits<T>::less(u, v))
|
||||
constexpr_swap(u, v);
|
||||
|
||||
unsigned shifts = 0;
|
||||
|
||||
if(!u)
|
||||
return v;
|
||||
if(!v)
|
||||
return u;
|
||||
|
||||
shifts = constexpr_min(gcd_traits<T>::make_odd(u), gcd_traits<T>::make_odd(v));
|
||||
|
||||
while(gcd_traits<T>::less(1, v))
|
||||
{
|
||||
u %= v;
|
||||
v -= u;
|
||||
if(!u)
|
||||
return v << shifts;
|
||||
if(!v)
|
||||
return u << shifts;
|
||||
gcd_traits<T>::make_odd(u);
|
||||
gcd_traits<T>::make_odd(v);
|
||||
if(gcd_traits<T>::less(u, v))
|
||||
constexpr_swap(u, v);
|
||||
}
|
||||
return (v == 1 ? v : u) << shifts;
|
||||
}
|
||||
|
||||
/** Stein gcd (aka 'binary gcd')
|
||||
*
|
||||
* From Mathematics to Generic Programming, Alexander Stepanov, Daniel Rose
|
||||
*/
|
||||
template <typename SteinDomain>
|
||||
BOOST_CXX14_CONSTEXPR SteinDomain Stein_gcd(SteinDomain m, SteinDomain n) BOOST_GCD_NOEXCEPT(SteinDomain)
|
||||
{
|
||||
BOOST_ASSERT(m >= 0);
|
||||
BOOST_ASSERT(n >= 0);
|
||||
if (m == SteinDomain(0))
|
||||
return n;
|
||||
if (n == SteinDomain(0))
|
||||
return m;
|
||||
// m > 0 && n > 0
|
||||
int d_m = gcd_traits<SteinDomain>::make_odd(m);
|
||||
int d_n = gcd_traits<SteinDomain>::make_odd(n);
|
||||
// odd(m) && odd(n)
|
||||
while (m != n)
|
||||
{
|
||||
if (n > m)
|
||||
constexpr_swap(n, m);
|
||||
m -= n;
|
||||
gcd_traits<SteinDomain>::make_odd(m);
|
||||
}
|
||||
// m == n
|
||||
m <<= constexpr_min(d_m, d_n);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
/** Euclidean algorithm
|
||||
*
|
||||
* From Mathematics to Generic Programming, Alexander Stepanov, Daniel Rose
|
||||
*
|
||||
*/
|
||||
template <typename EuclideanDomain>
|
||||
inline BOOST_CXX14_CONSTEXPR EuclideanDomain Euclid_gcd(EuclideanDomain a, EuclideanDomain b) BOOST_GCD_NOEXCEPT(EuclideanDomain)
|
||||
{
|
||||
while (b != EuclideanDomain(0))
|
||||
{
|
||||
a %= b;
|
||||
constexpr_swap(a, b);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == method_mixed, T>::type
|
||||
optimal_gcd_select(T const &a, T const &b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
return gcd_detail::mixed_binary_gcd(a, b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == method_binary, T>::type
|
||||
optimal_gcd_select(T const &a, T const &b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
return gcd_detail::Stein_gcd(a, b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == method_euclid, T>::type
|
||||
optimal_gcd_select(T const &a, T const &b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
return gcd_detail::Euclid_gcd(a, b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline BOOST_CXX14_CONSTEXPR T lcm_imp(const T& a, const T& b) BOOST_GCD_NOEXCEPT(T)
|
||||
{
|
||||
T temp = boost::math::gcd_detail::optimal_gcd_select(a, b);
|
||||
#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40500)
|
||||
return (temp != T(0)) ? T(a / temp * b) : T(0);
|
||||
#else
|
||||
return temp ? T(a / temp * b) : T(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
template <typename Integer>
|
||||
inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer)
|
||||
{
|
||||
return gcd_detail::optimal_gcd_select(static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(b)));
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer)
|
||||
{
|
||||
return gcd_detail::lcm_imp(static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_detail::gcd_traits<Integer>::abs(b)));
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
template <typename Integer, typename... Args>
|
||||
inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b, Args const&... args) BOOST_GCD_NOEXCEPT(Integer)
|
||||
{
|
||||
Integer t = gcd(b, args...);
|
||||
return t == 1 ? 1 : gcd(a, t);
|
||||
}
|
||||
|
||||
template <typename Integer, typename... Args>
|
||||
inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b, Args const&... args) BOOST_GCD_NOEXCEPT(Integer)
|
||||
{
|
||||
return lcm(a, lcm(b, args...));
|
||||
}
|
||||
#endif
|
||||
//
|
||||
// Special handling for rationals:
|
||||
//
|
||||
template <typename Integer>
|
||||
inline typename boost::enable_if_c<std::numeric_limits<Integer>::is_specialized, boost::rational<Integer> >::type gcd(boost::rational<Integer> const &a, boost::rational<Integer> const &b)
|
||||
{
|
||||
return boost::rational<Integer>(static_cast<Integer>(gcd(a.numerator(), b.numerator())), static_cast<Integer>(lcm(a.denominator(), b.denominator())));
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
inline typename boost::enable_if_c<std::numeric_limits<Integer>::is_specialized, boost::rational<Integer> >::type lcm(boost::rational<Integer> const &a, boost::rational<Integer> const &b)
|
||||
{
|
||||
return boost::rational<Integer>(static_cast<Integer>(lcm(a.numerator(), b.numerator())), static_cast<Integer>(gcd(a.denominator(), b.denominator())));
|
||||
}
|
||||
/**
|
||||
* Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
|
||||
* Chapter 4.5.2, Algorithm C: Greatest common divisor of n integers.
|
||||
*
|
||||
* Knuth counts down from n to zero but we naturally go from first to last.
|
||||
* We also return the termination position because it might be useful to know.
|
||||
*
|
||||
* Partly by quirk, partly by design, this algorithm is defined for n = 1,
|
||||
* because the gcd of {x} is x. It is not defined for n = 0.
|
||||
*
|
||||
* @tparam I Input iterator.
|
||||
* @return The gcd of the range and the iterator position at termination.
|
||||
*/
|
||||
template <typename I>
|
||||
std::pair<typename std::iterator_traits<I>::value_type, I>
|
||||
gcd_range(I first, I last) BOOST_GCD_NOEXCEPT(I)
|
||||
{
|
||||
BOOST_ASSERT(first != last);
|
||||
typedef typename std::iterator_traits<I>::value_type T;
|
||||
|
||||
T d = *first++;
|
||||
while (d != T(1) && first != last)
|
||||
{
|
||||
d = gcd(d, *first);
|
||||
first++;
|
||||
}
|
||||
return std::make_pair(d, first);
|
||||
}
|
||||
template <typename I>
|
||||
std::pair<typename std::iterator_traits<I>::value_type, I>
|
||||
lcm_range(I first, I last) BOOST_GCD_NOEXCEPT(I)
|
||||
{
|
||||
BOOST_ASSERT(first != last);
|
||||
typedef typename std::iterator_traits<I>::value_type T;
|
||||
|
||||
T d = *first++;
|
||||
while (d != T(1) && first != last)
|
||||
{
|
||||
d = lcm(d, *first);
|
||||
first++;
|
||||
}
|
||||
return std::make_pair(d, first);
|
||||
}
|
||||
|
||||
template < typename IntegerType >
|
||||
struct gcd_evaluator
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
: public std::binary_function<IntegerType, IntegerType, IntegerType>
|
||||
#endif
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef IntegerType first_argument_type;
|
||||
typedef IntegerType second_argument_type;
|
||||
typedef IntegerType result_type;
|
||||
#endif
|
||||
IntegerType operator()(IntegerType const &a, IntegerType const &b)const
|
||||
{
|
||||
return boost::math::gcd(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template < typename IntegerType >
|
||||
struct lcm_evaluator
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
: public std::binary_function<IntegerType, IntegerType, IntegerType>
|
||||
#endif
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef IntegerType first_argument_type;
|
||||
typedef IntegerType second_argument_type;
|
||||
typedef IntegerType result_type;
|
||||
#endif
|
||||
IntegerType operator()(IntegerType const &a, IntegerType const &b)const
|
||||
{
|
||||
return boost::math::lcm(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MATH_COMMON_FACTOR_RT_HPP
|
||||
|
||||
@@ -386,24 +386,6 @@ BOOST_AUTO_TEST_CASE( gcd_static_test )
|
||||
BOOST_CHECK( (static_gcd< 7, 49>::value) == 7 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(gcd_method_test)
|
||||
{
|
||||
// Verify that the 3 different methods all yield the same result:
|
||||
boost::random::mt19937 gen;
|
||||
boost::random::uniform_int_distribution<int> d(0, ((std::numeric_limits<int>::max)() / 2));
|
||||
|
||||
for (unsigned int i = 0; i < 10000; ++i)
|
||||
{
|
||||
int v1 = d(gen);
|
||||
int v2 = d(gen);
|
||||
int g = boost::math::gcd_detail::Euclid_gcd(v1, v2);
|
||||
BOOST_CHECK(v1 % g == 0);
|
||||
BOOST_CHECK(v2 % g == 0);
|
||||
BOOST_CHECK_EQUAL(g, boost::math::gcd_detail::mixed_binary_gcd(v1, v2));
|
||||
BOOST_CHECK_EQUAL(g, boost::math::gcd_detail::Stein_gcd(v1, v2));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
|
||||
@@ -557,90 +539,3 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(gcd_and_lcm_on_rationals, T, signed_test_types)
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
//
|
||||
// Compile time checks come last:
|
||||
//
|
||||
#ifndef BOOST_NO_CXX14_CONSTEXPR
|
||||
|
||||
void test_constexpr1()
|
||||
{
|
||||
constexpr const boost::int64_t i = 347 * 463 * 727;
|
||||
constexpr const boost::int64_t j = 191 * 347 * 281;
|
||||
|
||||
constexpr const boost::int64_t k = boost::math::gcd(i, j);
|
||||
constexpr const boost::int64_t l = boost::math::lcm(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not found in constexpr gcd.");
|
||||
static_assert(l == 6268802158037, "Expected result not found in constexpr lcm.");
|
||||
}
|
||||
|
||||
void test_constexpr2()
|
||||
{
|
||||
constexpr const boost::uint64_t i = 347 * 463 * 727;
|
||||
constexpr const boost::uint64_t j = 191 * 347 * 281;
|
||||
|
||||
constexpr const boost::uint64_t k = boost::math::gcd(i, j);
|
||||
constexpr const boost::uint64_t l = boost::math::lcm(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not found in constexpr gcd.");
|
||||
static_assert(l == 6268802158037, "Expected result not found in constexpr lcm.");
|
||||
}
|
||||
|
||||
void test_constexpr3()
|
||||
{
|
||||
constexpr const boost::uint64_t i = 347 * 463 * 727;
|
||||
constexpr const boost::uint64_t j = 191 * 347 * 281;
|
||||
|
||||
constexpr const boost::uint64_t k = boost::math::gcd_detail::Euclid_gcd(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not found in constexpr gcd.");
|
||||
}
|
||||
|
||||
void test_constexpr4()
|
||||
{
|
||||
constexpr const boost::uint64_t i = 347 * 463 * 727;
|
||||
constexpr const boost::uint64_t j = 191 * 347 * 281;
|
||||
|
||||
constexpr const boost::uint64_t k = boost::math::gcd_detail::mixed_binary_gcd(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not found in constexpr gcd.");
|
||||
}
|
||||
|
||||
void test_constexpr5()
|
||||
{
|
||||
constexpr const boost::uint64_t i = 347 * 463 * 727;
|
||||
constexpr const boost::uint64_t j = 191 * 347 * 281;
|
||||
|
||||
constexpr const boost::uint64_t k = boost::math::gcd_detail::Stein_gcd(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not found in constexpr gcd.");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
//
|
||||
// These tests don't pass with GCC-4.x:
|
||||
//
|
||||
#if !defined(BOOST_GCC) || (BOOST_GCC >= 50000)
|
||||
|
||||
void test_noexcept(unsigned char a, unsigned char b)
|
||||
{
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<unsigned char>(a), static_cast<unsigned char>(b))), "Expected a noexcept function.");
|
||||
#ifndef _MSC_VER
|
||||
// This generates an internal compiler error if enabled as well as the following test:
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<char>(a), static_cast<char>(b))), "Expected a noexcept function.");
|
||||
#endif
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<signed char>(a), static_cast<signed char>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<short>(a), static_cast<short>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<unsigned short>(a), static_cast<unsigned short>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<int>(a), static_cast<int>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<unsigned int>(a), static_cast<unsigned int>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<long>(a), static_cast<long>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<unsigned long>(a), static_cast<unsigned long>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<long long>(a), static_cast<long long>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::math::gcd(static_cast<unsigned long long>(a), static_cast<unsigned long long>(b))), "Expected a noexcept function.");
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
using namespace boost::math;
|
||||
using namespace boost::math::tools;
|
||||
using namespace std;
|
||||
using boost::math::gcd_detail::Euclid_gcd;
|
||||
using boost::integer::gcd_detail::Euclid_gcd;
|
||||
using boost::math::tools::subresultant_gcd;
|
||||
|
||||
template <typename T>
|
||||
|
||||
Reference in New Issue
Block a user