home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 44
/
Amiga_Dream_44.iso
/
RiscPc
/
programmation
/
scm4e2.arc
/
!Scm
/
scm
/
pi
< prev
next >
Wrap
Text File
|
1994-10-28
|
5KB
|
133 lines
;;;; "pi.scm", program for computing digits of numerical value of PI.
;;; Copyright (C) 1991 Aubrey Jaffer.
;;; See the file `COPYING' for terms applying to this program.
;;; (pi <n> <d>) prints out <n> digits of pi in groups of <d> digits.
;;; 'Spigot' algorithm origionally due to Stanly Rabinowitz.
;;; This algorithm takes time proportional to the square of <n>/<d>.
;;; This fact can make comparisons of computational speed between systems
;;; of vastly differring performances quicker and more accurate.
;;; Try (pi 100 5)
;;; The digit size <d> will have to be reduced for larger <n> or an
;;; overflow error will occur (on systems lacking bignums).
;;; It your Scheme has bignums try (pi 1000).
(define (pi n . args)
(if (null? args) (bigpi n)
(let* ((d (car args))
(r (do ((s 1 (* 10 s))
(i d (- i 1)))
((zero? i) s)))
(n (+ (quotient n d) 1))
(m (quotient (* n d 3322) 1000))
(a (make-vector (+ 1 m) 2)))
(vector-set! a m 4)
(do ((j 1 (+ 1 j))
(q 0 0)
(b 2 (remainder q r)))
((> j n))
(do ((k m (- k 1)))
((zero? k))
(set! q (+ q (* (vector-ref a k) r)))
(let ((t (+ 1 (* 2 k))))
(vector-set! a k (remainder q t))
(set! q (* k (quotient q t)))))
(let ((s (number->string (+ b (quotient q r)))))
(do ((l (string-length s) (+ 1 l)))
((>= l d) (display s))
(display #\0)))
(if (zero? (modulo j 10)) (newline) (display #\ )))
(newline))))
;;; "bigpi.scm", program for computing digits of numerical value of PI.
;;; Copyright (C) 1993, 1994 Jerry D. Hedden
;;; See the file `COPYING' for terms applying to this program.
;;; (pi <n>) prints out <n> digits of pi.
;;; 'Spigot' algorithm originally due to Stanly Rabinowitz:
;;;
;;; PI = 2+(1/3)*(2+(2/5)*(2+(3/7)*(2+ ... *(2+(k/(2k+1))*(4)) ... )))
;;;
;;; where 'k' is approximately equal to the desired precision of 'n'
;;; places times 'log2(10)'.
;;;
;;; This version takes advantage of "bignums" in SCM to compute all
;;; of the requested digits in one pass! Basically, it calculates
;;; the truncated portion of (PI * 10^n), and then displays it in a
;;; nice format.
(define (bigpi digits)
(let* ((n (* 10 (quotient (+ digits 9) 10))) ; digits in multiples of 10
(z (inexact->exact (truncate ; z = number of terms
(/ (* n (log 10)) (log 2)))))
(q (do ((x 2 (* 10000000000 x)) ; q = 2 * 10^n
(i (/ n 10) (- i 1)))
((zero? i) x)))
(_pi (number->string ; _pi = PI * 10^n
;; do the calculations in one pass!!!
(let pi_calc ((j z) (k (+ z z 1)) (p (+ q q)))
(if (zero? j)
p
(pi_calc (- j 1) (- k 2) (+ q (quotient (* p j) k))))))))
;; print out the result ("3." followed by 5 groups of 10 digits per line)
(display (substring _pi 0 1)) (display #\.) (newline)
(do ((i 0 (+ i 10)))
((>= i n))
(display (substring _pi (+ i 1) (+ i 11)))
(display (if (zero? (modulo (+ i 10) 50)) #\newline #\ )))
(if (not (zero? (modulo n 50))) (newline))))
;;; "e.scm", program for computing digits of numerical value of 'e'.
;;; Copyright (C) 1994 Jerry D. Hedden
;;; See the file 'COPYING' for terms applying to this program.
;;; (e <n>) prints out <n> digits of 'e'.
;;; Uses the formula:
;;;
;;; 1 1 1 1 1
;;; e = 1 + -- + -- + -- + -- + ... + --
;;; 1! 2! 3! 4! k!
;;;
;;; where 'k' is determined using the desired precision 'n' in:
;;;
;;; n < ((k * (ln(k) - 1)) / ln(10))
;;;
;;; which uses Stirling's formula for approximating ln(k!)
;;;
;;; This program takes advantage of "bignums" in SCM to compute all
;;; the requested digits at once! Basically, it calculates the
;;; fractional part of 'e' (i.e., e-2) as a fraction of two bignums
;;; 'e_n' and 'e_d', determines the integer part of (e_n * 10^n)/e_d,
;;; and then displays it in a nice format.
(define (e digits)
(let* ((n (* 10 (quotient (+ digits 9) 10))) ; digits in multiples of 10
(k (do ((i 15 (+ i 1))) ; k = number of terms
((< n (/ (* i (- (log i) 1)) (log 10))) i)))
(q (do ((x 1 (* 10000000000 x)) ; q = 10^n
(i (/ n 10) (- i 1)))
((zero? i) x)))
(_e (let ((ee
; do calculations
(let e_calc ((i k) (e_d 1) (e_n 0))
(if (= i 1)
(cons (* q e_n) e_d)
(e_calc (- i 1) (* e_d i) (+ e_n e_d))))))
(number->string (+ (quotient (car ee) (cdr ee))
; rounding
(if (< (remainder (car ee) (cdr ee))
(quotient (cdr ee) 2))
0 1))))))
;; print out the result ("2." followed by 5 groups of 10 digits per line)
(display "2.") (newline)
(do ((i 0 (+ i 10)))
((>= i n))
(display (substring _e i (+ i 10)))
(display (if (zero? (modulo (+ i 10) 50)) #\newline #\ )))
(if (not (zero? (modulo n 50))) (newline))))