オイラー数については良く知らないんだけど、プログラムする機会があったのでまとめてみる
オイラー数とは
オイラー数は、双曲線正割関数のテイラー展開における展開係数として定義される
\[
sech(z) = \frac{1}{sinh(z)}= \frac{2}{e^{z}+e^{-z}}= \sum_{k=0}^{\infty} \frac{E_{k}}{k!}z^{k}
\]
この$E_{k}$がオイラー数である特徴として、この数列は整数であり、奇数項がすべて 0、偶数項の符号が交互に切り替わる
オイラー数$E_{k}$は$k$が偶数のとき以下の漸化式を満たす
\[ E_0 = 1 \ \ ,\ \ \sum_{i=0}^{n} {}_{2n} C _{2i} E_{2i} = 0 \] ほぼWikiのコピペだけど、前知識はこんなもん。漸化式が解ればプログラムは組めるので..
プログラムでオイラー数を求める式をつくる
上記の漸化式のままでは、プログラムでオイラー数を求めにくいのでちょっと変形数列和の末項を取り出すと \[ \sum_{k=0}^{n} {}_{2n} C _{2k} E_{2k} = \sum_{k=0}^{n-1} {}_{2n} C _{2k} E_{2k} + {}_{2n} C _{2n} E_{2n} = \sum_{k=0}^{n-1} {}_{2n} C _{2k} E_{2k} + E_{2n} = 0 \] 移行して \[ E_{2n} = - \sum_{k=0}^{n-1} {}_{2n} C _{2k} E_{2k} \] これで、偶数のときのオイラー数を求める式ができた!
プログラム
Wiki見てる限り、オイラー数は非常にデカい数字になるプリミティブ型だとすぐオーバーフローしそうなので、JavaのBigIntegerクラスを使って計算してみる
計算結果は
$n$ | $E_n$ |
---|---|
0 | 1 |
2 | -1 |
4 | 5 |
6 | -61 |
8 | 1385 |
10 | -50521 |
12 | 2702765 |
14 | -199360981 |
16 | 19391512145 |
18 | -2404879675441 |
20 | 370371188237525 |
22 | -69348874393137901 |
24 | 15514534163557086905 |
26 | -4087072509293123892361 |
28 | 1252259641403629865468285 |
30 | -441543893249023104553682821 |
32 | 177519391579539289436664789665 |
34 | -80723299235887898062168247453281 |
36 | 41222060339517702122347079671259045 |
38 | -23489580527043108252017828576198947741 |
40 | 14851150718114980017877156781405826684425 |
42 | -10364622733519612119397957304745185976310201 |
44 | 7947579422597592703608040510088070619519273805 |
46 | -6667537516685544977435028474773748197524107684661 |
48 | 6096278645568542158691685742876843153976539044435185 |
50 | -6053285248188621896314383785111649088103498225146815121 |
プログラムの考察
40項目くらいからちょっと計算に時間がかかるなぁと感じたそりゃ再帰関数で同じオイラー数を何回も計算させてるからねw
なので、一度計算したオイラー数は再計算しないように修正してみたら、結構早くなった
実装は、ハッシュマップで、オイラー数の計算結果を保存していく感じ
mainの呼び元はE(50, null);とかにしたらよいかな
本実装のように、テーブル作るのが目的なら、メインの呼び元にハッシュマップのインスタンスを持たせるのが最適
0 件のコメント:
コメントを投稿