diff --git a/include/boost/math/common_factor_rt.hpp b/include/boost/math/common_factor_rt.hpp index 5b8cd45..97006c5 100644 --- a/include/boost/math/common_factor_rt.hpp +++ b/include/boost/math/common_factor_rt.hpp @@ -114,6 +114,62 @@ namespace detail return ( result < zero ) ? -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 + { + // Remove factors of two from the even one + while ( !(r[ which ] & 1u) ) + { + r[ which ] >>= 1; + } + + // 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 @@ -228,6 +284,50 @@ namespace detail }; #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( unsigned long long ); +#endif + +#ifdef BOOST_HAS_MS_INT64 + BOOST_PRIVATE_GCD_UF( unsigned __int64 ); +#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 ); + + BOOST_PRIVATE_GCD_SF( char, unsigned char ); // should work even if unsigned + +#ifdef BOOST_HAS_LONG_LONG + BOOST_PRIVATE_GCD_SF( long long, unsigned long long ); +#endif + +#ifdef BOOST_HAS_MS_INT64 + BOOST_PRIVATE_GCD_SF( __int64, unsigned __int64 ); +#endif + +#undef BOOST_PRIVATE_GCD_SF + #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS #ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION template < typename T, bool IsSpecialized, bool IsSigned > diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp index 6a897c6..80bc11c 100644 --- a/test/common_factor_test.cpp +++ b/test/common_factor_test.cpp @@ -8,6 +8,7 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 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) @@ -104,13 +105,23 @@ 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; +typedef ::boost::mpl::list signed_test_types; +typedef ::boost::mpl::list unsigned_test_types; } // namespace