forked from boostorg/integer
Switch over to using new Boost.Math version of gcd/lcm.
Please refer to the Boost.Math revision log for details of changes, but in summary: * New version of gcd/lcm internals by Jeremy Murphy include mixed-binary algorithm and better selection logic. * Support is now included for gcd's of polynomials. * Full C++14 constexpr support.
This commit is contained in:
@ -1,32 +1,28 @@
|
||||
// Boost common_factor_rt.hpp header file ----------------------------------//
|
||||
// (C) Copyright Jeremy William Murphy 2016.
|
||||
|
||||
// (C) Copyright Daryle Walker and Paul Moore 2001-2002. Permission to copy,
|
||||
// use, modify, sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided "as is"
|
||||
// without express or implied warranty, and with no claim as to its suitability
|
||||
// for any purpose.
|
||||
|
||||
// boostinspect:nolicense (don't complain about the lack of a Boost license)
|
||||
// (Paul Moore hasn't been in contact for years, so there's no way to change the
|
||||
// license.)
|
||||
|
||||
// See http://www.boost.org for updates, documentation, and revision history.
|
||||
// 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_INTEGER_COMMON_FACTOR_RT_HPP
|
||||
#define BOOST_INTEGER_COMMON_FACTOR_RT_HPP
|
||||
|
||||
#include <boost/integer_fwd.hpp> // self include
|
||||
#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_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
|
||||
# include <type_traits>
|
||||
# define BOOST_INT_NOEXCEPT(T) BOOST_NOEXCEPT_IF(std::is_arithmetic<T>::value)
|
||||
#else
|
||||
# define BOOST_INT_NOEXCEPT(T)
|
||||
#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
|
||||
@ -34,427 +30,538 @@
|
||||
#pragma warning(disable:4127 4244) // Conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
#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
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <class I>
|
||||
class rational;
|
||||
|
||||
namespace integer {
|
||||
|
||||
namespace gcd_detail{
|
||||
|
||||
//
|
||||
// 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,
|
||||
};
|
||||
|
||||
struct any_convert
|
||||
{
|
||||
template <class T>
|
||||
any_convert(const T&);
|
||||
};
|
||||
|
||||
struct unlikely_size
|
||||
{
|
||||
char buf[9973];
|
||||
};
|
||||
|
||||
unlikely_size operator <<= (any_convert, any_convert);
|
||||
unlikely_size operator >>= (any_convert, any_convert);
|
||||
|
||||
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 T& get_value();
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
static const bool has_operator_left_shift_equal = sizeof(get_value() <<= 2) != sizeof(unlikely_size);
|
||||
static const bool has_operator_right_shift_equal = sizeof(get_value() >>= 2) != sizeof(unlikely_size);
|
||||
#else
|
||||
static const bool has_operator_left_shift_equal = true;
|
||||
static const bool has_operator_right_shift_equal = true;
|
||||
#endif
|
||||
static const method_type method = std::numeric_limits<T>::is_specialized && std::numeric_limits<T>::is_integer && has_operator_left_shift_equal && has_operator_right_shift_equal ? 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::integer::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(0) ? 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)
|
||||
{
|
||||
namespace integer
|
||||
if(a == (std::numeric_limits<Integer>::min)())
|
||||
return a == static_cast<Integer>(0) ? b : gcd(static_cast<Integer>(a % b), b);
|
||||
else if (b == (std::numeric_limits<Integer>::min)())
|
||||
return b == static_cast<Integer>(0) ? a : gcd(a, static_cast<Integer>(b % a));
|
||||
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);
|
||||
}
|
||||
|
||||
// Forward declarations for function templates -----------------------------//
|
||||
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 IntegerType >
|
||||
BOOST_CXX14_CONSTEXPR IntegerType gcd( IntegerType const &a, IntegerType const &b )BOOST_INT_NOEXCEPT(IntegerType);
|
||||
|
||||
template < typename IntegerType >
|
||||
BOOST_CXX14_CONSTEXPR IntegerType lcm( IntegerType const &a, IntegerType const &b )BOOST_INT_NOEXCEPT(IntegerType);
|
||||
|
||||
|
||||
// Greatest common divisor evaluator class declaration ---------------------//
|
||||
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 >
|
||||
class gcd_evaluator
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
: public std::binary_function<IntegerType, IntegerType, IntegerType>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
// Types
|
||||
typedef IntegerType result_type, first_argument_type, second_argument_type;
|
||||
|
||||
// Function object interface
|
||||
BOOST_CXX14_CONSTEXPR result_type operator ()( first_argument_type const &a,
|
||||
second_argument_type const &b )const BOOST_INT_NOEXCEPT(IntegerType) ;
|
||||
|
||||
}; // boost::integer::gcd_evaluator
|
||||
|
||||
|
||||
// Least common multiple evaluator class declaration -----------------------//
|
||||
#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::integer::gcd(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
template < typename IntegerType >
|
||||
class lcm_evaluator
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
: public std::binary_function<IntegerType, IntegerType, IntegerType>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
// Types
|
||||
typedef IntegerType result_type, first_argument_type, second_argument_type;
|
||||
|
||||
// Function object interface
|
||||
BOOST_CXX14_CONSTEXPR result_type operator ()( first_argument_type const &a,
|
||||
second_argument_type const &b )const BOOST_INT_NOEXCEPT(IntegerType) ;
|
||||
|
||||
}; // boost::integer::lcm_evaluator
|
||||
|
||||
|
||||
// Implementation details --------------------------------------------------//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Greatest common divisor for rings (including unsigned integers)
|
||||
template < typename RingType >
|
||||
BOOST_CXX14_CONSTEXPR RingType
|
||||
gcd_euclidean
|
||||
(
|
||||
RingType a,
|
||||
RingType b
|
||||
)BOOST_INT_NOEXCEPT(RingType)
|
||||
{
|
||||
// Avoid repeated construction
|
||||
#ifndef __BORLANDC__
|
||||
RingType const zero = static_cast<RingType>( 0 );
|
||||
#else
|
||||
RingType zero = static_cast<RingType>( 0 );
|
||||
#endif
|
||||
|
||||
// Reduce by GCD-remainder property [GCD(a,b) == GCD(b,a MOD b)]
|
||||
while ( true )
|
||||
{
|
||||
if ( a == zero )
|
||||
return b;
|
||||
b %= a;
|
||||
|
||||
if ( b == zero )
|
||||
return a;
|
||||
a %= b;
|
||||
}
|
||||
}
|
||||
|
||||
// Greatest common divisor for (signed) integers
|
||||
template < typename IntegerType >
|
||||
inline
|
||||
BOOST_CXX14_CONSTEXPR IntegerType
|
||||
gcd_integer
|
||||
(
|
||||
IntegerType const & a,
|
||||
IntegerType const & b
|
||||
)BOOST_INT_NOEXCEPT(IntegerType)
|
||||
{
|
||||
// Avoid repeated construction
|
||||
IntegerType const zero = static_cast<IntegerType>( 0 );
|
||||
IntegerType const result = gcd_euclidean( a, b );
|
||||
|
||||
return ( result < zero ) ? static_cast<IntegerType>(-result) : result;
|
||||
}
|
||||
|
||||
// Greatest common divisor for unsigned binary integers
|
||||
template < typename BuiltInUnsigned >
|
||||
BOOST_CXX14_CONSTEXPR BuiltInUnsigned
|
||||
gcd_binary
|
||||
(
|
||||
BuiltInUnsigned u,
|
||||
BuiltInUnsigned v
|
||||
)BOOST_INT_NOEXCEPT(BuiltInUnsigned)
|
||||
{
|
||||
if ( u && v )
|
||||
{
|
||||
// Shift out common factors of 2
|
||||
unsigned shifts = 0;
|
||||
|
||||
while ( !(u & 1u) && !(v & 1u) )
|
||||
{
|
||||
++shifts;
|
||||
u >>= 1;
|
||||
v >>= 1;
|
||||
}
|
||||
|
||||
// Start with the still-even one, if any
|
||||
BuiltInUnsigned r[] = { u, v };
|
||||
unsigned which = static_cast<bool>( u & 1u );
|
||||
|
||||
// Whittle down the values via their differences
|
||||
do
|
||||
{
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
while ( !(r[ which ] & 1u) )
|
||||
{
|
||||
r[ which ] = (r[which] >> 1);
|
||||
}
|
||||
#else
|
||||
// Remove factors of two from the even one
|
||||
while ( !(r[ which ] & 1u) )
|
||||
{
|
||||
r[ which ] >>= 1;
|
||||
}
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef IntegerType first_argument_type;
|
||||
typedef IntegerType second_argument_type;
|
||||
typedef IntegerType result_type;
|
||||
#endif
|
||||
|
||||
// Replace the larger of the two with their difference
|
||||
if ( r[!which] > r[which] )
|
||||
{
|
||||
which ^= 1u;
|
||||
}
|
||||
|
||||
r[ which ] -= r[ !which ];
|
||||
}
|
||||
while ( r[which] );
|
||||
|
||||
// Shift-in the common factor of 2 to the residues' GCD
|
||||
return r[ !which ] << shifts;
|
||||
}
|
||||
else
|
||||
{
|
||||
// At least one input is zero, return the other
|
||||
// (adding since zero is the additive identity)
|
||||
// or zero if both are zero.
|
||||
return u + v;
|
||||
}
|
||||
}
|
||||
|
||||
// Least common multiple for rings (including unsigned integers)
|
||||
template < typename RingType >
|
||||
inline
|
||||
BOOST_CXX14_CONSTEXPR RingType
|
||||
lcm_euclidean
|
||||
(
|
||||
RingType const & a,
|
||||
RingType const & b
|
||||
)BOOST_INT_NOEXCEPT(RingType)
|
||||
{
|
||||
RingType const zero = static_cast<RingType>( 0 );
|
||||
RingType const temp = gcd_euclidean( a, b );
|
||||
|
||||
return ( temp != zero ) ? ( a / temp * b ) : zero;
|
||||
}
|
||||
|
||||
// Least common multiple for (signed) integers
|
||||
template < typename IntegerType >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
IntegerType
|
||||
lcm_integer
|
||||
(
|
||||
IntegerType const & a,
|
||||
IntegerType const & b
|
||||
)BOOST_INT_NOEXCEPT(IntegerType)
|
||||
{
|
||||
// Avoid repeated construction
|
||||
IntegerType const zero = static_cast<IntegerType>( 0 );
|
||||
IntegerType const result = lcm_euclidean( a, b );
|
||||
|
||||
return ( result < zero ) ? static_cast<IntegerType>(-result) : result;
|
||||
}
|
||||
|
||||
// Function objects to find the best way of computing GCD or LCM
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
template < typename T, bool IsSpecialized, bool IsSigned >
|
||||
struct gcd_optimal_evaluator_helper_t
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
return gcd_euclidean( a, b );
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct gcd_optimal_evaluator_helper_t< T, true, true >
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
return gcd_integer( a, b );
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct gcd_optimal_evaluator
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
typedef ::std::numeric_limits<T> limits_type;
|
||||
|
||||
typedef gcd_optimal_evaluator_helper_t<T,
|
||||
limits_type::is_specialized, limits_type::is_signed> helper_type;
|
||||
|
||||
helper_type solver;
|
||||
|
||||
return solver( a, b );
|
||||
}
|
||||
};
|
||||
#else // BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
template < typename T >
|
||||
struct gcd_optimal_evaluator
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
return gcd_integer( a, b );
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Specialize for the built-in integers
|
||||
#define BOOST_PRIVATE_GCD_UF( Ut ) \
|
||||
template < > struct gcd_optimal_evaluator<Ut> \
|
||||
{ BOOST_CXX14_CONSTEXPR Ut operator ()( Ut a, Ut b ) const BOOST_INT_NOEXCEPT(Ut) { return gcd_binary( a, b ); } }
|
||||
|
||||
BOOST_PRIVATE_GCD_UF( unsigned char );
|
||||
BOOST_PRIVATE_GCD_UF( unsigned short );
|
||||
BOOST_PRIVATE_GCD_UF( unsigned );
|
||||
BOOST_PRIVATE_GCD_UF( unsigned long );
|
||||
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
BOOST_PRIVATE_GCD_UF( boost::ulong_long_type );
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
BOOST_PRIVATE_GCD_UF( unsigned __int64 );
|
||||
#endif
|
||||
|
||||
#if CHAR_MIN == 0
|
||||
BOOST_PRIVATE_GCD_UF( char ); // char is unsigned
|
||||
#endif
|
||||
|
||||
#undef BOOST_PRIVATE_GCD_UF
|
||||
|
||||
#define BOOST_PRIVATE_GCD_SF( St, Ut ) \
|
||||
template < > struct gcd_optimal_evaluator<St> \
|
||||
{ BOOST_CXX14_CONSTEXPR St operator ()( St a, St b ) const BOOST_INT_NOEXCEPT(St) { Ut const a_abs = \
|
||||
static_cast<Ut>( a < 0 ? -a : +a ), b_abs = static_cast<Ut>( \
|
||||
b < 0 ? -b : +b ); return static_cast<St>( \
|
||||
gcd_optimal_evaluator<Ut>()(a_abs, b_abs) ); } }
|
||||
|
||||
BOOST_PRIVATE_GCD_SF( signed char, unsigned char );
|
||||
BOOST_PRIVATE_GCD_SF( short, unsigned short );
|
||||
BOOST_PRIVATE_GCD_SF( int, unsigned );
|
||||
BOOST_PRIVATE_GCD_SF( long, unsigned long );
|
||||
|
||||
#if CHAR_MIN < 0
|
||||
BOOST_PRIVATE_GCD_SF( char, unsigned char ); // char is signed
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_LONG_LONG
|
||||
BOOST_PRIVATE_GCD_SF( boost::long_long_type, boost::ulong_long_type );
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
BOOST_PRIVATE_GCD_SF( __int64, unsigned __int64 );
|
||||
#endif
|
||||
|
||||
#undef BOOST_PRIVATE_GCD_SF
|
||||
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
template < typename T, bool IsSpecialized, bool IsSigned >
|
||||
struct lcm_optimal_evaluator_helper_t
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
return lcm_euclidean( a, b );
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct lcm_optimal_evaluator_helper_t< T, true, true >
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
return lcm_integer( a, b );
|
||||
}
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct lcm_optimal_evaluator
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
typedef ::std::numeric_limits<T> limits_type;
|
||||
|
||||
typedef lcm_optimal_evaluator_helper_t<T,
|
||||
limits_type::is_specialized, limits_type::is_signed> helper_type;
|
||||
|
||||
helper_type solver;
|
||||
|
||||
return solver( a, b );
|
||||
}
|
||||
};
|
||||
#else // BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
template < typename T >
|
||||
struct lcm_optimal_evaluator
|
||||
{
|
||||
BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
return lcm_integer( a, b );
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Functions to find the GCD or LCM in the best way
|
||||
template < typename T >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
T
|
||||
gcd_optimal
|
||||
(
|
||||
T const & a,
|
||||
T const & b
|
||||
)BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
gcd_optimal_evaluator<T> solver;
|
||||
|
||||
return solver( a, b );
|
||||
}
|
||||
|
||||
template < typename T >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
T
|
||||
lcm_optimal
|
||||
(
|
||||
T const & a,
|
||||
T const & b
|
||||
)BOOST_INT_NOEXCEPT(T)
|
||||
{
|
||||
lcm_optimal_evaluator<T> solver;
|
||||
|
||||
return solver( a, b );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
// Greatest common divisor evaluator member function definition ------------//
|
||||
|
||||
template < typename IntegerType >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
typename gcd_evaluator<IntegerType>::result_type
|
||||
gcd_evaluator<IntegerType>::operator ()
|
||||
(
|
||||
first_argument_type const & a,
|
||||
second_argument_type const & b
|
||||
) const BOOST_INT_NOEXCEPT(IntegerType)
|
||||
{
|
||||
return detail::gcd_optimal( a, b );
|
||||
}
|
||||
|
||||
|
||||
// Least common multiple evaluator member function definition --------------//
|
||||
|
||||
template < typename IntegerType >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
typename lcm_evaluator<IntegerType>::result_type
|
||||
lcm_evaluator<IntegerType>::operator ()
|
||||
(
|
||||
first_argument_type const & a,
|
||||
second_argument_type const & b
|
||||
) const BOOST_INT_NOEXCEPT(IntegerType)
|
||||
{
|
||||
return detail::lcm_optimal( a, b );
|
||||
}
|
||||
|
||||
|
||||
// Greatest common divisor and least common multiple function definitions --//
|
||||
|
||||
template < typename IntegerType >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
IntegerType
|
||||
gcd
|
||||
(
|
||||
IntegerType const & a,
|
||||
IntegerType const & b
|
||||
) BOOST_INT_NOEXCEPT(IntegerType)
|
||||
{
|
||||
gcd_evaluator<IntegerType> solver;
|
||||
|
||||
return solver( a, b );
|
||||
}
|
||||
|
||||
template < typename IntegerType >
|
||||
inline BOOST_CXX14_CONSTEXPR
|
||||
IntegerType
|
||||
lcm
|
||||
(
|
||||
IntegerType const & a,
|
||||
IntegerType const & b
|
||||
) BOOST_INT_NOEXCEPT(IntegerType)
|
||||
{
|
||||
lcm_evaluator<IntegerType> solver;
|
||||
|
||||
return solver( a, b );
|
||||
}
|
||||
|
||||
IntegerType operator()(IntegerType const &a, IntegerType const &b)const
|
||||
{
|
||||
return boost::integer::lcm(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace integer
|
||||
} // namespace boost
|
||||
|
@ -20,6 +20,7 @@ test-suite integer
|
||||
[ compile static_min_max_include_test.cpp ]
|
||||
[ compile integer_fwd_include_test.cpp ]
|
||||
[ compile gcd_constexpr14_test.cpp ]
|
||||
[ compile gcd_noexcept_test.cpp ]
|
||||
[ compile-fail fail_int_exact.cpp ]
|
||||
[ compile-fail fail_int_fast.cpp ]
|
||||
[ compile-fail fail_int_least.cpp ]
|
||||
|
@ -15,14 +15,17 @@
|
||||
// 02 Nov 2006 Change to Boost.Test's unit test system (Daryle Walker)
|
||||
// 07 Nov 2001 Initial version (Daryle Walker)
|
||||
|
||||
#define BOOST_TEST_MAIN "Boost.Math GCD & LCM unit tests"
|
||||
#define BOOST_TEST_MAIN "Boost.integer GCD & LCM unit tests"
|
||||
|
||||
#include <boost/integer/common_factor.hpp>
|
||||
|
||||
#include <boost/config.hpp> // for BOOST_MSVC, etc.
|
||||
#include <boost/config.hpp> // for BOOST_MSVC, etc.
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/integer/common_factor.hpp> // for boost::integer::gcd, etc.
|
||||
#include <boost/mpl/list.hpp> // for boost::mpl::list
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
#include <istream> // for std::basic_istream
|
||||
#include <limits> // for std::numeric_limits
|
||||
@ -109,6 +112,25 @@ MyUnsigned1 dummy2;
|
||||
MyInt2 dummy3;
|
||||
MyUnsigned2 dummy4;
|
||||
|
||||
// Various types to test with each GCD/LCM
|
||||
typedef ::boost::mpl::list<signed char, short, int, long,
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1500)
|
||||
#elif defined(BOOST_HAS_LONG_LONG)
|
||||
boost::long_long_type,
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
__int64,
|
||||
#endif
|
||||
MyInt1, boost::multiprecision::cpp_int> signed_test_types;
|
||||
typedef ::boost::mpl::list<unsigned char, unsigned short, unsigned,
|
||||
unsigned long,
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1500)
|
||||
#elif defined(BOOST_HAS_LONG_LONG)
|
||||
boost::ulong_long_type,
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
unsigned __int64,
|
||||
#endif
|
||||
MyUnsigned1, MyUnsigned2 /*, boost::multiprecision::uint256_t*/> unsigned_test_types;
|
||||
|
||||
} // namespace
|
||||
|
||||
#define BOOST_NO_MACRO_EXPAND /**/
|
||||
@ -246,7 +268,12 @@ inline ostream& operator<<(ostream& os, unsigned __int64 i)
|
||||
// GCD on signed integer types
|
||||
template< class T > void gcd_int_test() // signed_test_types
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::gcd;
|
||||
using boost::integer::gcd_evaluator;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
// Originally from Boost.Rational tests
|
||||
BOOST_TEST_EQ( gcd<T>( 1, -1), static_cast<T>( 1) );
|
||||
@ -265,12 +292,33 @@ template< class T > void gcd_int_test() // signed_test_types
|
||||
BOOST_TEST_EQ( gcd<T>( 3, 7), static_cast<T>( 1) );
|
||||
BOOST_TEST_EQ( gcd<T>( 8, 9), static_cast<T>( 1) );
|
||||
BOOST_TEST_EQ( gcd<T>( 7, 49), static_cast<T>( 7) );
|
||||
// Again with function object:
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(1, -1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(-1, 1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(1, 1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(-1, -1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(0, 0), static_cast<T>(0));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(7, 0), static_cast<T>(7));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(0, 9), static_cast<T>(9));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(-7, 0), static_cast<T>(7));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(0, -9), static_cast<T>(9));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(42, 30), static_cast<T>(6));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(6, -9), static_cast<T>(3));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(-10, -10), static_cast<T>(10));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(-25, -10), static_cast<T>(5));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(3, 7), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(8, 9), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(gcd_evaluator<T>()(7, 49), static_cast<T>(7));
|
||||
}
|
||||
|
||||
// GCD on unmarked signed integer type
|
||||
void gcd_unmarked_int_test()
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::gcd;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
// The regular signed-integer GCD function performs the unsigned version,
|
||||
// then does an absolute-value on the result. Signed types that are not
|
||||
@ -297,7 +345,11 @@ void gcd_unmarked_int_test()
|
||||
// GCD on unsigned integer types
|
||||
template< class T > void gcd_unsigned_test() // unsigned_test_types
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::gcd;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
// Note that unmarked types (i.e. have no std::numeric_limits
|
||||
// specialization) are treated like non/unsigned types
|
||||
@ -314,29 +366,53 @@ template< class T > void gcd_unsigned_test() // unsigned_test_types
|
||||
// GCD at compile-time
|
||||
void gcd_static_test()
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::static_gcd;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
BOOST_TEST_EQ( (static_gcd< 1, 1>::value), 1 );
|
||||
BOOST_TEST_EQ( (static_gcd< 0, 0>::value), 0 );
|
||||
BOOST_TEST_EQ( (static_gcd< 7, 0>::value), 7 );
|
||||
BOOST_TEST_EQ( (static_gcd< 0, 9>::value), 9 );
|
||||
BOOST_TEST_EQ( (static_gcd<42, 30>::value), 6 );
|
||||
BOOST_TEST_EQ( (static_gcd< 3, 7>::value), 1 );
|
||||
BOOST_TEST_EQ( (static_gcd< 8, 9>::value), 1 );
|
||||
BOOST_TEST_EQ( (static_gcd< 7, 49>::value), 7 );
|
||||
// Can't use "BOOST_TEST_EQ", otherwise the "value" member will be
|
||||
// disqualified as compile-time-only constant, needing explicit definition
|
||||
BOOST_TEST( (static_gcd< 1, 1>::value) == 1 );
|
||||
BOOST_TEST( (static_gcd< 0, 0>::value) == 0 );
|
||||
BOOST_TEST( (static_gcd< 7, 0>::value) == 7 );
|
||||
BOOST_TEST( (static_gcd< 0, 9>::value) == 9 );
|
||||
BOOST_TEST( (static_gcd<42, 30>::value) == 6 );
|
||||
BOOST_TEST( (static_gcd< 3, 7>::value) == 1 );
|
||||
BOOST_TEST( (static_gcd< 8, 9>::value) == 1 );
|
||||
BOOST_TEST( (static_gcd< 7, 49>::value) == 7 );
|
||||
}
|
||||
|
||||
// TODO: non-built-in signed and unsigned integer tests, with and without
|
||||
// numeric_limits specialization; polynominal tests; note any changes if
|
||||
// built-ins switch to binary-GCD algorithm
|
||||
void 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::integer::gcd_detail::Euclid_gcd(v1, v2);
|
||||
BOOST_TEST(v1 % g == 0);
|
||||
BOOST_TEST(v2 % g == 0);
|
||||
BOOST_TEST_EQ(g, boost::integer::gcd_detail::mixed_binary_gcd(v1, v2));
|
||||
BOOST_TEST_EQ(g, boost::integer::gcd_detail::Stein_gcd(v1, v2));
|
||||
}
|
||||
}
|
||||
|
||||
// LCM tests
|
||||
|
||||
// LCM on signed integer types
|
||||
template< class T > void lcm_int_test() // signed_test_types
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::lcm;
|
||||
using boost::integer::lcm_evaluator;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
// Originally from Boost.Rational tests
|
||||
BOOST_TEST_EQ( lcm<T>( 1, -1), static_cast<T>( 1) );
|
||||
@ -355,12 +431,33 @@ template< class T > void lcm_int_test() // signed_test_types
|
||||
BOOST_TEST_EQ( lcm<T>( 3, 7), static_cast<T>(21) );
|
||||
BOOST_TEST_EQ( lcm<T>( 8, 9), static_cast<T>(72) );
|
||||
BOOST_TEST_EQ( lcm<T>( 7, 49), static_cast<T>(49) );
|
||||
// Again with function object:
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(1, -1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(-1, 1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(1, 1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(-1, -1), static_cast<T>(1));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(0, 0), static_cast<T>(0));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(6, 0), static_cast<T>(0));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(0, 7), static_cast<T>(0));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(-5, 0), static_cast<T>(0));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(0, -4), static_cast<T>(0));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(18, 30), static_cast<T>(90));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(-6, 9), static_cast<T>(18));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(-10, -10), static_cast<T>(10));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(25, -10), static_cast<T>(50));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(3, 7), static_cast<T>(21));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(8, 9), static_cast<T>(72));
|
||||
BOOST_TEST_EQ(lcm_evaluator<T>()(7, 49), static_cast<T>(49));
|
||||
}
|
||||
|
||||
// LCM on unmarked signed integer type
|
||||
void lcm_unmarked_int_test()
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::lcm;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
// The regular signed-integer LCM function performs the unsigned version,
|
||||
// then does an absolute-value on the result. Signed types that are not
|
||||
@ -387,7 +484,11 @@ void lcm_unmarked_int_test()
|
||||
// LCM on unsigned integer types
|
||||
template< class T > void lcm_unsigned_test() // unsigned_test_types
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::lcm;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
// Note that unmarked types (i.e. have no std::numeric_limits
|
||||
// specialization) are treated like non/unsigned types
|
||||
@ -404,23 +505,46 @@ template< class T > void lcm_unsigned_test() // unsigned_test_types
|
||||
// LCM at compile-time
|
||||
void lcm_static_test()
|
||||
{
|
||||
#ifndef BOOST_MSVC
|
||||
using boost::integer::static_lcm;
|
||||
#else
|
||||
using namespace boost::integer;
|
||||
#endif
|
||||
|
||||
BOOST_TEST_EQ( (static_lcm< 1, 1>::value), 1 );
|
||||
BOOST_TEST_EQ( (static_lcm< 0, 0>::value), 0 );
|
||||
BOOST_TEST_EQ( (static_lcm< 6, 0>::value), 0 );
|
||||
BOOST_TEST_EQ( (static_lcm< 0, 7>::value), 0 );
|
||||
BOOST_TEST_EQ( (static_lcm<18, 30>::value), 90 );
|
||||
BOOST_TEST_EQ( (static_lcm< 3, 7>::value), 21 );
|
||||
BOOST_TEST_EQ( (static_lcm< 8, 9>::value), 72 );
|
||||
BOOST_TEST_EQ( (static_lcm< 7, 49>::value), 49 );
|
||||
// Can't use "BOOST_TEST_EQ", otherwise the "value" member will be
|
||||
// disqualified as compile-time-only constant, needing explicit definition
|
||||
BOOST_TEST( (static_lcm< 1, 1>::value) == 1 );
|
||||
BOOST_TEST( (static_lcm< 0, 0>::value) == 0 );
|
||||
BOOST_TEST( (static_lcm< 6, 0>::value) == 0 );
|
||||
BOOST_TEST( (static_lcm< 0, 7>::value) == 0 );
|
||||
BOOST_TEST( (static_lcm<18, 30>::value) == 90 );
|
||||
BOOST_TEST( (static_lcm< 3, 7>::value) == 21 );
|
||||
BOOST_TEST( (static_lcm< 8, 9>::value) == 72 );
|
||||
BOOST_TEST( (static_lcm< 7, 49>::value) == 49 );
|
||||
}
|
||||
|
||||
// TODO: see GCD to-do
|
||||
void variadics()
|
||||
{
|
||||
unsigned i[] = { 44, 56, 76, 88 };
|
||||
BOOST_TEST_EQ(boost::integer::gcd_range(i, i + 4).first, 4);
|
||||
BOOST_TEST_EQ(boost::integer::gcd_range(i, i + 4).second, i + 4);
|
||||
BOOST_TEST_EQ(boost::integer::lcm_range(i, i + 4).first, 11704);
|
||||
BOOST_TEST_EQ(boost::integer::lcm_range(i, i + 4).second, i + 4);
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
BOOST_TEST_EQ(boost::integer::gcd(i[0], i[1], i[2], i[3]), 4);
|
||||
BOOST_TEST_EQ(boost::integer::lcm(i[0], i[1], i[2], i[3]), 11704);
|
||||
#endif
|
||||
}
|
||||
|
||||
// main
|
||||
|
||||
// Various types to test with each GCD/LCM
|
||||
// Test case from Boost.Rational, need to make sure we don't break the rational lib:
|
||||
template <class T> void gcd_and_lcm_on_rationals()
|
||||
{
|
||||
typedef boost::rational<T> rational;
|
||||
BOOST_TEST_EQ(boost::integer::gcd(rational(1, 4), rational(1, 3)),
|
||||
rational(1, 12));
|
||||
BOOST_TEST_EQ(boost::integer::lcm(rational(1, 4), rational(1, 3)),
|
||||
rational(1));
|
||||
}
|
||||
|
||||
#define TEST_SIGNED_( test ) \
|
||||
test<signed char>(); \
|
||||
@ -459,15 +583,18 @@ void lcm_static_test()
|
||||
|
||||
int main()
|
||||
{
|
||||
TEST_SIGNED( gcd_int_test )
|
||||
gcd_unmarked_int_test();
|
||||
TEST_UNSIGNED( gcd_unsigned_test )
|
||||
gcd_static_test();
|
||||
TEST_SIGNED(gcd_int_test)
|
||||
gcd_unmarked_int_test();
|
||||
TEST_UNSIGNED(gcd_unsigned_test)
|
||||
gcd_static_test();
|
||||
gcd_method_test();
|
||||
|
||||
TEST_SIGNED( lcm_int_test )
|
||||
lcm_unmarked_int_test();
|
||||
TEST_UNSIGNED( lcm_unsigned_test )
|
||||
lcm_static_test();
|
||||
TEST_SIGNED(lcm_int_test)
|
||||
lcm_unmarked_int_test();
|
||||
TEST_UNSIGNED(lcm_unsigned_test)
|
||||
lcm_static_test();
|
||||
variadics();
|
||||
TEST_SIGNED(gcd_and_lcm_on_rationals)
|
||||
|
||||
return boost::report_errors();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#ifndef BOOST_NO_CXX14_CONSTEXPR
|
||||
|
||||
void test_constexpr()
|
||||
void test_constexpr1()
|
||||
{
|
||||
constexpr const boost::int64_t i = 347 * 463 * 727;
|
||||
constexpr const boost::int64_t j = 191 * 347 * 281;
|
||||
@ -16,30 +16,51 @@ void test_constexpr()
|
||||
constexpr const boost::int64_t k = boost::integer::gcd(i, j);
|
||||
constexpr const boost::int64_t l = boost::integer::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.");
|
||||
static_assert(k == 347, "Expected result not integer in constexpr gcd.");
|
||||
static_assert(l == 6268802158037, "Expected result not integer in constexpr lcm.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX11_NOEXCEPT
|
||||
|
||||
void test_noexcept()
|
||||
void test_constexpr2()
|
||||
{
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned char>(2), static_cast<unsigned char>(4))), "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::integer::gcd(static_cast<char>(2), static_cast<char>(4))), "Expected a noexcept function.");
|
||||
#endif
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<signed char>(2), static_cast<signed char>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<short>(2), static_cast<short>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned short>(2), static_cast<unsigned short>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<int>(2), static_cast<int>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned int>(2), static_cast<unsigned int>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<long>(2), static_cast<long>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned long>(2), static_cast<unsigned long>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<long long>(2), static_cast<long long>(4))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned long long>(2), static_cast<unsigned long long>(4))), "Expected a noexcept function.");
|
||||
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::integer::gcd(i, j);
|
||||
constexpr const boost::uint64_t l = boost::integer::lcm(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not integer in constexpr gcd.");
|
||||
static_assert(l == 6268802158037, "Expected result not integer 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::integer::gcd_detail::Euclid_gcd(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not integer 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::integer::gcd_detail::mixed_binary_gcd(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not integer 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::integer::gcd_detail::Stein_gcd(i, j);
|
||||
|
||||
static_assert(k == 347, "Expected result not integer in constexpr gcd.");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
35
test/gcd_noexcept_test.cpp
Normal file
35
test/gcd_noexcept_test.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
|
||||
// (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)
|
||||
|
||||
#include <boost/integer/common_factor.hpp>
|
||||
|
||||
#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::integer::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::integer::gcd(static_cast<char>(a), static_cast<char>(b))), "Expected a noexcept function.");
|
||||
#endif
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<signed char>(a), static_cast<signed char>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<short>(a), static_cast<short>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned short>(a), static_cast<unsigned short>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<int>(a), static_cast<int>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned int>(a), static_cast<unsigned int>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<long>(a), static_cast<long>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned long>(a), static_cast<unsigned long>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<long long>(a), static_cast<long long>(b))), "Expected a noexcept function.");
|
||||
static_assert(noexcept(boost::integer::gcd(static_cast<unsigned long long>(a), static_cast<unsigned long long>(b))), "Expected a noexcept function.");
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user