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