// 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 // 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 // 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; static int const 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 template < typename Ch, class Tr > friend std::basic_istream & operator >>( std::basic_istream &i, self_type &x ) { return i >> x.v_; } template < typename Ch, class Tr > friend std::basic_ostream & operator <<( std::basic_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; // Various types to test with each GCD/LCM typedef ::boost::mpl::list signed_test_types; typedef ::boost::mpl::list unsigned_test_types; } // namespace // 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: static const bool is_specialized = limits_type::is_specialized; static MyInt1 min() throw() { return limits_type::min(); } static MyInt1 max() throw() { return limits_type::max(); } static const int digits = limits_type::digits; static const int digits10 = limits_type::digits10; static const bool is_signed = limits_type::is_signed; static const bool is_integer = limits_type::is_integer; static const bool is_exact = limits_type::is_exact; static const int radix = limits_type::radix; static MyInt1 epsilon() throw() { return limits_type::epsilon(); } static MyInt1 round_error() throw() { return limits_type::round_error(); } static const int min_exponent = limits_type::min_exponent; static const int min_exponent10 = limits_type::min_exponent10; static const int max_exponent = limits_type::max_exponent; static const int max_exponent10 = limits_type::max_exponent10; static const bool has_infinity = limits_type::has_infinity; static const bool has_quiet_NaN = limits_type::has_quiet_NaN; static const bool has_signaling_NaN = limits_type::has_signaling_NaN; static const float_denorm_style has_denorm = limits_type::has_denorm; static const 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(); } static const bool is_iec559 = limits_type::is_iec559; static const bool is_bounded = limits_type::is_bounded; static const bool is_modulo = limits_type::is_modulo; static const bool traps = limits_type::traps; static const bool tinyness_before = limits_type::tinyness_before; static const 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: static const bool is_specialized = limits_type::is_specialized; static MyUnsigned1 min() throw() { return limits_type::min(); } static MyUnsigned1 max() throw() { return limits_type::max(); } static const int digits = limits_type::digits; static const int digits10 = limits_type::digits10; static const bool is_signed = limits_type::is_signed; static const bool is_integer = limits_type::is_integer; static const bool is_exact = limits_type::is_exact; static const int radix = limits_type::radix; static MyUnsigned1 epsilon() throw() { return limits_type::epsilon(); } static MyUnsigned1 round_error() throw(){return limits_type::round_error();} static const int min_exponent = limits_type::min_exponent; static const int min_exponent10 = limits_type::min_exponent10; static const int max_exponent = limits_type::max_exponent; static const int max_exponent10 = limits_type::max_exponent10; static const bool has_infinity = limits_type::has_infinity; static const bool has_quiet_NaN = limits_type::has_quiet_NaN; static const bool has_signaling_NaN = limits_type::has_signaling_NaN; static const float_denorm_style has_denorm = limits_type::has_denorm; static const 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(); } static const bool is_iec559 = limits_type::is_iec559; static const bool is_bounded = limits_type::is_bounded; static const bool is_modulo = limits_type::is_modulo; static const bool traps = limits_type::traps; static const bool tinyness_before = limits_type::tinyness_before; static const float_round_style round_style = limits_type::round_style; }; // std::numeric_limits } // 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()