Boost.Raito で、コンパイル時に Sqrt 計算

とかやってました。
最初に言い訳しておくと、桁の切り捨てをものすごく適当にしているので精度はそんなによくないです。
もうちょっといいやり方があると思うけども…ぐぬぬ……。
あとコンパイラによると思いますが、コンパイルが、Booooost ってレベルじゃねーぞ!ってぐらい Booooost します。
constexpr?なにそれおいしいの。

[ソース]

#define BOOST_RATIO_USES_MPL_ASSERT
#define BOOST_RATIO_EXTENSIONS
#include <boost/ratio.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/print.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/multiplies.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/identity.hpp>

namespace mpl {

using namespace boost::mpl;
template<typename Tag>
struct numerator_impl;

template<>
struct numerator_impl<mpl::rational_c_tag>{
    template<typename T>
    struct apply : mpl::integral_c<typename T::num_type, T::num>{};
};

template<typename T>
struct numerator
    : mpl::apply<numerator_impl<typename T::type::tag>, typename T::type>::type{};

template<typename Tag>
struct denominator_impl;

template<>
struct denominator_impl<mpl::rational_c_tag>{
    template<typename T>
    struct apply : mpl::integral_c<typename T::den_type, T::den>{};
};

template<typename T>
struct denominator
    : mpl::apply<denominator_impl<typename T::type::tag>, typename T::type>::type{};

template<typename S>
struct sute : if_<
    and_<greater<numerator<S>, int_<0x3000> >, greater<denominator<S>, int_<0x3000> > >,
    boost::ratio<((numerator<S>::value) >> 5), ((denominator<S>::value) >> 5)>,
    S
>::type{};

template<typename X, typename S, typename Last, typename = void>
struct sqrt_impl : Last{};

template<typename X, typename S, typename Last>
struct sqrt_impl<X, S, Last,
    typename boost::enable_if<
        less<S, minus<Last, boost::ratio<1, 10000> > > 
    >::type
> : sqrt_impl<X,
    sute<divides<plus<sute<divides<X, sute<S> > >, sute<S> >, int_<2> > >,
    S>{};

template<typename X>
struct sqrt :
    if_<
        less<X, int_<0> >,
        boost::ratio<0,1>,
        sqrt_impl<
            X,
            plus<
                boost::ratio<1,2>,
                boost::ratio<X::value, 2>
            >,
            X
        >
    >::type
{};

}  // namespace mpl


#include <iostream>
#include <boost/rational.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/range_c.hpp>
#include <math.h>


struct disp{
    template<typename T>
    void operator ()(T) const{
        double sqrt1 = boost::rational_cast<double>(mpl::sqrt<T>::value());
        std::cout << T::value << ":" << sqrt1 << std::endl;
        std::cout << T::value << ":" << sqrt(static_cast<double>(T::value)) << std::endl;
        std::cout << "差分:" << sqrt1 - sqrt(static_cast<double>(T::value)) << std::endl;
    }
};

int
main(){
    mpl::for_each<mpl::range_c<int, 2, 101> >(disp());
    return 0;
}

[出力]

2:1.41422
2:1.41421
差分:2.1239e-006
3:1.73214
3:1.73205
差分:9.20496e-005
4:2
4:2
差分:2.97352e-006
5:2.23607
5:2.23607
差分:9.18144e-007
6:2.44949
6:2.44949
差分:5.09441e-006
7:2.64577
7:2.64575
差分:1.43424e-005
8:2.82854
8:2.82843
差分:0.000113529
9:3
9:3
差分:0
10:3.16285
10:3.16228
差分:0.000572538
11:3.31671
11:3.31662
差分:8.56557e-005
12:3.46411
12:3.4641
差分:6.08344e-006
13:3.60576
13:3.60555
差分:0.000210303
14:3.74166
14:3.74166
差分:1.28245e-006
15:3.87299
15:3.87298
差分:3.91068e-006
16:4.00006
16:4
差分:5.5732e-005
17:4.12311
17:4.12311
差分:1.26946e-006
18:4.24242
18:4.24264
差分:-0.000216445
19:4.35891
19:4.3589
差分:1.09737e-005
20:4.47224
20:4.47214
差分:0.000102734
21:4.58261
21:4.58258
差分:3.10836e-005
22:4.69042
22:4.69042
差分:2.81882e-006
23:4.79584
23:4.79583
差分:3.77704e-006
24:4.89911
24:4.89898
差分:0.000135017
25:5.00003
25:5
差分:2.60815e-005


一応、2〜100 の定数で動作確認していますが、それ以外だと動かないかも知れません。
桁が多すぎるといい感じに吹っ飛ぶので、適当に桁を切り捨てています。
適当なので、桁が多すぎると華麗に吹っ飛ぶと思います。
ここら辺は、ratio 側で保証してくれてもいいような気がしないでもないですが…ぐぬぬ


まぁこれ以上凝っても仕方がないので、こんな感じですかね。
\誰か数学を教えてくれ/
あ、コンパイル時に Sqrt 計算が必要なのかは知りません。

[boost]

ver 1.47.0beta1