東京工芸大学 工学部  電子機械学科 2年 後期 

応用プログラミング 第13回
 2017.12.19
藤木 文彦

http://fujiki.tv/t-kougei/ouyouprog/
fujiki.kougei@gmail.com 
 ■ 1   ■ 2   ■ 3   ■ 4  ■5   ■ 6   ■ 7   ■ 8   ■ 9   ■ 10   ■ 11  ■ 12    ■ 13   ■ 14    0  

インデックスに戻る



【授業と試験の予定】


 ■ 試験は、1月16日の1,2限の授業の時に、普段と同様の形式でプログラム作成実習試験を行います。
 新年第1回は、1月9日で、その日に試験範囲の総復習を行います。

今日やること

(1) 先週の授業のゲームの出来たところまでを、独立実行形式に変換し、メールに添付して送る。(送り方の指示をよく読むこと)
(2) 先週のゲームプログラム課題が終わってなければ全て終わるまでそれを続けて行い、終了したら(1)のようにして、(再度)メールを送る。
(3) 今日のテキストの続きに書かれている。「最小2乗法」の演習を行う。

 


授業の始めに、前回の授業で制作したゲームプログラムを実行形式に変換して、提出してもらいます。

前回作成したゲーム( project1201 )の、現状で出来ているところまでのプログラムを、この独立実行ファイルにしてみなさい。

 できた実行ファイルを、

Zドライブに、ouyouprog フォルダを作成し、そこに、その実行ファイルをコピーしなさい。

 また、そこにコピーしたファイルを、ダブルクリックして、独立実行できることを確認しなさい。

 
 独立実行できることがわかったら、そのファイルを、  e0000000game.ex   ( exe ではなく ex ) という名前のファイルとしてコピーし、メールに添付して送りなさい。ファイル名の最初は自分の学生番号とします。


 実行ファイルへの変換法、および、メールに添付して送る方法は、次の項目で説明します。


(ファイルをコピーするには、マウスでそのファイルを右クリックして、「コピー」を選び、その場で「貼付け」を選ぶと、同じファイル名に、「〜コピー」という名前がついたものとして出来上がります。
 このファイルの名前を "game.ex" という名前に変更します。)

 メールのタイトルは、

"Projedt1300"

 とします。

 なお、その後、提出用フォルダにコピーして提出してもらうかもしれませんが、その方法は授業中に指示します。







 0.プログラムを独立実行ファイルにする方法



今まで、プログラムは、VisualStudio を起動してから読み込んで実行していました。
 普通のプログラムのように、プログラム名を指定するだけで実行できるようにする方法を示します。

 ある程度動くプログラムができたら、

「ビルド」−>「ソリューションのビルド」  を選びます。




 そうすると、以下のように実行ファイル( .EXE ファイル) ができます。



 上の図面は文字が見にくいのですが、自分で実行してみてください。ここでできた、 exeファイル(ここでは、 Project1201.exe という名前になっている)をコピーしてそのまま指定すると、実行されるはずです。

 今日は、この実行ファイルをメールに添付して送って欲しいのですが、

 学校内のメールでは、 .exe などの実行ファイルは送れないようになっていますので、ファイル名を、  .exe ー> .ex  などに変更して送ってください。


(実行ファイルをそのまま送ることは、ウイルスをそのまま送ってしまう可能性があるからです。知らず知らずのうちにウイルスファイルを送ることを防ぐために、多くのメールソフトでは実行ファイルをそのまま送れないようになっています。)

(これでもうまくいかないときは授業中に指示します。)



 最後の「演習課題」に指示しましたが、昨年作成したゲーム( project1201 )の、現状で出来ているところまでのプログラムを、この独立実行ファイルにしてみなさい。

 できた実行ファイルを、

Zドライブに、ouyouprog フォルダを作成し、そこに、その実行ファイルをコピーしなさい。

 また、そこにコピーしたファイルを、ダブルクリックして、独立実行できることを確認しなさい。

 独立実行できることがわかったら、そのファイルを、  game.ex   ( exe ではなく ex ) という名前のファイルとしてコピーし、メールに添付して送りなさい。

(ファイルをコピーするには、マウスでそのファイルを右クリックして、「コピー」を選び、その場で「貼付け」を選ぶと、同じファイル名に、「〜コピー」という名前がついたものとして出来上がります。
 このファイルの名前を "game.ex" という名前に変更します。)

 メールのタイトルは、

"Projedt1300"

 とします。

 なお、その後、提出用フォルダにコピーして提出してもらうかもしれませんが、その方法は授業中に指示します。

 【演習問題0】 


【メール0】ここで、CSファイルを " Project1300.cs " という名前で保存し、メールに添付し、タイトルを " Project1300 " として送りなさい。
(プロジェクト番号のしたの桁は、前回からの連番になっています。)
【提出物0】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。


 
 これ以下が今日の課題ですが、先週のゲームが完成してから行いなさい。



  1.最小自乗法(最小2乗法)のプログラム
  プログラム中にデータを配列で入れておく方法



Project1301 として始めます。

 こんな画面を作ってください。
 真ん中は、pictureBox
 右と、下は、 textBox です。




using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace saisyo2jyou_1
{

public partial class Form1 : Form
{
public const int DOT = 2;
public const int DATANUM = 5;
public const int XM = 20;
public const int YM = 20;

public Form1()
{
InitializeComponent();
}

private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}

private void button1_Click(object sender, EventArgs e)
{
Graphics g = this.pictureBox1.CreateGraphics();
int x, y;
int width = this.pictureBox1.Width - 1;
int height = this.pictureBox1.Height - 1;
g.DrawRectangle(Pens.Black, 0, 0, width, height);
Pen deepPinkPen = new Pen(Color.DeepPink, 2);
Pen bluePen=new Pen(Color.Blue,2);


// Point[].X などでは、整数型しか宣言できないので、2次元の配列にする。

/* データ初期値設定
* 配列は、 [データ個数,次元] なので、X,Y座標を指定するときには、
* 後ろが2でないとならない。
* 測定値データを {x,y} のように入れていく。
* 配列の [番号, 0=x 1=y] と混同しないように。
* 初期値を設定するときは、データの個数があっていないとエラーになる。
* 初期値を指定しないときは、{ } を含めて空白にしておくと
* 自動調整してくれる。(0データが入る。)
*/
double[,] data = new double[DATANUM,2]
{
{1.1, 2.0 },
{2.3, 4.7 },
{2.9, 6.7 },
{4.2, 7.9 },
{5.4, 10.1}
};

/* 正しく動作しているかどうか確認するときは、以下のデータを使用
* y= 1.00 x + 0.00 になればよい。違うときはプログラムをチェックすること。
* 上のデータを、コメントに変えることを忘れないように。
*/
// {{1,1},{2,2},{3,3},{4,4},{5,5}};

// データプロット
for (int i = 0; i < DATANUM; i++)
{
textBox1.Text += data[i,0] ;
textBox1.Text += '\t';
textBox1.Text += data[i,1];

// 改行は、次のようにする。
//textBox1.Text += '\r';  なぜかこれだとうまくいきません。
textBox1.Text += System.Environment.NewLine;

x = (int)(data[i,0] * XM);
y = (int)(data[i,1] * YM);

x = (int)(data[i, 0] * XM);
y = (int)(data[i, 1] * YM);
y = height - y;
g.DrawEllipse(deepPinkPen, x, y, DOT, DOT);
}

// y = a0 + a1 * x という直線の係数の計算
// 計算式の理論については、説明すると時間が無くなるので、別途
// ネットで「最小二乗法」などで検索してください。

double a0, a1;
double a00, a01, a02, a11, a12;
a00 = a01 = a02 = a11 = a12 = 0.0;
// ↑いっぺんに初期化しちゃう便利な方法

for (int i = 0; i < DATANUM; i++)
{
a00 += 1.0;
a01 += data[i,0];
a02 += data[i,1];
a11 += data[i,0] * data[i,0];
a12 += data[i,0] * data[i,1];
}

a0 = (a02 * a11 - a01 * a12) / (a00 * a11 - a01 * a01);
a1 = (a00 * a12 - a01 * a02) / (a00 * a11 - a01 * a01);

// F2 は、少数以下2桁まで表示という書式指定 これがないと、長く表示される。
// 他に、 E G N なども試してみよう。"0.000" なんて指定法もあるらしい。
textBox2.Text = "y= " + a1.ToString("F2") + " x + " + a0.ToString("F2");

// 直線を描く x 座標の最小、最大を計算
double xmin = data[0,0];
double xmax = data[0,0];
for (int i = 1; i < DATANUM; i++)
{
if (data[i,0] < xmin) xmin = data[i,0];
if (data[i,0] > xmax) xmax = data[i,0];
}
xmin -= 1.0;
xmax += 1.0;

int startX, startY, endX, endY;
startX = (int)(xmin * XM);
startY = (int)(height-(a0 + a1 * xmin) * YM);
endX = (int)(xmax * XM);
endY = (int)(height - (a0 + a1 * xmax) * YM);

g.DrawLine(bluePen, startX,startY,endX,endY);

}

private void textBox3_TextChanged(object sender, EventArgs e)
{

}

private void textBox2_TextChanged(object sender, EventArgs e)
{

}
}
}


実行すると次のような表示が出るはずです。




理論のイメージがわかりやすい図画、以下のページに出ています。
http://szksrv.isc.chubu.ac.jp/lms/lms1.html


 2次以上の曲線や、ガウス曲線、対数曲線などにも近似できますが詳細は専門文献に譲ることとします。

http://ja.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%97%E6%B3%95
http://pc-physics.com/saisyounizyouhou1.html

 【演習問題1】 

【メール1】ここで、CSファイルを " Project1301.cs " という名前で保存し、メールに添付し、タイトルを " Project1301 " として送りなさい。

【提出物1】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。


 2.データをファイルから入力する方法


 前のプログラムを活かして続けてもいいのですが、いろいろと書き直しますので、新しいプロジェクトを作ります。

Project1302

こんな画面になります。



作成時の注意

 ファイルを画面上で選択するには、
 "openFileDialog" をツールボックスから選んでデザイン画面にドロップしておく必要があります



このような表示をするために、次のようなデータファイルをエディタで作ります。
比例するはずのデータを10個測定した、という想定でデータを作りました。

ファイル名はなんでもいいのですが、とりあえず、testdata2.txt とでもしておいてください。

 データは、

x1、y1

 の形式で並べます。

 ,を忘れたり、形式、個数を間違えると、読み込みエラーとなるので注意してください。

 最大100個まで、任意の数並べられます。 DATANUM で変更できます。
 大きさの自動調整もできるようにプログラムを改造することができますが、とりあえず、固定でやってみましょう。

1.1, 1.5
2.1, 2.4
3.0, 2.9
3.8, 4.0
5.1, 5.3
6.0, 6.9
7.1, 7.5
8.0, 8.2
9.3, 8.9
10.2, 10.5


プログラムは次のようになります。

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace saisyo2jyou_1
{

public partial class Form1 : Form
{
public const int DOT = 2;
public const int DATANUM = 100;
public const int XM = 20;
public const int YM = 20;

public Form1()
{
InitializeComponent();
}

private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}



private void textBox3_TextChanged(object sender, EventArgs e)
{

}

private void textBox2_TextChanged(object sender, EventArgs e)
{

}

private void button1_Click(object sender, EventArgs e)
{

int width = this.pictureBox1.Width - 1;
int height = this.pictureBox1.Height - 1;
System.IO.StreamReader textFile;
string line;

int num;


double[,] data = new double[DATANUM, 2];

Graphics g = this.pictureBox1.CreateGraphics();
Pen redPen = new Pen(Color.Red, 2);

DialogResult ret;

this.openFileDialog1.Title = "ファイル選択";
this.openFileDialog1.CheckFileExists = true;
this.openFileDialog1.RestoreDirectory = true;
ret = this.openFileDialog1.ShowDialog();

if (ret == DialogResult.OK)
{
this.textBox3.Text = this.openFileDialog1.FileName;
}
else
{
this.textBox3.Text = "No File";
this.pictureBox1.Image = null;
}

textFile = new System.IO.StreamReader(
this.openFileDialog1.FileName, System.Text.Encoding.Default);

num = 0;

while ((line = textFile.ReadLine()) != null)
{
String[] dataxy =line.Split(',');
double.TryParse(dataxy[0],out data[num,0]);
double.TryParse(dataxy[1], out data[num, 1]);
num++;
}
textFile.Close();


// ここから最小2乗


int x, y;
g.DrawRectangle(Pens.Black, 0, 0, width, height);
Pen deepPinkPen = new Pen(Color.DeepPink, 2);
Pen bluePen = new Pen(Color.Blue, 2);

// データプロット
for (int i = 0; i < num; i++)
{
textBox1.Text += data[i, 0];
textBox1.Text += '\t';
textBox1.Text += data[i, 1];
textBox1.Text += System.Environment.NewLine;

x = (int)(data[i, 0] * XM);
y = (int)(data[i, 1] * YM);
y = height - y;
g.DrawEllipse(deepPinkPen, x, y, DOT, DOT);
}

// y = a0 + a1 * x という直線の係数の計算
// 計算式の理論については、説明すると時間が無くなるので、別途
// ネットで「最小二乗法」などで検索してください。

double a0, a1;
double a00, a01, a02, a11, a12;
a00 = a01 = a02 = a11 = a12 = 0.0;
// ↑いっぺんに初期化しちゃう便利な方法

for (int i = 0; i < num; i++)
{
a00 += 1.0;
a01 += data[i, 0];
a02 += data[i, 1];
a11 += data[i, 0] * data[i, 0];
a12 += data[i, 0] * data[i, 1];
}

a0 = (a02 * a11 - a01 * a12) / (a00 * a11 - a01 * a01);
a1 = (a00 * a12 - a01 * a02) / (a00 * a11 - a01 * a01);

// F2 は、少数以下2桁まで表示という書式指定 これがないと、長く表示される。
// 他に、 E G N なども試してみよう。"0.000" なんて指定法もあるらしい。
textBox2.Text = "y= " + a1.ToString("F2") + " x + " + a0.ToString("F2");

// 直線を描く x 座標の最小、最大を計算
double xmin = data[0, 0];
double xmax = data[0, 0];
for (int i = 1; i < num; i++)
{
if (data[i, 0] < xmin) xmin = data[i, 0];
if (data[i, 0] > xmax) xmax = data[i, 0];
}
xmin -= 1.0;
xmax += 1.0;

int startX, startY, endX, endY;
startX = (int)(xmin * XM);
startY = (int)(height - (a0 + a1 * xmin) * YM);
endX = (int)(xmax * XM);
endY = (int)(height - (a0 + a1 * xmax) * YM);

g.DrawLine(bluePen, startX, startY, endX, endY);

}
}
}


// 行分割の例 http://jeanne.wankuma.com/tips/csharp/string/split.html
//


 【演習問題2】 


【メール2】ここで、CSファイルを " Project1302.cs " という名前で保存し、メールに添付し、タイトルを " Project1302 " として送りなさい。

【提出物2】 上記のような画像ファイルを表示した画面のスクリーンショットをプリントして提出しなさい。



 【演習問題3】 

最小自乗法は、データに異常値が入っているとおかしなことになります。これを除外する方法を考えないとならないのですが、とりあえず、先ほどのデータの一つにおかしな値を入れて実行してみましょう。

1.1, 1.5
2.1, 2.4
3.0, 2.9
3.8, 4.0
5.1, 5.3
6.0, 6.9
7.1, 7.5
8.0, 8.2
9.3, 2.2                     <− ここだけ書き換えてデータファイルとして読み込ませてみてください。
10.2, 10.5


【メール3】前の問題そのままですので、csファイルは添付しなくて構いません。内容は、データのコピーとします。タイトルを " Project1303 " として送りなさい。

【提出物3】 上記のようにデータに異常値を入力して実行した結果の表示画面のスクリーンショットをプリントして提出しなさい。