js8call/.svn/pristine/61/61c26fbe377109081ecf0288ef29dce48ce3cc36.svn-base

429 lines
16 KiB
Plaintext
Raw Normal View History

2018-02-08 21:28:33 -05:00
// (C) Copyright Jeremy William Murphy 2016.
// Use, modification and distribution are subject to 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 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/mpl/and.hpp>
#include <boost/type_traits.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>
#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
namespace boost {
namespace math {
template <class T, bool a = is_unsigned<T>::value || (std::numeric_limits<T>::is_specialized && !std::numeric_limits<T>::is_signed)>
struct gcd_traits_abs_defaults
{
inline static const T& abs(const T& val) { return val; }
};
template <class T>
struct gcd_traits_abs_defaults<T, false>
{
inline static T abs(const T& val)
{
using std::abs;
return abs(val);
}
};
template <class T>
struct gcd_traits_defaults : public gcd_traits_abs_defaults<T>
{
BOOST_FORCEINLINE static unsigned make_odd(T& val)
{
unsigned r = 0;
while(!(val & 1u))
{
val >>= 1;
++r;
}
return r;
}
inline static bool less(const T& a, const T& b)
{
return a < b;
}
enum method_type
{
method_euclid = 0,
method_binary = 1,
method_mixed = 2,
};
static const method_type method =
boost::has_right_shift_assign<T>::value && boost::has_left_shift_assign<T>::value && boost::has_less<T>::value && boost::has_modulus<T>::value
? method_mixed :
boost::has_right_shift_assign<T>::value && boost::has_left_shift_assign<T>::value && boost::has_less<T>::value
? method_binary : method_euclid;
};
//
// Default gcd_traits just inherits from defaults:
//
template <class T>
struct gcd_traits : public gcd_traits_defaults<T> {};
//
// Special handling for polynomials:
//
namespace tools {
template <class T>
class polynomial;
}
template <class T>
struct gcd_traits<boost::math::tools::polynomial<T> > : public gcd_traits_defaults<T>
{
static const boost::math::tools::polynomial<T>& abs(const boost::math::tools::polynomial<T>& val) { return val; }
};
//
// Some platforms have fast bitscan operations, that allow us to implement
// make_odd much more efficiently:
//
#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)
{
unsigned long result;
_BitScanForward(&result, val);
return result;
}
BOOST_FORCEINLINE static unsigned make_odd(unsigned long& val)
{
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)
{
unsigned long result;
_BitScanForward64(&result, mask);
return result;
}
BOOST_FORCEINLINE static unsigned make_odd(unsigned __int64& val)
{
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){ 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){ 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){ 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){ 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){ 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){ 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){ 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){ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
template <> struct gcd_traits<wchar_t> : public gcd_traits_defaults<wchar_t>
{ BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val){ unsigned result = gcd_traits<unsigned long>::find_lsb(val); val >>= result; return result; } };
#ifdef _M_X64
template <> struct gcd_traits<__int64> : public gcd_traits_defaults<__int64>
{ BOOST_FORCEINLINE static unsigned make_odd(__int64& val){ 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)
{
return __builtin_ctz(mask);
}
BOOST_FORCEINLINE static unsigned make_odd(unsigned& val)
{
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)
{
return __builtin_ctzl(mask);
}
BOOST_FORCEINLINE static unsigned make_odd(unsigned long& val)
{
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)
{
return __builtin_ctzll(mask);
}
BOOST_FORCEINLINE static unsigned make_odd(boost::ulong_long_type& val)
{
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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
};
template <> struct gcd_traits<wchar_t> : public gcd_traits_defaults<wchar_t>
{
BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val) { unsigned result = gcd_traits<unsigned>::find_lsb(val); val >>= result; return result; }
};
#endif
namespace detail
{
//
// The Mixed Binary Euclid Algorithm
// Sidi Mohamed Sedjelmaci
// Electronic Notes in Discrete Mathematics 35 (2009) 169-176
//
template <class T>
T mixed_binary_gcd(T u, T v)
{
using std::swap;
if(gcd_traits<T>::less(u, v))
swap(u, v);
unsigned shifts = 0;
if(!u)
return v;
if(!v)
return u;
shifts = (std::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))
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>
SteinDomain Stein_gcd(SteinDomain m, SteinDomain n)
{
using std::swap;
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)
swap(n, m);
m -= n;
gcd_traits<SteinDomain>::make_odd(m);
}
// m == n
m <<= (std::min)(d_m, d_n);
return m;
}
/** Euclidean algorithm
*
* From Mathematics to Generic Programming, Alexander Stepanov, Daniel Rose
*
*/
template <typename EuclideanDomain>
inline EuclideanDomain Euclid_gcd(EuclideanDomain a, EuclideanDomain b)
{
using std::swap;
while (b != EuclideanDomain(0))
{
a %= b;
swap(a, b);
}
return a;
}
template <typename T>
inline BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == gcd_traits<T>::method_mixed, T>::type
optimal_gcd_select(T const &a, T const &b)
{
return detail::mixed_binary_gcd(a, b);
}
template <typename T>
inline BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == gcd_traits<T>::method_binary, T>::type
optimal_gcd_select(T const &a, T const &b)
{
return detail::Stein_gcd(a, b);
}
template <typename T>
inline BOOST_DEDUCED_TYPENAME enable_if_c<gcd_traits<T>::method == gcd_traits<T>::method_euclid, T>::type
optimal_gcd_select(T const &a, T const &b)
{
return detail::Euclid_gcd(a, b);
}
template <class T>
inline T lcm_imp(const T& a, const T& b)
{
T temp = boost::math::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 Integer gcd(Integer const &a, Integer const &b)
{
return detail::optimal_gcd_select(static_cast<Integer>(gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_traits<Integer>::abs(b)));
}
template <typename Integer>
inline Integer lcm(Integer const &a, Integer const &b)
{
return detail::lcm_imp(static_cast<Integer>(gcd_traits<Integer>::abs(a)), static_cast<Integer>(gcd_traits<Integer>::abs(b)));
}
/**
* 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_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);
}
} // namespace math
} // namespace boost
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#endif // BOOST_MATH_COMMON_FACTOR_RT_HPP