簡単なプログラミング(1)

演習問題を行う前に 1-2. Mathematica を使うときの注意を良く読んでください.


内容

  1. 手続き型プログラミング
  2. プログラミングの解説
  3. 演習問題

手続き型プログラミング

Mathematica では C言語や Fortran のように通常の手続き型プログラミングを行うことが可能です.この場合、Mathematica はプログラミング言語を解釈し、実行するインタープリターとして機能します(これが何のことを言っているのかわからない人はあまり気にしないでください.要するに、C言語と同じようにプログラムが書けるということです).

Mathematica の文法

プログラミング言語ですから、もちろんそのための文法があります.Mathematica の文法は C 言語の文法と非常によく似ていて、ほぼ一対一の対応がつきます.そのため C 言語をすでに知っている人には非常に覚えやすいものになっています.みなさんは2年次で C 言語を勉強してきているはずですから、ここでは C 言語は知っているものとして、特に C言語との違いについて解説することにします.

関数定義

C言語では関数定義は

関数値の型 関数名(引数1の型 引数1, 引数2の型 引数2, …, 引数nの型 引数n)
{
 ローカル変数1の型 ローカル変数1, …, ローカル変数nの型 ローカル変数n;

 関数の内容
}

でしたが、 Mathematica では

関数名[引数1_, 引数2_, …, 引数n_] :=
Module[
{ローカル変数1, …, ローカル変数n},

 関数の内容
]

となります.引数やローカル変数の型は特に必要とされるとき以外は指定する必要はありません.

具体例:

C言語 Mathematica

if 命令

C言語では if 命令は

if (A) {
 A が真の時の実行文
} else {
 A が偽の時の実行文
}

の形をとりましたが、Mathematica では

If [A, A が真の時の実行文, A が偽の時の実行文]

となります.

具体例:

C言語 Mathematica

for 命令

C言語では for 命令は

for (初期化文; ループ終了条件; 各ループの最後に実行される文){
  ループ中に実行される文

でしたが、Mathematica では

For[初期化文, ループ終了条件, 各ループの最後に実行される文,
 ループ中に実行される文
]

となります.

具体例:

C言語 Mathematica

while 命令

C言語ではwhile 命令は

while (A) {
 A が真である間に実行する命令
}

の形をとりますが、Mathematica では

While [A, A が真である間に実行する命令]

となります.

具体例:

C言語 Mathematica

Switch 命令

C言語ではswitch 命令は

switch (A) {
 case B1: A=B1 の時に実行する処理
       break;
 case B2: A=B2 の時に実行する処理
       break;
        .
        .
 case Bn: A=Bn の時に実行する処理
       break;
 default: その他のときに実行する処理
}

の形をとりますが、Mathematica では

Switch [A, B1, A=B1 の時に実行する処理, B2, A=B2 の時に実行する処理, … , Bn, A=Bn の時に実行する処理, A, その他の時に実行する処理]

となります.

具体例:

C言語 Mathematica

プログラミング例

それでは、ルールベースドプログラミングで行ったのと同じように goukei[n] を定義してみましょう.goukei[n] は 1 から n までの数の和を求める関数ですから C言語では次のようになります.

C言語でのプログラム

これを上の変換規則にしたがって Mathematica 用に書き換えたものは次のようになりますね.

入力
出力

それではプログラムを実行してみましょう.上のように入力した後で、goukei[10], goukei[100] を計算してください.

入力
出力
入力
出力

注意:

Mathematica では引数として与えられた変数に代入をすることはできません.次のプログラムはエラーになり、正しい答えを返しません.

入力
出力
入力
出力

上のプログラムは次のようにする必要があります.

入力
出力
入力
出力

プログラミングの解説

1からnまでの和を求める

まず、1 から n までの和を求めるプログラムを作ってみましょう.いろいろな方法がありますが、まず、For 命令を使ったものを説明します.

For 命令を使う

3までの和

1 から 3 までの和を計算するには下のようにすればよいですね.

[Graphics:images/math5sub_gr_1.gif]

もちろん、sum には 1+2+3 = 6 が入っています.

[Graphics:images/math5sub_gr_2.gif]
[Graphics:images/math5sub_gr_3.gif]

この計算を行う関数 wa を作ってみます.次のように書けばよいですね.

[Graphics:images/math5sub_gr_4.gif]

もちろん、計算結果は 6 になります.wa は関数ですから、次のように呼び出します.

[Graphics:images/math5sub_gr_5.gif]
[Graphics:images/math5sub_gr_6.gif]

nまでの和

それでは、今度は 1 から n までの和を計算する関数 wa1 を作ってみましょう.先ほどの

[Graphics:images/math5sub_gr_7.gif]

の部分は

For [ i = 1, i<=3, i++,
  sum = sum + i
]

と書けることに注意すると、1 から n までの和を計算する関数 wa1 は次のようになります.

[Graphics:images/math5sub_gr_8.gif]

それでは、1 から 10 まで和と 1 から 100 までの和を計算してみましょう.

[Graphics:images/math5sub_gr_9.gif]
[Graphics:images/math5sub_gr_10.gif]
[Graphics:images/math5sub_gr_11.gif]
[Graphics:images/math5sub_gr_12.gif]

If命令を使う

次に If 命令を使って同じく、1 から n までの和を計算してみましょう.今度は関数名を wa2 とします.先ほどの For 命令を使った関数 wa1 を If 命令を使って書き直すと、次のようになります.

[Graphics:images/math5sub_gr_13.gif]

1 から 10 までの和と 1 から 100 までの和を計算すると、もちろん先ほどの答えと一致します.

[Graphics:images/math5sub_gr_14.gif]
[Graphics:images/math5sub_gr_15.gif]
[Graphics:images/math5sub_gr_16.gif]
[Graphics:images/math5sub_gr_17.gif]

While命令を使う

それでは、今度は While 命令を使って同じことをしてみましょう. For 命令を使った関数 wa1 を While 命令を使って書き直すと、次のようになります.

[Graphics:images/math5sub_gr_18.gif]

ちゃんと計算が正しいことを確認してみましょう.

[Graphics:images/math5sub_gr_19.gif]
[Graphics:images/math5sub_gr_20.gif]
[Graphics:images/math5sub_gr_21.gif]
[Graphics:images/math5sub_gr_22.gif]

最小値を求める

それでは、次にリストが与えられたとき、そのリストの要素のうちで最小値を求めるプログラムを書いてみましょう.

2つのうち最小値を求める

まず、2つの要素が与えられた時、小さいほうを返す関数を作ってみます.If 命令を使えば簡単ですね.

[Graphics:images/math5sub_gr_23.gif]

要素が2つの場合

2つの要素をもつリストが与えられたとき、小さいほうを返すプログラムを書いてみましょう.リスト m の1番目の要素は m[[1]], 2番目の要素は m[[2]] ですから、上と同じことを行う関数は次のようになりますね.

[Graphics:images/math5sub_gr_24.gif]

確認してみましょう.

[Graphics:images/math5sub_gr_25.gif]
[Graphics:images/math5sub_gr_26.gif]
[Graphics:images/math5sub_gr_27.gif]
[Graphics:images/math5sub_gr_28.gif]

要素が3つの場合

それでは、今度はリストの要素が3つの場合を考えてみましょう.この場合には、次にようにすればよいですね.

(1)1 番目の要素と 2 番目の要素を比較し、小さいほうを変数 kekka に代入する.
(2)3番目の要素と kekka を比較し、もし3 番目の要素の方が kekka より小さければ、kekka に3番目の要素を代入する.
(3)kekka を関数の値として返す.

これを行う関数 saisyouti を定義してみましょう.

[Graphics:images/math5sub_gr_29.gif]

それでは、計算が正しいかどうか確認します.

[Graphics:images/math5sub_gr_30.gif]
[Graphics:images/math5sub_gr_31.gif]
[Graphics:images/math5sub_gr_32.gif]
[Graphics:images/math5sub_gr_33.gif]

要素が4つの場合

次にリストの要素が4つの場合を考えてみましょう.この場合も、基本的には先ほどと同じです.

(1)1 番目の要素と 2 番目の要素を比較し、小さいほうを変数 kekka に代入する.
(2)3番目の要素と kekka を比較し、もし3 番目の要素の方が kekka より小さければ、kekka に3番目の要素を代入する.
(3)4番目の要素と kekka を比較し、もし4 番目の要素の方が kekka より小さければ、kekka に4番目の要素を代入する.
(4)kekka を関数の値として返す.

これを行う関数 saisyouti は次のようになりますね.

[Graphics:images/math5sub_gr_34.gif]

計算が正しいかどうか確認します.

[Graphics:images/math5sub_gr_35.gif]
[Graphics:images/math5sub_gr_36.gif]
[Graphics:images/math5sub_gr_37.gif]
[Graphics:images/math5sub_gr_38.gif]

要素がn個の場合

それでは、要素が n 個の場合を考えます.先ほどのプログラムをよく眺めると

[Graphics:images/math5sub_gr_39.gif]

の部分が

[Graphics:images/math5sub_gr_40.gif]

となればよいわけですから、ここの部分を For 命令を使って

[Graphics:images/math5sub_gr_41.gif]

とすればよいですね.リスト l の要素の個数 は Length[ l ] で求まりますから、

[Graphics:images/math5sub_gr_42.gif]

でリストの要素の数を n に代入します.以上より、プログラムは次のようになります.

[Graphics:images/math5sub_gr_43.gif]

それでは、計算が正しいかどうか確認してみましょう.

[Graphics:images/math5sub_gr_44.gif]
[Graphics:images/math5sub_gr_45.gif]
[Graphics:images/math5sub_gr_46.gif]
[Graphics:images/math5sub_gr_47.gif]

saisyouti の変更

先ほどの関数 saisyouti は、最小値のみを返しましたが、最小値とその最小値が何番目の要素であるかを返すように、関数を変えてみましょう.最小値が何番目の要素であるかを表す変数を bango とすると、次のようにすればよいですね.

[Graphics:images/math5sub_gr_48.gif]

それでは、確認してみましょう.

[Graphics:images/math5sub_gr_49.gif]
[Graphics:images/math5sub_gr_50.gif]

上の例では、最小値は -3 で それはリストの 2 番目の要素ですから計算結果は合っていますね.

[Graphics:images/math5sub_gr_51.gif]
[Graphics:images/math5sub_gr_52.gif]

これも計算結果は合っています(最小値は -5 で、それはリストの 1 番目の要素).

リストを小さい順に並べ替える

それでは、次にリストが与えられたとき、そのリストの要素のうちで最小値を求めるプログラムを書いてみましょう.

小さい順に2つ並べる

先ほどの、関数 saisyouti はリストの要素のうちで最も小さい要素しか返しませんでした.最も小さい要素とその次に小さい要素を返すようにするには、次のようにすればよいですね.

(1)与えられたリストから、最も小さい要素を関数 saisyouti2 を使って選び出す.
(2)与えられたリストから、(1)で選んだ要素を除いたリストを新たに作り、そのうちで最も小さい要素を関数 saisyouti2 を使って選び出す.
(3)(1)で選んだ要素を1番目、(2)で選んだ要素を2番目の要素とするリストを作り、それを関数値として返す.

上の計算を行うプログラムは以下のようになります.

[Graphics:images/math5sub_gr_53.gif]

確認してみましょう.

[Graphics:images/math5sub_gr_54.gif]
[Graphics:images/math5sub_gr_55.gif]

ちゃんと、一番小さい要素 -3 とその次に小さい要素 -1 が選ばれました.

小さい順に3つ並べる

今度は、最も小さい要素から3番目に小さい要素までを順番に返す関数を作ってみましょう.先ほどとまったく考え方は同じです.

(1)与えられたリストから、最も小さい要素を関数 saisyouti2 を使って選び出す.
(2)与えられたリストから、(1)で選んだ要素を除いたリストを新たに作り、そのうちで最も小さい要素を関数 saisyouti2 を使って選び出す.
(3)(1)用いたリストから、(2)で選んだ要素を除いたリストを新たに作り、そのうちで最も小さい要素を関数 saisyouti2 を使って選び出す.
(4)(1)で選んだ要素を1番目、(2)で選んだ要素を2番目、(3)で選んだ要素を3番目の要素とするリストを作り、それを関数値として返す.

上の計算を行うプログラムは以下のようになります.

[Graphics:images/math5sub_gr_56.gif]

確認してみましょう.

[Graphics:images/math5sub_gr_57.gif]
[Graphics:images/math5sub_gr_58.gif]

変数を減らす

先ほどは変数 l, l1, l2 を使いましたが、次のように書き換えても計算の内容は変わりませんね.

[Graphics:images/math5sub_gr_59.gif]

こうすると、プログラムの

[Graphics:images/math5sub_gr_60.gif]

の部分が

[Graphics:images/math5sub_gr_61.gif]

の繰り返しとなり、For 命令を使うのに都合がよいですね.計算が先ほどと同じか確認します.

[Graphics:images/math5sub_gr_62.gif]
[Graphics:images/math5sub_gr_63.gif]

n 個並べる

それでは、与えられたリストの要素を全て小さい順に並べ替えるプログラムを作りましょう.リストの要素を n 個とすると、小さい順に n 個並べればよいですね.先ほどの小さい順に 3 個並べるプログラムでは、

[Graphics:images/math5sub_gr_64.gif]

が2回、繰り返して実行されましたから、n 個の場合には n-1 回繰り返して実行されればよいですね.ですから、次のようなプログラムを作ります.

[Graphics:images/math5sub_gr_65.gif]

それでは、実行してみましょう.

[Graphics:images/math5sub_gr_66.gif]
[Graphics:images/math5sub_gr_67.gif]
[Graphics:images/math5sub_gr_68.gif]

おっと、エラーが出てプログラムがうまく動きませんでした.何故でしょうか?
実は、前に定義した関数 saisyouti2 にバグ(プログラムの誤りのこと)があったのです.

[Graphics:images/math5sub_gr_69.gif]
[Graphics:images/math5sub_gr_70.gif]

上のように要素が2つ以上の時は良いのですが、要素が1つであるリストを与えると

[Graphics:images/math5sub_gr_71.gif]
[Graphics:images/math5sub_gr_72.gif]
[Graphics:images/math5sub_gr_73.gif]

となって正しい答えを返しません.saisyouti2 の定義を見ればわかりますが、これは

[Graphics:images/math5sub_gr_74.gif]

で1番目の要素と2番目の要素の比較を行っているためです.与えられたリスト l の要素が1つだけの場合にには 2番目の要素  [Graphics:images/math5sub_gr_75.gif] は存在しませんから、プログラムが誤動作します.これを修正するために要素が1つだけのリスト {a} が与えられたときは、{a,1} を返すように、saiyouti2 を定義しなおしましょう.ルールベースドプログラミングを使えば、次のようにすればよいですね.

[Graphics:images/math5sub_gr_76.gif]

saiyouti2 の定義を確認してみましょう.

[Graphics:images/math5sub_gr_77.gif]
[Graphics:images/math5sub_gr_78.gif]
[Graphics:images/math5sub_gr_79.gif]

要素が1つだけのリストが与えられたときには1番目の定義が、その他の時には 2番目の定義が適用されます.それでは、新しい saiyouti2 に要素が1つだけのリストを与えてみましょう.

[Graphics:images/math5sub_gr_80.gif]
[Graphics:images/math5sub_gr_81.gif]

今度はきちんとした答えを返します.それではもう一度、関数 [Graphics:images/math5sub_gr_82.gif] をテストしてみましょう.

[Graphics:images/math5sub_gr_83.gif]
[Graphics:images/math5sub_gr_84.gif]

うまく動きましたね.


演習問題

(1)行列 m が与えられたとき、そのトレース(対角成分の和)を返す関数 trace を自分で作れ.

(2) 行列 m が与えられたとき、その転置行列を返す関数 tenti を自分で作れ(関数 Transpose[] を用いるのは禁ずる).

(3) 行列 m1 と m2 が与えられたとき、その積 m1.m2 を返す関数 seki を自分で作れ.

(4)要素が数値のリスト L = {a0,a1,a2,…,an} と数値 x が与えられたとき、a0+a1*x+a2*x^2+…+an*x^n の値を返す関数 atai を自分で作れ

(5) の問題は選択式である。(5-1) もしくは (5-2) の 問題を解け。

(5-1) 行列 m が与えられたとき、その行列式の値を返す関数 gyoretusiki を自分で作れ.ただし、Det[] を使ってはならない

(5-2) 自然数 n が与えられたとき、n の分け方の個数を返す関数 wakekata を自分で作れ.例えば 4 は 4, 3+1, 2+2, 2+1+1, 1+1+1+1 と5種類の分け方があるので、wakekata[4] = 5 である.