複素数を意味するデータ構造をペアを用いて表現し、以下のような関数を定義せよ。ここでは、
(define (complex a b)) ; aを実数部、bを虚数部とする複素数を返す。
(define (complex= c1 c2)) ; 複素数`c1'と`c2'が等しいかどうかをブール値で返す。
(define (complex+ c1 c2)) ; 複素数`c1'と`c2'の和を返す。
(define (complex* c1 c2)) ; 複素数`c1'と`c2'の積を返す。
締切: 11/17 23:59
以下の2つの関数「exp1」と「exp2」は、ともに冪乗を求める関数である。
(define (exp1 a n)
(cond ((< n 0) 0)
((= n 0) 1)
((even? n) (* (exp1 a (/ n 2)) (exp1 a (/ n 2))))
(else (* a (exp1 a (- n 1))))))
(define (exp2 a n)
(let ((square (lambda (x) (* x x))))
(cond ((< n 0) 0)
((= n 0) 1)
((even? n) (square (exp2 a (/ n 2))))
(else (* a (exp2 a (- n 1)))))))
しかしながら、以下のような2つの式を実行して比較すると、実行時間に大きな差が見られる。この差はどのような理由によるものか説明せよ。レポートはテキストファイルとして作成すること。レポート課題としての注意事項は課題C36と同様である。
(exp1 1 (exp1 2 60))
(exp2 1 (exp2 2 60))
締切: 11/17 23:59
関数「if-fun」と「fact3」を以下のように定義する。このとき「(fact3 10)」を評価しても、答えが返ってくる事はない。なぜそうなるかについて理由を説明せよ。ただしif-funではなくifを使った場合なぜ正常に動くのかについても説明する事。レポートはテキストファイルとして作成すること。レポート課題としての注意事項は課題C36と同様である。
(define (if-fun exp1 exp2 exp3)
(if exp1 exp2 exp3))
(define (fact3 n)
(if-fun (< n 1)
1
(* n (fact3 (- n 1)))))
締切: 11/17 23:59
引数として代数式と変数を取り、変数に対する式の導関数を返す関数「deriv」を作成したい。(このような操作は記号微分と呼ばれる。) 簡単のため、二引数の足し算のみから構築される記号微分プログラムを考える。また変数はシンボルとして表現し、代数式は演算子を先頭においたリストとして表現するものとする。この時、derivは次のような結果を返すことが期待される関数である。
> (deriv '(+ x 3) 'x)
1
> (deriv '(+ x (+ x 3)) 'x)
2
> (deriv '(+ y 3) 'y)
1
このような記号微分操作を実現するために、次のような実装を行なった。
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (make-sum a1 a2) (list '+ a1 a2))
(define (sum? x) (and (pair? x) (eq? (car x) '+)))
(define (addend s) (cadr s))
(define (augend s) (caddr s))
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp) (if (same-variable? exp var) 1 0))
((sum? exp) (make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
))
variable?関数はxが変数であるかを評価する関数であり、組み込み関数のsymbol?を利用する。symbol?は引数がシンボル型であるか否かを判定する関数である。same-variable?関数は2つの引数が等しい変数であるか否かを評価する。make-sum関数は2つの引数を受け取って、加算の代数式を返す。また、sum?関数は引数が加算の代数式であるか否かを判定する関数であり、addend関数およびaugend関数はそれぞれ加算の代数式の第一項と第二項を返す関数であるとする。また、deriv関数内で利用されているnumber?は引数が数値であるか否かを判定する組み込み関数である。
さて、このように定義した関数において、上記の例を適用したところ、次の結果が得られた。
> (deriv '(+ x 3) 'x)
(+ 1 0)
> (deriv '(+ x (+ x 3)) 'x)
(+ 1 (+ 1 0))
> (deriv '(+ y 3) 'y)
(+ 1 0)
この結果を踏まえた上で、deriv関数に次の2つの改良を加えよ。
作成したプログラムは数式として正しい回答になっているが、結果が簡約されておらず望んだ結果とはなっていない。make-sum関数を変更することによって、期待した結果を返すようプログラムを改良せよ。
二引数の足し算だけではなく、二引数の掛け算も微分できるようプログラムを拡張せよ。すなわち、
> (deriv '(* x y) 'x)
y
となるようにせよ
注1: 累乗についての微分を行う必要はなく、二引数の掛け算が微分出来れば良い。また、複雑な数式に対して良い簡約を行うことは非常に難しい課題であるため、上記例題で示した簡約ができていれば受理するものとする。
注2: (+ y 0)のような結果もより簡約されることが望ましい。
締切: 11/17 23:59