From 175a1caa584584fbb1ecebcb668f68616bb7aaed Mon Sep 17 00:00:00 2001 From: pabristow Date: Thu, 29 Jan 2015 11:53:02 +0000 Subject: [PATCH 01/33] Placed GCD and LCM typdefs and declarations in integer_fwd.hpp inside namespace boost::integer (was in boost::math) and checked that expected tests pass (and expected fails fail). (Major update to Boost.Integer docs available for review at https://dl.dropboxusercontent.com/u/43940943/modular-boost/libs/integer/index.html on branch doc-revision). --- include/boost/integer_fwd.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/integer_fwd.hpp b/include/boost/integer_fwd.hpp index 10577ae..18519dd 100644 --- a/include/boost/integer_fwd.hpp +++ b/include/boost/integer_fwd.hpp @@ -159,6 +159,8 @@ template #ifdef BOOST_NO_INTEGRAL_INT64_T @@ -180,6 +182,7 @@ template < typename IntegerType > template < typename IntegerType > class lcm_evaluator; +} // namespace integer } // namespace boost From 89cec128bd96150b50bb9c3921b0fb69cc10bf84 Mon Sep 17 00:00:00 2001 From: Kohei Takahashi Date: Sat, 30 Jul 2016 16:12:07 +0900 Subject: [PATCH 02/33] Fix compile error on GCC6 or later. Bitwise not yields integral promotion and to be signed type. --- include/boost/integer/integer_mask.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/integer/integer_mask.hpp b/include/boost/integer/integer_mask.hpp index 2acf7f7..2cc9a1d 100644 --- a/include/boost/integer/integer_mask.hpp +++ b/include/boost/integer/integer_mask.hpp @@ -63,7 +63,7 @@ struct low_bits_mask_t typedef typename uint_t::least least; typedef typename uint_t::fast fast; - BOOST_STATIC_CONSTANT( least, sig_bits = (~( ~(least( 0u )) << Bits )) ); + BOOST_STATIC_CONSTANT( least, sig_bits = (~(least(~(least( 0u ))) << Bits )) ); BOOST_STATIC_CONSTANT( fast, sig_bits_fast = fast(sig_bits) ); BOOST_STATIC_CONSTANT( std::size_t, bit_count = Bits ); From 13b153c657697129cabe7ac8b3e62ef844a62945 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Fri, 7 Oct 2016 23:07:34 -0500 Subject: [PATCH 03/33] Add, and update, documentation build targets. --- doc/Jamfile.v2 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 92609ff..22d3eca 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -53,4 +53,8 @@ boostbook standalone install pdfinstall : standalone/pdf : . PDF ; explicit pdfinstall ; - +############################################################################### +alias boostdoc ; +explicit boostdoc ; +alias boostrelease : standalone ; +explicit boostrelease ; From a52bae36394553e0240503da222c3317fc613f57 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Tue, 28 Mar 2017 18:57:50 +0100 Subject: [PATCH 04/33] Improve C++14 support: * Make functions constexpr. * Make functions noexcept where appropriate. * Add test case for the above. --- doc/gcd/math-gcd.qbk | 27 +++++--- doc/html/boost_integer/cstdint.html | 2 +- doc/html/boost_integer/history.html | 2 +- doc/html/boost_integer/integer.html | 4 +- doc/html/boost_integer/log2.html | 4 +- doc/html/boost_integer/mask.html | 4 +- doc/html/boost_integer/minmax.html | 4 +- doc/html/boost_integer/traits.html | 4 +- doc/html/index.html | 6 +- include/boost/integer/common_factor_rt.hpp | 81 ++++++++++++---------- 10 files changed, 77 insertions(+), 61 deletions(-) diff --git a/doc/gcd/math-gcd.qbk b/doc/gcd/math-gcd.qbk index 4d3edd6..346050c 100644 --- a/doc/gcd/math-gcd.qbk +++ b/doc/gcd/math-gcd.qbk @@ -24,9 +24,9 @@ programming problems. class lcm_evaluator; template < typename IntegerType > - IntegerType gcd( IntegerType const &a, IntegerType const &b ); + constexpr IntegerType gcd( IntegerType const &a, IntegerType const &b ); template < typename IntegerType > - IntegerType lcm( IntegerType const &a, IntegerType const &b ); + constexpr IntegerType lcm( IntegerType const &a, IntegerType const &b ); typedef ``['see-below]`` static_gcd_type; @@ -54,8 +54,9 @@ programming problems. typedef IntegerType second_argument_type; // Function object interface - result_type operator ()( first_argument_type const &a, - second_argument_type const &b ) const; + constexpr result_type operator ()( + first_argument_type const &a, + second_argument_type const &b ) const; }; The boost::math::gcd_evaluator class template defines a function object @@ -70,6 +71,9 @@ the GCD function template. If a numeric type wants to customize evaluations of its greatest common divisors, then the type should specialize on the gcd_evaluator class template. +Note that these function objects are `constexpr` in C++14 and later only. +They are also declared `noexcept` when appropriate. + [endsect] [section LCM Function Object] @@ -86,8 +90,9 @@ gcd_evaluator class template. typedef IntegerType second_argument_type; // Function object interface - result_type operator ()( first_argument_type const &a, - second_argument_type const &b ) const; + constexpr result_type operator ()( + first_argument_type const &a, + second_argument_type const &b ) const; }; The boost::math::lcm_evaluator class template defines a function object @@ -103,6 +108,9 @@ of the LCM function template. If a numeric type wants to customize evaluations of its least common multiples, then the type should specialize on the lcm_evaluator class template. +Note that these function objects are constexpr in C++14 and later only. +They are also declared `noexcept` when appropriate. + [endsect] [section:run_time Run-time GCD & LCM Determination] @@ -110,10 +118,10 @@ specialize on the lcm_evaluator class template. [*Header: ] [@../../../../boost/math/common_factor_rt.hpp ] template < typename IntegerType > - IntegerType boost::math::gcd( IntegerType const &a, IntegerType const &b ); + constexpr IntegerType boost::math::gcd( IntegerType const &a, IntegerType const &b ); template < typename IntegerType > - IntegerType boost::math::lcm( IntegerType const &a, IntegerType const &b ); + constexpr IntegerType boost::math::lcm( IntegerType const &a, IntegerType const &b ); The boost::math::gcd function template returns the greatest common (nonnegative) divisor of the two integers passed to it. @@ -124,6 +132,9 @@ IntegerType, which is also the return type. Internally, these function templates use an object of the corresponding version of the gcd_evaluator and lcm_evaluator class templates, respectively. +Note that these functions are constexpr in C++14 and later only. +They are also declared `noexcept` when appropriate. + [endsect] [section:compile_time Compile time GCD and LCM determination] diff --git a/doc/html/boost_integer/cstdint.html b/doc/html/boost_integer/cstdint.html index 2aeb66a..cb0223f 100644 --- a/doc/html/boost_integer/cstdint.html +++ b/doc/html/boost_integer/cstdint.html @@ -3,7 +3,7 @@ Removed from library: Standard Integer Types - + diff --git a/doc/html/boost_integer/history.html b/doc/html/boost_integer/history.html index 4248b7c..77257ba 100644 --- a/doc/html/boost_integer/history.html +++ b/doc/html/boost_integer/history.html @@ -3,7 +3,7 @@ History - + diff --git a/doc/html/boost_integer/integer.html b/doc/html/boost_integer/integer.html index 082e1d7..825ecf4 100644 --- a/doc/html/boost_integer/integer.html +++ b/doc/html/boost_integer/integer.html @@ -3,7 +3,7 @@ Integer Type Selection - + @@ -26,7 +26,7 @@ -
+
Synopsis
Easiest-to-Manipulate Types
diff --git a/doc/html/boost_integer/log2.html b/doc/html/boost_integer/log2.html index 2749cf2..19c1a21 100644 --- a/doc/html/boost_integer/log2.html +++ b/doc/html/boost_integer/log2.html @@ -3,7 +3,7 @@ Compile Time log2 Calculation - + @@ -26,7 +26,7 @@ -
+
Synopsis
Usage
Demonstration diff --git a/doc/html/boost_integer/mask.html b/doc/html/boost_integer/mask.html index 1cf8892..05c0f77 100644 --- a/doc/html/boost_integer/mask.html +++ b/doc/html/boost_integer/mask.html @@ -3,7 +3,7 @@ Integer Masks - + @@ -26,7 +26,7 @@ -
+
Overview
Synopsis
Single diff --git a/doc/html/boost_integer/minmax.html b/doc/html/boost_integer/minmax.html index 1fae3ad..d67425f 100644 --- a/doc/html/boost_integer/minmax.html +++ b/doc/html/boost_integer/minmax.html @@ -3,7 +3,7 @@ Compile time min/max calculation - + @@ -26,7 +26,7 @@ -
+
Synopsis
Usage
Example
diff --git a/doc/html/boost_integer/traits.html b/doc/html/boost_integer/traits.html index 90a5188..76987ad 100644 --- a/doc/html/boost_integer/traits.html +++ b/doc/html/boost_integer/traits.html @@ -3,7 +3,7 @@ Integer Traits - + @@ -26,7 +26,7 @@ -
+
Motivation
Synopsis
Description
diff --git a/doc/html/index.html b/doc/html/index.html index 2217d35..90fe0b7 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -3,7 +3,7 @@ Boost.Integer - + @@ -50,7 +50,7 @@

Table of Contents

-
+
Overview
Integer Traits
Integer Type Selection
@@ -219,7 +219,7 @@
- +

Last revised: June 01, 2014 at 19:57:36 GMT

Last revised: March 28, 2017 at 17:56:42 GMT


diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index c2b54db..64224e4 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -22,6 +22,10 @@ #include // for CHAR_MIN #include +#ifndef BOOST_NO_CXX11_NOEXCEPT +#include +#endif + #ifdef BOOST_MSVC #pragma warning(push) #pragma warning(disable:4127 4244) // Conditional expression is constant @@ -32,14 +36,15 @@ namespace boost namespace integer { +#define BOOST_INT_NOEXCEPT(T) BOOST_NOEXCEPT_IF(boost::is_arithmetic::value) // Forward declarations for function templates -----------------------------// template < typename IntegerType > - IntegerType gcd( IntegerType const &a, IntegerType const &b ); +BOOST_CXX14_CONSTEXPR IntegerType gcd( IntegerType const &a, IntegerType const &b )BOOST_INT_NOEXCEPT(IntegerType); template < typename IntegerType > - IntegerType lcm( IntegerType const &a, IntegerType const &b ); +BOOST_CXX14_CONSTEXPR IntegerType lcm( IntegerType const &a, IntegerType const &b )BOOST_INT_NOEXCEPT(IntegerType); // Greatest common divisor evaluator class declaration ---------------------// @@ -52,8 +57,8 @@ public: typedef IntegerType result_type, first_argument_type, second_argument_type; // Function object interface - result_type operator ()( first_argument_type const &a, - second_argument_type const &b ) const; + 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 @@ -68,8 +73,8 @@ public: typedef IntegerType result_type, first_argument_type, second_argument_type; // Function object interface - result_type operator ()( first_argument_type const &a, - second_argument_type const &b ) const; + 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 @@ -80,12 +85,12 @@ namespace detail { // Greatest common divisor for rings (including unsigned integers) template < typename RingType > - RingType + BOOST_CXX14_CONSTEXPR RingType gcd_euclidean ( RingType a, RingType b - ) + )BOOST_INT_NOEXCEPT(RingType) { // Avoid repeated construction #ifndef __BORLANDC__ @@ -110,12 +115,12 @@ namespace detail // Greatest common divisor for (signed) integers template < typename IntegerType > inline - IntegerType + 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 ); @@ -126,12 +131,12 @@ namespace detail // Greatest common divisor for unsigned binary integers template < typename BuiltInUnsigned > - BuiltInUnsigned + BOOST_CXX14_CONSTEXPR BuiltInUnsigned gcd_binary ( BuiltInUnsigned u, BuiltInUnsigned v - ) + )BOOST_INT_NOEXCEPT(BuiltInUnsigned) { if ( u && v ) { @@ -190,12 +195,12 @@ namespace detail // Least common multiple for rings (including unsigned integers) template < typename RingType > inline - RingType + 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 ); @@ -205,13 +210,13 @@ namespace detail // Least common multiple for (signed) integers template < typename IntegerType > - inline + 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 ); @@ -225,7 +230,7 @@ namespace detail template < typename T, bool IsSpecialized, bool IsSigned > struct gcd_optimal_evaluator_helper_t { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { return gcd_euclidean( a, b ); } @@ -234,7 +239,7 @@ namespace detail template < typename T > struct gcd_optimal_evaluator_helper_t< T, true, true > { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { return gcd_integer( a, b ); } @@ -243,7 +248,7 @@ namespace detail template < typename T > struct gcd_optimal_evaluator { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { typedef ::std::numeric_limits limits_type; @@ -259,7 +264,7 @@ namespace detail template < typename T > struct gcd_optimal_evaluator { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { return gcd_integer( a, b ); } @@ -269,7 +274,7 @@ namespace detail // Specialize for the built-in integers #define BOOST_PRIVATE_GCD_UF( Ut ) \ template < > struct gcd_optimal_evaluator \ - { Ut operator ()( Ut a, Ut b ) const { return gcd_binary( a, b ); } } + { 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 ); @@ -290,7 +295,7 @@ namespace detail #define BOOST_PRIVATE_GCD_SF( St, Ut ) \ template < > struct gcd_optimal_evaluator \ - { St operator ()( St a, St b ) const { Ut const a_abs = \ + { 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) ); } } @@ -316,7 +321,7 @@ namespace detail template < typename T, bool IsSpecialized, bool IsSigned > struct lcm_optimal_evaluator_helper_t { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { return lcm_euclidean( a, b ); } @@ -325,7 +330,7 @@ namespace detail template < typename T > struct lcm_optimal_evaluator_helper_t< T, true, true > { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { return lcm_integer( a, b ); } @@ -334,7 +339,7 @@ namespace detail template < typename T > struct lcm_optimal_evaluator { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { typedef ::std::numeric_limits limits_type; @@ -350,7 +355,7 @@ namespace detail template < typename T > struct lcm_optimal_evaluator { - T operator ()( T const &a, T const &b ) + BOOST_CXX14_CONSTEXPR T operator ()( T const &a, T const &b )BOOST_INT_NOEXCEPT(T) { return lcm_integer( a, b ); } @@ -359,13 +364,13 @@ namespace detail // Functions to find the GCD or LCM in the best way template < typename T > - inline + inline BOOST_CXX14_CONSTEXPR T gcd_optimal ( T const & a, T const & b - ) + )BOOST_INT_NOEXCEPT(T) { gcd_optimal_evaluator solver; @@ -373,13 +378,13 @@ namespace detail } template < typename T > - inline + inline BOOST_CXX14_CONSTEXPR T lcm_optimal ( T const & a, T const & b - ) + )BOOST_INT_NOEXCEPT(T) { lcm_optimal_evaluator solver; @@ -392,13 +397,13 @@ namespace detail // Greatest common divisor evaluator member function definition ------------// template < typename IntegerType > -inline +inline BOOST_CXX14_CONSTEXPR typename gcd_evaluator::result_type gcd_evaluator::operator () ( first_argument_type const & a, second_argument_type const & b -) const +) const BOOST_INT_NOEXCEPT(IntegerType) { return detail::gcd_optimal( a, b ); } @@ -407,13 +412,13 @@ gcd_evaluator::operator () // Least common multiple evaluator member function definition --------------// template < typename IntegerType > -inline +inline BOOST_CXX14_CONSTEXPR typename lcm_evaluator::result_type lcm_evaluator::operator () ( first_argument_type const & a, second_argument_type const & b -) const +) const BOOST_INT_NOEXCEPT(IntegerType) { return detail::lcm_optimal( a, b ); } @@ -422,13 +427,13 @@ lcm_evaluator::operator () // Greatest common divisor and least common multiple function definitions --// template < typename IntegerType > -inline +inline BOOST_CXX14_CONSTEXPR IntegerType gcd ( IntegerType const & a, IntegerType const & b -) +) BOOST_INT_NOEXCEPT(IntegerType) { gcd_evaluator solver; @@ -436,13 +441,13 @@ gcd } template < typename IntegerType > -inline +inline BOOST_CXX14_CONSTEXPR IntegerType lcm ( IntegerType const & a, IntegerType const & b -) +) BOOST_INT_NOEXCEPT(IntegerType) { lcm_evaluator solver; From 13b36d84325fcad9987161fc7482fbe804b003af Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Tue, 28 Mar 2017 19:06:13 +0100 Subject: [PATCH 05/33] Add tests for C++14 support. --- test/Jamfile.v2 | 1 + test/gcd_constexpr14_test.cpp | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 test/gcd_constexpr14_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e3b5be1..ea29336 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -19,6 +19,7 @@ test-suite integer [ compile static_log2_include_test.cpp ] [ compile static_min_max_include_test.cpp ] [ compile integer_fwd_include_test.cpp ] + [ compile gcd_constexpr14_test.cpp ] [ compile-fail fail_int_exact.cpp ] [ compile-fail fail_int_fast.cpp ] [ compile-fail fail_int_least.cpp ] diff --git a/test/gcd_constexpr14_test.cpp b/test/gcd_constexpr14_test.cpp new file mode 100644 index 0000000..e915ce8 --- /dev/null +++ b/test/gcd_constexpr14_test.cpp @@ -0,0 +1,42 @@ + +// (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 + +#ifndef BOOST_NO_CXX14_CONSTEXPR + +void test_constexpr() +{ + constexpr const boost::int64_t i = 347 * 463 * 727; + constexpr const boost::int64_t j = 191 * 347 * 281; + + constexpr const boost::int64_t k = boost::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."); +} + +#endif + +#ifndef BOOST_NO_CXX11_NOEXCEPT + +void test_noexcept() +{ + 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."); + 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."); +} + +#endif From 39d97018573fa1d3a90d9b1e8408b882d30faf87 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Tue, 28 Mar 2017 19:30:48 +0100 Subject: [PATCH 06/33] Enable one more noexcept test --- test/gcd_constexpr14_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gcd_constexpr14_test.cpp b/test/gcd_constexpr14_test.cpp index e915ce8..943af8c 100644 --- a/test/gcd_constexpr14_test.cpp +++ b/test/gcd_constexpr14_test.cpp @@ -27,7 +27,7 @@ void test_constexpr() void test_noexcept() { 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."); From f650385f6568ea4168ae7036bb514d287cd97b97 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Thu, 30 Mar 2017 18:50:57 +0100 Subject: [PATCH 07/33] Disable test case that causes msvc internal error. --- test/gcd_constexpr14_test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/gcd_constexpr14_test.cpp b/test/gcd_constexpr14_test.cpp index 943af8c..6e4bf30 100644 --- a/test/gcd_constexpr14_test.cpp +++ b/test/gcd_constexpr14_test.cpp @@ -27,7 +27,10 @@ void test_constexpr() void test_noexcept() { 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."); From 162e48d14ad118298de1e1e958c214d0c5403481 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Fri, 31 Mar 2017 18:34:14 +0100 Subject: [PATCH 08/33] Remove dependency to mpl and type_traits. --- include/boost/integer/common_factor_rt.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index 64224e4..6d035b0 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -22,8 +22,11 @@ #include // for CHAR_MIN #include -#ifndef BOOST_NO_CXX11_NOEXCEPT -#include +#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) #endif #ifdef BOOST_MSVC @@ -36,8 +39,6 @@ namespace boost namespace integer { -#define BOOST_INT_NOEXCEPT(T) BOOST_NOEXCEPT_IF(boost::is_arithmetic::value) - // Forward declarations for function templates -----------------------------// template < typename IntegerType > From beb68718640150f67fe5671bbbb7848d9e7170b8 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sun, 23 Apr 2017 13:01:09 +0100 Subject: [PATCH 09/33] 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. --- include/boost/integer/common_factor_rt.hpp | 955 ++++++++++++--------- test/Jamfile.v2 | 1 + test/common_factor_test.cpp | 199 ++++- test/gcd_constexpr14_test.cpp | 65 +- test/gcd_noexcept_test.cpp | 35 + 5 files changed, 773 insertions(+), 482 deletions(-) create mode 100644 test/gcd_noexcept_test.cpp 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 + From efb84707f04f154d2cf391f7149c371bedee1c9c Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 24 Apr 2017 13:01:57 +0100 Subject: [PATCH 10/33] Update docs to match new gcd/lcm code. --- doc/gcd/math-gcd.qbk | 44 +++- doc/html/boost_integer/gcd_lcm.html | 395 ++++++++++++++++++++++++++++ doc/html/boost_integer/integer.html | 6 +- doc/html/boost_integer/mask.html | 6 +- doc/html/index.html | 25 +- doc/integer.qbk | 6 + 6 files changed, 469 insertions(+), 13 deletions(-) create mode 100644 doc/html/boost_integer/gcd_lcm.html diff --git a/doc/gcd/math-gcd.qbk b/doc/gcd/math-gcd.qbk index 346050c..7b9b312 100644 --- a/doc/gcd/math-gcd.qbk +++ b/doc/gcd/math-gcd.qbk @@ -1,5 +1,5 @@ -[mathpart gcd_lcm Integer Utilities (Greatest Common Divisor and Least Common Multiple)] +[section:gcd_lcm Greatest Common Divisor and Least Common Multiple] [section Introduction] @@ -27,6 +27,17 @@ programming problems. constexpr IntegerType gcd( IntegerType const &a, IntegerType const &b ); template < typename IntegerType > constexpr IntegerType lcm( IntegerType const &a, IntegerType const &b ); + template < typename IntegerType, typename... Args > + constexpr IntegerType gcd( IntegerType const &a, IntegerType const &b, Args const&... ); + template < typename IntegerType, typename... Args > + constexpr IntegerType lcm( IntegerType const &a, IntegerType const &b, Args const&... ); + + template + std::pair::value_type, I> + gcd_range(I first, I last); + template + std::pair::value_type, I> + lcm_range(I first, I last); typedef ``['see-below]`` static_gcd_type; @@ -123,14 +134,33 @@ They are also declared `noexcept` when appropriate. template < typename IntegerType > constexpr IntegerType boost::math::lcm( IntegerType const &a, IntegerType const &b ); + template < typename IntegerType, typename... Args > + constexpr IntegerType gcd( IntegerType const &a, IntegerType const &b, Args const&... ); + + template < typename IntegerType, typename... Args > + constexpr IntegerType lcm( IntegerType const &a, IntegerType const &b, Args const&... ); + + template + std::pair::value_type, I> + gcd_range(I first, I last); + + template + std::pair::value_type, I> + lcm_range(I first, I last); + The boost::math::gcd function template returns the greatest common (nonnegative) divisor of the two integers passed to it. +`boost::math::gcd_range` is the iteration of the above gcd algorithm over a +range, returning the greatest common divisor of all the elements. The algorithm +terminates when the gcd reaches unity or the end of the range. Thus it also +returns the iterator after the last element inspected because this may not be +equal to the end of the range. The variadic version of `gcd` behaves similarly +but does not indicate which input value caused the gcd to reach unity. + The boost::math::lcm function template returns the least common (nonnegative) multiple of the two integers passed to it. -The function templates are parameterized on the function arguments' -IntegerType, which is also the return type. Internally, these function -templates use an object of the corresponding version of the -gcd_evaluator and lcm_evaluator class templates, respectively. +As with gcd, there are range and variadic versions of the function for +more than 2 arguments. Note that these functions are constexpr in C++14 and later only. They are also declared `noexcept` when appropriate. @@ -139,6 +169,8 @@ They are also declared `noexcept` when appropriate. [section:compile_time Compile time GCD and LCM determination] +[note These functions are deprecated in favor of constexpr `gcd` and `lcm` on C++14 capable compilers.] + [*Header: ] [@../../../../boost/math/common_factor_ct.hpp ] typedef ``['unspecified]`` static_gcd_type; @@ -246,7 +278,7 @@ pool library. The code had updates by Helmut Zeisel. [endsect] -[endmathpart] +[endsect] [/ Copyright 2005, 2013 Daryle Walker. diff --git a/doc/html/boost_integer/gcd_lcm.html b/doc/html/boost_integer/gcd_lcm.html new file mode 100644 index 0000000..25aaa55 --- /dev/null +++ b/doc/html/boost_integer/gcd_lcm.html @@ -0,0 +1,395 @@ + + + +Greatest Common Divisor and Least Common Multiple + + + + + + + + + + + + + + + +
Boost C++ LibrariesHomeLibrariesPeopleFAQMore
+
+
+PrevUpHomeNext +
+
+ + +
+ +

+ The class and function templates in <boost/math/common_factor.hpp> + provide run-time and compile-time evaluation of the greatest common divisor + (GCD) or least common multiple (LCM) of two integers. These facilities are + useful for many numeric-oriented generic programming problems. +

+
+
+ +
namespace boost
+{
+namespace math
+{
+
+template < typename IntegerType >
+   class gcd_evaluator;
+template < typename IntegerType >
+   class lcm_evaluator;
+
+template < typename IntegerType >
+   constexpr IntegerType  gcd( IntegerType const &a, IntegerType const &b );
+template < typename IntegerType >
+   constexpr IntegerType  lcm( IntegerType const &a, IntegerType const &b );
+template < typename IntegerType, typename... Args >
+   constexpr IntegerType  gcd( IntegerType const &a, IntegerType const &b, Args const&... );
+template < typename IntegerType, typename... Args >
+   constexpr IntegerType  lcm( IntegerType const &a, IntegerType const &b, Args const&... );
+
+template <typename I>
+std::pair<typename std::iterator_traits<I>::value_type, I>
+   gcd_range(I first, I last);
+template <typename I>
+std::pair<typename std::iterator_traits<I>::value_type, I>
+   lcm_range(I first, I last);
+
+typedef see-below static_gcd_type;
+
+template < static_gcd_type Value1, static_gcd_type Value2 >
+   struct static_gcd;
+template < static_gcd_type Value1, static_gcd_type Value2 >
+   struct static_lcm;
+
+}
+}
+
+
+
+ +

+ Header: <boost/math/common_factor_rt.hpp> +

+
template < typename IntegerType >
+class boost::math::gcd_evaluator
+{
+public:
+   // Types
+   typedef IntegerType  result_type;
+   typedef IntegerType  first_argument_type;
+   typedef IntegerType  second_argument_type;
+
+   // Function object interface
+   constexpr result_type  operator ()(
+      first_argument_type const &a,
+      second_argument_type const &b ) const;
+};
+
+

+ The boost::math::gcd_evaluator class template defines a function object class + to return the greatest common divisor of two integers. The template is parameterized + by a single type, called IntegerType here. This type should be a numeric + type that represents integers. The result of the function object is always + nonnegative, even if either of the operator arguments is negative. +

+

+ This function object class template is used in the corresponding version + of the GCD function template. If a numeric type wants to customize evaluations + of its greatest common divisors, then the type should specialize on the gcd_evaluator + class template. +

+

+ Note that these function objects are constexpr + in C++14 and later only. They are also declared noexcept + when appropriate. +

+
+
+ +

+ Header: <boost/math/common_factor_rt.hpp> +

+
template < typename IntegerType >
+class boost::math::lcm_evaluator
+{
+public:
+   // Types
+   typedef IntegerType  result_type;
+   typedef IntegerType  first_argument_type;
+   typedef IntegerType  second_argument_type;
+
+   // Function object interface
+   constexpr result_type  operator ()(
+     first_argument_type const &a,
+     second_argument_type const &b ) const;
+};
+
+

+ The boost::math::lcm_evaluator class template defines a function object class + to return the least common multiple of two integers. The template is parameterized + by a single type, called IntegerType here. This type should be a numeric + type that represents integers. The result of the function object is always + nonnegative, even if either of the operator arguments is negative. If the + least common multiple is beyond the range of the integer type, the results + are undefined. +

+

+ This function object class template is used in the corresponding version + of the LCM function template. If a numeric type wants to customize evaluations + of its least common multiples, then the type should specialize on the lcm_evaluator + class template. +

+

+ Note that these function objects are constexpr in C++14 and later only. They + are also declared noexcept when + appropriate. +

+
+
+ +

+ Header: <boost/math/common_factor_rt.hpp> +

+
template < typename IntegerType >
+constexpr IntegerType  boost::math::gcd( IntegerType const &a, IntegerType const &b );
+
+template < typename IntegerType >
+constexpr IntegerType  boost::math::lcm( IntegerType const &a, IntegerType const &b );
+
+template < typename IntegerType, typename... Args >
+   constexpr IntegerType  gcd( IntegerType const &a, IntegerType const &b, Args const&... );
+
+template < typename IntegerType, typename... Args >
+   constexpr IntegerType  lcm( IntegerType const &a, IntegerType const &b, Args const&... );
+
+template <typename I>
+std::pair<typename std::iterator_traits<I>::value_type, I>
+   gcd_range(I first, I last);
+
+template <typename I>
+std::pair<typename std::iterator_traits<I>::value_type, I>
+   lcm_range(I first, I last);
+
+

+ The boost::math::gcd function template returns the greatest common (nonnegative) + divisor of the two integers passed to it. boost::math::gcd_range + is the iteration of the above gcd algorithm over a range, returning the greatest + common divisor of all the elements. The algorithm terminates when the gcd + reaches unity or the end of the range. Thus it also returns the iterator + after the last element inspected because this may not be equal to the end + of the range. The variadic version of gcd + behaves similarly but does not indicate which input value caused the gcd + to reach unity. +

+

+ The boost::math::lcm function template returns the least common (nonnegative) + multiple of the two integers passed to it. As with gcd, there are range and + variadic versions of the function for more than 2 arguments. +

+

+ Note that these functions are constexpr in C++14 and later only. They are + also declared noexcept when + appropriate. +

+
+
+ +
+ + + + + +
[Note]Note

+ These functions are deprecated in favor of constexpr gcd + and lcm on C++14 capable + compilers. +

+

+ Header: <boost/math/common_factor_ct.hpp> +

+
typedef unspecified static_gcd_type;
+
+template < static_gcd_type Value1, static_gcd_type Value2 >
+struct boost::math::static_gcd : public mpl::integral_c<static_gcd_type, implementation_defined>
+{
+};
+
+template < static_gcd_type Value1, static_gcd_type Value2 >
+struct boost::math::static_lcm : public mpl::integral_c<static_gcd_type, implementation_defined>
+{
+};
+
+

+ The type static_gcd_type + is the widest unsigned-integer-type that is supported for use in integral-constant-expressions + by the compiler. Usually this the same type as boost::uintmax_t, + but may fall back to being unsigned + long for some older compilers. +

+

+ The boost::math::static_gcd and boost::math::static_lcm class templates take + two value-based template parameters of the static_gcd_type + type and inherit from the type boost::mpl::integral_c. Inherited from the base class, + they have a member value that is the greatest common + factor or least common multiple, respectively, of the template arguments. + A compile-time error will occur if the least common multiple is beyond the + range of static_gcd_type. +

+

+ + Example +

+
#include <boost/math/common_factor.hpp>
+#include <algorithm>
+#include <iterator>
+#include <iostream>
+
+int main()
+{
+   using std::cout;
+   using std::endl;
+
+   cout << "The GCD and LCM of 6 and 15 are "
+   << boost::math::gcd(6, 15) << " and "
+   << boost::math::lcm(6, 15) << ", respectively."
+   << endl;
+
+   cout << "The GCD and LCM of 8 and 9 are "
+   << boost::math::static_gcd<8, 9>::value
+   << " and "
+   << boost::math::static_lcm<8, 9>::value
+   << ", respectively." << endl;
+
+   int  a[] = { 4, 5, 6 }, b[] = { 7, 8, 9 }, c[3];
+   std::transform( a, a + 3, b, c, boost::math::gcd_evaluator<int>() );
+   std::copy( c, c + 3, std::ostream_iterator<int>(cout, " ") );
+}
+
+
+
+ +

+ This header simply includes the headers <boost/math/common_factor_ct.hpp> + and <boost/math/common_factor_rt.hpp>. +

+

+ Note this is a legacy header: it used to contain the actual implementation, + but the compile-time and run-time facilities were moved to separate headers + (since they were independent of each other). +

+
+
+ +

+ The program common_factor_test.cpp + is a demonstration of the results from instantiating various examples of + the run-time GCD and LCM function templates and the compile-time GCD and + LCM class templates. (The run-time GCD and LCM class templates are tested + indirectly through the run-time function templates.) +

+
+
+ +

+ The greatest common divisor and least common multiple functions are greatly + used in some numeric contexts, including some of the other Boost libraries. + Centralizing these functions to one header improves code factoring and eases + maintainence. +

+
+
+ +
    +
  • + 13 May 2013 Moved into main Boost.Math Quickbook documentation. +
  • +
  • + 17 Dec 2005: Converted documentation to Quickbook Format. +
  • +
  • + 2 Jul 2002: Compile-time and run-time items separated to new headers. +
  • +
  • + 7 Nov 2001: Initial version +
  • +
+
+
+ +

+ The author of the Boost compilation of GCD and LCM computations is Daryle + Walker. The code was prompted by existing code hiding in the implementations + of Paul Moore's rational library and Steve Cleary's pool library. The code + had updates by Helmut Zeisel. +

+
+
+ + + +
+
+
+PrevUpHomeNext +
+ + diff --git a/doc/html/boost_integer/integer.html b/doc/html/boost_integer/integer.html index 825ecf4..6dc60ef 100644 --- a/doc/html/boost_integer/integer.html +++ b/doc/html/boost_integer/integer.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@

-PrevUpHomeNext +PrevUpHomeNext

@@ -426,7 +426,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/boost_integer/mask.html b/doc/html/boost_integer/mask.html index 05c0f77..0d72e1e 100644 --- a/doc/html/boost_integer/mask.html +++ b/doc/html/boost_integer/mask.html @@ -6,7 +6,7 @@ - + @@ -20,7 +20,7 @@
-PrevUpHomeNext +PrevUpHomeNext

@@ -374,7 +374,7 @@
-PrevUpHomeNext +PrevUpHomeNext
diff --git a/doc/html/index.html b/doc/html/index.html index 90fe0b7..65dbc1c 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -54,6 +54,8 @@
Overview
Integer Traits
Integer Type Selection
+
Greatest Common Divisor and Least + Common Multiple
Integer Masks
Compile Time log2 Calculation
Compile time min/max calculation
@@ -158,6 +160,27 @@ + +

+ Greatest Common Divisor and + Least Common Multiple. +

+ + +

+ <boost/integer/common_factor_rt.hpp> + and <boost/integer/common_factor_ct.hpp> +

+ + +

+ Functions gcd and + lcm plus function + objects and compile time versions. +

+ + +

Integer Masks. @@ -219,7 +242,7 @@

- +

Last revised: March 28, 2017 at 17:56:42 GMT

Last revised: April 24, 2017 at 12:00:17 GMT


diff --git a/doc/integer.qbk b/doc/integer.qbk index 6beb0f4..75042f2 100644 --- a/doc/integer.qbk +++ b/doc/integer.qbk @@ -42,6 +42,11 @@ compile-time value; and computing min and max of constant expressions. Use to select the type of an integer when some property such as maximum value or number of bits is known. Useful for generic programming. ] ] + [ + [[link boost_integer.gcd_lcm Greatest Common Divisor and Least Common Multiple].] + [[^[@../../../../boost/integer/common_factor_rt.hpp ]] and [^[@../../../../boost/integer/common_factor_ct.hpp ]]] + [Functions `gcd` and `lcm` plus function objects and compile time versions.] + ] [ [[link boost_integer.mask Integer Masks].] [[^[@../../../../boost/integer/integer_mask.hpp ]]] @@ -358,6 +363,7 @@ for sharing their designs for similar templates. [endsect] [endsect] +[include gcd/math-gcd.qbk] [section:mask Integer Masks] From f5eff7d83dea410ba04f2a1ba3fb7f5e26be9a7c Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 24 Apr 2017 18:13:56 +0100 Subject: [PATCH 11/33] MSVC-8 has no . --- include/boost/integer/common_factor_rt.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index c52067d..d86155d 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -21,7 +21,7 @@ #include #endif -#if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64)) +#if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64)) #include #endif @@ -165,7 +165,7 @@ namespace boost { // 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)) +#if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (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 From 58d53beae412fa1c4b511d527cc5c587d7b82786 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 24 Apr 2017 18:18:36 +0100 Subject: [PATCH 12/33] Add missing #include for older compilers. --- include/boost/integer/common_factor_rt.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index d86155d..d27f094 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -20,6 +20,9 @@ #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS #include #endif +#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL +#include +#endif #if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64)) #include From b2dcad8daf3748317c8f6b9337965303575462c7 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 24 Apr 2017 20:49:14 +0300 Subject: [PATCH 13/33] Add .travis.yml --- .travis.yml | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..24b872e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,328 @@ +# Copyright 2016, 2017 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +language: cpp + +sudo: false + +python: "2.7" + +os: + - linux + - osx + +branches: + only: + - master + - develop + +env: + matrix: + - BOGUS_JOB=true + +matrix: + + exclude: + - env: BOGUS_JOB=true + + include: + - os: linux + env: TOOLSET=gcc COMPILER=g++ CXXSTD=c++03 + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=c++03 + addons: + apt: + packages: + - g++-4.7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=c++11 + addons: + apt: + packages: + - g++-4.7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=c++03 + addons: + apt: + packages: + - g++-4.8 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=c++11 + addons: + apt: + packages: + - g++-4.8 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=c++03 + addons: + apt: + packages: + - g++-4.9 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=c++11 + addons: + apt: + packages: + - g++-4.9 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=c++03 + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=c++11 + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=c++14 + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=c++03 + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=c++11 + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=c++14 + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=c++1z + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++03 + + - os: linux + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++11 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=c++03 + addons: + apt: + packages: + - clang-3.5 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=c++11 + addons: + apt: + packages: + - clang-3.5 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=c++03 + addons: + apt: + packages: + - clang-3.6 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=c++11 + addons: + apt: + packages: + - clang-3.6 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=c++03 + addons: + apt: + packages: + - clang-3.7 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=c++11 + addons: + apt: + packages: + - clang-3.7 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=c++03 + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=c++11 + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=c++1z + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=c++03 + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=c++11 + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=c++14 + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=c++1z + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++03 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++11 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++14 + + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=c++1z + +install: + - cd .. + - git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init libs/assert + - git submodule update --init libs/core + - git submodule update --init libs/static_assert + - cp -r $TRAVIS_BUILD_DIR/* libs/integer + - ./bootstrap.sh + - ./b2 headers + +script: + - |- + echo "using $TOOLSET : : $COMPILER : -std=$CXXSTD ;" > ~/user-config.jam + - ./b2 libs/integer/test toolset=$TOOLSET + +notifications: + email: + on_success: always From 3e43dd6fc2dd2bf2cf58f7f144e5eee96b3edea5 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 24 Apr 2017 18:50:19 +0100 Subject: [PATCH 14/33] Update history. --- doc/gcd/math-gcd.qbk | 2 ++ doc/html/boost_integer/gcd_lcm.html | 5 +++++ doc/html/index.html | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/gcd/math-gcd.qbk b/doc/gcd/math-gcd.qbk index 7b9b312..23472de 100644 --- a/doc/gcd/math-gcd.qbk +++ b/doc/gcd/math-gcd.qbk @@ -262,6 +262,8 @@ code factoring and eases maintainence. [section:gcd_history History] +* 24th April 2017 Moved to Jeremy Murphy's improved algorithms, added constexpr and noexcept support, +added compiler intrinsic support, added variadic and range based versions of the algorithms. * 13 May 2013 Moved into main Boost.Math Quickbook documentation. * 17 Dec 2005: Converted documentation to Quickbook Format. * 2 Jul 2002: Compile-time and run-time items separated to new headers. diff --git a/doc/html/boost_integer/gcd_lcm.html b/doc/html/boost_integer/gcd_lcm.html index 25aaa55..097afc0 100644 --- a/doc/html/boost_integer/gcd_lcm.html +++ b/doc/html/boost_integer/gcd_lcm.html @@ -352,6 +352,11 @@ History

    +
  • + 24th April 2017 Moved to Jeremy Murphy's improved algorithms, added constexpr + and noexcept support, added compiler intrinsic support, added variadic + and range based versions of the algorithms. +
  • 13 May 2013 Moved into main Boost.Math Quickbook documentation.
  • diff --git a/doc/html/index.html b/doc/html/index.html index 65dbc1c..040ad3e 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -242,7 +242,7 @@
- +

Last revised: April 24, 2017 at 12:00:17 GMT

Last revised: April 24, 2017 at 17:49:59 GMT


From 55e81c5ba796519162b585ef21162bde1bb6a9dd Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 24 Apr 2017 21:07:48 +0300 Subject: [PATCH 15/33] Fetch test dependencies in .travis.yml --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 24b872e..16cb4ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -311,10 +311,9 @@ install: - cd boost-root - git submodule update --init tools/build - git submodule update --init libs/config - - git submodule update --init libs/assert - - git submodule update --init libs/core - - git submodule update --init libs/static_assert + - git submodule update --init tools/boostdep - cp -r $TRAVIS_BUILD_DIR/* libs/integer + - python tools/boostdep/depinst/depinst.py integer - ./bootstrap.sh - ./b2 headers From 4991d82385c9cb215ce5230c90b452a8b7f31d91 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Mon, 24 Apr 2017 19:19:48 +0100 Subject: [PATCH 16/33] Need to take abs of return value in short-circuit gcd code. --- include/boost/integer/common_factor_rt.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index d27f094..2f65d67 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -447,9 +447,9 @@ template inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer) { if(a == (std::numeric_limits::min)()) - return a == static_cast(0) ? b : gcd(static_cast(a % b), b); + return a == static_cast(0) ? gcd_detail::gcd_traits::abs(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 b == static_cast(0) ? gcd_detail::gcd_traits::abs(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))); } From 240b96ddecc41795aa51792433c585a800ef59f3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 25 Apr 2017 17:26:57 +0300 Subject: [PATCH 17/33] Add appveyor.yml --- appveyor.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..1f4b748 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,29 @@ +# Copyright 2016 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + +install: + - cd .. + - git clone -b %APPVEYOR_REPO_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init tools/boostdep + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\integer + - python tools/boostdep/depinst/depinst.py integer + - bootstrap + - b2 headers + +build: off + +test_script: + - b2 libs/integer/test toolset=msvc-9.0,msvc-10.0,msvc-11.0,msvc-14.0 From 395735a1935b7293ac812ba4f13392a6bd3b0649 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 26 Apr 2017 18:24:09 +0100 Subject: [PATCH 18/33] Add tests for multiprecision types and fix test program to still compile. --- test/common_factor_test.cpp | 135 ++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 9457e1a..4a39cb8 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -276,22 +276,22 @@ template< class T > void gcd_int_test() // signed_test_types #endif // Originally from Boost.Rational tests - BOOST_TEST_EQ( gcd( 1, -1), static_cast( 1) ); - BOOST_TEST_EQ( gcd( -1, 1), static_cast( 1) ); - BOOST_TEST_EQ( gcd( 1, 1), static_cast( 1) ); - BOOST_TEST_EQ( gcd( -1, -1), static_cast( 1) ); - BOOST_TEST_EQ( gcd( 0, 0), static_cast( 0) ); - BOOST_TEST_EQ( gcd( 7, 0), static_cast( 7) ); - BOOST_TEST_EQ( gcd( 0, 9), static_cast( 9) ); - BOOST_TEST_EQ( gcd( -7, 0), static_cast( 7) ); - BOOST_TEST_EQ( gcd( 0, -9), static_cast( 9) ); - BOOST_TEST_EQ( gcd( 42, 30), static_cast( 6) ); - BOOST_TEST_EQ( gcd( 6, -9), static_cast( 3) ); - BOOST_TEST_EQ( gcd(-10, -10), static_cast(10) ); - BOOST_TEST_EQ( gcd(-25, -10), static_cast( 5) ); - 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) ); + BOOST_TEST_EQ( gcd(static_cast(1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( gcd(static_cast(-1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( gcd(static_cast(1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( gcd(static_cast(-1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( gcd(static_cast(0), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( gcd(static_cast(7), static_cast(0)), static_cast( 7) ); + BOOST_TEST_EQ( gcd(static_cast(0), static_cast(9)), static_cast( 9) ); + BOOST_TEST_EQ( gcd(static_cast(-7), static_cast(0)), static_cast( 7) ); + BOOST_TEST_EQ( gcd(static_cast(0), static_cast(-9)), static_cast( 9) ); + BOOST_TEST_EQ( gcd(static_cast(42), static_cast(30)), static_cast( 6) ); + BOOST_TEST_EQ( gcd(static_cast(6), static_cast(-9)), static_cast( 3) ); + BOOST_TEST_EQ( gcd(static_cast(-10), static_cast(-10)), static_cast(10) ); + BOOST_TEST_EQ( gcd(static_cast(-25), static_cast(-10)), static_cast( 5) ); + BOOST_TEST_EQ( gcd(static_cast(3), static_cast(7)), static_cast( 1) ); + BOOST_TEST_EQ( gcd(static_cast(8), static_cast(9)), static_cast( 1) ); + BOOST_TEST_EQ( gcd(static_cast(7), static_cast(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)); @@ -324,22 +324,22 @@ void gcd_unmarked_int_test() // then does an absolute-value on the result. Signed types that are not // marked as such (due to no std::numeric_limits specialization) may be off // by a sign. - BOOST_TEST_EQ( abs(gcd( 1, -1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd( -1, 1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd( 1, 1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd( -1, -1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd( 0, 0 )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(gcd( 7, 0 )), MyInt2( 7) ); - BOOST_TEST_EQ( abs(gcd( 0, 9 )), MyInt2( 9) ); - BOOST_TEST_EQ( abs(gcd( -7, 0 )), MyInt2( 7) ); - BOOST_TEST_EQ( abs(gcd( 0, -9 )), MyInt2( 9) ); - BOOST_TEST_EQ( abs(gcd( 42, 30 )), MyInt2( 6) ); - BOOST_TEST_EQ( abs(gcd( 6, -9 )), MyInt2( 3) ); - BOOST_TEST_EQ( abs(gcd( -10, -10 )), MyInt2(10) ); - BOOST_TEST_EQ( abs(gcd( -25, -10 )), MyInt2( 5) ); - BOOST_TEST_EQ( abs(gcd( 3, 7 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd( 8, 9 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd( 7, 49 )), MyInt2( 7) ); + BOOST_TEST_EQ( abs(gcd(static_cast(1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(gcd(static_cast(-1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(gcd(static_cast(1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(gcd(static_cast(-1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(gcd(static_cast(0), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(gcd(static_cast(7), static_cast(0) )), MyInt2( 7) ); + BOOST_TEST_EQ( abs(gcd(static_cast(0), static_cast(9) )), MyInt2( 9) ); + BOOST_TEST_EQ( abs(gcd(static_cast(-7), static_cast(0) )), MyInt2( 7) ); + BOOST_TEST_EQ( abs(gcd(static_cast(0), static_cast(-9) )), MyInt2( 9) ); + BOOST_TEST_EQ( abs(gcd(static_cast(42), static_cast(30))), MyInt2( 6) ); + BOOST_TEST_EQ( abs(gcd(static_cast(6), static_cast(-9) )), MyInt2( 3) ); + BOOST_TEST_EQ( abs(gcd(static_cast(-10), static_cast(-10) )), MyInt2(10) ); + BOOST_TEST_EQ( abs(gcd(static_cast(-25), static_cast(-10) )), MyInt2( 5) ); + BOOST_TEST_EQ( abs(gcd(static_cast(3), static_cast(7) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(gcd(static_cast(8), static_cast(9) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(gcd(static_cast(7), static_cast(49) )), MyInt2( 7) ); } // GCD on unsigned integer types @@ -353,14 +353,14 @@ template< class T > void gcd_unsigned_test() // unsigned_test_types // Note that unmarked types (i.e. have no std::numeric_limits // specialization) are treated like non/unsigned types - BOOST_TEST_EQ( gcd( 1u, 1u), static_cast( 1u) ); - BOOST_TEST_EQ( gcd( 0u, 0u), static_cast( 0u) ); - BOOST_TEST_EQ( gcd( 7u, 0u), static_cast( 7u) ); - BOOST_TEST_EQ( gcd( 0u, 9u), static_cast( 9u) ); - BOOST_TEST_EQ( gcd(42u, 30u), static_cast( 6u) ); - BOOST_TEST_EQ( gcd( 3u, 7u), static_cast( 1u) ); - BOOST_TEST_EQ( gcd( 8u, 9u), static_cast( 1u) ); - BOOST_TEST_EQ( gcd( 7u, 49u), static_cast( 7u) ); + BOOST_TEST_EQ( gcd(static_cast(1u), static_cast(1u)), static_cast( 1u) ); + BOOST_TEST_EQ( gcd(static_cast(0u), static_cast(0u)), static_cast( 0u) ); + BOOST_TEST_EQ( gcd(static_cast(7u), static_cast(0u)), static_cast( 7u) ); + BOOST_TEST_EQ( gcd(static_cast(0u), static_cast(9u)), static_cast( 9u) ); + BOOST_TEST_EQ( gcd(static_cast(42u), static_cast(30u)), static_cast( 6u) ); + BOOST_TEST_EQ( gcd(static_cast(3u), static_cast(7u)), static_cast( 1u) ); + BOOST_TEST_EQ( gcd(static_cast(8u), static_cast(9u)), static_cast( 1u) ); + BOOST_TEST_EQ( gcd(static_cast(7u), static_cast(49u)), static_cast( 7u) ); } // GCD at compile-time @@ -415,22 +415,22 @@ template< class T > void lcm_int_test() // signed_test_types #endif // Originally from Boost.Rational tests - BOOST_TEST_EQ( lcm( 1, -1), static_cast( 1) ); - BOOST_TEST_EQ( lcm( -1, 1), static_cast( 1) ); - BOOST_TEST_EQ( lcm( 1, 1), static_cast( 1) ); - BOOST_TEST_EQ( lcm( -1, -1), static_cast( 1) ); - BOOST_TEST_EQ( lcm( 0, 0), static_cast( 0) ); - BOOST_TEST_EQ( lcm( 6, 0), static_cast( 0) ); - BOOST_TEST_EQ( lcm( 0, 7), static_cast( 0) ); - BOOST_TEST_EQ( lcm( -5, 0), static_cast( 0) ); - BOOST_TEST_EQ( lcm( 0, -4), static_cast( 0) ); - BOOST_TEST_EQ( lcm( 18, 30), static_cast(90) ); - BOOST_TEST_EQ( lcm( -6, 9), static_cast(18) ); - BOOST_TEST_EQ( lcm(-10, -10), static_cast(10) ); - BOOST_TEST_EQ( lcm( 25, -10), static_cast(50) ); - 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) ); + BOOST_TEST_EQ( lcm(static_cast(1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( lcm(static_cast(-1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( lcm(static_cast(1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( lcm(static_cast(-1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( lcm(static_cast(0), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( lcm(static_cast(6), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( lcm(static_cast(0), static_cast(7)), static_cast( 0) ); + BOOST_TEST_EQ( lcm(static_cast(-5), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( lcm(static_cast(0), static_cast(-4)), static_cast( 0) ); + BOOST_TEST_EQ( lcm(static_cast(18), static_cast(30)), static_cast(90) ); + BOOST_TEST_EQ( lcm(static_cast(-6), static_cast(9)), static_cast(18) ); + BOOST_TEST_EQ( lcm(static_cast(-10), static_cast(-10)), static_cast(10) ); + BOOST_TEST_EQ( lcm(static_cast(25), static_cast(-10)), static_cast(50) ); + BOOST_TEST_EQ( lcm(static_cast(3), static_cast(7)), static_cast(21) ); + BOOST_TEST_EQ( lcm(static_cast(8), static_cast(9)), static_cast(72) ); + BOOST_TEST_EQ( lcm(static_cast(7), static_cast(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)); @@ -492,14 +492,14 @@ template< class T > void lcm_unsigned_test() // unsigned_test_types // Note that unmarked types (i.e. have no std::numeric_limits // specialization) are treated like non/unsigned types - BOOST_TEST_EQ( lcm( 1u, 1u), static_cast( 1u) ); - BOOST_TEST_EQ( lcm( 0u, 0u), static_cast( 0u) ); - BOOST_TEST_EQ( lcm( 6u, 0u), static_cast( 0u) ); - BOOST_TEST_EQ( lcm( 0u, 7u), static_cast( 0u) ); - BOOST_TEST_EQ( lcm(18u, 30u), static_cast(90u) ); - BOOST_TEST_EQ( lcm( 3u, 7u), static_cast(21u) ); - BOOST_TEST_EQ( lcm( 8u, 9u), static_cast(72u) ); - BOOST_TEST_EQ( lcm( 7u, 49u), static_cast(49u) ); + BOOST_TEST_EQ( lcm(static_cast(1u), static_cast(1u)), static_cast( 1u) ); + BOOST_TEST_EQ( lcm(static_cast(0u), static_cast(0u)), static_cast( 0u) ); + BOOST_TEST_EQ( lcm(static_cast(6u), static_cast(0u)), static_cast( 0u) ); + BOOST_TEST_EQ( lcm(static_cast(0u), static_cast(7u)), static_cast( 0u) ); + BOOST_TEST_EQ( lcm(static_cast(18u), static_cast(30u)), static_cast(90u) ); + BOOST_TEST_EQ( lcm(static_cast(3u), static_cast(7u)), static_cast(21u) ); + BOOST_TEST_EQ( lcm(static_cast(8u), static_cast(9u)), static_cast(72u) ); + BOOST_TEST_EQ( lcm(static_cast(7u), static_cast(49u)), static_cast(49u) ); } // LCM at compile-time @@ -551,7 +551,9 @@ template void gcd_and_lcm_on_rationals() test(); \ test(); \ test(); \ - test(); + test(); \ + test(); \ + test(); #ifdef BOOST_HAS_LONG_LONG # define TEST_SIGNED( test ) \ @@ -569,7 +571,8 @@ template void gcd_and_lcm_on_rationals() test(); \ test(); \ test(); \ - test(); + test(); \ + test(); #ifdef BOOST_HAS_LONG_LONG # define TEST_UNSIGNED( test ) \ From 7c0151c93a65f3eb5cebdf56a2b8bfb1170ca41c Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 26 Apr 2017 18:30:11 +0100 Subject: [PATCH 19/33] Enumerators don't need a final , in their list. --- include/boost/integer/common_factor_rt.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index 2f65d67..ed8690f 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -106,7 +106,7 @@ namespace boost { { method_euclid = 0, method_binary = 1, - method_mixed = 2, + method_mixed = 2 }; struct any_convert From 9c75396c059e36b76f5fedef46aa93bcc3a975c1 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 26 Apr 2017 19:11:18 +0100 Subject: [PATCH 20/33] Fix more explicit instantiations in test cases. --- test/common_factor_test.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 4a39cb8..e071afe 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -463,22 +463,22 @@ void lcm_unmarked_int_test() // then does an absolute-value on the result. Signed types that are not // marked as such (due to no std::numeric_limits specialization) may be off // by a sign. - BOOST_TEST_EQ( abs(lcm( 1, -1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm( -1, 1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm( 1, 1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm( -1, -1 )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm( 0, 0 )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm( 6, 0 )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm( 0, 7 )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm( -5, 0 )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm( 0, -4 )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm( 18, 30 )), MyInt2(90) ); - BOOST_TEST_EQ( abs(lcm( -6, 9 )), MyInt2(18) ); - BOOST_TEST_EQ( abs(lcm( -10, -10 )), MyInt2(10) ); - BOOST_TEST_EQ( abs(lcm( 25, -10 )), MyInt2(50) ); - BOOST_TEST_EQ( abs(lcm( 3, 7 )), MyInt2(21) ); - BOOST_TEST_EQ( abs(lcm( 8, 9 )), MyInt2(72) ); - BOOST_TEST_EQ( abs(lcm( 7, 49 )), MyInt2(49) ); + BOOST_TEST_EQ( abs(lcm( static_cast(1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(lcm(static_cast(-1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(lcm(static_cast(1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(lcm(static_cast(-1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(lcm(static_cast(0), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(lcm(static_cast(6), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(lcm(static_cast(0), static_cast(7) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(lcm(static_cast(-5), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(lcm(static_cast(0), static_cast(-4) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(lcm(static_cast(18), static_cast(30) )), MyInt2(90) ); + BOOST_TEST_EQ( abs(lcm(static_cast(-6), static_cast(9) )), MyInt2(18) ); + BOOST_TEST_EQ( abs(lcm(static_cast(-10), static_cast(-10) )), MyInt2(10) ); + BOOST_TEST_EQ( abs(lcm(static_cast(25), static_cast(-10) )), MyInt2(50) ); + BOOST_TEST_EQ( abs(lcm(static_cast(3), static_cast(7) )), MyInt2(21) ); + BOOST_TEST_EQ( abs(lcm(static_cast(8), static_cast(9) )), MyInt2(72) ); + BOOST_TEST_EQ( abs(lcm(static_cast(7), static_cast(49) )), MyInt2(49) ); } // LCM on unsigned integer types From 1d934167fd3689826240c991eb620651df41ad28 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 26 Apr 2017 19:51:03 +0100 Subject: [PATCH 21/33] Tentative fix for overload resolution issue with Oracle C++. --- include/boost/integer/common_factor_rt.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index ed8690f..7ecedd8 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -459,17 +459,21 @@ inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b) BOO 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 +// +// This looks slightly odd, but the variadic forms must have 3 or more arguments, and the variadic argument pack may be empty. +// This matters not at all for most compilers, but Oracle C++ selects the wrong overload in the 2-arg case unless we do this. +// template -inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b, Args const&... args) BOOST_GCD_NOEXCEPT(Integer) +inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b, const Integer& c, Args const&... args) BOOST_GCD_NOEXCEPT(Integer) { Integer t = gcd(b, args...); return t == 1 ? 1 : gcd(a, t); } template -inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b, Args const&... args) BOOST_GCD_NOEXCEPT(Integer) +inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b, Integer const& c, Args const&... args) BOOST_GCD_NOEXCEPT(Integer) { - return lcm(a, lcm(b, args...)); + return lcm(a, lcm(b, c, args...)); } #endif // From 53306630db3a6be4147d92e2432fd4ea67306285 Mon Sep 17 00:00:00 2001 From: John Maddock Date: Thu, 27 Apr 2017 17:23:40 +0000 Subject: [PATCH 22/33] Fix for Oracle 12.4 compiler --- include/boost/integer/common_factor_rt.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index 7ecedd8..a4f44d4 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -98,7 +98,7 @@ namespace boost { 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; + return val < T(0) ? -val : val; } }; From c1a08d3185b630c5f7c49b7d9cf942ac8e32bf7f Mon Sep 17 00:00:00 2001 From: John Maddock Date: Sun, 30 Apr 2017 18:49:47 +0100 Subject: [PATCH 23/33] We can enable compiler intrinsics with GCC in C++14 mode after all --- include/boost/integer/common_factor_rt.hpp | 36 ++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index a4f44d4..761e7dc 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -162,13 +162,12 @@ namespace boost { 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) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64)) +#if defined(BOOST_NO_CXX14_CONSTEXPR) && ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (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 @@ -241,11 +240,11 @@ namespace boost { template <> struct gcd_traits : public gcd_traits_defaults { - BOOST_FORCEINLINE static unsigned find_lsb(unsigned mask)BOOST_NOEXCEPT + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned find_lsb(unsigned mask)BOOST_NOEXCEPT { return __builtin_ctz(mask); } - BOOST_FORCEINLINE static unsigned make_odd(unsigned& val)BOOST_NOEXCEPT + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(unsigned& val)BOOST_NOEXCEPT { unsigned result = find_lsb(val); val >>= result; @@ -255,11 +254,11 @@ namespace boost { template <> struct gcd_traits : public gcd_traits_defaults { - BOOST_FORCEINLINE static unsigned find_lsb(unsigned long mask)BOOST_NOEXCEPT + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned find_lsb(unsigned long mask)BOOST_NOEXCEPT { return __builtin_ctzl(mask); } - BOOST_FORCEINLINE static unsigned make_odd(unsigned long& val)BOOST_NOEXCEPT + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(unsigned long& val)BOOST_NOEXCEPT { unsigned result = find_lsb(val); val >>= result; @@ -269,11 +268,11 @@ namespace boost { template <> struct gcd_traits : public gcd_traits_defaults { - BOOST_FORCEINLINE static unsigned find_lsb(boost::ulong_long_type mask)BOOST_NOEXCEPT + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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 + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR unsigned make_odd(boost::ulong_long_type& val)BOOST_NOEXCEPT { unsigned result = find_lsb(val); val >>= result; @@ -287,44 +286,43 @@ namespace boost { // 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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; } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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 @@ -466,7 +464,7 @@ inline BOOST_CXX14_CONSTEXPR Integer lcm(Integer const &a, Integer const &b) BOO template inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b, const Integer& c, Args const&... args) BOOST_GCD_NOEXCEPT(Integer) { - Integer t = gcd(b, args...); + Integer t = gcd(b, c, args...); return t == 1 ? 1 : gcd(a, t); } From 84ded579f304ebca7169b6a9876a141ad7b1612a Mon Sep 17 00:00:00 2001 From: John Maddock Date: Thu, 4 May 2017 11:12:33 +0100 Subject: [PATCH 24/33] Qualify recursive calls to avoid ambiguity for types that have their own gcd/lcm --- include/boost/integer/common_factor_rt.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index 761e7dc..b043e31 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -445,9 +445,9 @@ template inline BOOST_CXX14_CONSTEXPR Integer gcd(Integer const &a, Integer const &b) BOOST_GCD_NOEXCEPT(Integer) { if(a == (std::numeric_limits::min)()) - return a == static_cast(0) ? gcd_detail::gcd_traits::abs(b) : gcd(static_cast(a % b), b); + return a == static_cast(0) ? gcd_detail::gcd_traits::abs(b) : boost::integer::gcd(static_cast(a % b), b); else if (b == (std::numeric_limits::min)()) - return b == static_cast(0) ? gcd_detail::gcd_traits::abs(a) : gcd(a, static_cast(b % a)); + return b == static_cast(0) ? gcd_detail::gcd_traits::abs(a) : boost::integer::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))); } From 7ccb820893f04028e97c512df74d0c4f5c23cbb4 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sun, 7 May 2017 13:15:15 +0100 Subject: [PATCH 25/33] Test mpz_class when available. And fix errors compiling with that type. --- include/boost/integer/common_factor_rt.hpp | 8 ++++---- test/Jamfile.v2 | 5 ++++- test/common_factor_test.cpp | 16 ++++++++++++++-- test/has_gmpxx.cpp | 7 +++++++ 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 test/has_gmpxx.cpp diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index b043e31..341b316 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -336,9 +336,9 @@ namespace boost { unsigned shifts = 0; - if(!u) + if(u == T(0)) return v; - if(!v) + if(v == T(0)) return u; shifts = constexpr_min(gcd_traits::make_odd(u), gcd_traits::make_odd(v)); @@ -347,9 +347,9 @@ namespace boost { { u %= v; v -= u; - if(!u) + if(u == T(0)) return v << shifts; - if(!v) + if(v == T(0)) return u << shifts; gcd_traits::make_odd(u); gcd_traits::make_odd(v); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 691b703..23b3fe8 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -6,6 +6,9 @@ import testing ; project : requirements all gcc:-Wextra ; +obj has_gmpxx : has_gmpxx.cpp ; +explicit has_gmpxx ; + test-suite integer : [ run integer_traits_test.cpp ] @@ -28,5 +31,5 @@ test-suite integer [ compile-fail fail_uint_fast.cpp ] [ compile-fail fail_uint_least.cpp ] [ compile-fail fail_uint_65.cpp ] - [ run common_factor_test.cpp ] + [ run common_factor_test.cpp : : : [ check-target-builds "Checking for gmpxx.h" : BOOST_INTEGER_HAS_GMPXX_H=1 ] ] ; diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index e071afe..0c36984 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -31,6 +31,10 @@ #include // for std::numeric_limits #include // for std::basic_ostream +#ifdef BOOST_INTEGER_HAS_GMPXX_H +#include +#endif + namespace { @@ -556,11 +560,11 @@ template void gcd_and_lcm_on_rationals() test(); #ifdef BOOST_HAS_LONG_LONG -# define TEST_SIGNED( test ) \ +# define TEST_SIGNED__( test ) \ TEST_SIGNED_( test ) \ test(); #elif defined(BOOST_HAS_MS_INT64) -# define TEST_SIGNED( test ) \ +# define TEST_SIGNED__( test ) \ TEST_SIGNED_( test ) \ test<__int64>(); #endif @@ -584,6 +588,14 @@ template void gcd_and_lcm_on_rationals() test(); #endif +#ifdef BOOST_INTEGER_HAS_GMPXX_H +# define TEST_SIGNED(test)\ + TEST_SIGNED__(test)\ + test(); +#else +# define TEST_SIGNED(test) TEST_SIGNED__(test) +#endif + int main() { TEST_SIGNED(gcd_int_test) diff --git a/test/has_gmpxx.cpp b/test/has_gmpxx.cpp new file mode 100644 index 0000000..edf62d8 --- /dev/null +++ b/test/has_gmpxx.cpp @@ -0,0 +1,7 @@ +// Copyright John Maddock 2008. +// 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) + +#include + From 943d63e309ab75af4a0e5ef5b838244972e8dbc4 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Tue, 9 May 2017 18:03:03 +0100 Subject: [PATCH 26/33] Fix use of check-target-builds in Jamfile. --- test/Jamfile.v2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 23b3fe8..c6b48c2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -31,5 +31,5 @@ test-suite integer [ compile-fail fail_uint_fast.cpp ] [ compile-fail fail_uint_least.cpp ] [ compile-fail fail_uint_65.cpp ] - [ run common_factor_test.cpp : : : [ check-target-builds "Checking for gmpxx.h" : BOOST_INTEGER_HAS_GMPXX_H=1 ] ] + [ run common_factor_test.cpp : : : [ check-target-builds has_gmpxx "Checking for gmpxx.h" : BOOST_INTEGER_HAS_GMPXX_H=1 ] ] ; From 0c956331a04ffd02f9444703349225b579960c7a Mon Sep 17 00:00:00 2001 From: John Maddock Date: Tue, 9 May 2017 19:52:20 +0100 Subject: [PATCH 27/33] Fix gmp test failures --- test/Jamfile.v2 | 2 +- test/common_factor_test.cpp | 164 ++++++++++++++++++------------------ 2 files changed, 84 insertions(+), 82 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index c6b48c2..31dcd2a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -31,5 +31,5 @@ test-suite integer [ compile-fail fail_uint_fast.cpp ] [ compile-fail fail_uint_least.cpp ] [ compile-fail fail_uint_65.cpp ] - [ run common_factor_test.cpp : : : [ check-target-builds has_gmpxx "Checking for gmpxx.h" : BOOST_INTEGER_HAS_GMPXX_H=1 ] ] + [ run common_factor_test.cpp : : : [ check-target-builds has_gmpxx "Checking for gmpxx.h" : BOOST_INTEGER_HAS_GMPXX_H=1 -lgmp -lgmpxx ] ] ; diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 0c36984..131c78c 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -280,22 +280,22 @@ template< class T > void gcd_int_test() // signed_test_types #endif // Originally from Boost.Rational tests - BOOST_TEST_EQ( gcd(static_cast(1), static_cast(-1)), static_cast( 1) ); - BOOST_TEST_EQ( gcd(static_cast(-1), static_cast(1)), static_cast( 1) ); - BOOST_TEST_EQ( gcd(static_cast(1), static_cast(1)), static_cast( 1) ); - BOOST_TEST_EQ( gcd(static_cast(-1), static_cast(-1)), static_cast( 1) ); - BOOST_TEST_EQ( gcd(static_cast(0), static_cast(0)), static_cast( 0) ); - BOOST_TEST_EQ( gcd(static_cast(7), static_cast(0)), static_cast( 7) ); - BOOST_TEST_EQ( gcd(static_cast(0), static_cast(9)), static_cast( 9) ); - BOOST_TEST_EQ( gcd(static_cast(-7), static_cast(0)), static_cast( 7) ); - BOOST_TEST_EQ( gcd(static_cast(0), static_cast(-9)), static_cast( 9) ); - BOOST_TEST_EQ( gcd(static_cast(42), static_cast(30)), static_cast( 6) ); - BOOST_TEST_EQ( gcd(static_cast(6), static_cast(-9)), static_cast( 3) ); - BOOST_TEST_EQ( gcd(static_cast(-10), static_cast(-10)), static_cast(10) ); - BOOST_TEST_EQ( gcd(static_cast(-25), static_cast(-10)), static_cast( 5) ); - BOOST_TEST_EQ( gcd(static_cast(3), static_cast(7)), static_cast( 1) ); - BOOST_TEST_EQ( gcd(static_cast(8), static_cast(9)), static_cast( 1) ); - BOOST_TEST_EQ( gcd(static_cast(7), static_cast(49)), static_cast( 7) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(-1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(-1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(0), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(7), static_cast(0)), static_cast( 7) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(0), static_cast(9)), static_cast( 9) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(-7), static_cast(0)), static_cast( 7) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(0), static_cast(-9)), static_cast( 9) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(42), static_cast(30)), static_cast( 6) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(6), static_cast(-9)), static_cast( 3) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(-10), static_cast(-10)), static_cast(10) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(-25), static_cast(-10)), static_cast( 5) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(3), static_cast(7)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(8), static_cast(9)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(7), static_cast(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)); @@ -328,22 +328,22 @@ void gcd_unmarked_int_test() // then does an absolute-value on the result. Signed types that are not // marked as such (due to no std::numeric_limits specialization) may be off // by a sign. - BOOST_TEST_EQ( abs(gcd(static_cast(1), static_cast(-1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd(static_cast(-1), static_cast(1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd(static_cast(1), static_cast(1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd(static_cast(-1), static_cast(-1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd(static_cast(0), static_cast(0) )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(gcd(static_cast(7), static_cast(0) )), MyInt2( 7) ); - BOOST_TEST_EQ( abs(gcd(static_cast(0), static_cast(9) )), MyInt2( 9) ); - BOOST_TEST_EQ( abs(gcd(static_cast(-7), static_cast(0) )), MyInt2( 7) ); - BOOST_TEST_EQ( abs(gcd(static_cast(0), static_cast(-9) )), MyInt2( 9) ); - BOOST_TEST_EQ( abs(gcd(static_cast(42), static_cast(30))), MyInt2( 6) ); - BOOST_TEST_EQ( abs(gcd(static_cast(6), static_cast(-9) )), MyInt2( 3) ); - BOOST_TEST_EQ( abs(gcd(static_cast(-10), static_cast(-10) )), MyInt2(10) ); - BOOST_TEST_EQ( abs(gcd(static_cast(-25), static_cast(-10) )), MyInt2( 5) ); - BOOST_TEST_EQ( abs(gcd(static_cast(3), static_cast(7) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd(static_cast(8), static_cast(9) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(gcd(static_cast(7), static_cast(49) )), MyInt2( 7) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(-1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(-1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(0), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(7), static_cast(0) )), MyInt2( 7) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(0), static_cast(9) )), MyInt2( 9) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(-7), static_cast(0) )), MyInt2( 7) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(0), static_cast(-9) )), MyInt2( 9) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(42), static_cast(30))), MyInt2( 6) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(6), static_cast(-9) )), MyInt2( 3) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(-10), static_cast(-10) )), MyInt2(10) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(-25), static_cast(-10) )), MyInt2( 5) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(3), static_cast(7) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(8), static_cast(9) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::gcd(static_cast(7), static_cast(49) )), MyInt2( 7) ); } // GCD on unsigned integer types @@ -357,14 +357,14 @@ template< class T > void gcd_unsigned_test() // unsigned_test_types // Note that unmarked types (i.e. have no std::numeric_limits // specialization) are treated like non/unsigned types - BOOST_TEST_EQ( gcd(static_cast(1u), static_cast(1u)), static_cast( 1u) ); - BOOST_TEST_EQ( gcd(static_cast(0u), static_cast(0u)), static_cast( 0u) ); - BOOST_TEST_EQ( gcd(static_cast(7u), static_cast(0u)), static_cast( 7u) ); - BOOST_TEST_EQ( gcd(static_cast(0u), static_cast(9u)), static_cast( 9u) ); - BOOST_TEST_EQ( gcd(static_cast(42u), static_cast(30u)), static_cast( 6u) ); - BOOST_TEST_EQ( gcd(static_cast(3u), static_cast(7u)), static_cast( 1u) ); - BOOST_TEST_EQ( gcd(static_cast(8u), static_cast(9u)), static_cast( 1u) ); - BOOST_TEST_EQ( gcd(static_cast(7u), static_cast(49u)), static_cast( 7u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(1u), static_cast(1u)), static_cast( 1u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(0u), static_cast(0u)), static_cast( 0u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(7u), static_cast(0u)), static_cast( 7u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(0u), static_cast(9u)), static_cast( 9u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(42u), static_cast(30u)), static_cast( 6u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(3u), static_cast(7u)), static_cast( 1u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(8u), static_cast(9u)), static_cast( 1u) ); + BOOST_TEST_EQ( boost::integer::gcd(static_cast(7u), static_cast(49u)), static_cast( 7u) ); } // GCD at compile-time @@ -419,22 +419,22 @@ template< class T > void lcm_int_test() // signed_test_types #endif // Originally from Boost.Rational tests - BOOST_TEST_EQ( lcm(static_cast(1), static_cast(-1)), static_cast( 1) ); - BOOST_TEST_EQ( lcm(static_cast(-1), static_cast(1)), static_cast( 1) ); - BOOST_TEST_EQ( lcm(static_cast(1), static_cast(1)), static_cast( 1) ); - BOOST_TEST_EQ( lcm(static_cast(-1), static_cast(-1)), static_cast( 1) ); - BOOST_TEST_EQ( lcm(static_cast(0), static_cast(0)), static_cast( 0) ); - BOOST_TEST_EQ( lcm(static_cast(6), static_cast(0)), static_cast( 0) ); - BOOST_TEST_EQ( lcm(static_cast(0), static_cast(7)), static_cast( 0) ); - BOOST_TEST_EQ( lcm(static_cast(-5), static_cast(0)), static_cast( 0) ); - BOOST_TEST_EQ( lcm(static_cast(0), static_cast(-4)), static_cast( 0) ); - BOOST_TEST_EQ( lcm(static_cast(18), static_cast(30)), static_cast(90) ); - BOOST_TEST_EQ( lcm(static_cast(-6), static_cast(9)), static_cast(18) ); - BOOST_TEST_EQ( lcm(static_cast(-10), static_cast(-10)), static_cast(10) ); - BOOST_TEST_EQ( lcm(static_cast(25), static_cast(-10)), static_cast(50) ); - BOOST_TEST_EQ( lcm(static_cast(3), static_cast(7)), static_cast(21) ); - BOOST_TEST_EQ( lcm(static_cast(8), static_cast(9)), static_cast(72) ); - BOOST_TEST_EQ( lcm(static_cast(7), static_cast(49)), static_cast(49) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(-1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(1), static_cast(1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(-1), static_cast(-1)), static_cast( 1) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(0), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(6), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(0), static_cast(7)), static_cast( 0) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(-5), static_cast(0)), static_cast( 0) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(0), static_cast(-4)), static_cast( 0) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(18), static_cast(30)), static_cast(90) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(-6), static_cast(9)), static_cast(18) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(-10), static_cast(-10)), static_cast(10) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(25), static_cast(-10)), static_cast(50) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(3), static_cast(7)), static_cast(21) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(8), static_cast(9)), static_cast(72) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(7), static_cast(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)); @@ -467,22 +467,22 @@ void lcm_unmarked_int_test() // then does an absolute-value on the result. Signed types that are not // marked as such (due to no std::numeric_limits specialization) may be off // by a sign. - BOOST_TEST_EQ( abs(lcm( static_cast(1), static_cast(-1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm(static_cast(-1), static_cast(1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm(static_cast(1), static_cast(1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm(static_cast(-1), static_cast(-1) )), MyInt2( 1) ); - BOOST_TEST_EQ( abs(lcm(static_cast(0), static_cast(0) )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm(static_cast(6), static_cast(0) )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm(static_cast(0), static_cast(7) )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm(static_cast(-5), static_cast(0) )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm(static_cast(0), static_cast(-4) )), MyInt2( 0) ); - BOOST_TEST_EQ( abs(lcm(static_cast(18), static_cast(30) )), MyInt2(90) ); - BOOST_TEST_EQ( abs(lcm(static_cast(-6), static_cast(9) )), MyInt2(18) ); - BOOST_TEST_EQ( abs(lcm(static_cast(-10), static_cast(-10) )), MyInt2(10) ); - BOOST_TEST_EQ( abs(lcm(static_cast(25), static_cast(-10) )), MyInt2(50) ); - BOOST_TEST_EQ( abs(lcm(static_cast(3), static_cast(7) )), MyInt2(21) ); - BOOST_TEST_EQ( abs(lcm(static_cast(8), static_cast(9) )), MyInt2(72) ); - BOOST_TEST_EQ( abs(lcm(static_cast(7), static_cast(49) )), MyInt2(49) ); + BOOST_TEST_EQ( abs(boost::integer::lcm( static_cast(1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(-1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(1), static_cast(1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(-1), static_cast(-1) )), MyInt2( 1) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(0), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(6), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(0), static_cast(7) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(-5), static_cast(0) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(0), static_cast(-4) )), MyInt2( 0) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(18), static_cast(30) )), MyInt2(90) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(-6), static_cast(9) )), MyInt2(18) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(-10), static_cast(-10) )), MyInt2(10) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(25), static_cast(-10) )), MyInt2(50) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(3), static_cast(7) )), MyInt2(21) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(8), static_cast(9) )), MyInt2(72) ); + BOOST_TEST_EQ( abs(boost::integer::lcm(static_cast(7), static_cast(49) )), MyInt2(49) ); } // LCM on unsigned integer types @@ -496,14 +496,14 @@ template< class T > void lcm_unsigned_test() // unsigned_test_types // Note that unmarked types (i.e. have no std::numeric_limits // specialization) are treated like non/unsigned types - BOOST_TEST_EQ( lcm(static_cast(1u), static_cast(1u)), static_cast( 1u) ); - BOOST_TEST_EQ( lcm(static_cast(0u), static_cast(0u)), static_cast( 0u) ); - BOOST_TEST_EQ( lcm(static_cast(6u), static_cast(0u)), static_cast( 0u) ); - BOOST_TEST_EQ( lcm(static_cast(0u), static_cast(7u)), static_cast( 0u) ); - BOOST_TEST_EQ( lcm(static_cast(18u), static_cast(30u)), static_cast(90u) ); - BOOST_TEST_EQ( lcm(static_cast(3u), static_cast(7u)), static_cast(21u) ); - BOOST_TEST_EQ( lcm(static_cast(8u), static_cast(9u)), static_cast(72u) ); - BOOST_TEST_EQ( lcm(static_cast(7u), static_cast(49u)), static_cast(49u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(1u), static_cast(1u)), static_cast( 1u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(0u), static_cast(0u)), static_cast( 0u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(6u), static_cast(0u)), static_cast( 0u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(0u), static_cast(7u)), static_cast( 0u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(18u), static_cast(30u)), static_cast(90u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(3u), static_cast(7u)), static_cast(21u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(8u), static_cast(9u)), static_cast(72u) ); + BOOST_TEST_EQ( boost::integer::lcm(static_cast(7u), static_cast(49u)), static_cast(49u) ); } // LCM at compile-time @@ -592,8 +592,10 @@ template void gcd_and_lcm_on_rationals() # define TEST_SIGNED(test)\ TEST_SIGNED__(test)\ test(); +# define TEST_SIGNED_NO_GMP(test) TEST_SIGNED__(test) #else # define TEST_SIGNED(test) TEST_SIGNED__(test) +# define TEST_SIGNED_NO_GMP(test) TEST_SIGNED__(test) #endif int main() @@ -609,7 +611,7 @@ int main() TEST_UNSIGNED(lcm_unsigned_test) lcm_static_test(); variadics(); - TEST_SIGNED(gcd_and_lcm_on_rationals) + TEST_SIGNED_NO_GMP(gcd_and_lcm_on_rationals) return boost::report_errors(); } From 8e63e7f284f075f813446705bb5caae47131bbdf Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 31 May 2017 18:45:16 +0100 Subject: [PATCH 28/33] CI: Add more testers and minimise dependencies. --- .travis.yml | 24 +++++++++++++++++++-- appveyor.yml | 59 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 16cb4ef..c589d61 100644 --- a/.travis.yml +++ b/.travis.yml @@ -311,9 +311,29 @@ install: - cd boost-root - git submodule update --init tools/build - git submodule update --init libs/config - - git submodule update --init tools/boostdep + - git submodule update --init libs/core + - git submodule update --init libs/detail + - git submodule update --init libs/assert + - git submodule update --init libs/static_assert + - git submodule update --init libs/type_traits + - git submodule update --init libs/mpl + - git submodule update --init libs/preprocessor + - git submodule update --init libs/multiprecision + - git submodule update --init libs/math + - git submodule update --init libs/rational + - git submodule update --init libs/throw_exception + - git submodule update --init libs/predef + - git submodule update --init libs/lexical_cast + - git submodule update --init libs/range + - git submodule update --init libs/iterator + - git submodule update --init libs/concept_check + - git submodule update --init libs/numeric + - git submodule update --init libs/array + - git submodule update --init libs/container + - git submodule update --init libs/move + - git submodule update --init libs/functional + - git submodule update --init libs/random - cp -r $TRAVIS_BUILD_DIR/* libs/integer - - python tools/boostdep/depinst/depinst.py integer - ./bootstrap.sh - ./b2 headers diff --git a/appveyor.yml b/appveyor.yml index 1f4b748..17922c5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,19 +11,72 @@ branches: - master - develop +platform: + - x64 + +environment: + matrix: + - ARGS: --toolset=msvc-9.0 address-model=32 + - ARGS: --toolset=msvc-10.0 address-model=32 + - ARGS: --toolset=msvc-11.0 address-model=32 + - ARGS: --toolset=msvc-12.0 address-model=32 + - ARGS: --toolset=msvc-14.0 address-model=32 + - ARGS: --toolset=msvc-12.0 address-model=64 + - ARGS: --toolset=msvc-14.0 address-model=64 + - ARGS: --toolset=msvc-14.0 address-model=64 cxxflags=-std:c++latest + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARGS: --toolset=msvc-14.1 address-model=64 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARGS: --toolset=msvc-14.1 address-model=32 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + ARGS: --toolset=msvc-14.1 address-model=64 cxxflags=-std:c++latest + - ARGS: --toolset=gcc address-model=64 + PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH% + - ARGS: --toolset=gcc address-model=64 cxxflags=-std=gnu++1z + PATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH% + - ARGS: --toolset=gcc address-model=32 + PATH: C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;%PATH% + - ARGS: --toolset=gcc address-model=32 linkflags=-Wl,-allow-multiple-definition + PATH: C:\MinGW\bin;%PATH% + + install: - cd .. - git clone -b %APPVEYOR_REPO_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - git submodule update --init tools/build - git submodule update --init libs/config - - git submodule update --init tools/boostdep + - git submodule update --init libs/core + - git submodule update --init libs/detail + - git submodule update --init libs/assert + - git submodule update --init libs/static_assert + - git submodule update --init libs/type_traits + - git submodule update --init libs/mpl + - git submodule update --init libs/preprocessor + - git submodule update --init libs/multiprecision + - git submodule update --init libs/math + - git submodule update --init libs/rational + - git submodule update --init libs/throw_exception + - git submodule update --init libs/predef + - git submodule update --init libs/lexical_cast + - git submodule update --init libs/range + - git submodule update --init libs/iterator + - git submodule update --init libs/concept_check + - git submodule update --init libs/numeric + - git submodule update --init libs/array + - git submodule update --init libs/container + - git submodule update --init libs/move + - git submodule update --init libs/functional + - git submodule update --init libs/random - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\integer - - python tools/boostdep/depinst/depinst.py integer - bootstrap - b2 headers build: off test_script: - - b2 libs/integer/test toolset=msvc-9.0,msvc-10.0,msvc-11.0,msvc-14.0 + - cd libs\config\test + - ..\..\..\b2 config_info_travis_install toolset=%TOOLSET% + - config_info_travis + - cd ..\..\integer\test + - ..\..\..\b2 -j3 toolset=%TOOLSET% define=CI_SUPPRESS_KNOWN_ISSUES From 81a7c92b6c487bbbbf62e319fc2aff5a30be3a72 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Thu, 1 Jun 2017 08:48:02 +0100 Subject: [PATCH 29/33] CI: Add missing dependency to utility. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index c589d61..f73f33d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -333,6 +333,7 @@ install: - git submodule update --init libs/move - git submodule update --init libs/functional - git submodule update --init libs/random + - git submodule update --init libs/utility - cp -r $TRAVIS_BUILD_DIR/* libs/integer - ./bootstrap.sh - ./b2 headers From 6662dbdbbd0b8e593d9ccf5dd1d8d384a39aff83 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Sun, 4 Jun 2017 08:02:14 +0100 Subject: [PATCH 30/33] CI: Fix appveyor bjam arguments. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 17922c5..ccc8849 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -76,7 +76,7 @@ build: off test_script: - cd libs\config\test - - ..\..\..\b2 config_info_travis_install toolset=%TOOLSET% + - ..\..\..\b2 config_info_travis_install %ARGS% - config_info_travis - cd ..\..\integer\test - - ..\..\..\b2 -j3 toolset=%TOOLSET% define=CI_SUPPRESS_KNOWN_ISSUES + - ..\..\..\b2 -j3 %ARGS% define=CI_SUPPRESS_KNOWN_ISSUES From 6ebccd6c80b7f15be9131156bff68d02658c2caa Mon Sep 17 00:00:00 2001 From: Daniela Engert Date: Wed, 26 Apr 2017 14:49:04 +0200 Subject: [PATCH 31/33] fix narrowing warnings due to integer promotion. Signed-off-by: Daniela Engert --- include/boost/integer/integer_mask.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/boost/integer/integer_mask.hpp b/include/boost/integer/integer_mask.hpp index 2cc9a1d..eee4679 100644 --- a/include/boost/integer/integer_mask.hpp +++ b/include/boost/integer/integer_mask.hpp @@ -57,19 +57,27 @@ struct high_bit_mask_t // Makes masks for the lowest N bits // (Specializations are needed when N fills up a type.) +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4310) // cast truncates constant value +#endif + template < std::size_t Bits > struct low_bits_mask_t { typedef typename uint_t::least least; typedef typename uint_t::fast fast; - BOOST_STATIC_CONSTANT( least, sig_bits = (~(least(~(least( 0u ))) << Bits )) ); + BOOST_STATIC_CONSTANT( least, sig_bits = least(~(least(~(least( 0u ))) << Bits )) ); BOOST_STATIC_CONSTANT( fast, sig_bits_fast = fast(sig_bits) ); BOOST_STATIC_CONSTANT( std::size_t, bit_count = Bits ); }; // boost::low_bits_mask_t +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif #define BOOST_LOW_BITS_MASK_SPECIALIZE( Type ) \ template < > struct low_bits_mask_t< std::numeric_limits::digits > { \ From 5c129565d50c11ecff80be1dd95cfcddb77748fd Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Fri, 9 Jun 2017 14:51:50 +0100 Subject: [PATCH 32/33] CI: add missing appveyor dependency --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index ccc8849..956073a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -68,6 +68,7 @@ install: - git submodule update --init libs/move - git submodule update --init libs/functional - git submodule update --init libs/random + - git submodule update --init libs/utility - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\integer - bootstrap - b2 headers From 10026d9b6fcb3ad592bbe56669a868f916818524 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Fri, 9 Jun 2017 19:47:18 +0100 Subject: [PATCH 33/33] Disable some tests on older compilers that we know won't pass. --- test/common_factor_test.cpp | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 131c78c..fa12338 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -23,7 +23,6 @@ #include // for boost::mpl::list #include #include -#include #include #include @@ -35,6 +34,13 @@ #include #endif +#if (defined(BOOST_MSVC) && (BOOST_MSVC < 1500)) || (defined(__clang_major__) && (__clang_major__ == 3) && (__clang_minor__ < 2)) +#define DISABLE_MP_TESTS +#endif + +#ifndef DISABLE_MP_TESTS +#include +#endif namespace { @@ -124,7 +130,11 @@ typedef ::boost::mpl::list signed_test_types; + MyInt1 +#ifndef DISABLE_MP_TESTS + , boost::multiprecision::cpp_int +#endif +> signed_test_types; typedef ::boost::mpl::list void gcd_and_lcm_on_rationals() rational(1)); } +#ifndef DISABLE_MP_TESTS #define TEST_SIGNED_( test ) \ test(); \ test(); \ @@ -558,6 +569,14 @@ template void gcd_and_lcm_on_rationals() test(); \ test(); \ test(); +#else +#define TEST_SIGNED_( test ) \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); +#endif #ifdef BOOST_HAS_LONG_LONG # define TEST_SIGNED__( test ) \ @@ -568,7 +587,7 @@ template void gcd_and_lcm_on_rationals() TEST_SIGNED_( test ) \ test<__int64>(); #endif - +#ifndef DISABLE_MP_TESTS #define TEST_UNSIGNED_( test ) \ test(); \ test(); \ @@ -577,6 +596,15 @@ template void gcd_and_lcm_on_rationals() test(); \ test(); \ test(); +#else +#define TEST_UNSIGNED_( test ) \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); +#endif #ifdef BOOST_HAS_LONG_LONG # define TEST_UNSIGNED( test ) \