From 56b287a59020232337ffa7fc65acf9d1d03bbe5e Mon Sep 17 00:00:00 2001 From: Daryle Walker Date: Fri, 3 Nov 2006 22:43:34 +0000 Subject: [PATCH] Added custom integer types, signed and unsigned, with and without std::numeric_limits<> specializations, to test [SVN r35830] --- test/common_factor_test.cpp | 305 ++++++++++++++++++++++++++++++++---- 1 file changed, 277 insertions(+), 28 deletions(-) diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 661bdff..6a897c6 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -8,7 +8,8 @@ // See http://www.boost.org for most recent version including documentation. // Revision History -// 02 Nov 2006 Change to Boost.Test's unit test system +// 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" @@ -16,29 +17,211 @@ #include // for BOOST_MSVC #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 new signed and unsigned types here, with and without numeric_limits -// specialization; add polynominal/non-real type; especially after any switch to -// the binary-GCD algorithm for built-in types +// 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 builtin_signed_test_types; typedef ::boost::mpl::list builtin_unsigned_test_types; +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 built-in signed integer types -BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_int_test, T, builtin_signed_test_types ) +// GCD on signed integer types +BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_int_test, T, signed_test_types ) { #ifndef BOOST_MSVC using boost::math::gcd; @@ -65,8 +248,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( gcd_int_test, T, builtin_signed_test_types ) BOOST_CHECK_EQUAL( gcd( 7, 49), static_cast( 7) ); } -// GCD on built-in unsigned integer types -BOOST_AUTO_TEST_CASE_TEMPLATE(gcd_unsigned_test, T, builtin_unsigned_test_types) +// GCD on unmarked signed integer type +BOOST_AUTO_TEST_CASE( gcd_unmarked_int_test ) { #ifndef BOOST_MSVC using boost::math::gcd; @@ -74,14 +257,47 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(gcd_unsigned_test, T, builtin_unsigned_test_types) using namespace boost::math; #endif - 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) ); + // 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 @@ -115,8 +331,8 @@ BOOST_AUTO_TEST_SUITE_END() // LCM tests BOOST_AUTO_TEST_SUITE( lcm_test_suite ) -// LCM on built-in signed integer types -BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_int_test, T, builtin_signed_test_types ) +// LCM on signed integer types +BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_int_test, T, signed_test_types ) { #ifndef BOOST_MSVC using boost::math::lcm; @@ -143,8 +359,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( lcm_int_test, T, builtin_signed_test_types ) BOOST_CHECK_EQUAL( lcm( 7, 49), static_cast(49) ); } -// LCM on built-in unsigned integer types -BOOST_AUTO_TEST_CASE_TEMPLATE(lcm_unsigned_test, T, builtin_unsigned_test_types) +// LCM on unmarked signed integer type +BOOST_AUTO_TEST_CASE( lcm_unmarked_int_test ) { #ifndef BOOST_MSVC using boost::math::lcm; @@ -152,14 +368,47 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(lcm_unsigned_test, T, builtin_unsigned_test_types) using namespace boost::math; #endif - 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) ); + // 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