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カウンター
カテゴリ
ユーザータグ

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

最新コメント
リンク

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