sp-10. 構造体
1
金子邦彦
Scheme プログラミング)
URL: https://www.kkaneko.jp/pro/scheme/index.html
アウトライン
10-1 構造体,構造体の定義,構造体の使用
10-2 パソコン演習
10-3 課題
2
10-1 構造体,構造体の定義,構造体の
使用
3
複数のデータが集まって,1つ
のデータを構成
新しい型の名前が付いている
structure ともいう
構造体とは?
4
name
age
address
AddressNote
x
y
delta-x
delta-y
ball
例題1
例題2
例題3
例題4
型の名前
データの
集まり
構造体の例
5
6
define-struct ・・・ の機能
(define-struct ball (x y delta-x delta-y))
名前 属性の並び
上記のプログラムの実行によって
コンストラクタ: make-ball
セレクタ: ball-x, ball-y, ball-delta-x, ball-delta-y
が使えるようになる
7
コンストラクタとセレクタ
コンストラクタ
構造体の生成
(例) make-ball
セレクタ
属性値の取得
(例) ball-x, ball-y, ball-delta-x, ball-delta-y
10-2 パソコン演習
8
資料を見ながら,「例題」を行ってみる
各自,「課題」に挑戦する
自分のペースで先に進んで構いません
9
パソコン演習の進め方
DrScheme の起動
プログラム PLT Scheme → DrScheme
今日の演習では「Intermediate Student
に設定
Language
→ Choose Language
→ Intermediate Student
→ Execute ボタン
10
DrScheme の使用
ball 構造体(ball structure)を定義するプログラムを書
ball は,x, y, delta-x, delta-y から構成する
define-struct 文を使用
位置
速度
x
y
delta-x
delta-y
11
例題1.ball 構造体
1. 次を「定義用ウインドウ」で,実行しなさい
入力した後に,Execute ボタンを押す
(define-struct ball
(x y delta-x delta-y))
次は,例題2に進んでください
(これは,例題2,3で使います)
12
「例題1.ball 構造体」の手順
ball 構造体を定義している
(実行結果は出ない)
13
(define-struct ball
(x y delta-x delta-y))
名前
属性の並び
(それぞれの属性にも名前がある)
14
ball 構造体
15
コンストラクタとセレクタ
(define-struct ball (x y delta-x delta-y))
名前 属性の並び
上記の定義によって
コンストラクタ: make-ball
セレクタ: ball-x, ball-y, ball-delta-x, ball-delta-y
が使えるようになる
例題2.ball の原点からの距離
ボールの座標値から,原点からの距離を求める関
distance-to-0 を作り,実行する
例題1の ball 構造体を使用
属性 x, y を取り出すために ball-x, ball-y (セレクタ)
を使う
位置
速度
x
y
delta-x
delta-y
16
1. 次を「定義用ウインドウ」で,実行しなさい
入力した後に,Execute ボタンを押す
(define-struct ball
(x y delta-x delta-y))
;; distance-to-0: ball -> number
;; to compute the distance of a ball to the origin
;; (distance-to-0 (make-ball 3 4 0 0)) = 5
(define (sqr x)
(* x x))
(define (distance-to-0 a-ball)
(sqrt
(+ (sqr (ball-x a-ball))
(sqr (ball-y a-ball)))))
2. その後,次を「実行用ウインドウ」で実行しなさい
次は,例題3に進んでください
(distance-to-0 (make-ball 3 4 0 0))
例題1と同じ
17
「例題2.ball の原点からの距離」の手順
まず,関数 sqr と関数
distance-to-0 を定義している
18
これは,
(distance-to-0 (make-ball 3 4 0 0))
と書いて,a-ball の値を
(make-ball 3 4 0 0) に設定しての実行
実行結果である「5」が
表示される
19
distance-to-0
5
入力 出力
a-ball の値:
(make-ball 3 4 0 0)
入力は ball 構造体 出力は数値
20
distance-to-0 の入力と出力
(define-struct ball (x y delta-x delta-y))
;; distance-to-0 : ball -> number
;; to compute the distance of a ball to the origin
;; (distance-to-0 (make-ball 3 4 0 0)) = 5
(define (sqr x)
(* x x))
(define (distance-to-0 a-ball)
(sqrt
(+ (sqr (ball-x a-ball))
(sqr (ball-y a-ball)))))
21
(define-struct ball (x y delta-x delta-y))
;; distance-to-0 : ball -> number
;; to compute the distance of a ball to the origin
;; (distance-to-0 (make-ball 3 4 0 0)) = 5
(define (sqr x)
(* x x))
(define (distance-to-0 a-ball)
(sqrt
(+ (sqr (ball-x a-ball))
(sqr (ball-y a-ball)))))
ball-xは,x の値の取得
ball-y は,x の値の取得
22
23
例題3.ステップ実行
関数 distance-to-0 (例題2)について,実行
結果に至る過程を見る
(distance-to-0 (make-ball 3 4 0 0)) から 5 に至る過
程を見る
DrScheme stepper を使用する
(distance-to-0 (make-ball 3 4 0 0))
= (sqrt (+ (sqr (ball-x (make-ball 3 4 0 0)))
(sqr (ball-y (make-ball 3 4 0 0)))))
= (sqrt (+ (sqr 3)
(sqr (ball-y (make-ball 3 4 0 0)))))
= ...
= (sqrt (+ 9
(sqr (ball-y (make-ball 3 4 0 0)))))
= (sqrt (+ 9
(sqr 4)))
= ...
= (sqrt (+ 9 16))
= (sqrt 25)
= 5
1. 次を「定義用ウインドウ」で,実行しなさい
Intermediate Student で実行すること
入力した後に,Execute ボタンを押す
(define-struct ball
(x y delta-x delta-y))
;; distance-to-0: ball -> number
;; to compute the distance of a ball to the origin
;; (distance-to-0 (make-ball 3 4 0 0)) = 5
(define (sqr x)
(* x x))
(define (distance-to-0 a-ball)
(sqrt
(+ (sqr (ball-x a-ball))
(sqr (ball-y a-ball)))))
(distance-to-0 (make-ball 3 4 0 0))
2. DrScheme を使って,ステップ実行の様子
確認しなさい Step ボタン,Next ボタンを使用)
理解しながら進むこと
次は,例題4に進んでください
例題2と同じ
24
「例題3.ステップ実行」の手
(distance-to-0 (make-ball 3 4 0 0)) から 5 に至る過程の概略
(distance-to-0 (make-ball 3 4 0 0))
= (sqrt (+ (sqr (ball-x (make-ball 3 4 0 0)))
(sqr (ball-y (make-ball 3 4 0 0)))))
= (sqrt (+ (sqr 3)
(sqr (ball-y (make-ball 3 4 0 0)))))
= ...
= (sqrt (+ 9
(sqr (ball-y (make-ball 3 4 0 0)))))
= (sqrt (+ 9
(sqr 4)))
= ...
= (sqrt (+ 9 16))
= (sqrt 25)
= 5
最初の式
実行結果
コンピュータ内部での計算
25
(distance-to-0 (make-ball 3 4 0 0)) から 5 に至る過程の概略
(distance-to-0 (make-ball 3 4 0 0))
= (sqrt (+ (sqr (ball-x (make-ball 3 4 0 0)))
(sqr (ball-y (make-ball 3 4 0 0)))))
= (sqrt (+ (sqr 3)
(sqr (ball-y (make-ball 3 4 0 0)))))
= ...
= (sqrt (+ 9
(sqr (ball-y (make-ball 3 4 0 0)))))
= (sqrt (+ 9
(sqr 4)))
= ...
= (sqrt (+ 9 16))
= (sqrt 25)
= 5
これは,
(define (distance-to-0 a-ball)
(sqrt
(+ (sqr (ball-x a-ball))
(sqr (ball-y a-ball)))))
a-ball (make-ball 3 4 0 0) で置き換えたもの
26
AddressNote 構造体を定義するプロ
グラムを書く
AddressNote は,name, age,
address から構成する
define-struct 文を使用
name
age
address
AddressNote 27
例題4.AddressNote 構造体
1. 次を「定義用ウインドウ」で,実行しなさい
入力した後に,Execute ボタンを押す
(define-struct AddressNote
(name age address))
次は,例題5に進んでください
(これは,例題5で使います)
28
「例題4.ball 構造体」の手順
AddressNote 構造体を
定義している
(実行結果は出ない)
29
(define-struct AddressNote
(name age address))
名前
属性の並び
(それぞれの属性にも名前がある)
30
AddressNote 構造体
31
コンストラクタとセレクタ
(define-struct AddressNote (name age address))
名前 属性の並び
上記のプログラムの実行によって
make-AddressNote
AddressNote-name, AddressNote-age,
AddressNote-address
が使えるようになる
AddressNote 構造体のリストから,名前
name)のリストを得る関数 select-name を作
り,実行する
例題3の AddressNote 構造体を使用
構造体1つ 1人分
構造体のリスト 複数人
属性 name を取り出すために AddressNote-name
(セレクタ)を使う
name
age
address
AddressNote 32
例題5.住所録
1. 次を「定義用ウインドウ」で,実行しなさい
入力した後に,Execute ボタンを押す
(define-struct AddressNote
(name age address))
;; select-name: a list of AddressNote -> a list of string
;; to select name from an AddressNote list
(define (select-name a-list)
(cond
[(empty? a-list) empty]
[else (cons (AddressNote-name (first a-list))
(select-name (rest a-list)))]))
2. その後,次を「実行用ウインドウ」で実行しなさい
次は,例題6に進んでください
(select-name (list
(make-AddressNote "Ken" 35 "Fukuoka")
(make-AddressNote "Bill" 30 "Saga")
(make-AddressNote "Mike" 28 "Nagasaki")))
例題4と同じ
33
「例題5.住所録」の手順
まず,関数 select-name
を定義している
34
ここでは,make-AddressNote
を使って,AddressNote 構造体のリスト
を作っている
実行結果である
(list "Bill" "Ken" "Mike)
が表示される 35
select-name
(list "Ken" "Bill" "Mike")
入力 出力
(list
(make-AddressNote "Ken" 35 "Fukuoka")
(make-AddressNote "Bill" 30 "Saga")
(make-AddressNote "Mike" 28 "Nagasaki"))
入力は AddressNote
構造体のリスト
出力はリスト
36
select-name の入力と出力
(define-struct AddressNote
(name age address))
;; select-name: a list of AddressNote -> a list of string
;; to select name from an AddressNote list
(define (select-name a-list)
(cond
[(empty? a-list) empty]
[else (cons (AddressNote-name (first a-list))
(select-name (rest a-list)))]))
37
(select-name (list
(make-AddressNote "Ken" 35 "Fukuoka")
(make-AddressNote "Bill" 30 "Saga")
(make-AddressNote "Mike" 28 "Nagasaki")))
select-name の入力は リスト
AddressNote 構造体のリストを作るために,
make-AddressNote(コンストラクタ) を並べている
38
select-name の実行では
DrScheme にすでに組み込み済みの構造体
rectangular を使って,複素数の計算を行ってみる
足し算 (1+2i) + (3+4i)
引き算 (5+7i) (3+4i)
かけ算 (1+2i) ×(3+4i)
割り算 (-5+10i) / (3+4i)
39
例題6.複素数の計算
DrScheme では make-rectangular を使用
実数部が x で,虚数部が y であるような複素数は,
(make-rectangular x y)
例: (make-rectangular 3 4)」は 3+4i
rectangularは,DrScheme に組み込み済みの
構造体
40
複素数の計算
よくある間違い
(+ (1+2i) (3+4i)) は,シンタックスエラー(文法エラー)
(+ (make-rectangular 1 2) (make-rectangular 3 4)) と書くべき
41
1. 次の式を「実行用ウインドウ」で,実行しな
さい
(+ (make-rectangular 1 2)
(make-rectangular 3 4))
(- (make-rectangular 5 7)
(make-rectangular 3 4))
(* (make-rectangular 1 2)
(make-rectangular 3 4))
(/ (make-rectangular -5 10)
(make-rectangular 3 4))
次は,例題7に進んでください 42
「例題6.複素数の計算」の手順
43
例題7.複素数のべき乗
2つの値 theta nから (cosθ+isinθ)nを計算す
るプログラム myexp を作り,実行する
θはの単位はラジアン
(cosθ+isinθ)nの計算: expt を使用
expt は複素数にも使える
44
1. 次を「定義用ウインドウ」で,実行しなさい
入力した後に,Execute ボタンを押す
(define (myexp theta n)
(expt (make-rectangular (cos theta)
(sin theta))
n))
2. その後,次を「実行用ウインドウ」で実行しなさい
次は,課題に進んでください
(myexp 0.5236 1)
(myexp 0.5236 2)
(myexp 0.5236 3)
45
「例題7.複素数のべき乗」の手順
#i」は「近似値」という意味
46
「例題7.複素数のべき乗」の実行結果
10-3 課題
47
課題1
関数 distance-to-0 (授業の例題2)につい
ての問題
次の式を実行し,実行結果を報告せよ
1. (distance-to-0 (make-posn 1 2))
2. (distance-to-0 (make-posn (- 5 3) (- 4 6))
3. (distance-to-0 (make-posn (* 2 3) (* 4 5))
48
ball 構造体(授業の例題1)についての問
ball のデータ a-ball x の値が 0 100 の間にある
ときに限り true を返し,範囲外 のときには false
返すような関数 in を作成し,実行結果を報告しなさ
但し,x = 0 あるいは x = 100 のときには false を返す
こと.
ヒント: 次の空欄を埋めなさい
(define-struct ball (x y delta-x delta-y))
(define (in a-ball)
(cond
[ ]
[ else ]))
49
課題2
AddressNote 構造体(授業の例題4)につい
ての問題
AddressNote のデータ a-person の氏名を取り出す
関数 get-name は,セレクタ AddressNote-name
を使って,次のように書ける.
(define (get-name a-person)
address-note-name a-person)
では,AddressNote のデータ a-person の年齢
(age)が20以上ならば「'Adult」を,20以下な
ら「'Clild」を出力する関数を作成し,実行結果を
報告しなさい
50
課題3
AddressNote 構造体(授業の例題4)についての
問題
a-person の年齢が、ある年齢 an-age と一致していれ
ば名前(name)を、さもなければ,文字列 "none"
返す関数 check-by-age を作成し,実行結果を報告しな
さい
例えば
(check-by-age (make-address-note "Kunihiko
Kaneko" 35 "Hakozaki") 35) = "Kunihiko Kaneko"
(check-by-age (make-address-note "Kunihiko
Kaneko" 35 "Hakozaki") 30) = "none"
51
課題4
AddressNote 構造体(授業の例題4)につい
ての問題
AddressNote 構造体のリスト a-list と年齢 an-age
から,年齢が an-age に一致する人のリストを出
力する関数 selection-by-age を作成し,実行結果
について報告しなさい
例えば
(selection-by-age
(list (make-address-note Kunihiko Kaneko” 35 “Hakozaki”)
(make-address-note “Taro Tanaka” 34 “Kaizuka”)
(make-address-note “Hanako Saito” 35 “Tenjin”)) 35)
= (list (make-address-note Kunihiko Kaneko” 35 “Hakozaki”)
(make-address-note Hanako Saito” 35 “Tenjin”))
52
課題5
AddressNote 構造体のリストから,年齢(age)
平均を求める関数 sum-age を作り,実行
結果を報告しなさい
53
課題6
さらに勉強したい人への
補足説明資料
ドモアブルの定理
54
n = 1, 2, …, 20 について,(cosθ+isinθ)ncos
+ isin を計算するプログラム f1, f2 を書
結果は,長さ20のリストとして得る
近似値を使った計算を繰り返すと,誤差が積み重な
ことを確かめる
(cosθ+ isinθ)nは,(cosθ+ isinθ)の値(これは
近似値)を使っての計算
55
ドモアブルの定理
1. 次を「定義用ウインドウ」で,実行しなさい
入力した後に,Execute ボタンを押す
(define (f1 theta n)
(cond
[(= n0) empty]
[else (cons (expt (make-rectangular (cos theta)
(sin theta))
n)
(f1 theta (- n1)))]))
(define (f2 theta n)
(cond
[(= n0) empty]
[else (cons (make-rectangular (cos (* n theta))
(sin (* n theta)))
(f2 theta (- n1)))]))
56
「ド・モアブルの定理」の手順 (1/2)
2. その後,次を「実行用ウインドウ」で実行しなさい
(f1 0.05 20)
(f2 0.05 20)
57
「ド・モアブルの定理」の手順 (2/2)
58
「ド・モアブルの定理」の実行結果
> (f1 0.05 20)
(list
#i0.5403023058681402+0.8414709848078972i
#i0.5816830894638839+0.8134155047893742i
#i0.6216099682706648+0.7833269096274839i
#i0.6599831458849826+0.7512804051402932i
#i0.6967067093471658+0.7173560908995231i
#i0.731688868873821+0.6816387600233345i
#i0.7648421872844886+0.6442176872376914i
#i0.796083798549056+0.6051864057360399i
#i0.8253356149096784+0.5646424733950356i
#i0.8525245220595062+0.5226872289306593i
#i0.8775825618903731+0.47942553860420317i
#i0.9004471023526772+0.43496553411123035i
#i0.9210609940028853+0.3894183423086506i
#i0.939372712847379+0.34289780745545145i
#i0.9553364891256061+0.29552020666133966i
#i0.968912421710645+0.24740395925452296i
#i0.9800665778412417+0.19866933079506124i
#i0.9887710779360424+0.14943813247359924i
#i0.9950041652780258+0.09983341664682816i
#i0.9987502603949663+0.04997916927067833i)
> (f2 0.05 20)
(list
#i0.5403023058681398+0.8414709848078965i
#i0.5816830894638836+0.8134155047893737i
#i0.6216099682706644+0.7833269096274834i
#i0.6599831458849822+0.7512804051402927i
#i0.6967067093471654+0.7173560908995228i
#i0.7316888688738209+0.6816387600233341i
#i0.7648421872844885+0.644217687237691i
#i0.7960837985490559+0.6051864057360396i
#i0.8253356149096783+0.5646424733950354i
#i0.8525245220595057+0.5226872289306592i
#i0.8775825618903728+0.479425538604203i
#i0.9004471023526769+0.43496553411123023i
#i0.9210609940028851+0.3894183423086505i
#i0.9393727128473789+0.34289780745545134i
#i0.955336489125606+0.29552020666133955i
#i0.9689124217106447+0.24740395925452294i
#i0.9800665778412416+0.19866933079506122i
#i0.9887710779360422+0.14943813247359922i
#i0.9950041652780258+0.09983341664682816i
#i0.9987502603949663+0.04997916927067833i)
(cosθ+ i sinθ)ncos nθ+ i sin nθ
値は、ほぼ一致しているが,わずかに食い違う
不一致
59
実行結果の比較
ド・モアブルの定理は:
なお,i は虚数単位
n
i
sincos
nin sincos
60
ド・モアブルの定理
(cosθ+ i sinθ)2= cos2θ- sin2θ+ 2i cosθsin θ
= cos2θ+ i sin2θ
(cosθ+ i sinθ)3= (cosθ+ i sinθ)2(cosθ+ i sinθ)
= (cos2θ+i sin2θ) (cosθ+ i sinθ)
= cos2θcosθ-sin2θsinθ
+ i (cos2θsi-sin2θcosθ)
= cos (2θ+θ) + i sin (2θ+θ)
= cos3θ+ i sin3θ
(以下同様に考える.数学的帰納法で証明できる)
61
(cosθ+ isinθ)n = cos + isin
z1= x1+ iy1
z2= x2+ iy2のとき
z1z2= (x1+ iy1) (x2+ iy2)
= x1x2+ x1iy2+ iy1x2+ iy1iy2
= x1x2- y1y2+ i(x1y2+ y1x2)
実数部 虚数部 62
複素数の掛け算
本来なら「 (cosθ+ i sinθ)n = cos nθ+ i sin nθ 」が
成り立つはず
しかし,ここで実行される計算は,あくまでも
似計算
sin, cos, log 等の計算結果は,近似値でしか得られない
例:「(sin 0.1)」を実行すると
#i0.09983341664682816
計算を繰り返す(つまり、計算結果を使った計
算)と,誤差が積み重なる
(cosθ+ i sinθ)nは,(cosθ+ i sinθ)の値(これは近似
値)を使っての計算 63
実際の計算では