Up

テキストファイル入出力―その2

相関係数の計算

 

テキストファイルからデータを読み込み、計算結果などをテキストファイルへ書き出すプログラムを作成した。データのテキストファイルは図1のような形式である。

図1

 

行の先頭がスラッシュ/で始まる行に挟まれて、データが1行に2つずつペアで書かれている。データの読み込みのときは、このスラッシュ/で始まる行まで読み飛ばし、次のスラッシュ/で始まる行までデータを各行から1つのペアずつ読み込んでいく。

 プログラムの作成は、まずメニュ「ファイル|新規作成|プロジェクト」を選ぶ(図2)。

図2

 

表示されたダイアログボックス(図3)でプロジェクトの種類「CLR」、テンプレート「Windowsフォームアプリケーション」を選択する。

図3

 

フォームのデザインは、Buttonを2個、Labelを1個、図4のように配置する。さらにOpenFileDialogSaveFileDialogを用意する。

図4

 

コードは以下のように用意する。

 

#pragma endregion

        private: System::Void buttonClose_Click(System::Object^  sender, System::EventArgs^  e) {

                                 Close();

                         }

        private: System::Void buttonGO_Click(System::Object^  sender, System::EventArgs^  e) {

                                 openFileDialog1->FileName = "*.txt";

                                 if (openFileDialog1->ShowDialog() != System::Windows::Forms::DialogResult::OK){

                                         label1->Text = "openFileDialog is canceled";

                                         return;

                                 }

 

                                 try {

                                         FileStream ^ fs = gcnew FileStream(openFileDialog1->FileName, FileMode::Open);

                                         StreamReader ^ fin = gcnew StreamReader(fs,

                                                                                System::Text::Encoding::GetEncoding("Shift-JIS"));

                 

                                         saveFileDialog1->FileName = "";

                                         if (saveFileDialog1->ShowDialog() != System::Windows::Forms::DialogResult::OK){

                                                 label1->Text = "saveFileDialog is canceled";

                                                 return;

                                         }

                                         fs = gcnew FileStream(saveFileDialog1->FileName,FileMode::Create);

                                         StreamWriter ^ fout = gcnew StreamWriter(fs);

 

                                         String ^ s;

 

                                         s = "Data File..." + openFileDialog1->FileName;

                                         fout->WriteLine(s);

 

                                         int ck = 0;

                                         do {

                                                 s = fin->ReadLine()->Trim();

                                                 if (s->Length > 0){

                                   if (s[0] == '/') ck = 1;

                                                 }

                                         } while (ck == 0);

 

                                         double x[1000], y[1000];

                                         double sumX = 0.0, sumY = 0.0;

                                         double meanX, meanY;

                                         int n = 0;

                                         for (;;) {

                                                 s = fin->ReadLine();

                                                 if (s[0] == '/') break;

                                 n++;

                                                 s = s->Trim();

                                                 x[n-1] = XmlConvert::ToDouble(extract_data(s,0));

                                                 y[n-1] = XmlConvert::ToDouble(extract_data(s,1));

                                                 sumX += x[n-1];

                                                 sumY += y[n-1];

                                         }

                                         meanX = sumX/n;

                                         meanY = sumY/n;

 

                                         s = "入力データ...";

                                         fout->WriteLine(s);

                                         for (int i = 0; i < n; i++){

                                                 s = "X[" + (i+1).ToString() + "] = " + x[i].ToString() +

                                                         "    Y[" + (i+1).ToString() + "] = " + y[i].ToString();

                                                 fout->WriteLine(s);

                                         }

                                         fout->WriteLine("");

                                         fout->WriteLine("平均値(X) = " + meanX.ToString() +

                                                        "    平均値(Y) = " + meanY.ToString());

 

                                         double sumXX = 0.0, sumYY = 0.0, sumXY = 0.0;

                                         for (int i = 0; i < n; i++){

                                       sumXX += (x[i]-meanX)*(x[i]-meanX);

                                                   sumYY += (y[i]-meanY)*(y[i]-meanY);

                                                   sumXY += (x[i]-meanX)*(y[i]-meanY);

                                         }

                                         double SDx1 = Math::Sqrt(sumXX/(n-1));

                                         double SDy1 = Math::Sqrt(sumYY/(n-1));

                                         double cov = sumXY/n;

                               double SDx = Math::Sqrt(sumXX/n);

                                         double SDy = Math::Sqrt(sumYY/n);

                                         double r   = cov/(SDx*SDy);

                                         fout->WriteLine("標準偏差(X) = " + SDx1.ToString("0.#####E0") +

                                                 "    標準偏差(Y) = " + SDy1.ToString("0.#####E0") );

                                         fout->WriteLine("共分散= " + cov.ToString("0.#####E0") );

                                         fout->WriteLine("相関係数= " + r.ToString("0.#####"));

 

                                         fin->Close();

 

                                         fout->Close();

 

                                         label1->Text = "Output File..." + saveFileDialog1->FileName;

                                 }

                                 catch (Exception ^ e1) {

                                         label1->Text = "Err..." + e1;

                                         return;

                                 }

 

                                 return;

                         }

 

 

関数extract_dataはインクルードファイルmyLib.hとして以下のように用意して、Form1.hと同じフォルダ内に置いている。

 

 

namespace MyLib {

 

  using namespace System;  //  Stringクラス用

 

/*

       文字列sにおいて空白で区切られた部分文字列の

           n_p番目の部分文字列を返す。

           部分文字列は0番目から数える。

                                        By Y. Okamoto, 2006,8

*/

        String ^ extract_data( String^ s, int n_p ) {

                       

                 if (n_p < 0) return "";

 

                                 s = s->Trim();

 

                                 int ck;

                                 int s_p = 0;

                                 int e_p;

 

                                 if (s == "") return "";

 

                                 //  s_pn_p番目の部分文字列の先頭位置に設定する

                                 if (n_p > 0) {

                                         for (int i = 0; i < n_p; i++) {

                                     ck = 0;

                                                 do {

                                           s_p++;

                                                         if (s_p >= s->Length) { ck = 9; }

                                                         else {

                                                                 if (s[s_p] == ' ') { ck = 1; };

                                                         };

                                                 } while (ck == 0);

                                                 if (ck == 9) return "";

 

                                                 while (s[s_p] == ' ') s_p++;

                                         }

                                  }

                  

                                 //  e_sn_p番目の部分文字列の最後尾の次の位置に設定する

                           e_p = s_p;

                                   ck = 0;

                                   do {

                                 e_p++;

                                           if (e_p >= s->Length) {ck = 9;}

                                           else {

                                           if (s[e_p] == ' ') ck = 1;

                                           }

                                   } while (ck == 0);

               

                                   //  求める部分文字列を返す

                                   return s->Substring(s_p, e_p-s_p);

                         }

 

}

 

この関数extract_dataは、与えられた文字列内において任意個の空白(半角文字)で区切られた文字列のグループからn_p番目のグループを取り出すものである。グループは0番目から数える。

このヘッダーファイルmyLib.hのインクルード、およびファイルストリームを用いるために名前空間System::IO、文字列をその表す実数値に変換する関数ToDoubleを用いるために図5のようにincludeusing namespaceの使用を宣言しておく。

図5

 

プログラムを実行すると図6のフォームが表示される。

図6

 

「GO」ボタンをクリックすると図7のように入力データファイル名の設定を求めるダイアログボックスが表示される。

図7

 

図1の形式で用意してあるテキストファイル名を設定後「開く」ボタンをクリックすると、出力ファイル名の設定を求めるダイアログボックスが表示される(図8)。

図8

 

適当な出力用ファイル名を設定して「保存」ボタンをクリックすると指定したファイル名のテキストファイルに書き込みが始まり、終了後図9のように「Output File…」のメッセージが表示される。

図9

 

フォームとメッセージの長さの関係が気になるときは、フォームの端をドラッグすることにより調整できる(図10)。

図10

 

Close」ボタンをクリックするとプログラムの実行終了となる。プログラムの終了後、書き込まれたファイルを開くと図11のようになっている。

図11

 

プログラムのソースファイルは圧縮ファイルcor.ZIPとして用意した。ここをクリックしてダウンロードすることができる。

 

 

 

Up