// 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.Math GCD & LCM unit tests" #include // for BOOST_MSVC, etc. #include #include // for boost::math::gcd, etc. #include // for boost::mpl::list #include #include #include #include // for std::basic_istream #include // for std::numeric_limits #include // for std::basic_ostream 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); 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); 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 // http://support.microsoft.com/default.aspx?scid=kb;en-us;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 BOOST_AUTO_TEST_SUITE( gcd_test_suite ) // GCD on signed integer types BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_int_test, T, signed_test_types ) { #ifndef BOOST_MSVC using boost::math::gcd; #else using namespace boost::math; #endif // Originally from Boost.Rational tests BOOST_CHECK_EQUAL( gcd( 1, -1), static_cast( 1) ); BOOST_CHECK_EQUAL( gcd( -1, 1), static_cast( 1) ); BOOST_CHECK_EQUAL( gcd( 1, 1), static_cast( 1) ); BOOST_CHECK_EQUAL( gcd( -1, -1), static_cast( 1) ); BOOST_CHECK_EQUAL( gcd( 0, 0), static_cast( 0) ); BOOST_CHECK_EQUAL( gcd( 7, 0), static_cast( 7) ); BOOST_CHECK_EQUAL( gcd( 0, 9), static_cast( 9) ); BOOST_CHECK_EQUAL( gcd( -7, 0), static_cast( 7) ); BOOST_CHECK_EQUAL( gcd( 0, -9), static_cast( 9) ); BOOST_CHECK_EQUAL( gcd( 42, 30), static_cast( 6) ); BOOST_CHECK_EQUAL( gcd( 6, -9), static_cast( 3) ); BOOST_CHECK_EQUAL( gcd(-10, -10), static_cast(10) ); BOOST_CHECK_EQUAL( gcd(-25, -10), static_cast( 5) ); BOOST_CHECK_EQUAL( gcd( 3, 7), static_cast( 1) ); BOOST_CHECK_EQUAL( gcd( 8, 9), static_cast( 1) ); BOOST_CHECK_EQUAL( gcd( 7, 49), static_cast( 7) ); } // GCD on unmarked signed integer type BOOST_AUTO_TEST_CASE( gcd_unmarked_int_test ) { #ifndef BOOST_MSVC using boost::math::gcd; #else using namespace boost::math; #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_CHECK_EQUAL( abs(gcd( 1, -1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(gcd( -1, 1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(gcd( 1, 1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(gcd( -1, -1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(gcd( 0, 0 )), MyInt2( 0) ); BOOST_CHECK_EQUAL( abs(gcd( 7, 0 )), MyInt2( 7) ); BOOST_CHECK_EQUAL( abs(gcd( 0, 9 )), MyInt2( 9) ); BOOST_CHECK_EQUAL( abs(gcd( -7, 0 )), MyInt2( 7) ); BOOST_CHECK_EQUAL( abs(gcd( 0, -9 )), MyInt2( 9) ); BOOST_CHECK_EQUAL( abs(gcd( 42, 30 )), MyInt2( 6) ); BOOST_CHECK_EQUAL( abs(gcd( 6, -9 )), MyInt2( 3) ); BOOST_CHECK_EQUAL( abs(gcd( -10, -10 )), MyInt2(10) ); BOOST_CHECK_EQUAL( abs(gcd( -25, -10 )), MyInt2( 5) ); BOOST_CHECK_EQUAL( abs(gcd( 3, 7 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(gcd( 8, 9 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(gcd( 7, 49 )), MyInt2( 7) ); } // GCD on unsigned integer types BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_unsigned_test, T, unsigned_test_types ) { #ifndef BOOST_MSVC using boost::math::gcd; #else using namespace boost::math; #endif // Note that unmarked types (i.e. have no std::numeric_limits // specialization) are treated like non/unsigned types BOOST_CHECK_EQUAL( gcd( 1u, 1u), static_cast( 1u) ); BOOST_CHECK_EQUAL( gcd( 0u, 0u), static_cast( 0u) ); BOOST_CHECK_EQUAL( gcd( 7u, 0u), static_cast( 7u) ); BOOST_CHECK_EQUAL( gcd( 0u, 9u), static_cast( 9u) ); BOOST_CHECK_EQUAL( gcd(42u, 30u), static_cast( 6u) ); BOOST_CHECK_EQUAL( gcd( 3u, 7u), static_cast( 1u) ); BOOST_CHECK_EQUAL( gcd( 8u, 9u), static_cast( 1u) ); BOOST_CHECK_EQUAL( gcd( 7u, 49u), static_cast( 7u) ); } // GCD at compile-time BOOST_AUTO_TEST_CASE( gcd_static_test ) { #ifndef BOOST_MSVC using boost::math::static_gcd; #else using namespace boost::math; #endif // Can't use "BOOST_CHECK_EQUAL", otherwise the "value" member will be // disqualified as compile-time-only constant, needing explicit definition BOOST_CHECK( (static_gcd< 1, 1>::value) == 1 ); BOOST_CHECK( (static_gcd< 0, 0>::value) == 0 ); BOOST_CHECK( (static_gcd< 7, 0>::value) == 7 ); BOOST_CHECK( (static_gcd< 0, 9>::value) == 9 ); BOOST_CHECK( (static_gcd<42, 30>::value) == 6 ); BOOST_CHECK( (static_gcd< 3, 7>::value) == 1 ); BOOST_CHECK( (static_gcd< 8, 9>::value) == 1 ); BOOST_CHECK( (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 BOOST_AUTO_TEST_SUITE_END() // LCM tests BOOST_AUTO_TEST_SUITE( lcm_test_suite ) // LCM on signed integer types BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_int_test, T, signed_test_types ) { #ifndef BOOST_MSVC using boost::math::lcm; #else using namespace boost::math; #endif // Originally from Boost.Rational tests BOOST_CHECK_EQUAL( lcm( 1, -1), static_cast( 1) ); BOOST_CHECK_EQUAL( lcm( -1, 1), static_cast( 1) ); BOOST_CHECK_EQUAL( lcm( 1, 1), static_cast( 1) ); BOOST_CHECK_EQUAL( lcm( -1, -1), static_cast( 1) ); BOOST_CHECK_EQUAL( lcm( 0, 0), static_cast( 0) ); BOOST_CHECK_EQUAL( lcm( 6, 0), static_cast( 0) ); BOOST_CHECK_EQUAL( lcm( 0, 7), static_cast( 0) ); BOOST_CHECK_EQUAL( lcm( -5, 0), static_cast( 0) ); BOOST_CHECK_EQUAL( lcm( 0, -4), static_cast( 0) ); BOOST_CHECK_EQUAL( lcm( 18, 30), static_cast(90) ); BOOST_CHECK_EQUAL( lcm( -6, 9), static_cast(18) ); BOOST_CHECK_EQUAL( lcm(-10, -10), static_cast(10) ); BOOST_CHECK_EQUAL( lcm( 25, -10), static_cast(50) ); BOOST_CHECK_EQUAL( lcm( 3, 7), static_cast(21) ); BOOST_CHECK_EQUAL( lcm( 8, 9), static_cast(72) ); BOOST_CHECK_EQUAL( lcm( 7, 49), static_cast(49) ); } // LCM on unmarked signed integer type BOOST_AUTO_TEST_CASE( lcm_unmarked_int_test ) { #ifndef BOOST_MSVC using boost::math::lcm; #else using namespace boost::math; #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_CHECK_EQUAL( abs(lcm( 1, -1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(lcm( -1, 1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(lcm( 1, 1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(lcm( -1, -1 )), MyInt2( 1) ); BOOST_CHECK_EQUAL( abs(lcm( 0, 0 )), MyInt2( 0) ); BOOST_CHECK_EQUAL( abs(lcm( 6, 0 )), MyInt2( 0) ); BOOST_CHECK_EQUAL( abs(lcm( 0, 7 )), MyInt2( 0) ); BOOST_CHECK_EQUAL( abs(lcm( -5, 0 )), MyInt2( 0) ); BOOST_CHECK_EQUAL( abs(lcm( 0, -4 )), MyInt2( 0) ); BOOST_CHECK_EQUAL( abs(lcm( 18, 30 )), MyInt2(90) ); BOOST_CHECK_EQUAL( abs(lcm( -6, 9 )), MyInt2(18) ); BOOST_CHECK_EQUAL( abs(lcm( -10, -10 )), MyInt2(10) ); BOOST_CHECK_EQUAL( abs(lcm( 25, -10 )), MyInt2(50) ); BOOST_CHECK_EQUAL( abs(lcm( 3, 7 )), MyInt2(21) ); BOOST_CHECK_EQUAL( abs(lcm( 8, 9 )), MyInt2(72) ); BOOST_CHECK_EQUAL( abs(lcm( 7, 49 )), MyInt2(49) ); } // LCM on unsigned integer types BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_unsigned_test, T, unsigned_test_types ) { #ifndef BOOST_MSVC using boost::math::lcm; #else using namespace boost::math; #endif // Note that unmarked types (i.e. have no std::numeric_limits // specialization) are treated like non/unsigned types BOOST_CHECK_EQUAL( lcm( 1u, 1u), static_cast( 1u) ); BOOST_CHECK_EQUAL( lcm( 0u, 0u), static_cast( 0u) ); BOOST_CHECK_EQUAL( lcm( 6u, 0u), static_cast( 0u) ); BOOST_CHECK_EQUAL( lcm( 0u, 7u), static_cast( 0u) ); BOOST_CHECK_EQUAL( lcm(18u, 30u), static_cast(90u) ); BOOST_CHECK_EQUAL( lcm( 3u, 7u), static_cast(21u) ); BOOST_CHECK_EQUAL( lcm( 8u, 9u), static_cast(72u) ); BOOST_CHECK_EQUAL( lcm( 7u, 49u), static_cast(49u) ); } // LCM at compile-time BOOST_AUTO_TEST_CASE( lcm_static_test ) { #ifndef BOOST_MSVC using boost::math::static_lcm; #else using namespace boost::math; #endif // Can't use "BOOST_CHECK_EQUAL", otherwise the "value" member will be // disqualified as compile-time-only constant, needing explicit definition BOOST_CHECK( (static_lcm< 1, 1>::value) == 1 ); BOOST_CHECK( (static_lcm< 0, 0>::value) == 0 ); BOOST_CHECK( (static_lcm< 6, 0>::value) == 0 ); BOOST_CHECK( (static_lcm< 0, 7>::value) == 0 ); BOOST_CHECK( (static_lcm<18, 30>::value) == 90 ); BOOST_CHECK( (static_lcm< 3, 7>::value) == 21 ); BOOST_CHECK( (static_lcm< 8, 9>::value) == 72 ); BOOST_CHECK( (static_lcm< 7, 49>::value) == 49 ); } // TODO: see GCD to-do BOOST_AUTO_TEST_SUITE_END()