Scilabで数値微分 その1

数値計算から関数の微分を求めようと考えたとき、微分の定義の通りに差分を計算すれば良いということはすぐに思いつきます。

f'(x) = \lim_{h \to 0} \frac{f(x+h)-f(x)}{h}

上記の式のhを次第に小さくしていけばf'(x)の近似値が得られます。
しかしながらhの数を小さくしすぎると数値計算の丸め誤差の影響で逆にf'(x)の値からずれていってしまうことが知られています。

これに関連する重要なポイントをまとめると以下の3つになります。

  • 倍精度浮動小数点数を使い丸め誤差を小さくする
  • 打切り誤差の小さいアルゴリズムを使う
  • 丸め誤差と打切り誤差のトータルで誤差が小さくなるhを探す


Scilabは特に指定をしなくても倍精度浮動小数点数演算をしてくれるので、今回は数値計算の常識に倣って数値微分の式とhの大きさを色々と変更したときに誤差の大きさがどのようになるのかを見てみます。


数値微分の近似式


数値微分を計算する公式として数値計算の常識に倣って前進差分f1(x)、中心差分f2(x)、及びそれらのRomberg 1段公式を用いました。

前進差分
f_1(x,h) = \frac{f(x+h)-f(x)}{h}

中心差分
f_2(x,h) = \frac{f(x+h)-f(x-h)}{2h}

前進差分に対するRomberg 1段
\frac{f_1(x,h)-\frac{1}{2}f_1(x,2h)}{1-\frac{1}{2}}

中心差分に対するRomberg 1段
\frac{f_2(x,h)-\frac{1}{4}f_2(x,2h)}{1-\frac{1}{4}}

Scilabプログラム


実際に計算する関数は普通のサイン関数f(x)=sin(x)とします。
当然ながら解析的に微分が可能でf'(x)=cos(x)です。

数値計算の常識と同様にx=0.3πのときの微分を計算します。

微分の刻み幅hは
h = 2^{-n}

とし、nが大きくなるほどhは小さくなります。

作成したScilabのプログラムはdiff_sce.txtです。

clear;

// *** 刻み幅の設定 ***
n = [0:1:50];
h = 2 ^ (- n);

x = 0.3 * %pi;

// *** 微分の近似値 ***
// 前進差分
f1 = (sin(x + h) - sin(x)) ./ h;
// 中心差分
f2 = (sin(x + h) - sin(x - h)) ./ (2 * h);
// 前進差分に対するRomberg 1段公式
romberg1 = 2 * ((sin(x + h) - sin(x)) ./ h - 0.5 * (sin(x + 2 * h) - sin(x)) ./ (2 * h));
// 中心差分に対するRomberg 1段
romberg2 = ((sin(x + h) - sin(x - h)) ./ (2 * h) - 0.25 * (sin(x + 2 * h) - sin(x - 2 * h)) ./ (4 * h)) / 0.75;

// *** グラフの軸設定 ***
a = gca();
a.data_bounds = [0,1E-16;50,1];
a.log_flags = "nl";

// *** グラフのプロット ***
plot(n,abs(f1 - cos(x)),'-sr');
plot(n,abs(f2 - cos(x)),'-sm');
plot(n,abs(romberg1 - cos(x)),'-sb');
plot(n,abs(romberg2 - cos(x)),'-sg');

// *** グラフの体裁 ***
xlabel("n");
ylabel("Err");
legend(['f1(x)','f2(x)','Romberg f1(x)','Romberg f2(x)'],4);


結果


以下に示すFig.1は上記の4つの式で計算したf(x)のx=0.3πでの微分の値とf'(x)=cos(x)の値の差の絶対値を取ったものです。
この2つの差が数値計算の誤差ということになります。

001_20131110042107c73.png

Fig.1: 数値微分と解析的な微分の間の関係。縦軸は誤差の絶対値、横軸はnで、nが大きくなるほどhは小さくなる(h = 2-n)。


まずn>25では、全てのグラフにおいて同じ挙動を示しています。これが丸め誤差によるものでどの式を使っても丸め誤差の問題は改善されないことが分かります。

次にnが小さい側、すなわち打切り誤差の影響を見てみます。
前進差分f1(x)(赤)と中心差分f2(x)(ピンク)を比べてみると、nが小さいとき中心差分f2(x)(ピンク)の方が誤差が小さくなることが分かります。

また前進差分f1(x)(赤)とそのRomberg 1段(青)を比較すると、Romberg 1段(青)で打切り誤差が改善していることが見て取れます。

中心差分f2(x)(ピンク)とf1(x)に対するRomberg 1段(青)では誤差はほとんど変わりませんが、中心差分f2(x)(ピンク)にさらにRomberg 1段(緑)をおこなうとこれら4つの式の中で最も誤差の少ない式に出来ることがわかります。

関連エントリ




付録


このエントリで使用したScilabのプログラムを添付します。ファイル名末尾の".txt"を削除して、"_"を"."に変更すれば使えるはずです。(参考:ねがてぃぶろぐの付録)


参考文献/使用機器




フィードバック



にほんブログ村 その他趣味ブログ 電子工作へ

 ↑ 電子工作ブログランキング参加中です。1クリックお願いします。


コメント・トラックバックも歓迎です。 ↓      


 ↓ この記事が面白かった方は「拍手」をお願いします。


tag: Scilab 数値微分 

comment

Secret

FC2カウンター
カテゴリ
ユーザータグ

LTspiceAkaiKKRmachikaneyamaScilabKKRPSoCOPアンプCPA強磁性PICモンテカルロ解析常微分方程式odeトランジスタecalj状態密度DOSインターフェース定電流スイッチング回路PDS5022半導体シェルスクリプト乱数レベルシフトHP6632A温度解析分散関係I2Cトランジスタ技術R6452A可変抵抗ブレッドボードセミナーバンドギャップ数値積分確率論反強磁性偏微分方程式バンド構造絶縁熱設計非線形方程式ソルバフォトカプラシュミットトリガLEDLM358カオスISO-I2C三端子レギュレータGW近似A/Dコンバータカレントミラーアナログスイッチ数値微分マフィンティン半径TL431発振回路サーボPC817CUSB直流動作点解析74HC4053補間FFTBSch開発環境パラメトリック解析2ちゃんねるチョッパアンプ量子力学bzqlty電子負荷イジング模型LDA標準ロジックアセンブラ基本並進ベクトルブラべ格子単振り子熱伝導位相図TLP621キュリー温度繰り返し状態方程式MaximaVESTAスイッチト・キャパシタ相対論FETランダムウォークスピン軌道相互作用SMP六方最密充填構造抵抗不規則合金ewidthスレーターポーリング曲線GGAラプラス方程式cygwingfortranQSGW失敗談コバルト条件分岐TLP521テスタLM555Writer509TLP552格子比熱マントルデータロガー自動計測詰め回路ガイガー管ダイヤモンドQNAPMCUFXA-7020ZR過渡解析三角波UPSNE555固有値問題熱力学ブラウン運動フェルミ面awk起電力第一原理計算OpenMPfsolveubuntu最大値xcrysden最小値最適化仮想結晶近似VCA差し込みグラフスーパーセル井戸型ポテンシャル平均場近似シュレディンガー方程式FSMフラクタルOPA2277固定スピンモーメント2SC1815全エネルギー合金multiplotgnuplotc/aTeX結晶磁気異方性interp1ウィグナーザイツ胞初期値マンデルブロ集合疎行列面心立方構造fcc不純物問題非線型方程式ソルバフィルタL10構造PGA半金属二相共存SICZnOウルツ鉱構造BaO重積分クーロン散乱磁気モーメント電荷密度三次元CIF岩塩構造CapSenseノコギリ波デバイ模型ハーフメタル正規分布フォノンquantumESPRESSOルチル構造スワップ領域リジッドバンド模型edelt縮退キーボード軸ラベルグラフの分割凡例トラックボールPC不規則局所モーメント片対数グラフトランス両対数グラフCK1026MAS830L直流解析Excel円周率パラメータ・モデルヒストグラム日本語最小二乗法等価回路モデルGimp線種シンボルTS-110TS-112PIC16F785LMC662化学反応文字列specx.f入出力ifortマテリアルデザインヒストグラム確率論Realforce等高線ジバニャン方程式P-10Ubuntuナイキスト線図Crank-Nicolson法陰解法熱拡散方程式HiLAPWAACircuit連立一次方程式負帰還安定性境界条件EAGLEMBE関数フィッティング

最新コメント
リンク

にほんブログ村 その他趣味ブログ 電子工作へ