diff --git a/doc/gcd/math-gcd.qbk b/doc/gcd/math-gcd.qbk new file mode 100644 index 0000000..4d3edd6 --- /dev/null +++ b/doc/gcd/math-gcd.qbk @@ -0,0 +1,247 @@ + +[mathpart gcd_lcm Integer Utilities (Greatest Common Divisor and Least Common Multiple)] + +[section Introduction] + +The class and function templates in +provide run-time and compile-time evaluation of the greatest common divisor +(GCD) or least common multiple (LCM) of two integers. +These facilities are useful for many numeric-oriented generic +programming problems. + +[endsect] + +[section Synopsis] + + namespace boost + { + namespace math + { + + template < typename IntegerType > + class gcd_evaluator; + template < typename IntegerType > + class lcm_evaluator; + + template < typename IntegerType > + IntegerType gcd( IntegerType const &a, IntegerType const &b ); + template < typename IntegerType > + IntegerType lcm( IntegerType const &a, IntegerType const &b ); + + typedef ``['see-below]`` static_gcd_type; + + template < static_gcd_type Value1, static_gcd_type Value2 > + struct static_gcd; + template < static_gcd_type Value1, static_gcd_type Value2 > + struct static_lcm; + + } + } + +[endsect] + +[section GCD Function Object] + +[*Header: ] [@../../../../boost/math/common_factor_rt.hpp ] + + template < typename IntegerType > + class boost::math::gcd_evaluator + { + public: + // Types + typedef IntegerType result_type; + typedef IntegerType first_argument_type; + typedef IntegerType second_argument_type; + + // Function object interface + result_type operator ()( first_argument_type const &a, + second_argument_type const &b ) const; + }; + +The boost::math::gcd_evaluator class template defines a function object +class to return the greatest common divisor of two integers. +The template is parameterized by a single type, called IntegerType here. +This type should be a numeric type that represents integers. +The result of the function object is always nonnegative, even if either of +the operator arguments is negative. + +This function object class template is used in the corresponding version of +the GCD function template. If a numeric type wants to customize evaluations +of its greatest common divisors, then the type should specialize on the +gcd_evaluator class template. + +[endsect] + +[section LCM Function Object] + +[*Header: ] [@../../../../boost/math/common_factor_rt.hpp ] + + template < typename IntegerType > + class boost::math::lcm_evaluator + { + public: + // Types + typedef IntegerType result_type; + typedef IntegerType first_argument_type; + typedef IntegerType second_argument_type; + + // Function object interface + result_type operator ()( first_argument_type const &a, + second_argument_type const &b ) const; + }; + +The boost::math::lcm_evaluator class template defines a function object +class to return the least common multiple of two integers. The template +is parameterized by a single type, called IntegerType here. This type +should be a numeric type that represents integers. The result of the +function object is always nonnegative, even if either of the operator +arguments is negative. If the least common multiple is beyond the range +of the integer type, the results are undefined. + +This function object class template is used in the corresponding version +of the LCM function template. If a numeric type wants to customize +evaluations of its least common multiples, then the type should +specialize on the lcm_evaluator class template. + +[endsect] + +[section:run_time Run-time GCD & LCM Determination] + +[*Header: ] [@../../../../boost/math/common_factor_rt.hpp ] + + template < typename IntegerType > + IntegerType boost::math::gcd( IntegerType const &a, IntegerType const &b ); + + template < typename IntegerType > + IntegerType boost::math::lcm( IntegerType const &a, IntegerType const &b ); + +The boost::math::gcd function template returns the greatest common +(nonnegative) divisor of the two integers passed to it. +The boost::math::lcm function template returns the least common +(nonnegative) multiple of the two integers passed to it. +The function templates are parameterized on the function arguments' +IntegerType, which is also the return type. Internally, these function +templates use an object of the corresponding version of the +gcd_evaluator and lcm_evaluator class templates, respectively. + +[endsect] + +[section:compile_time Compile time GCD and LCM determination] + +[*Header: ] [@../../../../boost/math/common_factor_ct.hpp ] + + typedef ``['unspecified]`` static_gcd_type; + + template < static_gcd_type Value1, static_gcd_type Value2 > + struct boost::math::static_gcd : public mpl::integral_c + { + }; + + template < static_gcd_type Value1, static_gcd_type Value2 > + struct boost::math::static_lcm : public mpl::integral_c + { + }; + +The type `static_gcd_type` is the widest unsigned-integer-type that is supported +for use in integral-constant-expressions by the compiler. Usually this +the same type as `boost::uintmax_t`, but may fall back to being `unsigned long` +for some older compilers. + +The boost::math::static_gcd and boost::math::static_lcm class templates +take two value-based template parameters of the ['static_gcd_type] type +and inherit from the type `boost::mpl::integral_c`. +Inherited from the base class, they have a member /value/ +that is the greatest common factor or least +common multiple, respectively, of the template arguments. +A compile-time error will occur if the least common multiple +is beyond the range of `static_gcd_type`. + +[h3 Example] + + #include + #include + #include + #include + + int main() + { + using std::cout; + using std::endl; + + cout << "The GCD and LCM of 6 and 15 are " + << boost::math::gcd(6, 15) << " and " + << boost::math::lcm(6, 15) << ", respectively." + << endl; + + cout << "The GCD and LCM of 8 and 9 are " + << boost::math::static_gcd<8, 9>::value + << " and " + << boost::math::static_lcm<8, 9>::value + << ", respectively." << endl; + + int a[] = { 4, 5, 6 }, b[] = { 7, 8, 9 }, c[3]; + std::transform( a, a + 3, b, c, boost::math::gcd_evaluator() ); + std::copy( c, c + 3, std::ostream_iterator(cout, " ") ); + } + +[endsect] + +[section:gcd_header Header ] + +This header simply includes the headers +[@../../../../boost/math/common_factor_ct.hpp ] +and [@../../../../boost/math/common_factor_rt.hpp ]. + +Note this is a legacy header: it used to contain the actual implementation, +but the compile-time and run-time facilities +were moved to separate headers (since they were independent of each other). + +[endsect] + +[section:demo Demonstration Program] + +The program [@../../../../libs/math/test/common_factor_test.cpp common_factor_test.cpp] is a demonstration of the results from +instantiating various examples of the run-time GCD and LCM function +templates and the compile-time GCD and LCM class templates. +(The run-time GCD and LCM class templates are tested indirectly through +the run-time function templates.) + +[endsect] + +[section Rationale] + +The greatest common divisor and least common multiple functions are +greatly used in some numeric contexts, including some of the other +Boost libraries. Centralizing these functions to one header improves +code factoring and eases maintainence. + +[endsect] + +[section:gcd_history History] + +* 13 May 2013 Moved into main Boost.Math Quickbook documentation. +* 17 Dec 2005: Converted documentation to Quickbook Format. +* 2 Jul 2002: Compile-time and run-time items separated to new headers. +* 7 Nov 2001: Initial version + +[endsect] + +[section:gcd_credits Credits] + +The author of the Boost compilation of GCD and LCM computations is +Daryle Walker. The code was prompted by existing code hiding in the +implementations of Paul Moore's rational library and Steve Cleary's +pool library. The code had updates by Helmut Zeisel. + +[endsect] + +[endmathpart] + +[/ +Copyright 2005, 2013 Daryle Walker. +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). +] + + diff --git a/include/boost/math/common_factor.hpp b/include/boost/math/common_factor.hpp new file mode 100644 index 0000000..21a71e4 --- /dev/null +++ b/include/boost/math/common_factor.hpp @@ -0,0 +1,16 @@ +// Boost common_factor.hpp header file -------------------------------------// + +// (C) Copyright Daryle Walker 2001-2002. +// 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 updates, documentation, and revision history. + +#ifndef BOOST_MATH_COMMON_FACTOR_HPP +#define BOOST_MATH_COMMON_FACTOR_HPP + +#include +#include + +#endif // BOOST_MATH_COMMON_FACTOR_HPP diff --git a/include/boost/math/common_factor_ct.hpp b/include/boost/math/common_factor_ct.hpp new file mode 100644 index 0000000..bf58b94 --- /dev/null +++ b/include/boost/math/common_factor_ct.hpp @@ -0,0 +1,97 @@ +// Boost common_factor_ct.hpp header file ----------------------------------// + +// (C) Copyright Daryle Walker and Stephen Cleary 2001-2002. +// 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 updates, documentation, and revision history. + +#ifndef BOOST_MATH_COMMON_FACTOR_CT_HPP +#define BOOST_MATH_COMMON_FACTOR_CT_HPP + +#include // self include +#include // for BOOST_STATIC_CONSTANT, etc. +#include + +namespace boost +{ +namespace math +{ + +// Implementation details --------------------------------------------------// + +namespace detail +{ + // Build GCD with Euclid's recursive algorithm + template < static_gcd_type Value1, static_gcd_type Value2 > + struct static_gcd_helper_t + { + private: + BOOST_STATIC_CONSTANT( static_gcd_type, new_value1 = Value2 ); + BOOST_STATIC_CONSTANT( static_gcd_type, new_value2 = Value1 % Value2 ); + + #ifndef __BORLANDC__ + #define BOOST_DETAIL_GCD_HELPER_VAL(Value) static_cast(Value) + #else + typedef static_gcd_helper_t self_type; + #define BOOST_DETAIL_GCD_HELPER_VAL(Value) (self_type:: Value ) + #endif + + typedef static_gcd_helper_t< BOOST_DETAIL_GCD_HELPER_VAL(new_value1), + BOOST_DETAIL_GCD_HELPER_VAL(new_value2) > next_step_type; + + #undef BOOST_DETAIL_GCD_HELPER_VAL + + public: + BOOST_STATIC_CONSTANT( static_gcd_type, value = next_step_type::value ); + }; + + // Non-recursive case + template < static_gcd_type Value1 > + struct static_gcd_helper_t< Value1, 0UL > + { + BOOST_STATIC_CONSTANT( static_gcd_type, value = Value1 ); + }; + + // Build the LCM from the GCD + template < static_gcd_type Value1, static_gcd_type Value2 > + struct static_lcm_helper_t + { + typedef static_gcd_helper_t gcd_type; + + BOOST_STATIC_CONSTANT( static_gcd_type, value = Value1 / gcd_type::value + * Value2 ); + }; + + // Special case for zero-GCD values + template < > + struct static_lcm_helper_t< 0UL, 0UL > + { + BOOST_STATIC_CONSTANT( static_gcd_type, value = 0UL ); + }; + +} // namespace detail + + +// Compile-time greatest common divisor evaluator class declaration --------// + +template < static_gcd_type Value1, static_gcd_type Value2 > +struct static_gcd : public mpl::integral_c::value) > +{ +}; // boost::math::static_gcd + + +// Compile-time least common multiple evaluator class declaration ----------// + +template < static_gcd_type Value1, static_gcd_type Value2 > +struct static_lcm : public mpl::integral_c::value) > +{ +}; // boost::math::static_lcm + + +} // namespace math +} // namespace boost + + +#endif // BOOST_MATH_COMMON_FACTOR_CT_HPP diff --git a/include/boost/math/common_factor_rt.hpp b/include/boost/math/common_factor_rt.hpp new file mode 100644 index 0000000..10a92eb --- /dev/null +++ b/include/boost/math/common_factor_rt.hpp @@ -0,0 +1,460 @@ +// Boost common_factor_rt.hpp header file ----------------------------------// + +// (C) Copyright Daryle Walker and Paul Moore 2001-2002. Permission to copy, +// use, modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided "as is" +// without express or implied warranty, and with no claim as to its suitability +// for any purpose. + +// boostinspect:nolicense (don't complain about the lack of a Boost license) +// (Paul Moore hasn't been in contact for years, so there's no way to change the +// license.) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP +#define BOOST_MATH_COMMON_FACTOR_RT_HPP + +#include // self include + +#include // for BOOST_NESTED_TEMPLATE, etc. +#include // for std::numeric_limits +#include // for CHAR_MIN +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127 4244) // Conditional expression is constant +#endif + +namespace boost +{ +namespace math +{ + + +// Forward declarations for function templates -----------------------------// + +template < typename IntegerType > + IntegerType gcd( IntegerType const &a, IntegerType const &b ); + +template < typename IntegerType > + IntegerType lcm( IntegerType const &a, IntegerType const &b ); + + +// Greatest common divisor evaluator class declaration ---------------------// + +template < typename IntegerType > +class gcd_evaluator +{ +public: + // Types + typedef IntegerType result_type, first_argument_type, second_argument_type; + + // Function object interface + result_type operator ()( first_argument_type const &a, + second_argument_type const &b ) const; + +}; // boost::math::gcd_evaluator + + +// Least common multiple evaluator class declaration -----------------------// + +template < typename IntegerType > +class lcm_evaluator +{ +public: + // Types + typedef IntegerType result_type, first_argument_type, second_argument_type; + + // Function object interface + result_type operator ()( first_argument_type const &a, + second_argument_type const &b ) const; + +}; // boost::math::lcm_evaluator + + +// Implementation details --------------------------------------------------// + +namespace detail +{ + // Greatest common divisor for rings (including unsigned integers) + template < typename RingType > + RingType + gcd_euclidean + ( + RingType a, + RingType b + ) + { + // Avoid repeated construction + #ifndef __BORLANDC__ + RingType const zero = static_cast( 0 ); + #else + RingType zero = static_cast( 0 ); + #endif + + // Reduce by GCD-remainder property [GCD(a,b) == GCD(b,a MOD b)] + while ( true ) + { + if ( a == zero ) + return b; + b %= a; + + if ( b == zero ) + return a; + a %= b; + } + } + + // Greatest common divisor for (signed) integers + template < typename IntegerType > + inline + IntegerType + gcd_integer + ( + IntegerType const & a, + IntegerType const & b + ) + { + // Avoid repeated construction + IntegerType const zero = static_cast( 0 ); + IntegerType const result = gcd_euclidean( a, b ); + + return ( result < zero ) ? static_cast(-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 + { +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + while ( !(r[ which ] & 1u) ) + { + r[ which ] = (r[which] >> 1); + } +#else + // Remove factors of two from the even one + while ( !(r[ which ] & 1u) ) + { + r[ which ] >>= 1; + } +#endif + + // 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 + RingType + lcm_euclidean + ( + RingType const & a, + RingType const & b + ) + { + RingType const zero = static_cast( 0 ); + RingType const temp = gcd_euclidean( a, b ); + + return ( temp != zero ) ? ( a / temp * b ) : zero; + } + + // Least common multiple for (signed) integers + template < typename IntegerType > + inline + IntegerType + lcm_integer + ( + IntegerType const & a, + IntegerType const & b + ) + { + // Avoid repeated construction + IntegerType const zero = static_cast( 0 ); + IntegerType const result = lcm_euclidean( a, b ); + + return ( result < zero ) ? static_cast(-result) : result; + } + + // Function objects to find the best way of computing GCD or LCM +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + template < typename T, bool IsSpecialized, bool IsSigned > + struct gcd_optimal_evaluator_helper_t + { + T operator ()( T const &a, T const &b ) + { + return gcd_euclidean( a, b ); + } + }; + + template < typename T > + struct gcd_optimal_evaluator_helper_t< T, true, true > + { + T operator ()( T const &a, T const &b ) + { + return gcd_integer( a, b ); + } + }; + + template < typename T > + struct gcd_optimal_evaluator + { + T operator ()( T const &a, T const &b ) + { + typedef ::std::numeric_limits limits_type; + + typedef gcd_optimal_evaluator_helper_t helper_type; + + helper_type solver; + + return solver( a, b ); + } + }; +#else // BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + template < typename T > + struct gcd_optimal_evaluator + { + T operator ()( T const &a, T const &b ) + { + return gcd_integer( a, b ); + } + }; +#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( boost::ulong_long_type ); +#elif defined(BOOST_HAS_MS_INT64) + BOOST_PRIVATE_GCD_UF( unsigned __int64 ); +#endif + +#if CHAR_MIN == 0 + BOOST_PRIVATE_GCD_UF( char ); // char is unsigned +#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 ); + +#if CHAR_MIN < 0 + BOOST_PRIVATE_GCD_SF( char, unsigned char ); // char is signed +#endif + +#ifdef BOOST_HAS_LONG_LONG + BOOST_PRIVATE_GCD_SF( boost::long_long_type, boost::ulong_long_type ); +#elif defined(BOOST_HAS_MS_INT64) + BOOST_PRIVATE_GCD_SF( __int64, unsigned __int64 ); +#endif + +#undef BOOST_PRIVATE_GCD_SF + +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + template < typename T, bool IsSpecialized, bool IsSigned > + struct lcm_optimal_evaluator_helper_t + { + T operator ()( T const &a, T const &b ) + { + return lcm_euclidean( a, b ); + } + }; + + template < typename T > + struct lcm_optimal_evaluator_helper_t< T, true, true > + { + T operator ()( T const &a, T const &b ) + { + return lcm_integer( a, b ); + } + }; + + template < typename T > + struct lcm_optimal_evaluator + { + T operator ()( T const &a, T const &b ) + { + typedef ::std::numeric_limits limits_type; + + typedef lcm_optimal_evaluator_helper_t helper_type; + + helper_type solver; + + return solver( a, b ); + } + }; +#else // BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + template < typename T > + struct lcm_optimal_evaluator + { + T operator ()( T const &a, T const &b ) + { + return lcm_integer( a, b ); + } + }; +#endif + + // Functions to find the GCD or LCM in the best way + template < typename T > + inline + T + gcd_optimal + ( + T const & a, + T const & b + ) + { + gcd_optimal_evaluator solver; + + return solver( a, b ); + } + + template < typename T > + inline + T + lcm_optimal + ( + T const & a, + T const & b + ) + { + lcm_optimal_evaluator solver; + + return solver( a, b ); + } + +} // namespace detail + + +// Greatest common divisor evaluator member function definition ------------// + +template < typename IntegerType > +inline +typename gcd_evaluator::result_type +gcd_evaluator::operator () +( + first_argument_type const & a, + second_argument_type const & b +) const +{ + return detail::gcd_optimal( a, b ); +} + + +// Least common multiple evaluator member function definition --------------// + +template < typename IntegerType > +inline +typename lcm_evaluator::result_type +lcm_evaluator::operator () +( + first_argument_type const & a, + second_argument_type const & b +) const +{ + return detail::lcm_optimal( a, b ); +} + + +// Greatest common divisor and least common multiple function definitions --// + +template < typename IntegerType > +inline +IntegerType +gcd +( + IntegerType const & a, + IntegerType const & b +) +{ + gcd_evaluator solver; + + return solver( a, b ); +} + +template < typename IntegerType > +inline +IntegerType +lcm +( + IntegerType const & a, + IntegerType const & b +) +{ + lcm_evaluator solver; + + return solver( a, b ); +} + + +} // namespace math +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif // BOOST_MATH_COMMON_FACTOR_RT_HPP diff --git a/test/common_factor_test.cpp b/test/common_factor_test.cpp new file mode 100644 index 0000000..11c32a6 --- /dev/null +++ b/test/common_factor_test.cpp @@ -0,0 +1,478 @@ +// 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 // 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); +#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 +// 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()