書くことがなさすぎるので、自作ライブラリの紹介をします
初めに
このブログは作ってみたものの、特に書くこともなく放置していました() なので、いつか書こうと思っていた自作ユーティリティーのドキュメントなどを書こうと思います。
nyaruga::util::diff
今回は、関数を微分する関数を紹介します。nyaruga::util::diff
です。
nyaruga_util/diff.hpp at master · alphya/nyaruga_util · GitHub
using num_t = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<1000>>; // 微分します // 7 点近似です template <typename Number = num_t, typename F> constexpr auto diff(F && f) noexcept { return [f](auto && x) noexcept(noexcept(f(x))) -> Number { auto h = 1e-7; if constexpr (std::is_same_v<Number, num_t>) h = DBL_EPSILON; auto&& y1 = f(static_cast<Number>(x + h)); auto&& y2 = f(static_cast<Number>(x - h)); auto&& y3 = f(static_cast<Number>(x + 2 * h)); auto&& y4 = f(static_cast<Number>(x - 2 * h)); auto&& y5 = f(static_cast<Number>(x + 3 * h)); auto&& y6 = f(static_cast<Number>(x - 3 * h)); return (y5 - 9 * y3 + 45 * y1 - 45 * y2 + 9 * y4 - y6) / (60 * h); }; }
上記の関数は、一引数の関数を引数にとって、「点x
での微分係数を返すような関数」を返す高階関数です。7 点近似らしいです。導出などは、検索すればおそらく見つけられると思われます() (自分でも、これでよいのかわかってないです。もっと良いやり方をご存じの方は教えてください...orz)
ちなみに、h の値も雰囲気で決定しました☆orz
使い方
int main() { auto fn = [](double x){ return std::pow(x, 2); }; // テンプレート引数は、関数の引数の型などに合わせてください auto d_fn_d_x = diff<double>(fn); std::cout << d_fn_d_x(3); // 6 }
nyaruga::util::partial_diff
せっかくなので、偏微分する関数も紹介します。
nyaruga_util/partial_diff.hpp at master · alphya/nyaruga_util · GitHub
namespace hana = boost::hana; // Partial differentiation template <std::size_t count, typename NumType = num_t, typename F> constexpr auto partial_diff(F && f) noexcept { return [f](auto&& ... args) noexcept -> NumType { return diff<NumType>(bind_select_arg_replace<count>(forward(f), args...)) (hana::arg<count>(forward(args)...)); }; }
テンプレート引数 count で、( 1 からスタートして)何番目の引数に関して偏微分するかを指定します。
bind_select_arg_replace<count>
は、count で指定した引数をプレースホルダーにするように、与えられた引数を引数の関数に束縛するような高階関数です。こうして一引数関数を作り、diff
関数でその引数に関して微分しています。
使い方
int main() { auto lambda = [](auto ... a) { return static_cast<nyaruga::util::num_t>((a * ... )); }; std::cout << std::setprecision(18) << nyaruga::util::partial_diff<1>(lambda)(nyaruga::util::num_t(2), 5., 6.); // 30 }
おわりに
すごく手抜き気味になってしまいましたが、たぶんこの記事は誰も見ないと思って公開しようと思います...