这题有几个子问题,我们逐个来解决。
product
计算给定范围中各点的某个函数值的乘积,它的递归版本和书本 38 页的递归版本 sum
非常相似:
;;; 31-rec-product.scm
(define (product term a next b)
(if (> a b)
1
(* (term a)
(product term (next a) next b))))
测试:
1 ]=> (load "31-rec-product.scm")
;Loading "31-rec-product.scm"... done
;Value: product
1 ]=> (product (lambda (x) x)
1
(lambda (i) (+ i 1))
10)
;Value: 3628800
迭代版本的 product
也和 练习 1.30 的迭代版本 sum
非常相似:
;;; 31-iter-product.scm
(define (product term a next b)
(define (iter a result)
(if (> a b)
result
(iter (+ a 1)
(* (term a) result))))
(iter a 1))
测试:
1 ]=> (load "31-iter-product.scm")
;Loading "31-iter-product.scm"... done
;Value: product
1 ]=> (product (lambda (x) x)
1
(lambda (i) (+ i 1))
10)
;Value: 3628800
factorial
也就是阶乘,书本 21 页介绍过阶乘的概念。
以下是使用 product
重定义的 factorial
:
;;; 31-factorial.scm
(load "31-iter-product.scm")
(define (factorial n)
(product (lambda (x) x)
1
(lambda (i) (+ i 1))
n))
测试:
1 ]=> (load "31-factorial.scm")
;Loading "31-factorial.scm"...
; Loading "31-iter-product.scm"... done
;... done
;Value: factorial
1 ]=> (factorial 10)
;Value: 3628800
可以将题目给出的公式
转换成
很明显,公式括号里面的分子和分母,可以分别用两个乘法序列来表示。
分子的乘法序列 \(2, 4, 4, 6, 6, 8, \dotsi\) 可以用函数 numer-term
生成:
;;; 31-numer-term.scm
(define (numer-term i)
(cond ((= i 1)
2)
((even? i)
(+ i 2))
(else
(+ i 1))))
分母的乘法序列 \(3, 3, 5, 5, 7, 7, \dotsi\) 可以用函数 denom-term
生成:
;;; 31-denom-term.scm
(define (denom-term i)
(if (odd? i)
(+ i 2)
(+ i 1)))
组合起 product
、 numer-term
和 denom-term
,完整的 \(\pi\) 值计算程序的定义如下:
;;; 31-pi.scm
(load "31-iter-product.scm")
(load "31-numer-term.scm")
(load "31-denom-term.scm")
(define (pi n)
(* 4
(exact->inexact
(/ (product numer-term
1
(lambda (i) (+ i 1))
n)
(product denom-term
1
(lambda (i) (+ i 1))
n)))))
程序使用了 exact->inexact 函数转换除法的商,确保计算所得的结果为浮点数格式(而不是份数格式)。
最后,对程序进行测试:
1 ]=> (load "31-pi.scm")
;Loading "31-pi.scm"...
; Loading "31-iter-product.scm"... done
; Loading "31-numer-term.scm"... done
; Loading "31-denom-term.scm"... done
;... done
;Value: pi
1 ]=> (pi 1)
;Value: 2.6666666666666665
1 ]=> (pi 10)
;Value: 3.2751010413348074
1 ]=> (pi 100)
;Value: 3.1570301764551676
1 ]=> (pi 1000)
;Value: 3.1431607055322663
1 ]=> (pi 10000)
;Value: 3.1417497057380523
1 ]=> (pi 100000)
;Value: 3.1416083612781764
增大和减少输入参数 n
可以控制计算出的 \(\pi\) 值的精度。