diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index 6d035b0..c52067d 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -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 // self include +#include +#include #include // for BOOST_NESTED_TEMPLATE, etc. #include // for std::numeric_limits #include // for CHAR_MIN #include +#include +#include +#include +#ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS +#include +#endif -#if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) -# include -# define BOOST_INT_NOEXCEPT(T) BOOST_NOEXCEPT_IF(std::is_arithmetic::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 #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::value) +#else +#define BOOST_GCD_NOEXCEPT(T) +#endif + +namespace boost { + + template + 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 + inline constexpr T constexpr_min(T const& a, T const& b) BOOST_GCD_NOEXCEPT(T) + { + return a < b ? a : b; + } + template + inline constexpr auto constexpr_swap(T&a, T& b) BOOST_GCD_NOEXCEPT(T) -> decltype(a.swap(b)) + { + return a.swap(b); + } + template + inline constexpr void constexpr_swap(T&a, U& b...) BOOST_GCD_NOEXCEPT(T) + { + T t(static_cast(a)); + a = static_cast(b); + b = static_cast(t); + } +#else + template + inline T constexpr_min(T const& a, T const& b) BOOST_GCD_NOEXCEPT(T) + { + return a < b ? a : b; + } + template + inline void constexpr_swap(T&a, T& b) BOOST_GCD_NOEXCEPT(T) + { + using std::swap; + swap(a, b); + } +#endif + + template ::value || +#endif + (std::numeric_limits::is_specialized && !std::numeric_limits::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 + struct gcd_traits_abs_defaults + { + 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 + 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 + struct gcd_traits_defaults : public gcd_traits_abs_defaults + { + 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::is_specialized && std::numeric_limits::is_integer && has_operator_left_shift_equal && has_operator_right_shift_equal ? method_mixed : method_euclid; + }; + // + // Default gcd_traits just inherits from defaults: + // + template + struct gcd_traits : public gcd_traits_defaults {}; + +#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 : public gcd_traits_defaults + { + 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 : public gcd_traits_defaults + { + 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 : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(long& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(unsigned int& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(int& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(unsigned short& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(short& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(unsigned char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static signed make_odd(signed char& val)BOOST_NOEXCEPT{ signed result = gcd_traits::find_lsb(val); val >>= result; return result; } }; + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(char& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } }; +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + template <> struct gcd_traits : public gcd_traits_defaults + { BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT{ unsigned result = gcd_traits::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::find_lsb(val); val >>= result; return result; } }; +#endif + +#elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__)) + + template <> + struct gcd_traits : public gcd_traits_defaults + { + 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 : public gcd_traits_defaults + { + 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 : public gcd_traits_defaults + { + 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 : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(boost::long_long_type& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(long& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(int& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(unsigned short& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(short& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(unsigned char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static signed make_odd(signed char& val)BOOST_NOEXCEPT { signed result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(char& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; +#ifndef BOOST_NO_INTRINSIC_WCHAR_T + template <> struct gcd_traits : public gcd_traits_defaults + { + BOOST_FORCEINLINE static unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::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 + BOOST_CXX14_CONSTEXPR T mixed_binary_gcd(T u, T v) BOOST_GCD_NOEXCEPT(T) + { + if(gcd_traits::less(u, v)) + constexpr_swap(u, v); + + unsigned shifts = 0; + + if(!u) + return v; + if(!v) + return u; + + shifts = constexpr_min(gcd_traits::make_odd(u), gcd_traits::make_odd(v)); + + while(gcd_traits::less(1, v)) + { + u %= v; + v -= u; + if(!u) + return v << shifts; + if(!v) + return u << shifts; + gcd_traits::make_odd(u); + gcd_traits::make_odd(v); + if(gcd_traits::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 + 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::make_odd(m); + int d_n = gcd_traits::make_odd(n); + // odd(m) && odd(n) + while (m != n) + { + if (n > m) + constexpr_swap(n, m); + m -= n; + gcd_traits::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 + 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 + inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c::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 + inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c::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 + inline BOOST_CXX14_CONSTEXPR BOOST_DEDUCED_TYPENAME enable_if_c::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 + 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 +inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer) { -namespace integer + if(a == (std::numeric_limits::min)()) + return a == static_cast(0) ? b : gcd(static_cast(a % b), b); + else if (b == (std::numeric_limits::min)()) + return b == static_cast(0) ? a : gcd(a, static_cast(b % a)); + return gcd_detail::optimal_gcd_select(static_cast(gcd_detail::gcd_traits::abs(a)), static_cast(gcd_detail::gcd_traits::abs(b))); +} + +template +inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer) { + return gcd_detail::lcm_imp(static_cast(gcd_detail::gcd_traits::abs(a)), static_cast(gcd_detail::gcd_traits::abs(b))); +} +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES +template +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 +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 +inline typename boost::enable_if_c::is_specialized, boost::rational >::type gcd(boost::rational const &a, boost::rational const &b) +{ + return boost::rational(static_cast(gcd(a.numerator(), b.numerator())), static_cast(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 +inline typename boost::enable_if_c::is_specialized, boost::rational >::type lcm(boost::rational const &a, boost::rational const &b) +{ + return boost::rational(static_cast(lcm(a.numerator(), b.numerator())), static_cast(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 +std::pair::value_type, I> +gcd_range(I first, I last) BOOST_GCD_NOEXCEPT(I) +{ + BOOST_ASSERT(first != last); + typedef typename std::iterator_traits::value_type T; + + T d = *first++; + while (d != T(1) && first != last) + { + d = gcd(d, *first); + first++; + } + return std::make_pair(d, first); +} +template +std::pair::value_type, I> +lcm_range(I first, I last) BOOST_GCD_NOEXCEPT(I) +{ + BOOST_ASSERT(first != last); + typedef typename std::iterator_traits::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 +#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 +#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( 0 ); - #else - RingType zero = static_cast( 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( 0 ); - IntegerType const result = gcd_euclidean( a, b ); - - return ( result < zero ) ? static_cast(-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( 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( 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( 0 ); - IntegerType const result = lcm_euclidean( a, b ); - - return ( result < zero ) ? static_cast(-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 limits_type; - - typedef gcd_optimal_evaluator_helper_t 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 \ - { 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 \ - { BOOST_CXX14_CONSTEXPR St operator ()( St a, St b ) const BOOST_INT_NOEXCEPT(St) { Ut const a_abs = \ - static_cast( a < 0 ? -a : +a ), b_abs = static_cast( \ - b < 0 ? -b : +b ); return static_cast( \ - gcd_optimal_evaluator()(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 limits_type; - - typedef lcm_optimal_evaluator_helper_t 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 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 solver; - - return solver( a, b ); - } - -} // namespace detail - - -// Greatest common divisor evaluator member function definition ------------// - -template < typename IntegerType > -inline BOOST_CXX14_CONSTEXPR -typename gcd_evaluator::result_type -gcd_evaluator::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::result_type -lcm_evaluator::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 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 solver; - - return solver( a, b ); -} - + IntegerType operator()(IntegerType const &a, IntegerType const &b)const + { + return boost::integer::lcm(a, b); + } +}; } // namespace integer } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ea29336..691b703 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -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 ] diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 81ffc47..9457e1a 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.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 - -#include // for BOOST_MSVC, etc. +#include // for BOOST_MSVC, etc. #include +#include // for boost::integer::gcd, etc. +#include // for boost::mpl::list #include #include +#include +#include +#include #include // for std::basic_istream #include // 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_test_types; +typedef ::boost::mpl::list 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( 1, -1), static_cast( 1) ); @@ -265,12 +292,33 @@ template< class T > void gcd_int_test() // signed_test_types BOOST_TEST_EQ( gcd( 3, 7), static_cast( 1) ); BOOST_TEST_EQ( gcd( 8, 9), static_cast( 1) ); BOOST_TEST_EQ( gcd( 7, 49), static_cast( 7) ); + // Again with function object: + BOOST_TEST_EQ(gcd_evaluator()(1, -1), static_cast(1)); + BOOST_TEST_EQ(gcd_evaluator()(-1, 1), static_cast(1)); + BOOST_TEST_EQ(gcd_evaluator()(1, 1), static_cast(1)); + BOOST_TEST_EQ(gcd_evaluator()(-1, -1), static_cast(1)); + BOOST_TEST_EQ(gcd_evaluator()(0, 0), static_cast(0)); + BOOST_TEST_EQ(gcd_evaluator()(7, 0), static_cast(7)); + BOOST_TEST_EQ(gcd_evaluator()(0, 9), static_cast(9)); + BOOST_TEST_EQ(gcd_evaluator()(-7, 0), static_cast(7)); + BOOST_TEST_EQ(gcd_evaluator()(0, -9), static_cast(9)); + BOOST_TEST_EQ(gcd_evaluator()(42, 30), static_cast(6)); + BOOST_TEST_EQ(gcd_evaluator()(6, -9), static_cast(3)); + BOOST_TEST_EQ(gcd_evaluator()(-10, -10), static_cast(10)); + BOOST_TEST_EQ(gcd_evaluator()(-25, -10), static_cast(5)); + BOOST_TEST_EQ(gcd_evaluator()(3, 7), static_cast(1)); + BOOST_TEST_EQ(gcd_evaluator()(8, 9), static_cast(1)); + BOOST_TEST_EQ(gcd_evaluator()(7, 49), static_cast(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 d(0, ((std::numeric_limits::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( 1, -1), static_cast( 1) ); @@ -355,12 +431,33 @@ template< class T > void lcm_int_test() // signed_test_types BOOST_TEST_EQ( lcm( 3, 7), static_cast(21) ); BOOST_TEST_EQ( lcm( 8, 9), static_cast(72) ); BOOST_TEST_EQ( lcm( 7, 49), static_cast(49) ); + // Again with function object: + BOOST_TEST_EQ(lcm_evaluator()(1, -1), static_cast(1)); + BOOST_TEST_EQ(lcm_evaluator()(-1, 1), static_cast(1)); + BOOST_TEST_EQ(lcm_evaluator()(1, 1), static_cast(1)); + BOOST_TEST_EQ(lcm_evaluator()(-1, -1), static_cast(1)); + BOOST_TEST_EQ(lcm_evaluator()(0, 0), static_cast(0)); + BOOST_TEST_EQ(lcm_evaluator()(6, 0), static_cast(0)); + BOOST_TEST_EQ(lcm_evaluator()(0, 7), static_cast(0)); + BOOST_TEST_EQ(lcm_evaluator()(-5, 0), static_cast(0)); + BOOST_TEST_EQ(lcm_evaluator()(0, -4), static_cast(0)); + BOOST_TEST_EQ(lcm_evaluator()(18, 30), static_cast(90)); + BOOST_TEST_EQ(lcm_evaluator()(-6, 9), static_cast(18)); + BOOST_TEST_EQ(lcm_evaluator()(-10, -10), static_cast(10)); + BOOST_TEST_EQ(lcm_evaluator()(25, -10), static_cast(50)); + BOOST_TEST_EQ(lcm_evaluator()(3, 7), static_cast(21)); + BOOST_TEST_EQ(lcm_evaluator()(8, 9), static_cast(72)); + BOOST_TEST_EQ(lcm_evaluator()(7, 49), static_cast(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 void gcd_and_lcm_on_rationals() +{ + typedef boost::rational 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(); \ @@ -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(); } diff --git a/test/gcd_constexpr14_test.cpp b/test/gcd_constexpr14_test.cpp index 6e4bf30..05bef34 100644 --- a/test/gcd_constexpr14_test.cpp +++ b/test/gcd_constexpr14_test.cpp @@ -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(2), static_cast(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(2), static_cast(4))), "Expected a noexcept function."); -#endif - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(4))), "Expected a noexcept function."); - static_assert(noexcept(boost::integer::gcd(static_cast(2), static_cast(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 + + diff --git a/test/gcd_noexcept_test.cpp b/test/gcd_noexcept_test.cpp new file mode 100644 index 0000000..9100744 --- /dev/null +++ b/test/gcd_noexcept_test.cpp @@ -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 + +#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(a), static_cast(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(a), static_cast(b))), "Expected a noexcept function."); +#endif + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); + static_assert(noexcept(boost::integer::gcd(static_cast(a), static_cast(b))), "Expected a noexcept function."); +} + +#endif +#endif +