第 10 回 Mupad, 配列、文字列

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

10-1. Mupad

この資料は平田 浩 一さん / 愛媛大学教育学部 の「数式処理 MuPAD 入門 」 Tomonori Kouya さんの「Documents on MuPAD」を参考にして作 りました。 また、Mupad の教科書として 赤間 世紀「はじめてのMuPAD」Springer-Verlag Tokyo が出版されています。

基本操作

Mupad では求めたい式を記述してそのまま Enter を押すだけです。 % (あるいは %1 )は直前の結果を指します。%2 は 2 個前の結果を、 %3 は 3 個前の結果を指します。

整数、有理数

整数や有理数の四則演算は +, -, *, / を使用します。割算は有理数として扱 われ、分数で計算されます。 なお、整数の割算で商と余りを求めるには div, mod を使います。 巾乗は ^ を使用します。 階乗は ! を使用します。

例
1+1
5/2
5 div 2
5 mod 2
2^10
6!

演習10-1

次の計算をしなさい

  1. 1/3+1/6
  2. 100!

ある数が素数かどうかを判断するには isprime 関数を使います。 また、素因数分解するには ifactor 関数を使います。

例
isprime(7)
ifactor(18)

演習10-2

2105-1, 2106-1,2107-1, は素数ですか? もし素数でなければ素因数分解しなさい。


実数

ルートの処理は基本的には開平されず、そのまま取り扱われます。 ルートは sqrt(2) でも 2^(1/2)でもどちらでも可能です。 また、円周率は PI、自然対数の底は E で表します。 一方、求めた値を数値で得たい場合は float 関数を使用します。必要な精度 は DIGITS 変数に桁数を代入することで与えます。

例
2^(1/2)
DIGITS:=30
float(PI)

演習10-3

√2 を 20 桁求めなさい。

変数

Mupad では任意の文字を変数として使うことができます。x, y x1 など。 代入は「:=」という記号を使います。

例
x:=1

なお、代入された変数は方程式には使えません。 代入を取り消すには、delete を使います。

例
delete x

式の計算

expand は式を展開します。 simplify は式を単純化します。 radsimp は根号を整理します。

例
expand((x+y)^2)
simplify(sqrt(2)*sqrt(8))
radsimp(1/sqrt(2))

演習10-4

次の計算をしなさい。

  1. (√2 + √3)2
  2. (1+√2)10

演習10-5

次の式において分母にルートがない形にしなさい。


frac { sqrt{3} + sqrt{2}}{sqrt{3} - sqrt{2}}

複素数

虚数単位 i=√(-1) は Mupad では「I(英字大文字)」で表します。 実部と虚部に分離する関数は rectform です。また絶対値は abs です。

例
rectform((-1)^(1/3))
(これは x2+x+1=0 の解の一つ)

演習10-6

次の値を求めなさい。 また大きさ(絶対値)も求めなさい。

  1. √(-1) の平方根
  2. (2+I)10
  3. e

多項式、方程式

多項式を因数分解するには factor を使います。 式をある変数に関して解くには collect を使います。 式に値を代入するには subs を使います。 方程式を解くには solve を使います。 なお、変数には任意の式を代入できます。

例
factor(x^2+2*x+1)
collect((x+y+z)^3,[x])
subs(x^2,[x=(y+1)])
solve(x^2+3*x+2,x)
solve({x+y=1,x-y=-1},{x,y})

演習10-7

次の多項式を因数分解しなさい

  1. a3+b3+c3-3abc

演習10-8

次の多項式を x についてまとめなさい。

(x+y)3+(x+y)2+(x+y)+1

演習10-9

X=(x+2), Y=(x-2) のとき、 X3=Y2を解きなさい。

ヒント

式に別の式を代入するには、 subs(X^3~Y^2,[X=x+2,Y=x-2]) とする。 Rootof という表記に関しては、 float(%) を指定すると、数値解が得られる。


微積分

関数を微分するには diff を使います。 不定積分を求めるには int を使用します(積分定数が付加されないことに注意)。 定積分も同様に int を使用しますが、第二引数で積分区間を指定します。 微分方程式を定義するには ode という関数を使います。 初期値を与えることもできます。

diff(x^2,x);
int(x,x);
int(x^2,x=1..2);
solve(ode(y'(x)=y(x),y(x)))
solve(ode({y'(x)=y(x),y(0)=1},y(x)))

演習10-10

次の関数を微分しなさい

  1. sin x
  2. 1/x
  3. exsin x

演習10-11

次の関数を積分しなさい

  1. sin x
  2. 1/x
  3. exsin x

演習10-12

次の常微分方程式を解きなさい。

  1. frac{ d y }{ d x} = x , y ( 0 ) = 1
  2. frac{ d y }{ d x} = x y , y ( 0 ) = 1
  3. frac{ d y }{ d x} = frac{1}{y} , y ( 0 ) = 1

グラフ

二次元グラフを書くには plotfunc2d、 三次元グラフを書くには plotfunc3d を使います。

例
plotfunc2d(sin(x),cos(x),x=-PI..PI)
plotfunc3d(x^2+y^2)

演習10-13

次のグラフを書きなさい

  1. y=tan(x)
  2. 
z = sin LRparen{ sqrt{ x^2 + y^2}}

数列

数列の和を求めるには sum を使います。 また極限を求めるには limit を使います。 なお無限大は infinity と表します。 右極限、左極限はそれぞれ最後に Right, Left のオプションを付けます。

例
sum(i,i=1..10)
sum(i,i=1..n)
sum(2^(-i),i=1..infinity)
limit(1/n, n=infinity)
limit(x^x,x=0,Right)
limit(x/abs(x),x=0,Right)
limit(x/abs(x),x=0,Left)

演習10-14

次の値を求めなさい。

  1. 1 + 3 + ... + (2n-1)
  2. 12 + 22 + ... + n2
  3. 
frac{1}{1^2} + frac{1}{2^2} + frac{1}{3^2} + ldots
  4. 
lim {n rightarrow infty} LRparen{ 1 + frac{x}{n}}^{n}
  5. 
1 + frac{1}{1 !} + frac{1}{ 2 ! } + frac{1}{3 !} + ldots

ベクトル、行列

行列は次のようにして定義します。

matrix([[1,2],[3,4]])

行ベクトル、列ベクトルは次のように定義します。

matrix([[1,2,3]])
matrix([1,2,3])

行列の演算は +, -, * が使用できます。 また逆行列は (1/行列) あるいは -1 乗で求めます。

例
A:=matrix([[1,2],[3,4]])
B:=matrix([[5,6],[7,8]])
A+B
A-B
3*A
A*B
1/A
A^(-1)

転置は linalg::transpose を使用します。 行列式は linalg::det を使用します。 Rank は linalg::rank を使用します。 ベクトルの大きさは norm(ベクトル,2) で求めます。 内積は linalg::scalarProduct を使用します。 二つのベクトルのなす角は linalg::angle を使用します。 外積は linalg::crossProduct を使用します。 n×n の正方行列 A と n 次元列ベクトル b に対して、方程式「Ax=b」を解く には linalg::linearSolve(A,b) を使います。

なお、「lialg::」を省略したい場合は始めに「export(linalg)」を実行しま す。

例
export(linalg)
A:=matrix([[1,2,3],[4,5,6],[7,8,9]])
traspose(A)
det(A)
rank(A)
rank(matrix([[1,1],[1,1]]))
x:=matrix([1,2,3])
y:=matrix([4,5,6])
norm(x,2)
scalarProduct(x,y)
transpose(x)*y
angle(x,y)
crossProduct(x,y)
linearSolve(A,x)

演習10-15

ベクトル x=(1,2), y=(3,4) に対して次の問いに答えなさい。

  1. x, y の大きさを求めなさい。
  2. x, y のなす角を求めなさい。

演習10-16

頂点座標が (1,2,3),(4,5,6),(7,8,9) の三角形の面積を求めなさい。

ヒント

三角形の二辺を表すベクトルを a, b とすると、面積は次の式 で求まる。

 1
--- * (aの長さ) * (bの長さ) * sin(abのなす角)
 2

10-2. 配列

宣言文での初期化

C 言語では宣言文で変数の値を代入(初期化)できます。

int i=0;
float a=2.3;
char d='F';

配列

C 言語で数列を取り扱うために配列という概念が用意されています。 添字は角括弧「[ ]」で括ります。 つまり、a0, a1, a2 はそれぞれ a[0], a[1], a[2] と表します。 aiは a[i] と表します。 ただし、添字に使用できる変数は整数型(int)だけです。 さらに添字には a[i+1] や b[j*2] など、整数を値に持つ式を書くことができます。

配列を使う時、宣言は次のようにします。

int a[5];
char b[3];
float c[4];

するとそれぞれ、次の変数が使えるようになります。

a[0], a[1], a[2], a[3], a[4]
b[0], b[1], b[2]
c[0], c[1], c[2], c[3]

プログラムでは、配列はそれぞれ普通の変数として使用することができます。 但し、実行中に配列の値をまとめて代入することはできません。 一方、初期化する際には次のようにまとめて値をセットできます。

int a[5]={ 3, 4, 6, 0, -1 };

このようにすると 次のように値が代入されます。

a[0]= 3,
a[1]= 4,
a[2]= 6,
a[3]= 0,
a[4]=-1

さらに値をまとめてセットする場合、要素数の指定を省略することができます。

float b[]={ 1.3, -3e-2, -5.0 };

このようにすると次のように値が代入されます。

b[0]= 1.3,
b[1]=-3e-2,
b[2]=-5.0

演習10-17

以下の方程式 a0 + a1x = 0 ( a1≠0 ) の解を求めるプログラムを完成させなさい。 そして、以下の方程式をこのプログラムで解きなさい。

  1. 2 + x = 0
  2. 2 - 4 x = 0
  3. 0 - 3 x = 0
#include <stdio.h>
main(){
  float a[]={2,1};
  float x;
  /* x の計算 */
  /* printf("方程式 %f + %f x = 0 の解は %f\n", ... );*/
}

演習10-18

以下の入力された配列変数を表示するプログラムを完成させなさい。 但し、#define X Y はプログラム中で Y を X という 名前で使うことを意味します。

#include <stdio.h>
#define N 6
main(){
  float a[N]={2, 1, 5, 6, 9, 2};
  int i;
  /* for( ; ; ){ */
  /* printf("a[%d] の値は %f\n",...); */
  /* } */
}

演習10-19

次のプログラムを完成させなさい。また、改造して平均値も出力するようにし なさい。

#include <stdio.h>
#define N 5
main(){
  int i;
  float a[N]={2.3, 4.4, 3.9, -1.2, 0.3};
  float s;
  i=0;
  s=0;
  while(i<N){
    printf("a[%1d]=%f\n",i,a[i]);
    /* s に a[i] を加える */
    /* i を 1 増やす */
  }
  printf("合計: %f\n",s);
}

10-3. 番兵

データの列の中に、列の終りを意味する値を付加してプログラムの流れを変え るというテクニックがあります。 そのようなデータのことを番兵と呼びます。 ループ変数を使うと、全体のデータの数を数えるなどデータの変更に対して細 かい管理が必要になりますが、番兵を用いるとデータの最後をデータ自身が教 えてくれるため、プログラムが簡潔になります。

演習10-20

次のプログラムを完成させ、正の値が出力されるようにしなさい。

#include <stdio.h>
main(){
  int a[]={5,3,10,2,0};
  int i=0;
  /* a[i] の値が 0 でないとき以下を繰り返す */
  {
    printf("%d\n",a[i]);
    /* i を 1 増やす */
  }
}

演習10-21

次のプログラムを完成させ、偶数がいくつあるか表示しなさい。

#include <stdio.h>
main(){
  int a[]={5,3,10,2,0};
  int n=0;
  int i;
  /* i を 0 にする */
  /* a[i] の値が 0 でないとき以下を繰り返す */
  {
    if(/* a[i] が偶数の時*/){
      /* 数を数える */
    }
    /* i を 1 増やす */
  }
  printf("与えられた入力中に偶数は %d 個\n",n);
}

演習10-22

番兵を使って次の正の値の列の合計が出力されるプログラムを書きなさい。

{2, 7, 1, 3, 9, 0}

演習10-23

番兵を使って次の正の値の列の平均が出力されるプログラムを書きなさい。

{2.1, 7.5, 1.2, 3.4, 9.9, 0}
ヒント

列の長さはあらかじめ決められないので、番兵が出てくるまで要素をひとつひ とつ数えて長さを求める。


10-4. 文字列

C 言語で文字列を扱うには、文字型の配列を使います。 ただし、配列の終りには配列の終りを示す(番兵)特別な文字\0を入 れます。従って、配列にあらかじめ文字列を入れるには次のようにします。

char x[]={'a','b','c','\0'};

ただし、文字列の扱いを簡単にするために、これを次のように書くことが可能 です。

char x[]="abc";

このように書くと配列変数 x の値は次のようになります。

x[0]='a', x[1]='b', x[2]='c', x[3]='\0'

二重引用符で括られた文字列を並べると一つの文字列として扱われます。 長い文字列を記述する場合、つぎのようにします。

char x[]="abc"
         "def"
         "ghi";

この宣言は char x[]="abcdefghi"; と同じになります。 なお、このような文字列の一括の代入はあくまでも宣言文の中でのみ有効で、 プログラムの実行中はできません。 プログラム中はひと文字ずつしか取り扱えません。 文字配列 x, y に対し、 x=y はできません(エラーにならず誤動作します)。

文字を画面に表示するには printf("%c",x[0]); などと書きますが、文字配列 を一括して画面に表示するには %s を使用します。 printf("%s",x); と %s に対して文字配列名を指定します。 これは、次のプログラムと同じ処理が行なわれます。

int i=0;
while(x[i]!='\0'){
  printf("%c",x[i++]);
}

演習10-24

文字列が与えられた時、縦書きに表示するプログラムを書きなさい。 そして "abcdefg" を縦書きにしなさい。


演習10-25

次のプログラムを完成させなさい。 また、文字列を "ABCDEF" に替えて実行しなさい。

#include <stdio.h>
main(){
  char x[]="abcdefgh";
  int y=0;
  while(x[y]!='\0'){
    printf("文字列 %s の %d 文字目は %c\n",?,?,?);
    y=y+1;
  }
  printf("全部で %d 文字\n",?);
}

演習10-26

文字列の長さを出力するプログラムを書きなさい。 文字列 "abcdefg" などで試しなさい。


演習10-27

次のプログラムを完成させなさい。 また、文字列を "ABC" と "DEF" に替えて実行しなさい。

#include <stdio.h>
main(){
  char x[]="abcdef", y[]="ghijkl", z[100];
  int i,j;
  printf("文字列 %s と文字列 %s をくっつけると",x,y);
  /* まず z に x をひと文字ずつコピーする */
  j=0;
  while(y[j]!='\0'){
    z[i]=y[j];
    i=i+1;
    j=j+1;
  }
  z[i]='\0';
  printf("%s\n",z);
}

演習10-28

文字列が与えられた時、先頭の 3 文字だけを表示するプログラムを書きなさ い。 作ったプログラムを文字列 "abcde", "ABC", "X" などで試しなさい。

ヒント

「文字が \0 かまたは 3 文字を越えた時」終了させるには次のように論理演算を 使います。

  while((文字が '\0' でない)&&(3 文字以内))

演習10-29

文字列が与えられた時、先頭の空白の文字数を数えるプログラムを書きなさい。 "a○b○c" なら 0, "○○def" なら 2 が出力されるようにしなさい(○は空白 を表す)。


演習10-30

文字配列 x 中に含まれている文字変数 y の文字の使用頻度を求めるプログラ ムを書きなさい。 例えば、 x[]="This is a pen.", y='i' ならば、 2 を表示しなさい。


演習10-31

文字列が与えられた時、二文字出力しては改行するように表示するプログラム を書きなさい。 そして、次の文字列で試しなさい。

  1. "a"
  2. "abcd"
  3. "abcde"

演習10-32

文字列が与えられた時、最初の文字から一文字おきに表示するプログラムを書 きなさい。 "abcde" なら出力は ace になります。 そして、次の文字列で試しなさい。

  1. "a"
  2. "abcd"
  3. "abcde"

演習10-33

文字列が与えられた時、逆向きに表示するプログラムを書きなさい。 "abcdefg" が与えられた時、「gfedcba」と表示されるようにしなさい。


10-5. 宿題

gnuplot をダウンロードしておいて下さい。


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科