コンピュータでおかしなことになる計算例 (2) ― 三角函数を定義通りに ―
小清水 (@curekoshimizu) です。
以前の記事に Excelで計算が破綻する例 を紹介しました。
紹介した数式は次でしたが、
実に 人工的 な感じがします。
Abstract
今回紹介する話は 数学上自然な定義 なのに
それが うまくいかない という話になります。
お題は 皆さん馴染みのある 三角函数 (sin) です。
三角函数の定義 といえばこの問題ですよね!
‘99年東京大学入試問題。意表を突かれる入試問題です。
この問題への回答ではありませんが、
sin 函数の定義 ってなんでしょう。
大学以降、sin 函数は次で定義されることが多いです。
sin 函数の定義
この式は 0周りの Talylor 展開ですが、
x : 実数全体 で (広義一様) 収束 する式になります。 (実は 複素数全体まで拡張できる)
非常に非常に自然な定義 です!
sin 函数を定義通りに コンピュータで計算してみよう
この式を使って計算をしてみると、
例えば次のようなプログラムになるかと思います。
(剰余項に関する評価は次の節で)
#include <stdio.h> #include <stdint.h> #include <math.h> double sin_taylor(double x) { const double minus_xx = -x*x; const double term_tho = 1.0e-16; /* Taylor展開第1項までは直接計算 (x) */ double term = x; double ret = x; /* Taylor展開第3項以降をループで計算 */ for (uint32_t k = 1; ; k++) { uint32_t n = 2*k + 1; /* Taylor 展開第x^n=x^{2k+1}項の計算式: (-1)^k x^n/n! */ term *= minus_xx / ( (n - 1.0) *n ); if (fabs(term) <= term_tho) { break; /* 充分収束したことを示す条件 (次の節を参照) */ } ret += term; } return ret; } int main(int argc, char** argv) { for (uint32_t ix = 0; ix <= 50; ix += 5) { double ret = sin_taylor((double)ix); printf("%d, %lf\n", ix, ret); } return 0; }
結果をまとめると
x | sin 計算結果 |
---|---|
0 | 0.000000 |
5 | -0.958924 |
10 | -0.544021 |
15 | 0.650288 |
20 | -0.988004 |
25 | -0.132351 |
30 | -0.988004 |
35 | -0.428035 |
40 | 1.069746 |
45 | 111.576759 |
50 | -25547.371714 |
0 から離れると 非常におかしい結果に変わっていきます。
実数上では 満たさないといけません。
しかし は明らかにおかしいです。
評価を間違えたのでしょうか?
評価方法を数学的に考える
: fixed としたとき、
Taylor の定理より
となる が存在することになります。
ここでは記法として を の 階導函数としました。
という評価を得ますので、
となる まで計算すれば
は sin と少なくとも絶対誤差 となる解を得るはずです。
しかし計算結果は そうなっていません
Summary
何が言いたかったかというと
実数上で証明された式 は
コンピュータの中の 浮動小数点環境 において
意味のある数式になるとは限らない
ということです。
「0 から遠いのにそんな式を使うから悪い」
という人はいるかと思います。
確かに 0 まわりで近似された Taylor 展開の式なので、
その主張もわかります。
しかし今回の数式については、
どんな実数値 であっても 実数空間において 収束 が約束されていたはずです。
結局のところ、
どんな数式だったら収束するのか? と心配する必要がありそうです。
次の主張として
という数式を使って 0周りに近づけて計算すべきだとも思いますが、
この がそもそも 浮動小数点数 では exact に表現できませんが大丈夫でしょうか。
この関係を使って0に近づけても やはりおかしなことは起こりうる ということを
を紹介する予定です。
この記事を読んで
浮動小数点・丸め が気になった方は是非こちらをどうぞ!
(追記)
コンピュータでおかしなことになる計算例シリーズ第三弾できました!