プログラム演習 (2) 配列を使う

1

はじめに
科学技術計算には行列演算は必須であり、行列やベクトルを記述するためには配列が必要となる。ベクトル、行列の例を以下に示す。

(a=)1,−2350
B= 2−13 024(1)行列の縦の並びは列（column）と呼び、横の並びは行（row）と呼ぶ。上の例では、a は列ベクトルである。また、行列に含まれる数値は要素 (entry、element) と呼ばれる。
行列の和算はおのおのの要素に対して行えばよいが、積算にはいくつか種類がある。ここでは内積について考えることとする。列ベクトル a と b の内積は以下のように定義される。
()() −3Ta b= 2 5= 2 · −3 + 5 · 4 = 144(2)ここで、a の肩添字 T は転置であることを意味する。
次に、行列とベクトルとの積算の例を示す。
 
()2 52·4+5·113
 4 Ab =  −1 3 =  −1 · 4 + 3 · 1  =  −1 
10 00·4+0·10(3)この例では、計算結果はベクトルとなる。この例から明らかなように行列とベクトルの積算は、ベクトルの大きさ（サイズ）と行列の列の大きさとが一致していなければならない。
最後に行列同士の積算の例を示す。

(AB=(=250−134)

6 −247−3 
12 · 6 + 5 · −2 + 0 · 4

2 · 7 + 5 · −3 + 0 · 1−1 · 6 + 3 · −2 + 4 · 4−1 · 7 + 3 · −3 + 4 · 1)(=2−14−12)(4)

それでは配列を用いた C++プログラムを以下に示していく。C++での配列の表現の方法はいくつかあるが、ここでは標準ライブラリの vector を用いた例を示す。
まずは式 (1) に現れたベクトル a を定義するプログラムを以下に示す。

Listing 1: prog1.cxx
123456789101112131415#include<cmath>#include<i o s t r e a m >#include<v e c t o r >using namespace s t d ;i n t main ( ) {v e c t o r <double> a ( 2 ) ;a [0]=1.;a [1]= =2.;};

return 0 ;vector 型の変数（正確には、vector クラスのインスタンス）を生成させているのが 9 行目であり、double 型のデータが格納される、大きさが 2 の配列として a が定義されている。vector クラスは標準ライブラリとして与えられており、31行目にあるように予めインクルードさせる必要がある。なお、C++の配列では、基本的に「0」から値が格納される。すなわち、大きさが 2 の vector クラスのインスタンス a のデータは、a[0] と a[1] となる（a[1] と a[2] とはならない）。
次にベクトル同士の和算を行う例を以下に示す。この例では、ベクトル a と b との和の計算を行い、解を c に代入している。

Listing 2: prog2.cxx
12345678910111213141516171819202122232425262728#include<cmath>#include<i o s t r e a m >#include<v e c t o r >using namespace s t d ;i n t main ( ) {v e c t o r <double> a ( 2 ) ;v e c t o r <double> b ( 2 ) ;v e c t o r <double> c ( 2 ) ;a [0]=1.;a [1]= =2.;b[0]= =1.;b[1]=5.;f o r ( i n t i =0; i <2; i ++){c [ i ]= a [ i ]+b [ i ] ;};f o r ( i n t i =0; i <2; i ++){
cout<<” c [ ”<<i <<” ] = ”<<c [ i ]<<” \n” ;};};return 0 ;最後に、行列を定義するプログラムを以下に示す。行列を配列で表現する場合には、この例のように二次元配列となる。

Listing 3: prog3.cxx
1234567891011121314151617181920#include<cmath>#include<i o s t r e a m >#include<v e c t o r >using namespace s t d ;i n t main ( ) {v e c t o r < v e c t o r <double> > a ( 2 ) ;f o r ( i n t i =0; i <2; i ++){a[ i ]. resize (2);};a[0][0]=1.;a[0][1]=2.;a [1][0]= =1.;a[1][1]=5.;};

return 0 ;二次元の配列は 9 行目のように定義する1 。9 行目で指定している 2 が、vector クラスのインスタンス a の一つ目の並びの個数を示し、10 行目から 12 行目のループで、a[0]、a[1] それぞれの二つめの並びの個数を resize により指定している。なお、この例では、列、行のサイズがそれぞれ 2 である以下の行列を定義している。
()
1 2
A=−1 5(5)なお、配列は vector クラスを用いなくても定義することが出来る。例えば、Listing 2 で示したプログラムは以下のように書くことも出来る。ここでは、変数 a と b について、vector クラスではない方法によって配列として定義している。

Listing 4: prog4.cxx
1234
5#include<cmath>#include<i o s t r e a m >#include<v e c t o r >using namespace s t d ;1 これはひとつの例である。

267891011121314151617181920212223i n t main ( ) {double a [ ] = { 1 . , = 2 . } ;double b [ ] = { = 1 . , 5 . } ;v e c t o r <double> c ( 2 ) ;f o r ( i n t i =0; i <2; i ++){c [ i ]= a [ i ]+b [ i ] ;};f o r ( i n t i =0; i <2; i ++){
cout<<” c [ ”<<i <<” ] = ”<<c [ i ]<<” \n” ;};};return 0 ;この例では配列 c は vector で定義しているが、これを a、b と同様の扱いとするならば、以下のように書く。

Listing 5: prog5.cxx
12345678910111213141516171819202122232425#include<cmath>#include<i o s t r e a m >#include<v e c t o r >using namespace s t d ;i n t main ( ) {float a []={1. , =2.};
float b[]={ =1. ,5.};f l o a t * c=new f l o a t [ 2 ] ;f o r ( i n t i =0; i <2; i ++){c [ i ]= a [ i ]+b [ i ] ;};f o r ( i n t i =0; i <2; i ++){cout<<” c [ ”<<i <<” ] = ”<<c [ i ]<<” \n” ;};delete};[]c;return 0 ;サイズが 2 である配列 c が 12 行目で定義されている。なお、このように（動的に）定義した配列は 22 行目にあるように delete でメモリから消去させる必要がある。
以降の課題では配列の定義に vector を用いること。


問題１：次のふたつのベクトルの和算、引き算、積算を行うプログラムを書きなさい（出力部分も）。なお、積算は行列の個々の要素の積を計算することではない（内積計算である）ことに留意せよ。
()
()
3
6
a=,b =5−1

(6)






問題２：次のふたつの行列の和算、引き算、積算を行うプログラムを書きなさい（出力部分も）。なお、積算は行列の個々の要素の積を計算することではないことに留意せよ。
()(3 −16a=,b =5 6−143)
(7)



問題３：問題２で作成したプログラムについて、任意のサイズの行列を計算できるように修正せよ。また、作成したプログラムで問題２を解かせて、正しい結果が得られることを確認せよ。なお、ここで「任意」と言っているのは、プログラムの最初に int n=2; のように行列のサイズを指定した以降は、全て行列のサイズを n で記述する、ということを意図している。このようにプログラムを記述することで、解きたい問題の行列のサイズが変更になった場
合でも、変数 n の値を変更するだけで対応が可能となる。
3