風と翼 Windandwing は、c++の数値計算から風と翼の計算へ を目的とした数値計算を行っています。

Addres http://www5.synapse.ne.jp/windandwing/
c++ 数値計算 1  三次・四次方程式、方程式求根、微分方程式、            最小二乗、フーリエ級数

第3章 三次四次方程式 方程式求根常微分方程式最小二乗フーリエ級数

・三次・四次方程式の解は、定式化されている。その解の計算を STL を利用し、行う。

 三次方程式の、実数係数複素数係数の二つ計算を示す。

 四次方程式の、実数係数複素数係数の二つの計算を示す。

・多次元の方程式の根を、Newton-Raphson法を用いて、求める。

・常微分方程式を Rungekutta で算出する。

・最小二乗法で、データを近似する。

・通常の関数(数値群)をフーリエ変換する。(FFTやDFTではない)


1、三次方程式 (実数係数)

1、概要
  三次方程式の解の式は、既にあり、カルダーノの公式と呼ばれる。
  複素数解を含んだ式に判別式Dを用いず、カルダーノ法により 9 ケースの数値を算出した。このように判別
  式を使用しない場合、 9 ケースが生じる。しかし、ケース低減を目論んだ一般に取られる一実根がある事を
  前提にした算出法でも、5ケースについて計算しなければならない。この 9 ケースは、許容されるのではな
  いだろうか。

2、三次方程式コード1
  コードについて
   ・三次方程式の解には、a1/3 (a;数)がある。この時に、複素数になる可能性があるので、

    その複素数から実数項や虚数項を取り出すために、real_unit(1.0,0.0)、imag_unit(0.0,1.0) を設けた。

   ・知られているように、解は、位相が 120° 異なった成分で構成されているので、
    絶対値が同じで、位相だけを 120° 変える位相転換用複素数

       complex<double> shift(-1.0/2.0,sqrt(3.0)/2.0);

    を設け、計算を行った。これをコードから抜き出した個所を下記にしめす。

       y[0]=    1.0*pow(y1,1/3.0)    +1.0*pow(y2,1/3.0);
       y[1]=    1.0*pow(y1,1/3.0)   +shift*pow(y2,1/3.0);
       y[2]=    1.0*pow(y1,1/3.0)+shift*shift*pow(y2,1/3.0);

       y[3]=   shift*pow(y1,1/3.0)    +1.0*pow(y2,1/3.0);
       y[4]=   shift*pow(y1,1/3.0)   +shift*pow(y2,1/3.0);
       y[5]=   shift*pow(y1,1/3.0)+shift*shift*pow(y2,1/3.0);

       y[6]=shift*shift*pow(y1,1/3.0)    +1.0*pow(y2,1/3.0);
       y[7]=shift*shift*pow(y1,1/3.0)    +shift*pow(y2,1/3.0);
       y[8]=shift*shift*pow(y1,1/3.0)+shift*shift*pow(y2,1/3.0);

   ・transform()の使い方として、関数オブジェクトを二通り作り、これを用いた計算を行った。
    なお、STL(vectorやstring)でない通常の関数 y1,y2 を 参照(&)にして、計算を行っている。
    この部分を下記にしめす。

    complex<double>c0(0.0,0.0);
    transform(&y1,&y1+1,&y2,&c0,csum0);//transform使用例。

    complex<double>c1(0.0,0.0);
    transform(&y1,&y1+1,&y2,&c1,binary_csum1());//transform使用例。

    transform()に対しては、この方法は、好ましくないやり方で、warning が出る。
    &y1 を y1.begin()、&y1+1 を y1.end()、&y2 を y2.begin() とするのが正しいのだが、y1 や y2 が
    vector でないので、正しいやり方は適用できない。しかし、transform() を使い、計算させたい時がある
    ので、忘備として記載した。

    なお、計算過程で生じる中間ファイルのデータ in3eq.csv を remove で削除した。

   三次方程式の適用は、管内を空気が流れる時、側壁からの熱放散の微分方程式の特性根算出に例がある。
   また、ガロワは、120° 位相を変えていくと、元に戻るという事から、循環の考えを考えたと聞く。

3、使用したSTLと関数
  xxx.is_open、xxx.eof()、strtod()、xxx.c_str()、vector、vector<complex<double>>、v1.push_back()、
  v1.resize(v1.size())、pow(complex,1.0/3.0)、abs()、
  120度の位相角のシフトに 0.5+i・sqrt(3)/2.0 の使用、transform()の使用



1-1、三次方程式 (複素数係数)

1、概要
  実数係数の三次方程式の解を求める数値計算は、上記 1、三次方程式(実数係数)に示した通りである。
  複素数係数の三次方程式の場合は、上記 コード1 を部分的に変更する事で、算出できる。
  計算の考え方は、実数係数の場合と同じく判別式を使用しない方法で、9 ケースの場合で算出した。

  複素係数の三次方程式では、データの読み込みを本ホームページ c++ STL 適用例の 9 に示した事があ
  るので、この変換を用いないで、入力の読み込みを行った。単純にした。


2、三次方程式 複素数係数コード1-1
  コードについて
   ・コードの計算は、殆ど、実数係数の場合と同じである。   
    なお、計算過程で生じる中間ファイルのデータ in3eq.csv を remove で削除した。


2、四次方程式 実数係数

1、四次方程式(コード2)
  この方程式の解をBrown法により計算した。三次分解式は、上記三次方程式を使用した。
  得た計算結果の精度は高くない。
  Brown法は、三次分解式の根の最大値を使用して、解く方法である。

2、コードについて
  Brown法では、三次分解式の解の内、最大値を使用する事が必要になるので、 *max_element() で求めた。

  double umax=*max_element(u.begin(),u.end());

  ここで、関数 max_element() は、要素 (element) の最大値のアドレスを得る事ができる STL である。
  そのアドレスにある数値を得るには、*max_element() のように、 * を最初に記載すればよい。

3、使用したSTLと関数
  xxx.is_open、xxx.eof()、strtod()、xxx.c_str()、vector、vector<complex<double>>、
  v1.push_back()、v1.resize(v1.size())、pow(complex,1.0/3.0)、abs()、*max_element()




2-1、四次方程式 複素数係数

1、四次方程式(コード2-1)
  複素数係数の四次方程式の解をBrown法により計算した。三次分解式は、上記三次方程式を使用した。
  Brown法は、三次分解式の根の最大値を使用して、解く方法である。三次分解式の根が複素数になるので、
  最大値は、絶対値の最大値で計算した。絶対値の最大値となる複素数の解を求めて計算した。

2、コードについて
  三次分解式の解が、複素数になるので、実数にのみ適用できる *max_element() では求める事が出来ない
  ために、一旦、解の絶対値の最大値の vector 内の位置を求め、この位置の複素数解で、算出した。
  この部分のコードを下記に抜き書きする。
  
   vector<double> uabs(u.size(),0.0);
   for (int i = 0; i <(int)u.size(); i++) uabs[i] = abs(u[i]);

   int uabs_max=max_element(uabs.begin(),uabs.end())-uabs.begin();
           //絶対最大値の位置探しで uabs.begin()で引き算している事に注意。

   complex<double> umax =u[uabs_max];//絶対値最大の複素数解

  ここで、関数 max_element() は、要素 (element) の最大値のアドレスを得る事ができる STL である。



3、方程式の求根

0、概要
  Newton-Raphson法と二分法類似形で、方程式の根を求めた。

1、Newton-Raphson法(コード3)
  Newton-Raphson法を用いて、単調増加の方程式の求根を行った。方程式とそれの一次微分を2つのclass文内
  に記載して計算を行った。10回以内で収束するが、2式を必要とするので、記述が面倒である。

  計算する多項式をコード内に記述しなければならないところが、このコードの問題である。

2、二分法類似形(コード4)
 二分法やfalsi法は、[a,b]区間にc点を設け、f(a)・f(c)の正負で、解を算出する方法である。
 この考えを基に、[a,b]区間を細分し、区間[n,n+1]で、f(n)*f(n+1)の積が負の時に、その区間内に解があり区間
 内に解が無い場合は全て積が正となるので、その区間を更に細分し、解を求めた計算である。積の正負の計算に
 STL/find_if()を利用した。
 関数オブジェクトであるclass文をfunction文的に利用した。また、min_elementの説明実施。

3、使用したSTLと関数
  bool形関数オブジェクト、find_if()、tranform()、break、vector、min_element()、clear()

4、参考図書
 J.M.マコーミク他著 FORTRANによる数値計算プログラム
  

4、常微分方程式

1、常微分方程式 Runge-Kutta法(コード5)
  関数オブジェクトであるclass文、typedef文をfunction文として使用した例を示した。

2、コードの説明
  Runge-Kuttal法は、k1の初期値を決め、その初期値によりk2の初期値を求め、更にk3の初期値を順次求める方
  法である。初期値をx0,y0 とすると、下記のように解を得ていく方法である。

   x1=x0+h;

  と x1 を決めた時、

   k1=h*f(x0,y0);k2=h*f(x0+h/2,yo+k1/2);k3=h*f(x0+h/2,y0+k2/2);k4=h*f(x0+h,y0+k3);

  として、

   k=(k1+k2+k3+k4)/6;y=y+k;x=x+h

  を求める。

  関数オブジェクト binary_function を文字数が多いので、binary_f と短くするとCompilerから拒否される。

  また、class文のfunction文的使用は常に動作するが、typedef文は時折動作しない場合がある。
  class文、typedef文であれ、同じ常微分方程式であれば、同じ結果を得る。
  
  class文、typedef文の中に、微分方程式を記述する方法で計算を行ったが、 微分方程式の式を外部から読込む
  手法があれば、便利である。VSの方式しかないのだろうか。

3、使用したSTLと関数
  operator()、binary_function

  参考図書;C言語と数値計算法


5、最小二乗法

1、概要
 1)最小二乗 直線近似(コード6)
  ・STL/algorithmを使用し、直線近似を記述した。直線近似の傾きと切片を 6行で求めた。
    相関係数を2通り(残差、偏差)の方法で、求めた。残差は、2種のSTLで、偏差は、rsqc_pmccと表示した。

  ・コードの説明
   コードで注目すべき点は、直線近似の y=a・x+b の係数 a,b を STL のみで、算出している点である。

   直線近似をSTLのみの表現で示した個所を下記に抜書きする。
   下記で x は、 x 軸の値を示し、y は x に対応した y 軸の値しめす。


   xの平均値を求める
   double average_x=accumulate(u.begin(),u.begin()+u.size()/2,0.0)/(u.size()/2);

   yの平均
   double average_y=accumulate(u.begin()+u.size()/2,u.end(),0.0)/(u.size()/2);

   xとyの積の平均 (この xと y の積をとる理由は、多くの本に記載してあるので参照方)
double average_xy=inner_product(u.begin(),u.begin()+u.size()/2,u.begin()+u.size()/2,0.0)/(u.size()/2)

   x の二乗の平均
   double average_xx=inner_product(u.begin(),u.begin()+u.size()/2,u.begin(),0.0)/(u.size()/2);

   直線近似の y=a・x+b の a の値 
   double a=(average_xy-average_x*average_y)/(average_xx-average_x*average_x);

   直線近似の y=a・x+b の b の値 
   double b=(average_y*average_xx-average_x*average_xy)/(average_xx-average_x*average_x);

   上記のように、直線近似の係数を accmulate と inner_product で求めた。

   コードの説明
   最小二乗法を適用する xi と yi=f(xi) の値を同じ vector u に入れて計算している。

   vector()で u.begen() と u[0] の関係
   u.begin()は、u[0]の前にある。そこからu[0]を含んだ以降を示す。u.begin()は u[0] からは始まらない。

   u.begin()+u.size()/2 は、その後ろにあるものの前までである。


 2)最小二乗 多項式近似 データ列数1列(コード7)
  STLの数値algorithmを使用し、多項式近似計算を記述した。残余値により、相関係数の算出を行った。

  csv形式で、x,yのデータ読込み法は、string形で読み、strtodで変換した。これは、第0章のcsvデータ読込み
  に、記載しているので、参照方。

  また、多項式近似における連立一次方程式の解法は、第4章の連立一次方程式のGauss-Jordan法(vector適用)
  に記載しているので、ご参照方。

  transformに2項関数オブジェクトを適用し、xのn乗を算出した。

  最大値がある要素位置を知る方法として、*max_element() は、要素の最大値を示すので、これを利用して、
  以下の手法で、

  double dfabsmax=*max_element(ddd.begin(),ddd.end());
  int inum;
  for(i=0;i<(int)ddd.size();i++) if(ddd[i]-dfabsmax ==0.00) inum=i;
  
  とし、最大値を示す要素の位置を inum から得る事ができる。

  更に容易な方法は、 max_element (ポインターが無い)はアドレスを示すので、ddd.begin()と組合わせると
  、ddd.begin()からの位置として最大値の要素位置を得る事ができる。これを以下に示す。

  int inum=max_element(ddd.begin(),ddd.end())-ddd.begin();
  

 3)最小二乗 多項式近似 データ列自由(コード8)
  上記に加えて、csv形式で、xとy1,y2,y3…yn のデータ読み、多項式近似計算が出来るようにした。
  相関係数の算出を行った。
  データの列および行数に制限のないコードである。


 4)最小二乗 1/xの-n乗 多項式近似(コード9)
  
xの増加に対して、yが低減する現象があるxのプラスn乗の多項式で近似できないケースである。
   このために作成した。考えを変え、本文のみで近似式算出を行った。

  上記(コード8)の2項関数nthmultiplies内のxの積個所と本文の検証計算のpow個所のxを1/xに変更するとxの
  マイナスn乗の多項式近似を求める事が出来る。
  なお、混合形態は今は断念。

2、使用したSTLと関数
 u.assign()、accumulate()、inner_product()、v.resize(v.size())、u[i+u.size()]、u.begin()、u.end()、
 v.push_back()、transform()、setw()、setprecision()、s.clear()

3、参考図書
 STLによるC++プログラミング、C言語と数値計算法

6、フーリエ級数展開

1、概要
 FFT、DFTではデータ個数に指定があるが、これは、1周期の入力データ数を限定しない一般の方法である。
 Fourier級数の係数算出はcos,sinの級数で行った。 得た係数から、sin、cosの関数による再構成を行った。


2、フーリエ級数展開(コード10)
  周期を [0,2d] として、計算した。

3、使用したSTLと関数
  xxx.is_open、xxx.eof()、strtod()、xxx.c_str()、vector、v1.push_back()、v1.resize(v1.size())、
  accumulate()、abs()、atan()、break、(int)v1.size()。

4、その他
  vector<complex<double>>の使用で少ない行数で、fourier級数算出が可能になったが、その算出の次数と再
  構成で釈然としない箇所があり、cos、sinで計算した。


2012年
この章の全体履歴
2012年1月3日 公開 
2012年
この章の変更追加履歴
5、複素数係数の四次方程式の追加 2016/7/28
4、複素数係数の三次方程式の追加 2016/7/28
3、写真の追加 2012/7/10
2、字句の修正 2012/1/30
1、花の写真追加

ナビゲーション


フランクフルト本駅 DB HB

雨上がりのムーブメント

忘れえぬ人への入り口

ガーナ 教育計画事務所 二階より

ハワイアンの踊り

いわき ゆもと

頭上の太陽と静かな道

横浜 みなとみらいの風景

九州新幹線 さくら

横浜みなとみらい 夜景

林が、造成地に、そして家々

春に咲く花

椿三十郎か、フラメンコか


 横浜みなとみらい 汽車道

環状2号線 シャネルの女性