2
0
mirror of https://github.com/boostorg/math.git synced 2026-01-19 04:22:09 +00:00

Adjusted for moving the Compile-Time and Run-Time GCD and LCM components to new, separate headers

[SVN r14273]
This commit is contained in:
Daryle Walker
2002-07-02 08:31:15 +00:00
parent 93af018235
commit 5255f7d989
4 changed files with 96 additions and 600 deletions

View File

@@ -23,20 +23,35 @@ programming problems.</p>
<ul>
<li><a href="#contents">Contents</a></li>
<li>Header <cite><a href="#cf_hpp">&lt;boost/math/common_factor.hpp&gt;</a></cite>
<ul>
<li><a href="#synopsis">Synopsis</a></li>
</ul></li>
<li>Header <cite><a href="#cfrt_hpp">&lt;boost/math/common_factor_rt.hpp&gt;</a></cite>
<ul>
<li><a href="#gcd_obj">GCD Function Object</a></li>
<li><a href="#lcm_obj">LCM Function Object</a></li>
<li><a href="#run_gcd_lcm">Run-time GCD &amp; LCM
Determination</a></li>
<li><a href="#ct_gcd_lcm">Compile-time GCD &amp; LCM
Determination</a></li>
<li><a href="#run_gcd_lcm">Run-time GCD &amp; LCM Determination</a></li>
</ul></li>
<li>Header <cite><a href="#cfct_hpp">&lt;boost/math/common_factor_ct.hpp&gt;</a></cite></li>
<li><a href="#example">Example</a></li>
<li><a href="#demo">Demonstration Program</a></li>
<li><a href="#rationale">Rationale</a></li>
<li><a href="#history">History</a></li>
<li><a href="#credits">Credits</a></li>
</ul>
<h2><a name="synopsis">Synopsis</a></h2>
<h2>Header <cite><a name="cf_hpp" href="../../../boost/math/common_factor.hpp">&lt;boost/math/common_factor.hpp&gt;</a></cite></h2>
<p>This header simply includes the headers <cite><a
href="../../../boost/math/common_factor_ct.hpp">&lt;boost/math/common_factor_ct.hpp&gt;</a></cite>
and <cite><a
href="../../../boost/math/common_factor_rt.hpp">&lt;boost/math/common_factor_rt.hpp&gt;</a></cite>.
It used to contain the code, but the compile-time and run-time
facilities were moved to separate headers (since they were independent),
and this header maintains compatibility.</p>
<h3><a name="synopsis">Synopsis</a></h3>
<blockquote><pre>namespace boost
{
@@ -62,7 +77,9 @@ template &lt; unsigned long Value1, unsigned long Value2 &gt;
}
</pre></blockquote>
<h2><a name="gcd_obj">GCD Function Object</a></h2>
<h2>Header <cite><a name="cfrt_hpp" href="../../../boost/math/common_factor_rt.hpp">&lt;boost/math/common_factor_rt.hpp&gt;</a></cite></h2>
<h3><a name="gcd_obj">GCD Function Object</a></h3>
<blockquote><pre>template &lt; typename IntegerType &gt;
class boost::math::gcd_evaluator
@@ -79,20 +96,20 @@ public:
};
</pre></blockquote>
<p>The <code>boost::math::gcd_evaluator</code> class template defines
a function object class to return the greatest common divisor of two
<p>The <code>boost::math::gcd_evaluator</code> 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
<code>IntegerType</code> here. This type should be a numeric type
that represents integers. The result of the function object is always
<code>IntegerType</code> 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.</p>
<p>This function object class template is used in the corresponding
version of the <a href="#run_gcd_lcm">GCD function template</a>. If
a numeric type wants to customize evaluations of its greatest common
divisors, then the type should specialize on the <code>gcd_evaluator</code>
class template.</p>
version of the <a href="#run_gcd_lcm">GCD function template</a>. If a
numeric type wants to customize evaluations of its greatest common
divisors, then the type should specialize on the
<code>gcd_evaluator</code> class template.</p>
<h2><a name="lcm_obj">LCM Function Object</a></h2>
<h3><a name="lcm_obj">LCM Function Object</a></h3>
<blockquote><pre>template &lt; typename IntegerType &gt;
class boost::math::lcm_evaluator
@@ -109,22 +126,22 @@ public:
};
</pre></blockquote>
<p>The <code>boost::math::lcm_evaluator</code> class template defines
a function object class to return the least common multiple of two
<p>The <code>boost::math::lcm_evaluator</code> 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
<code>IntegerType</code> 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.</p>
<code>IntegerType</code> 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.</p>
<p>This function object class template is used in the corresponding
version of the <a href="#run_gcd_lcm">LCM function template</a>. If a
numeric type wants to customize evaluations of its least common
multiples, then the type should specialize on the <code>lcm_evaluator</code>
class template.</p>
multiples, then the type should specialize on the
<code>lcm_evaluator</code> class template.</p>
<h2><a name="run_gcd_lcm">Run-time GCD &amp; LCM Determination</a></h2>
<h3><a name="run_gcd_lcm">Run-time GCD &amp; LCM Determination</a></h3>
<blockquote><pre>template &lt; typename IntegerType &gt;
IntegerType boost::math::gcd( IntegerType const &amp;a, IntegerType const &amp;b );
@@ -133,17 +150,18 @@ template &lt; typename IntegerType &gt;
IntegerType boost::math::lcm( IntegerType const &amp;a, IntegerType const &amp;b );
</pre></blockquote>
<p>The <code>boost::math::gcd</code> function template returns the greatest
common (nonnegative) divisor of the two integers passed to it. The
<code>boost::math::lcm</code> function template returns the least common
(nonnegative) multiple of the two integers passed to it. The function
templates are parameterized on the function arguments' <var>IntegerType</var>,
which is also the return type. Internally, these function templates use
an object of the corresponding version of the <code><a
href="#gcd_obj">gcd_evaluator</a></code> and <code><a
href="#lcm_obj">lcm_evaluator</a></code> class templates, respectively.</p>
<p>The <code>boost::math::gcd</code> function template returns the
greatest common (nonnegative) divisor of the two integers passed to it.
The <code>boost::math::lcm</code> function template returns the least
common (nonnegative) multiple of the two integers passed to it. The
function templates are parameterized on the function arguments'
<var>IntegerType</var>, which is also the return type. Internally,
these function templates use an object of the corresponding version of
the <code><a href="#gcd_obj">gcd_evaluator</a></code> and <code><a
href="#lcm_obj">lcm_evaluator</a></code> class templates,
respectively.</p>
<h2><a name="ct_gcd_lcm">Compile-time GCD &amp; LCM Determination</a></h2>
<h2>Header <cite><a name="cfct_hpp" href="../../../boost/math/common_factor_ct.hpp">&lt;boost/math/common_factor_ct.hpp&gt;</a></cite></h2>
<blockquote><pre>template &lt; unsigned long Value1, unsigned long Value2 &gt;
struct boost::math::static_gcd
@@ -158,13 +176,14 @@ struct boost::math::static_lcm
};
</pre></blockquote>
<p>The <code>boost::math::static_gcd</code> and <code>boost::math::static_lcm</code>
class templates take two value-based template parameters of the
<code>unsigned long</code> type and have a single static constant data
member, <code>value</code>, of that same type. The value of that member
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 an <code>unsigned long</code>.</p>
<p>The <code>boost::math::static_gcd</code> and
<code>boost::math::static_lcm</code> class templates take two
value-based template parameters of the <code>unsigned long</code> type
and have a single static constant data member, <code>value</code>, of
that same type. The value of that member 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 an <code>unsigned long</code>.</p>
<h2><a name="example">Example</a></h2>
@@ -211,6 +230,16 @@ 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.</p>
<h2><a name="history">History</a></h2>
<dl>
<dt>2 Jul 2002
<dd>Compile-time and run-time items separated to new headers.
<dt>7 Nov 2001
<dd>Initial version
</dl>
<h2><a name="credits">Credits</a></h2>
<p>The author of the Boost compilation of GCD and LCM computations is <a
@@ -223,9 +252,9 @@ Helmut Zeisel.</p>
<hr>
<p>Revised November 7, 2001</p>
<p>Revised July 2, 2002</p>
<p>&copy; Copyright Daryle Walker 2001. Permission to copy, use,
<p>&copy; Copyright Daryle Walker 2001-2002. Permission to copy, use,
modify, sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided
&quot;as is&quot; without express or implied warranty, and with no claim

View File

@@ -70,6 +70,8 @@
<tr>
<td align="center">
<code><a href="../../../boost/math/common_factor.hpp">&lt;boost/math/common_factor.hpp&gt;</a></code><br>
<code><a href="../../../boost/math/common_factor_ct.hpp">&lt;boost/math/common_factor_ct.hpp&gt;</a></code><br>
<code><a href="../../../boost/math/common_factor_rt.hpp">&lt;boost/math/common_factor_rt.hpp&gt;</a></code><br>
<br><a href="common_factor.html">documentation</a>
</td>
<td valign="top">Compile-time and run-time class and function
@@ -87,7 +89,7 @@ items.</p>
<hr>
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->30 November, 2001<!--webbot bot="Timestamp" i-checksum="39352" endspan --></p>
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->2 July, 2002<!--webbot bot="Timestamp" i-checksum="39352" endspan --></p>
</body>
</html>

View File

@@ -1,560 +1,17 @@
// Boost common_factor.hpp header file -------------------------------------//
// (C) Copyright Daryle Walker, Stephen Cleary, Paul Moore 2001. 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.
// (C) Copyright Daryle Walker 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.
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_MATH_COMMON_FACTOR_HPP
#define BOOST_MATH_COMMON_FACTOR_HPP
#include <boost/math_fwd.hpp> // self include
#include <boost/config.hpp> // for BOOST_STATIC_CONSTANT, etc.
#include <boost/limits.hpp> // for std::numeric_limits
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
{
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// Build GCD with Euclid's recursive algorithm
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd_helper_t
{
private:
BOOST_STATIC_CONSTANT( unsigned long, new_value1 = Value2 );
BOOST_STATIC_CONSTANT( unsigned long, new_value2 = Value1 % Value2 );
#ifndef __BORLANDC__
#define BOOST_DETAIL_GCD_HELPER_VAL(Value) 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( unsigned long, value = next_step_type::value );
};
// Non-recursive case
template < unsigned long Value1 >
struct static_gcd_helper_t< Value1, 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = Value1 );
};
#else
// Use inner class template workaround from Peter Dimov
template < unsigned long Value1 >
struct static_gcd_helper2_t
{
template < unsigned long Value2 >
struct helper
{
BOOST_STATIC_CONSTANT( unsigned long, value
= static_gcd_helper2_t<Value2>::helper<Value1 % Value2>::value );
};
template < >
struct helper< 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = Value1 );
};
};
// Special case
template < >
struct static_gcd_helper2_t< 0UL >
{
template < unsigned long Value2 >
struct helper
{
BOOST_STATIC_CONSTANT( unsigned long, value = Value2 );
};
};
// Build the GCD from the above template(s)
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd_helper_t
{
BOOST_STATIC_CONSTANT( unsigned long, value
= static_gcd_helper2_t<Value1>::BOOST_NESTED_TEMPLATE
helper<Value2>::value );
};
#endif
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// Build the LCM from the GCD
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm_helper_t
{
typedef static_gcd_helper_t<Value1, Value2> gcd_type;
BOOST_STATIC_CONSTANT( unsigned long, value = Value1 / gcd_type::value
* Value2 );
};
// Special case for zero-GCD values
template < >
struct static_lcm_helper_t< 0UL, 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = 0UL );
};
#else
// Adapt GCD's inner class template workaround for LCM
template < unsigned long Value1 >
struct static_lcm_helper2_t
{
template < unsigned long Value2 >
struct helper
{
typedef static_gcd_helper_t<Value1, Value2> gcd_type;
BOOST_STATIC_CONSTANT( unsigned long, value = Value1
/ gcd_type::value * Value2 );
};
template < >
struct helper< 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = 0UL );
};
};
// Special case
template < >
struct static_lcm_helper2_t< 0UL >
{
template < unsigned long Value2 >
struct helper
{
BOOST_STATIC_CONSTANT( unsigned long, value = 0UL );
};
};
// Build the LCM from the above template(s)
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm_helper_t
{
BOOST_STATIC_CONSTANT( unsigned long, value
= static_lcm_helper2_t<Value1>::BOOST_NESTED_TEMPLATE
helper<Value2>::value );
};
#endif
// 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 ) ? -result : result;
}
// 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 ) ? -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
#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
// Compile-time greatest common divisor evaluator class declaration --------//
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd
{
BOOST_STATIC_CONSTANT( unsigned long, value
= (detail::static_gcd_helper_t<Value1, Value2>::value) );
}; // boost::math::static_gcd
// Compile-time least common multiple evaluator class declaration ----------//
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm
{
BOOST_STATIC_CONSTANT( unsigned long, value
= (detail::static_lcm_helper_t<Value1, Value2>::value) );
}; // boost::math::static_lcm
// 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
#include <boost/math/common_factor_ct.hpp>
#include <boost/math/common_factor_rt.hpp>
#endif // BOOST_MATH_COMMON_FACTOR_HPP

View File

@@ -1,6 +1,6 @@
// Boost math_fwd.hpp header file ------------------------------------------//
// (C) Copyright boost.org 2001. Permission to copy, use, modify, sell
// (C) Copyright boost.org 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
@@ -75,16 +75,24 @@ template < >
// From <boost/math/common_factor.hpp> -------------------------------------//
template < typename IntegerType >
class gcd_evaluator;
template < typename IntegerType >
class lcm_evaluator;
// Only #includes other headers
// From <boost/math/common_factor_ct.hpp> ----------------------------------//
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd;
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm;
// From <boost/math/common_factor_rt.hpp> ----------------------------------//
template < typename IntegerType >
class gcd_evaluator;
template < typename IntegerType >
class lcm_evaluator;
// Also has a couple of function templates