// 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 <boost/math_fwd.hpp> // self include | |
#include <boost/config.hpp> // for BOOST_NESTED_TEMPLATE, etc. | |
#include <boost/limits.hpp> // for std::numeric_limits | |
#include <climits> // for CHAR_MIN | |
#include <boost/detail/workaround.hpp> | |
#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<RingType>( 0 ); | |
#else | |
RingType zero = static_cast<RingType>( 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<IntegerType>( 0 ); | |
IntegerType const result = gcd_euclidean( a, b ); | |
return ( result < zero ) ? static_cast<IntegerType>(-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<bool>( 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<RingType>( 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<IntegerType>( 0 ); | |
IntegerType const result = lcm_euclidean( a, b ); | |
return ( result < zero ) ? static_cast<IntegerType>(-result) : result; | |
} | |
// Function objects to find the best way of computing GCD or LCM | |
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS | |
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | |
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 ); | |
} | |
}; | |
#else | |
template < bool IsSpecialized, bool IsSigned > | |
struct gcd_optimal_evaluator_helper2_t | |
{ | |
template < typename T > | |
struct helper | |
{ | |
T operator ()( T const &a, T const &b ) | |
{ | |
return gcd_euclidean( a, b ); | |
} | |
}; | |
}; | |
template < > | |
struct gcd_optimal_evaluator_helper2_t< true, true > | |
{ | |
template < typename T > | |
struct helper | |
{ | |
T operator ()( T const &a, T const &b ) | |
{ | |
return gcd_integer( a, b ); | |
} | |
}; | |
}; | |
template < typename T, bool IsSpecialized, bool IsSigned > | |
struct gcd_optimal_evaluator_helper_t | |
: gcd_optimal_evaluator_helper2_t<IsSpecialized, IsSigned> | |
::BOOST_NESTED_TEMPLATE helper<T> | |
{ | |
}; | |
#endif | |
template < typename T > | |
struct gcd_optimal_evaluator | |
{ | |
T operator ()( T const &a, T const &b ) | |
{ | |
typedef ::std::numeric_limits<T> limits_type; | |
typedef gcd_optimal_evaluator_helper_t<T, | |
limits_type::is_specialized, limits_type::is_signed> 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> \ | |
{ 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> \ | |
{ St operator ()( St a, St b ) const { Ut const a_abs = \ | |
static_cast<Ut>( a < 0 ? -a : +a ), b_abs = static_cast<Ut>( \ | |
b < 0 ? -b : +b ); return static_cast<St>( \ | |
gcd_optimal_evaluator<Ut>()(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 | |
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | |
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 ); | |
} | |
}; | |
#else | |
template < bool IsSpecialized, bool IsSigned > | |
struct lcm_optimal_evaluator_helper2_t | |
{ | |
template < typename T > | |
struct helper | |
{ | |
T operator ()( T const &a, T const &b ) | |
{ | |
return lcm_euclidean( a, b ); | |
} | |
}; | |
}; | |
template < > | |
struct lcm_optimal_evaluator_helper2_t< true, true > | |
{ | |
template < typename T > | |
struct helper | |
{ | |
T operator ()( T const &a, T const &b ) | |
{ | |
return lcm_integer( a, b ); | |
} | |
}; | |
}; | |
template < typename T, bool IsSpecialized, bool IsSigned > | |
struct lcm_optimal_evaluator_helper_t | |
: lcm_optimal_evaluator_helper2_t<IsSpecialized, IsSigned> | |
::BOOST_NESTED_TEMPLATE helper<T> | |
{ | |
}; | |
#endif | |
template < typename T > | |
struct lcm_optimal_evaluator | |
{ | |
T operator ()( T const &a, T const &b ) | |
{ | |
typedef ::std::numeric_limits<T> limits_type; | |
typedef lcm_optimal_evaluator_helper_t<T, | |
limits_type::is_specialized, limits_type::is_signed> 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<T> solver; | |
return solver( a, b ); | |
} | |
template < typename T > | |
inline | |
T | |
lcm_optimal | |
( | |
T const & a, | |
T const & b | |
) | |
{ | |
lcm_optimal_evaluator<T> solver; | |
return solver( a, b ); | |
} | |
} // namespace detail | |
// Greatest common divisor evaluator member function definition ------------// | |
template < typename IntegerType > | |
inline | |
typename gcd_evaluator<IntegerType>::result_type | |
gcd_evaluator<IntegerType>::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<IntegerType>::result_type | |
lcm_evaluator<IntegerType>::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<IntegerType> solver; | |
return solver( a, b ); | |
} | |
template < typename IntegerType > | |
inline | |
IntegerType | |
lcm | |
( | |
IntegerType const & a, | |
IntegerType const & b | |
) | |
{ | |
lcm_evaluator<IntegerType> solver; | |
return solver( a, b ); | |
} | |
} // namespace math | |
} // namespace boost | |
#ifdef BOOST_MSVC | |
#pragma warning(pop) | |
#endif | |
#endif // BOOST_MATH_COMMON_FACTOR_RT_HPP |