|
Boost : |
From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2005-01-27 15:14:21
Jason Hise wrote:
> I was just playing around, trying to compute a square root at compile
> time. I came up with the following:
>
> template < unsigned int N, unsigned int X = 1, unsigned int X2 = ( X + N
> / X ) / 2 >
> struct Sqrt
> {
> typedef typename Sqrt < N, X2 > :: ValueHolder ValueHolder;
> };
>
> template < unsigned int N, unsigned int X >
> struct Sqrt < N, X, X >
> {
> struct ValueHolder
> {
> enum ValueStorage
> {
> Value = X
> };
> };
> };
>
> This works for most values, but unfortunately some ( like 80 ) end up
> oscillating and X never becomes equal to X2. How could I go about
> correcting this?
// This is a somewhat boostified implementation
// of your algorithm rotated by 180 degrees 8-)
#include <boost/config.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
using namespace boost::mpl;
template< unsigned int N>
struct sqrt_result
{
BOOST_STATIC_CONSTANT(unsigned int, value = N);
};
template< unsigned int N, unsigned int I >
struct sqrt_impl
{
// Note: Bare ICEs ( '(I*I>N)', '(I+N/I)/2' ) are not very portable
// [ ref. http://www.boost.org/more/int_const_guidelines.htm ].
// Using separate metafunctions (like sqrt_iteration_invariant,
// sqrt_approximation_step) can solve the problem.
typedef typename
eval_if_c< (I*I>N) // approximation from above
, sqrt_impl< N, (I+N/I)/2 > // step (original formula)
, identity< sqrt_result<I> >
>::type type;
};
template< unsigned int N >
struct sqrt
: sqrt_impl<N,N>::type // start with I=N
{
// Note: Inheritance of static constants does not work properly for
// all compilers. An explicit advice like:
//
// typedef typename sqrt_impl<N,N>::type base;
// using base::value
//
// may solve this problem.
typedef sqrt type;
};
// Test
#include <iostream>
using namespace std;
template< unsigned int N > void test()
{
cout << "sqrt(" << N << ") = " << ::sqrt< N >::value << std::endl;
}
int main()
{
test< 1>();
test< 2>();
test< 3>();
test< 4>();
test< 9>();
test< 16>();
test< 80>();
test< 81>();
test<144>();
return 0;
}
// Hey, that was fun.
//
// Regards,
//
// Tobias
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk