// Boost GCD & LCM common_factor.hpp test program --------------------------// // (C) Copyright Daryle Walker 2001, 2006. // 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) // See http://www.boost.org for most recent version including documentation. // Revision History // 01 Dec 2006 Various fixes for old compilers (Joaquin M Lopez Munoz) // 10 Nov 2006 Make long long and __int64 mutually exclusive (Daryle Walker) // 04 Nov 2006 Use more built-in numeric types, binary-GCD (Daryle Walker) // 03 Nov 2006 Use custom numeric types (Daryle Walker) // 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.integer GCD & LCM unit tests" #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 #include "multiprecision_config.hpp" #ifndef DISABLE_MP_TESTS #include #endif namespace { // TODO: add polynominal/non-real type; especially after any switch to the // binary-GCD algorithm for built-in types // Custom integer class (template) template < typename IntType, int ID = 0 > class my_wrapped_integer : private ::boost::shiftable1, ::boost::operators > > { // Helper type-aliases typedef my_wrapped_integer self_type; typedef IntType self_type::* bool_type; // Member data IntType v_; public: // Template parameters typedef IntType int_type; BOOST_STATIC_CONSTANT(int,id = ID); // Lifetime management (use automatic destructor and copy constructor) my_wrapped_integer( int_type const &v = int_type() ) : v_( v ) {} // Accessors int_type value() const { return this->v_; } // Operators (use automatic copy assignment) operator bool_type() const { return this->v_ ? &self_type::v_ : 0; } self_type & operator ++() { ++this->v_; return *this; } self_type & operator --() { --this->v_; return *this; } self_type operator ~() const { return self_type( ~this->v_ ); } self_type operator !() const { return self_type( !this->v_ ); } self_type operator +() const { return self_type( +this->v_ ); } self_type operator -() const { return self_type( -this->v_ ); } bool operator <( self_type const &r ) const { return this->v_ < r.v_; } bool operator ==( self_type const &r ) const { return this->v_ == r.v_; } self_type &operator *=(self_type const &r) {this->v_ *= r.v_; return *this;} self_type &operator /=(self_type const &r) {this->v_ /= r.v_; return *this;} self_type &operator %=(self_type const &r) {this->v_ %= r.v_; return *this;} self_type &operator +=(self_type const &r) {this->v_ += r.v_; return *this;} self_type &operator -=(self_type const &r) {this->v_ -= r.v_; return *this;} self_type &operator<<=(self_type const &r){this->v_ <<= r.v_; return *this;} self_type &operator>>=(self_type const &r){this->v_ >>= r.v_; return *this;} self_type &operator &=(self_type const &r) {this->v_ &= r.v_; return *this;} self_type &operator |=(self_type const &r) {this->v_ |= r.v_; return *this;} self_type &operator ^=(self_type const &r) {this->v_ ^= r.v_; return *this;} // Input & output friend std::istream & operator >>( std::istream &i, self_type &x ) { return i >> x.v_; } friend std::ostream & operator <<( std::ostream &o, self_type const &x ) { return o << x.v_; } }; // my_wrapped_integer template < typename IntType, int ID > my_wrapped_integer abs( my_wrapped_integer const &x ) { return ( x < my_wrapped_integer(0) ) ? -x : +x; } typedef my_wrapped_integer MyInt1; typedef my_wrapped_integer MyUnsigned1; typedef my_wrapped_integer MyInt2; typedef my_wrapped_integer MyUnsigned2; // Without these explicit instantiations, MSVC++ 6.5/7.0 does not find // some friend operators in certain contexts. MyInt1 dummy1; 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 /**/ // Specialize numeric_limits for _some_ of our types namespace std { template < > class numeric_limits< MyInt1 > { typedef MyInt1::int_type int_type; typedef numeric_limits limits_type; public: BOOST_STATIC_CONSTANT(bool, is_specialized = limits_type::is_specialized); static MyInt1 min BOOST_NO_MACRO_EXPAND() throw() { return (limits_type::min)(); } static MyInt1 max BOOST_NO_MACRO_EXPAND() throw() { return (limits_type::max)(); } BOOST_STATIC_CONSTANT(int, digits = limits_type::digits); BOOST_STATIC_CONSTANT(int, digits10 = limits_type::digits10); #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS BOOST_STATIC_CONSTANT(int, max_digits10 = limits_type::max_digits10); #endif BOOST_STATIC_CONSTANT(bool, is_signed = limits_type::is_signed); BOOST_STATIC_CONSTANT(bool, is_integer = limits_type::is_integer); BOOST_STATIC_CONSTANT(bool, is_exact = limits_type::is_exact); BOOST_STATIC_CONSTANT(int, radix = limits_type::radix); static MyInt1 epsilon() throw() { return limits_type::epsilon(); } static MyInt1 round_error() throw() { return limits_type::round_error(); } BOOST_STATIC_CONSTANT(int, min_exponent = limits_type::min_exponent); BOOST_STATIC_CONSTANT(int, min_exponent10 = limits_type::min_exponent10); BOOST_STATIC_CONSTANT(int, max_exponent = limits_type::max_exponent); BOOST_STATIC_CONSTANT(int, max_exponent10 = limits_type::max_exponent10); BOOST_STATIC_CONSTANT(bool, has_infinity = limits_type::has_infinity); BOOST_STATIC_CONSTANT(bool, has_quiet_NaN = limits_type::has_quiet_NaN); BOOST_STATIC_CONSTANT(bool, has_signaling_NaN = limits_type::has_signaling_NaN); BOOST_STATIC_CONSTANT(float_denorm_style, has_denorm = limits_type::has_denorm); BOOST_STATIC_CONSTANT(bool, has_denorm_loss = limits_type::has_denorm_loss); static MyInt1 infinity() throw() { return limits_type::infinity(); } static MyInt1 quiet_NaN() throw() { return limits_type::quiet_NaN(); } static MyInt1 signaling_NaN() throw() {return limits_type::signaling_NaN();} static MyInt1 denorm_min() throw() { return limits_type::denorm_min(); } BOOST_STATIC_CONSTANT(bool, is_iec559 = limits_type::is_iec559); BOOST_STATIC_CONSTANT(bool, is_bounded = limits_type::is_bounded); BOOST_STATIC_CONSTANT(bool, is_modulo = limits_type::is_modulo); BOOST_STATIC_CONSTANT(bool, traps = limits_type::traps); BOOST_STATIC_CONSTANT(bool, tinyness_before = limits_type::tinyness_before); BOOST_STATIC_CONSTANT(float_round_style, round_style = limits_type::round_style); }; // std::numeric_limits template < > class numeric_limits< MyUnsigned1 > { typedef MyUnsigned1::int_type int_type; typedef numeric_limits limits_type; public: BOOST_STATIC_CONSTANT(bool, is_specialized = limits_type::is_specialized); static MyUnsigned1 min BOOST_NO_MACRO_EXPAND() throw() { return (limits_type::min)(); } static MyUnsigned1 max BOOST_NO_MACRO_EXPAND() throw() { return (limits_type::max)(); } BOOST_STATIC_CONSTANT(int, digits = limits_type::digits); BOOST_STATIC_CONSTANT(int, digits10 = limits_type::digits10); #ifndef BOOST_NO_CXX11_NUMERIC_LIMITS BOOST_STATIC_CONSTANT(int, max_digits10 = limits_type::max_digits10); #endif BOOST_STATIC_CONSTANT(bool, is_signed = limits_type::is_signed); BOOST_STATIC_CONSTANT(bool, is_integer = limits_type::is_integer); BOOST_STATIC_CONSTANT(bool, is_exact = limits_type::is_exact); BOOST_STATIC_CONSTANT(int, radix = limits_type::radix); static MyUnsigned1 epsilon() throw() { return limits_type::epsilon(); } static MyUnsigned1 round_error() throw(){return limits_type::round_error();} BOOST_STATIC_CONSTANT(int, min_exponent = limits_type::min_exponent); BOOST_STATIC_CONSTANT(int, min_exponent10 = limits_type::min_exponent10); BOOST_STATIC_CONSTANT(int, max_exponent = limits_type::max_exponent); BOOST_STATIC_CONSTANT(int, max_exponent10 = limits_type::max_exponent10); BOOST_STATIC_CONSTANT(bool, has_infinity = limits_type::has_infinity); BOOST_STATIC_CONSTANT(bool, has_quiet_NaN = limits_type::has_quiet_NaN); BOOST_STATIC_CONSTANT(bool, has_signaling_NaN = limits_type::has_signaling_NaN); BOOST_STATIC_CONSTANT(float_denorm_style, has_denorm = limits_type::has_denorm); BOOST_STATIC_CONSTANT(bool, has_denorm_loss = limits_type::has_denorm_loss); static MyUnsigned1 infinity() throw() { return limits_type::infinity(); } static MyUnsigned1 quiet_NaN() throw() { return limits_type::quiet_NaN(); } static MyUnsigned1 signaling_NaN() throw() { return limits_type::signaling_NaN(); } static MyUnsigned1 denorm_min() throw(){ return limits_type::denorm_min(); } BOOST_STATIC_CONSTANT(bool, is_iec559 = limits_type::is_iec559); BOOST_STATIC_CONSTANT(bool, is_bounded = limits_type::is_bounded); BOOST_STATIC_CONSTANT(bool, is_modulo = limits_type::is_modulo); BOOST_STATIC_CONSTANT(bool, traps = limits_type::traps); BOOST_STATIC_CONSTANT(bool, tinyness_before = limits_type::tinyness_before); BOOST_STATIC_CONSTANT(float_round_style, round_style = limits_type::round_style); }; // std::numeric_limits #if BOOST_WORKAROUND(BOOST_MSVC,<1300) // MSVC 6.0 lacks operator<< for __int64, see // https://support.microsoft.com/kb/168440/ inline ostream& operator<<(ostream& os, __int64 i) { char buf[20]; sprintf(buf,"%I64d", i); os << buf; return os; } inline ostream& operator<<(ostream& os, unsigned __int64 i) { char buf[20]; sprintf(buf,"%I64u", i); os << buf; return os; } #endif } // namespace std // GCD tests // 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( 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(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( 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 // 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 ); } 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( 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(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( 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 // 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 ); } 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); unsigned i_gcd_unity[] = { 44, 56, 1, 88 }; BOOST_TEST_EQ(boost::integer::gcd_range(i_gcd_unity, i_gcd_unity + 4).first, 1); BOOST_TEST_EQ(boost::integer::gcd_range(i_gcd_unity, i_gcd_unity + 4).second, i_gcd_unity + 3); unsigned i_lcm_unity[] = { 44, 56, 0, 88 }; BOOST_TEST_EQ(boost::integer::lcm_range(i_lcm_unity, i_lcm_unity + 4).first, 0); BOOST_TEST_EQ(boost::integer::lcm_range(i_lcm_unity, i_lcm_unity + 4).second, i_lcm_unity + 3); #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 } // 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 ) \ TEST_SIGNED_( test ) \ test(); #elif defined(BOOST_HAS_MS_INT64) # 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(); \ test(); \ test(); \ test(); \ test(); #endif #ifdef BOOST_HAS_LONG_LONG # define TEST_UNSIGNED( test ) \ TEST_UNSIGNED_( test ) \ test(); #elif defined(BOOST_HAS_MS_INT64) # define TEST_UNSIGNED( test ) \ TEST_UNSIGNED_( 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(); gcd_method_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(); }