diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f73f33d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,348 @@ +# 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/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 + - git submodule update --init libs/utility + - 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 diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..956073a --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,83 @@ +# 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 + +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 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 + - git submodule update --init libs/utility + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\integer + - bootstrap + - b2 headers + +build: off + +test_script: + - cd libs\config\test + - ..\..\..\b2 config_info_travis_install %ARGS% + - config_info_travis + - cd ..\..\integer\test + - ..\..\..\b2 -j3 %ARGS% define=CI_SUPPRESS_KNOWN_ISSUES diff --git a/doc/gcd/math-gcd.qbk b/doc/gcd/math-gcd.qbk index 4d3edd6..23472de 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] @@ -24,9 +24,20 @@ 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 ); + 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; @@ -54,8 +65,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 +82,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 +101,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 +119,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,24 +129,48 @@ 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 ); + + 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. [endsect] [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; @@ -219,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. @@ -235,7 +280,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/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/gcd_lcm.html b/doc/html/boost_integer/gcd_lcm.html new file mode 100644 index 0000000..097afc0 --- /dev/null +++ b/doc/html/boost_integer/gcd_lcm.html @@ -0,0 +1,400 @@ + + + +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. +

+
+
+ +
    +
  • + 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. +
  • +
  • + 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/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..6dc60ef 100644 --- a/doc/html/boost_integer/integer.html +++ b/doc/html/boost_integer/integer.html @@ -3,11 +3,11 @@ Integer Type Selection - + - + @@ -20,13 +20,13 @@

-PrevUpHomeNext +PrevUpHomeNext
-
+
Synopsis
Easiest-to-Manipulate Types
@@ -426,7 +426,7 @@
-PrevUpHomeNext +PrevUpHomeNext
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..0d72e1e 100644 --- a/doc/html/boost_integer/mask.html +++ b/doc/html/boost_integer/mask.html @@ -3,10 +3,10 @@ Integer Masks - + - + @@ -20,13 +20,13 @@
-PrevUpHomeNext +PrevUpHomeNext
-
+
Overview
Synopsis
Single @@ -374,7 +374,7 @@
-PrevUpHomeNext +PrevUpHomeNext
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..040ad3e 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -3,7 +3,7 @@ Boost.Integer - + @@ -50,10 +50,12 @@
- +

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

Last revised: April 24, 2017 at 17:49:59 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] diff --git a/include/boost/integer/common_factor_rt.hpp b/include/boost/integer/common_factor_rt.hpp index c2b54db..341b316 100644 --- a/include/boost/integer/common_factor_rt.hpp +++ b/include/boost/integer/common_factor_rt.hpp @@ -1,454 +1,572 @@ -// 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 +#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 +#endif #ifdef BOOST_MSVC #pragma warning(push) #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 < T(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 {}; + + // + // 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_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 + { + 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 BOOST_CXX14_CONSTEXPR unsigned find_lsb(unsigned mask)BOOST_NOEXCEPT + { + return __builtin_ctz(mask); + } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR unsigned find_lsb(unsigned long mask)BOOST_NOEXCEPT + { + return __builtin_ctzl(mask); + } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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 BOOST_CXX14_CONSTEXPR unsigned find_lsb(boost::ulong_long_type mask)BOOST_NOEXCEPT + { + return __builtin_ctzll(mask); + } + BOOST_FORCEINLINE static BOOST_CXX14_CONSTEXPR 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 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 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 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 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 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 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 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 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 BOOST_CXX14_CONSTEXPR unsigned make_odd(wchar_t& val)BOOST_NOEXCEPT { unsigned result = gcd_traits::find_lsb(val); val >>= result; return result; } + }; +#endif +#endif + // + // 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 == T(0)) + return v; + if(v == T(0)) + 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 == T(0)) + return v << shifts; + if(v == T(0)) + 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) ? 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) : 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))); +} + +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 +// +// 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, const Integer& c, Args const&... args) BOOST_GCD_NOEXCEPT(Integer) +{ + Integer t = gcd(b, c, args...); + return t == 1 ? 1 : gcd(a, t); +} +template +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, c, 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()))); +} -// Forward declarations for function templates -----------------------------// - -template < typename IntegerType > - IntegerType gcd( IntegerType const &a, IntegerType const &b ); - -template < typename IntegerType > - IntegerType lcm( IntegerType const &a, IntegerType const &b ); - - -// 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 - result_type operator ()( first_argument_type const &a, - second_argument_type const &b ) const; - -}; // 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 - result_type operator ()( first_argument_type const &a, - second_argument_type const &b ) const; - -}; // boost::integer::lcm_evaluator - - -// Implementation details --------------------------------------------------// - -namespace detail -{ - // Greatest common divisor for rings (including unsigned integers) - template < typename RingType > - RingType - gcd_euclidean - ( - RingType a, - RingType b - ) - { - // 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 - IntegerType - gcd_integer - ( - IntegerType const & a, - IntegerType const & b - ) - { - // 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 > - BuiltInUnsigned - gcd_binary - ( - BuiltInUnsigned u, - BuiltInUnsigned v - ) - { - 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 - RingType - lcm_euclidean - ( - RingType const & a, - RingType const & b - ) - { - 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 - IntegerType - lcm_integer - ( - IntegerType const & a, - IntegerType const & b - ) - { - // 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 - { - T operator ()( T const &a, T const &b ) - { - return gcd_euclidean( a, b ); - } - }; - - template < typename T > - struct gcd_optimal_evaluator_helper_t< T, true, true > - { - T operator ()( T const &a, T const &b ) - { - return gcd_integer( a, b ); - } - }; - - template < typename T > - struct gcd_optimal_evaluator - { - T operator ()( T const &a, T const &b ) - { - 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 - { - T operator ()( T const &a, T const &b ) - { - return gcd_integer( a, b ); - } - }; -#endif - - // 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_PRIVATE_GCD_UF( unsigned char ); - BOOST_PRIVATE_GCD_UF( unsigned short ); - BOOST_PRIVATE_GCD_UF( unsigned ); - BOOST_PRIVATE_GCD_UF( unsigned long ); - -#ifdef BOOST_HAS_LONG_LONG - BOOST_PRIVATE_GCD_UF( boost::ulong_long_type ); -#elif defined(BOOST_HAS_MS_INT64) - BOOST_PRIVATE_GCD_UF( unsigned __int64 ); -#endif - -#if CHAR_MIN == 0 - BOOST_PRIVATE_GCD_UF( char ); // char is unsigned -#endif - -#undef BOOST_PRIVATE_GCD_UF - -#define BOOST_PRIVATE_GCD_SF( St, Ut ) \ - template < > struct gcd_optimal_evaluator \ - { St operator ()( St a, St b ) const { 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 - { - T operator ()( T const &a, T const &b ) - { - return lcm_euclidean( a, b ); - } - }; - - template < typename T > - struct lcm_optimal_evaluator_helper_t< T, true, true > - { - T operator ()( T const &a, T const &b ) - { - return lcm_integer( a, b ); - } - }; - - template < typename T > - struct lcm_optimal_evaluator - { - T operator ()( T const &a, T const &b ) - { - 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 - { - T operator ()( T const &a, T const &b ) - { - return lcm_integer( a, b ); - } - }; -#endif - - // Functions to find the GCD or LCM in the best way - template < typename T > - inline - T - gcd_optimal - ( - T const & a, - T const & b - ) - { - gcd_optimal_evaluator solver; - - return solver( a, b ); - } - - template < typename T > - inline - T - lcm_optimal - ( - T const & a, - T const & b - ) - { - lcm_optimal_evaluator solver; - - return solver( a, b ); - } - -} // namespace detail - - -// Greatest common divisor evaluator member function definition ------------// - -template < typename IntegerType > -inline -typename gcd_evaluator::result_type -gcd_evaluator::operator () -( - first_argument_type const & a, - second_argument_type const & b -) const -{ - return detail::gcd_optimal( a, b ); -} - - -// Least common multiple evaluator member function definition --------------// - -template < typename IntegerType > -inline -typename lcm_evaluator::result_type -lcm_evaluator::operator () -( - first_argument_type const & a, - second_argument_type const & b -) const -{ - return detail::lcm_optimal( a, b ); -} - - -// Greatest common divisor and least common multiple function definitions --// - -template < typename IntegerType > -inline -IntegerType -gcd -( - IntegerType const & a, - IntegerType const & b -) -{ - gcd_evaluator solver; - - return solver( a, b ); -} - -template < typename IntegerType > -inline -IntegerType -lcm -( - IntegerType const & a, - IntegerType const & b -) -{ - 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/include/boost/integer/integer_mask.hpp b/include/boost/integer/integer_mask.hpp index 2acf7f7..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( 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 > { \ 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 diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e3b5be1..31dcd2a 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 ] @@ -19,6 +22,8 @@ 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 gcd_noexcept_test.cpp ] [ compile-fail fail_int_exact.cpp ] [ compile-fail fail_int_fast.cpp ] [ compile-fail fail_int_least.cpp ] @@ -26,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 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 81ffc47..fa12338 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -15,19 +15,32 @@ // 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 // for std::basic_istream #include // for std::numeric_limits #include // for std::basic_ostream +#ifdef BOOST_INTEGER_HAS_GMPXX_H +#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 { @@ -109,6 +122,29 @@ 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,199 +282,321 @@ 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) ); - 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( 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)); + 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 // 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(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 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 - 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( 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 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) ); - 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( 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)); + 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 // 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(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 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 - 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( 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 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)); +} +#ifndef DISABLE_MP_TESTS +#define TEST_SIGNED_( test ) \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); +#else #define TEST_SIGNED_( test ) \ test(); \ test(); \ test(); \ test(); \ test(); +#endif #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 - +#ifndef DISABLE_MP_TESTS +#define TEST_UNSIGNED_( test ) \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); \ + test(); +#else #define TEST_UNSIGNED_( test ) \ test(); \ test(); \ @@ -446,6 +604,7 @@ void lcm_static_test() test(); \ test(); \ test(); +#endif #ifdef BOOST_HAS_LONG_LONG # define TEST_UNSIGNED( test ) \ @@ -457,17 +616,30 @@ void lcm_static_test() test(); #endif +#ifdef BOOST_INTEGER_HAS_GMPXX_H +# 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() { - 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_NO_GMP(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 new file mode 100644 index 0000000..05bef34 --- /dev/null +++ b/test/gcd_constexpr14_test.cpp @@ -0,0 +1,66 @@ + +// (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_constexpr1() +{ + constexpr const boost::int64_t i = 347 * 463 * 727; + constexpr const boost::int64_t j = 191 * 347 * 281; + + constexpr const boost::int64_t k = boost::integer::gcd(i, j); + constexpr const boost::int64_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_constexpr2() +{ + constexpr const boost::uint64_t i = 347 * 463 * 727; + constexpr const boost::uint64_t j = 191 * 347 * 281; + + constexpr const boost::uint64_t k = boost::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 + 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 +