--- /dev/null
+#| -*-Scheme-*-
+
+$Header: /Users/cph/tmp/foo/mit-scheme/mit-scheme/v7/src/runtime/arith.scm,v 1.1 1989/10/27 02:03:35 cph Exp $
+
+Copyright (c) 1989 Massachusetts Institute of Technology
+
+This material was developed by the Scheme project at the Massachusetts
+Institute of Technology, Department of Electrical Engineering and
+Computer Science. Permission to copy this software, to redistribute
+it, and to use it for any purpose is granted, subject to the following
+restrictions and understandings.
+
+1. Any copy made of this software must include this copyright notice
+in full.
+
+2. Users of this software agree to make their best efforts (a) to
+return to the MIT Scheme project any improvements or extensions that
+they make, so that these may be included in future releases; and (b)
+to inform MIT of noteworthy uses of this software.
+
+3. All materials developed as a consequence of the use of this
+software shall duly acknowledge such use, in accordance with the usual
+standards of acknowledging credit in academic research.
+
+4. MIT has made no warrantee or representation that the operation of
+this software will be error-free, and MIT is under no obligation to
+provide any services, by way of maintenance, update, or otherwise.
+
+5. In conjunction with products arising from the use of this material,
+there shall be no use of the name of the Massachusetts Institute of
+Technology nor of any adaptation thereof in any advertising,
+promotional, or sales literature without prior written consent from
+MIT in each case. |#
+
+;;;; Scheme Arithmetic
+;;; package: (runtime number)
+
+(declare (usual-integrations))
+\f
+;;;; Utilities
+
+(define-macro (copy x)
+ `(LOCAL-DECLARE ((INTEGRATE ,x)) ,x))
+
+(define (wrong-type operator-name object)
+ (error error-type:illegal-argument object
+ (error-irritant/noise char:newline)
+ (error-irritant/noise "within procedure")
+ operator-name))
+
+(define (bad-range operator-name object)
+ (error error-type:bad-range-argument object
+ (error-irritant/noise char:newline)
+ (error-irritant/noise "within procedure")
+ operator-name))
+
+(define (reduce-comparator binary-comparator numbers)
+ (or (null? numbers)
+ (let loop ((x (car numbers)) (rest (cdr numbers)))
+ (or (null? rest)
+ (let ((y (car rest)))
+ (and (binary-comparator x y)
+ (loop y (cdr rest))))))))
+
+(define (reduce-max/min max x1 xs)
+ (let loop ((x1 x1) (xs xs))
+ (if (null? xs)
+ x1
+ (loop (max x1 (car xs)) (cdr xs)))))
+\f
+;;;; Primitives
+
+(define-primitives
+ (listify-bignum 2)
+ (integer->flonum 2)
+ (flo:denormalize flonum-denormalize 2))
+
+(define-integrable (int:bignum? object)
+ (object-type? (ucode-type big-fixnum) object))
+
+(define-integrable (int:->flonum n)
+ (integer->flonum n #b10))
+
+(define-integrable (make-ratnum n d)
+ (system-pair-cons (ucode-type ratnum) n d))
+
+(define-integrable (ratnum? object)
+ (object-type? (ucode-type ratnum) object))
+
+(define-integrable (ratnum-numerator ratnum)
+ (system-pair-car ratnum))
+
+(define-integrable (ratnum-denominator ratnum)
+ (system-pair-cdr ratnum))
+
+(define-integrable (flonum? object)
+ (object-type? (ucode-type big-flonum) object))
+
+(define (flo:normalize x)
+ (let ((r ((ucode-primitive flonum-normalize 1) x)))
+ (values (car r) (cdr r))))
+
+(define-integrable flo:->integer
+ flo:truncate->exact)
+
+(define-integrable (recnum? object)
+ (object-type? (ucode-type recnum) object))
+
+(define-integrable (make-recnum real imag)
+ (system-pair-cons (ucode-type recnum) real imag))
+
+(define-integrable (rec:real-part recnum)
+ (system-pair-car recnum))
+
+(define-integrable (rec:imag-part recnum)
+ (system-pair-cdr recnum))
+\f
+;;;; Constants
+
+(define flo:0)
+(define flo:1)
+(define flo:log2)
+(define flo:log10/log2)
+;;; +2i is supposed to be a constant, but the reader
+;;; doesn't yet handle this syntax.
+(define rec:+2i)
+(define rec:pi/2)
+(define rec:pi)
+
+(define (initialize-package!)
+ (set! flo:0 (int:->flonum 0))
+ (set! flo:1 (int:->flonum 1))
+ (set! flo:log2 (flo:log (int:->flonum 2)))
+ (set! flo:log10/log2 (flo:/ (flo:log (int:->flonum 10)) flo:log2))
+ (set! rec:+2i (make-recnum 0 2))
+ (set! rec:pi/2 (real:* 2 (real:atan2 1 1)))
+ (set! rec:pi (real:* 2 rec:pi/2))
+ (initialize-microcode-dependencies!)
+ (add-event-receiver! event:after-restore initialize-microcode-dependencies!)
+ (let ((fixed-objects-vector (get-fixed-objects-vector)))
+ (let ((set-trampoline!
+ (lambda (slot operator)
+ (vector-set! fixed-objects-vector
+ (fixed-objects-vector-slot slot)
+ operator))))
+ (set-trampoline! 'GENERIC-TRAMPOLINE-ZERO? complex:zero?)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-POSITIVE? complex:positive?)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-NEGATIVE? complex:negative?)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-ADD-1 complex:1+)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-SUBTRACT-1 complex:-1+)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-EQUAL? complex:=)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-LESS? complex:<)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-GREATER? complex:>)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-ADD complex:+)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-SUBTRACT complex:-)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-MULTIPLY complex:*)
+ (set-trampoline! 'GENERIC-TRAMPOLINE-DIVIDE complex:/))))
+
+(define flo:epsilon)
+(define flo:1+epsilon)
+(define flo:1-epsilon)
+(define flo:significand-digits-base-2)
+(define flo:significand-digits-base-10)
+(define rat:flonum-epsilon/2)
+
+(define (initialize-microcode-dependencies!)
+ (let ((p microcode-id/floating-mantissa-bits)
+ (e microcode-id/floating-epsilon))
+ (set! flo:epsilon e)
+ (set! flo:1+epsilon (flo:+ flo:1 e))
+ (set! flo:1-epsilon (flo:- flo:1 e))
+ (set! flo:significand-digits-base-2 p)
+ ;; Add two here because first and last digits may be
+ ;; "partial" in the sense that each represents less than the
+ ;; `flo:log10/log2' bits. This is a kludge, but doing the
+ ;; "right thing" seems hard. See Steele&White for a discussion of
+ ;; this phenomenon.
+ (set! flo:significand-digits-base-10
+ (int:+ 2
+ (flo:floor->exact (flo:/ (int:->flonum p) flo:log10/log2)))))
+ (set! rat:flonum-epsilon/2
+ (rat:expt 2 (int:negate flo:significand-digits-base-2)))
+ unspecific)
+\f
+(define (int:max n m)
+ (if (int:< n m) m n))
+
+(define (int:min n m)
+ (if (int:< n m) n m))
+
+(define (int:abs n)
+ (if (int:negative? n) (int:negate n) n))
+
+(define (int:even? n)
+ (int:zero? (int:remainder n 2)))
+
+(define (int:modulo n d)
+ (let ((r (int:remainder n d)))
+ (if (or (int:zero? r)
+ (if (int:negative? n)
+ (int:negative? d)
+ (not (int:negative? d))))
+ r
+ (int:+ r d))))
+
+(define (int:gcd n m)
+ (let loop ((n n) (m m))
+ (cond ((not (int:zero? m)) (loop m (int:remainder n m)))
+ ((int:negative? n) (int:negate n))
+ (else n))))
+
+(define (int:lcm n m)
+ (if (or (int:zero? n) (int:zero? m))
+ 0
+ (int:quotient (let ((n (int:* n m)))
+ (if (int:negative? n)
+ (int:negate n)
+ n))
+ (int:gcd n m))))
+
+(define (int:floor n d)
+ (let ((qr (int:divide n d)))
+ (let ((q (integer-divide-quotient qr)))
+ (if (or (int:zero? (integer-divide-remainder qr))
+ (if (int:negative? n)
+ (int:negative? d)
+ (not (int:negative? d))))
+ q
+ (int:-1+ q)))))
+
+(define (int:ceiling n d)
+ (let ((qr (int:divide n d)))
+ (let ((q (integer-divide-quotient qr)))
+ (if (or (int:zero? (integer-divide-remainder qr))
+ (if (int:negative? n)
+ (not (int:negative? d))
+ (int:negative? d)))
+ q
+ (int:1+ q)))))
+
+(define (int:round n d)
+ (let ((positive-case
+ (lambda (n d)
+ (let ((c (int:divide (int:+ (int:* 2 n) d) (int:* 2 d))))
+ (let ((q (integer-divide-quotient c)))
+ (if (and (int:zero? (integer-divide-remainder c))
+ (not (int:zero? (int:remainder q 2))))
+ (int:-1+ q)
+ q))))))
+ (if (int:negative? n)
+ (if (int:negative? d)
+ (positive-case (int:negate n) (int:negate d))
+ (int:negate (positive-case (int:negate n) d)))
+ (if (int:negative? d)
+ (int:negate (positive-case n (int:negate d)))
+ (positive-case n d)))))
+\f
+(define (int:expt b e)
+ (cond ((or (int:zero? b) (int:= 1 b)) b)
+ ((int:positive? e)
+ (if (int:= 1 e)
+ b
+ (let loop ((b b) (e e) (answer 1))
+ (let ((qr (int:divide e 2)))
+ (let ((b (int:* b b))
+ (e (integer-divide-quotient qr))
+ (answer
+ (if (int:zero? (integer-divide-remainder qr))
+ answer
+ (int:* answer b))))
+ (if (int:= 1 e)
+ (int:* answer b)
+ (loop b e answer)))))))
+ ((int:zero? e) 1)
+ (else (bad-range 'EXPT e))))
+
+(define (int:->string n radix)
+ (if (int:integer? n)
+ (list->string
+ (let ((0<n
+ (lambda (n)
+ (let ((char
+ (lambda (digit)
+ (digit->char digit radix))))
+ (if (int:bignum? n)
+ (map char (listify-bignum n radix))
+ (let loop ((n n) (tail '()))
+ (if (int:zero? n)
+ tail
+ (let ((qr (integer-divide n radix)))
+ (loop (integer-divide-quotient qr)
+ (cons (char (integer-divide-remainder qr))
+ tail))))))))))
+ (cond ((int:positive? n) (0<n n))
+ ((int:negative? n) (cons #\- (0<n (int:negate n))))
+ (else (list #\0)))))
+ (wrong-type 'NUMBER->STRING n)))
+\f
+(declare (integrate-operator rat:rational?))
+(define (rat:rational? object)
+ (or (ratnum? object)
+ (int:integer? object)))
+
+(define (rat:integer? object)
+ (and (not (ratnum? object))
+ (int:integer? object)))
+
+(define (rat:= q r)
+ (if (ratnum? q)
+ (if (ratnum? r)
+ (and (int:= (ratnum-numerator q) (ratnum-numerator r))
+ (int:= (ratnum-denominator q) (ratnum-denominator r)))
+ (if (int:integer? r)
+ #f
+ (wrong-type '= r)))
+ (if (ratnum? r)
+ (if (int:integer? q)
+ #f
+ (wrong-type '= q))
+ (int:= q r))))
+
+(define (rat:< q r)
+ (if (ratnum? q)
+ (if (ratnum? r)
+ (int:< (int:* (ratnum-numerator q) (ratnum-denominator r))
+ (int:* (ratnum-numerator r) (ratnum-denominator q)))
+ (int:< (ratnum-numerator q) (int:* r (ratnum-denominator q))))
+ (if (ratnum? r)
+ (int:< (int:* q (ratnum-denominator r)) (ratnum-numerator r))
+ (int:< q r))))
+
+(define (rat:zero? q)
+ (and (not (ratnum? q))
+ (int:zero? q)))
+
+(define (rat:negative? q)
+ (if (ratnum? q)
+ (int:negative? (ratnum-numerator q))
+ (int:negative? q)))
+
+(define (rat:positive? q)
+ (if (ratnum? q)
+ (int:positive? (ratnum-numerator q))
+ (int:positive? q)))
+
+(define (rat:max m n)
+ (if (rat:< m n) n m))
+
+(define (rat:min m n)
+ (if (rat:< m n) m n))
+\f
+;;; The notation here is from Knuth (p. 291).
+;;; In various places we take the gcd of two numbers and then call
+;;; quotient to reduce those numbers. We could check for 1 here, but
+;;; this is generally important only for bignums, and the bignum
+;;; quotient already performs that check.
+
+(let-syntax
+ ((define-addition-operator
+ (macro (name int:op)
+ `(define (,name u/u* v/v*)
+ (rat:binary-operator u/u* v/v*
+ ,int:op
+ (lambda (u v v*)
+ (make-rational (,int:op (int:* u v*) v) v*))
+ (lambda (u u* v)
+ (make-rational (,int:op u (int:* v u*)) u*))
+ (lambda (u u* v v*)
+ (let ((d1 (int:gcd u* v*)))
+ (if (int:= d1 1)
+ (make-rational (,int:op (int:* u v*) (int:* v u*))
+ (int:* u* v*))
+ (let* ((u*/d1 (int:quotient u* d1))
+ (t
+ (,int:op (int:* u (int:quotient v* d1))
+ (int:* v u*/d1))))
+ (if (int:zero? t)
+ 0 ;(make-rational 0 1)
+ (let ((d2 (int:gcd t d1)))
+ (make-rational
+ (int:quotient t d2)
+ (int:* u*/d1 (int:quotient v* d2))))))))))))))
+ (define-addition-operator rat:+ int:+)
+ (define-addition-operator rat:- int:-))
+
+(define (rat:1+ v/v*)
+ (if (ratnum? v/v*)
+ (let ((v* (ratnum-denominator v/v*)))
+ (make-ratnum (int:+ (ratnum-numerator v/v*) v*) v*))
+ (int:1+ v/v*)))
+
+(define (rat:-1+ v/v*)
+ (if (ratnum? v/v*)
+ (let ((v* (ratnum-denominator v/v*)))
+ (make-ratnum (int:- (ratnum-numerator v/v*) v*) v*))
+ (int:-1+ v/v*)))
+
+(define (rat:negate v/v*)
+ (if (ratnum? v/v*)
+ (make-ratnum (int:negate (ratnum-numerator v/v*))
+ (ratnum-denominator v/v*))
+ (int:negate v/v*)))
+
+(define (rat:* u/u* v/v*)
+ (rat:binary-operator u/u* v/v*
+ int:*
+ (lambda (u v v*)
+ (let ((d (int:gcd u v*)))
+ (make-rational (int:* (int:quotient u d) v)
+ (int:quotient v* d))))
+ (lambda (u u* v)
+ (let ((d (int:gcd v u*)))
+ (make-rational (int:* u (int:quotient v d))
+ (int:quotient u* d))))
+ (lambda (u u* v v*)
+ (let ((d1 (int:gcd u v*))
+ (d2 (int:gcd v u*)))
+ (make-rational (int:* (int:quotient u d1) (int:quotient v d2))
+ (int:* (int:quotient u* d2) (int:quotient v* d1)))))))
+
+(define (rat:square q)
+ (if (ratnum? q)
+ (make-ratnum (let ((n (ratnum-numerator q))) (int:* n n))
+ (let ((d (ratnum-denominator q))) (int:* d d)))
+ (int:* q q)))
+\f
+(define (rat:/ u/u* v/v*)
+ (declare (integrate-operator rat:sign-correction))
+ (define (rat:sign-correction u v cont)
+ (declare (integrate u v))
+ (if (int:negative? v)
+ (cont (int:negate u) (int:negate v))
+ (cont u v)))
+ (rat:binary-operator u/u* v/v*
+ (lambda (u v)
+ (if (int:zero? v)
+ (bad-range '/ v)
+ (rat:sign-correction u v
+ (lambda (u v)
+ (let ((d (int:gcd u v)))
+ (make-rational (int:quotient u d)
+ (int:quotient v d)))))))
+ (lambda (u v v*)
+ (rat:sign-correction u v
+ (lambda (u v)
+ (let ((d (int:gcd u v)))
+ (make-rational (int:* (int:quotient u d) v*)
+ (int:quotient v d))))))
+ (lambda (u u* v)
+ (rat:sign-correction u v
+ (lambda (u v)
+ (let ((d (int:gcd u v)))
+ (make-rational (int:quotient u d)
+ (int:* u* (int:quotient v d)))))))
+ (lambda (u u* v v*)
+ (let ((d1 (int:gcd u v))
+ (d2
+ (let ((d2 (int:gcd v* u*)))
+ (if (int:negative? v)
+ (int:negate d2)
+ d2))))
+ (make-rational (int:* (int:quotient u d1) (int:quotient v* d2))
+ (int:* (int:quotient u* d2) (int:quotient v d1)))))))
+
+(define (rat:invert v/v*)
+ (if (ratnum? v/v*)
+ (let ((v (ratnum-numerator v/v*))
+ (v* (ratnum-denominator v/v*)))
+ (cond ((int:positive? v)
+ (make-rational v* v))
+ ((int:negative? v)
+ (make-rational (int:negate v*) (int:negate v)))
+ (else
+ (bad-range '/ v/v*))))
+ (cond ((int:positive? v/v*) (make-rational 1 v/v*))
+ ((int:negative? v/v*) (make-rational -1 (int:negate v/v*)))
+ (else (bad-range '/ v/v*)))))
+
+(define-integrable (rat:binary-operator u/u* v/v*
+ int*int int*rat rat*int rat*rat)
+ (if (ratnum? u/u*)
+ (if (ratnum? v/v*)
+ (rat*rat (ratnum-numerator u/u*)
+ (ratnum-denominator u/u*)
+ (ratnum-numerator v/v*)
+ (ratnum-denominator v/v*))
+ (rat*int (ratnum-numerator u/u*)
+ (ratnum-denominator u/u*)
+ v/v*))
+ (if (ratnum? v/v*)
+ (int*rat u/u*
+ (ratnum-numerator v/v*)
+ (ratnum-denominator v/v*))
+ (int*int u/u* v/v*))))
+\f
+(define (rat:abs q)
+ (cond ((ratnum? q)
+ (let ((numerator (ratnum-numerator q)))
+ (if (int:negative? numerator)
+ (make-ratnum (int:negate numerator) (ratnum-denominator q))
+ q)))
+ ((int:negative? q) (int:negate q))
+ (else q)))
+
+(define (rat:numerator q)
+ (cond ((ratnum? q) (ratnum-numerator q))
+ ((int:integer? q) q)
+ (else (wrong-type 'NUMERATOR q))))
+
+(define (rat:denominator q)
+ (cond ((ratnum? q) (ratnum-denominator q))
+ ((int:integer? q) 1)
+ (else (wrong-type 'DENOMINATOR q))))
+
+(let-syntax
+ ((define-integer-coercion
+ (macro (name operation-name coercion)
+ `(DEFINE (,name Q)
+ (COND ((RATNUM? Q)
+ (,coercion (RATNUM-NUMERATOR Q) (RATNUM-DENOMINATOR Q)))
+ ((INT:INTEGER? Q) Q)
+ (ELSE (WRONG-TYPE ',operation-name Q)))))))
+ (define-integer-coercion rat:floor floor int:floor)
+ (define-integer-coercion rat:ceiling ceiling int:ceiling)
+ (define-integer-coercion rat:truncate truncate int:quotient)
+ (define-integer-coercion rat:round round int:round))
+
+(define (rat:rationalize q e)
+ (rat:simplest-rational (rat:- q e) (rat:+ q e)))
+
+(define (rat:simplest-rational x y)
+ ;; Courtesy of Alan Bawden.
+ ;; Produces the simplest rational between X and Y inclusive.
+ ;; (In the comments that follow, [x] means (rat:floor x).)
+ (let ((x<y
+ (lambda (x y)
+ (define (loop x y)
+ (if (int:integer? x)
+ x
+ (let ((fx (rat:floor x)) ; [X] <= X < [X]+1
+ (fy (rat:floor y))) ; [Y] <= Y < [Y]+1, also [X] <= [Y]
+ (if (rat:= fx fy)
+ ;; [Y] = [X] < X < Y so expand the next term in
+ ;; the continued fraction:
+ (rat:+ fx
+ (rat:invert (loop (rat:invert (rat:- y fy))
+ (rat:invert (rat:- x fx)))))
+ ;; [X] < X < [X]+1 <= [Y] <= Y so [X]+1 is the answer:
+ (rat:1+ fx)))))
+ (cond ((rat:positive? x)
+ ;; 0 < X < Y
+ (loop x y))
+ ((rat:negative? y)
+ ;; X < Y < 0 so 0 < -Y < -X and we negate the answer:
+ (rat:negate (loop (rat:negate y) (rat:negate x))))
+ (else
+ ;; X <= 0 <= Y so zero is the answer:
+ 0)))))
+ (cond ((rat:< x y) (x<y x y))
+ ((rat:< y x) (x<y y x))
+ (else x))))
+\f
+(define (rat:expt b e)
+ (if (int:integer? e)
+ (if (int:integer? b)
+ (if (int:negative? e)
+ (rat:invert (int:expt b (int:negate e)))
+ (int:expt b e))
+ (let ((exact-method
+ (lambda (e)
+ (if (int:= 1 e)
+ b
+ (let loop ((b b) (e e) (answer 1))
+ (let ((qr (int:divide e 2)))
+ (let ((b (rat:* b b))
+ (e (integer-divide-quotient qr))
+ (answer
+ (if (int:zero? (integer-divide-remainder qr))
+ answer
+ (rat:* answer b))))
+ (if (int:= 1 e)
+ (rat:* answer b)
+ (loop b e answer)))))))))
+ (cond ((int:negative? e)
+ (rat:invert (exact-method (int:negate e))))
+ ((int:positive? e)
+ (exact-method e))
+ (else 1))))
+ (bad-range 'EXPT e)))
+
+(define (rat:->string q radix)
+ (if (ratnum? q)
+ (string-append (int:->string (ratnum-numerator q) radix)
+ "/"
+ (int:->string (ratnum-denominator q) radix))
+ (int:->string q radix)))
+
+(define (rat:->flonum q)
+ (if (ratnum? q)
+ (ratnum->flonum q)
+ (int:->flonum q)))
+
+(define (ratnum->flonum q)
+ (let ((n (integer->flonum (ratnum-numerator q) #b00))
+ (d (integer->flonum (ratnum-denominator q) #b00)))
+ (if (and n d)
+ (flo:/ n d)
+ (let ((q (rat:rationalize q (rat:* q rat:flonum-epsilon/2))))
+ (if (ratnum? q)
+ (flo:/ (int:->flonum (ratnum-numerator q))
+ (int:->flonum (ratnum-denominator q)))
+ (int:->flonum q))))))
+
+(define (make-rational n d)
+ (if (or (int:zero? n) (int:= 1 d))
+ n
+ (make-ratnum n d)))
+\f
+(define (flo:significand-digits radix)
+ (cond ((int:= radix 10)
+ flo:significand-digits-base-10)
+ ((int:= radix 2)
+ flo:significand-digits-base-2)
+ (else
+ (int:+ 2
+ (flo:floor->exact
+ (flo:/ (int:->flonum flo:significand-digits-base-2)
+ (flo:/ (flo:log (int:->flonum radix)) flo:log2)))))))
+
+(declare (integrate flo:integer?))
+(define (flo:integer? x)
+ (flo:= x (flo:round x)))
+
+(define (flo:simplest-rational x y)
+ ;; See comments at `rat:simplest-rational'.
+ (let ((x<y
+ (lambda (x y)
+ (define (loop x y)
+ (let ((fx (flo:floor x))
+ (fy (flo:floor y)))
+ (cond ((not (flo:< fx x)) fx)
+ ((flo:= fx fy)
+ (flo:+ fx
+ (flo:/ flo:1
+ (loop (flo:/ flo:1 (flo:- y fy))
+ (flo:/ flo:1 (flo:- x fx))))))
+ (else (flo:+ fx flo:1)))))
+ (cond ((flo:positive? x) (loop x y))
+ ((flo:negative? y)
+ (flo:negate (loop (flo:negate y) (flo:negate x))))
+ (else flo:0)))))
+ (cond ((flo:< x y) (x<y x y))
+ ((flo:< y x) (x<y y x))
+ (else x))))
+
+(define (flo:simplest-exact-rational x y)
+ ;; See comments at `rat:simplest-rational'.
+ (let ((x<y
+ (lambda (x y)
+ (define (loop x y)
+ (let ((fx (flo:floor x))
+ (fy (flo:floor y)))
+ (cond ((not (flo:< fx x))
+ (flo:->integer fx))
+ ((flo:= fx fy)
+ (rat:+ (flo:->integer fx)
+ (rat:invert (loop (flo:/ flo:1 (flo:- y fy))
+ (flo:/ flo:1 (flo:- x fx))))))
+ (else
+ (rat:1+ (flo:->integer fx))))))
+ (cond ((flo:positive? x) (loop x y))
+ ((flo:negative? y)
+ (rat:negate (loop (flo:negate y) (flo:negate x))))
+ (else 0)))))
+ (cond ((flo:< x y) (x<y x y))
+ ((flo:< y x) (x<y y x))
+ ((flo:integer? x) (flo:->integer x))
+ (else (flo:->rational x)))))
+
+(define (flo:->rational x)
+ (flo:simplest-exact-rational (flo:* x flo:1-epsilon)
+ (flo:* x flo:1+epsilon)))
+
+(define (flo:rationalize x e)
+ (flo:simplest-rational (flo:- x e) (flo:+ x e)))
+
+(define (flo:rationalize->exact x e)
+ (flo:simplest-exact-rational (flo:- x e) (flo:+ x e)))\f
+(define (real:real? object)
+ (or (flonum? object)
+ (rat:rational? object)))
+
+(define-integrable (real:0 exact?)
+ (if exact? 0 0.0))
+
+(define (real:exact1= x)
+ (and (real:exact? x)
+ (real:= 1 x)))
+
+(define (real:rational? x)
+ (or (flonum? x) (rat:rational? x)))
+
+(define (real:integer? x)
+ (if (flonum? x) (flo:integer? x) ((copy rat:integer?) x)))
+
+(define (real:exact? x)
+ (and (not (flonum? x))
+ (or (rat:rational? x)
+ (wrong-type 'EXACT? x))))
+
+(define (real:zero? x)
+ (if (flonum? x) (flo:zero? x) ((copy rat:zero?) x)))
+
+(define (real:exact0= x)
+ (and (not (flonum? x)) ((copy rat:zero?) x)))
+
+(define (real:negative? x)
+ (if (flonum? x) (flo:negative? x) ((copy rat:negative?) x)))
+
+(define (real:positive? x)
+ (if (flonum? x) (flo:positive? x) ((copy rat:positive?) x)))
+
+(let-syntax
+ ((define-standard-unary
+ (macro (name flo:op rat:op)
+ `(DEFINE (,name X)
+ (IF (FLONUM? X)
+ (,flo:op X)
+ (,rat:op X))))))
+ (define-standard-unary real:1+ (lambda (x) (flo:+ x flo:1)) (copy rat:1+))
+ (define-standard-unary real:-1+ (lambda (x) (flo:- x flo:1)) (copy rat:-1+))
+ (define-standard-unary real:negate flo:negate (copy rat:negate))
+ (define-standard-unary real:invert (lambda (x) (flo:/ flo:1 x)) rat:invert)
+ (define-standard-unary real:abs flo:abs rat:abs)
+ (define-standard-unary real:square (lambda (x) (flo:* x x)) rat:square)
+ (define-standard-unary real:floor flo:floor rat:floor)
+ (define-standard-unary real:ceiling flo:ceiling rat:ceiling)
+ (define-standard-unary real:truncate flo:truncate rat:truncate)
+ (define-standard-unary real:round flo:round rat:round)
+ (define-standard-unary real:floor->exact flo:floor->exact rat:floor)
+ (define-standard-unary real:ceiling->exact flo:ceiling->exact rat:ceiling)
+ (define-standard-unary real:truncate->exact flo:truncate->exact rat:truncate)
+ (define-standard-unary real:round->exact flo:round->exact rat:round)
+ (define-standard-unary real:exact->inexact (lambda (x) x) rat:->flonum)
+ (define-standard-unary real:inexact->exact flo:->rational
+ (lambda (q)
+ (if (rat:rational? q)
+ q
+ (wrong-type 'INEXACT->EXACT q)))))
+\f
+(let-syntax
+ ((define-standard-binary
+ (macro (name flo:op rat:op)
+ `(DEFINE (,name X Y)
+ (IF (FLONUM? X)
+ (IF (FLONUM? Y)
+ (,flo:op X Y)
+ (,flo:op X (RAT:->FLONUM Y)))
+ (IF (FLONUM? Y)
+ (,flo:op (RAT:->FLONUM X) Y)
+ (,rat:op X Y)))))))
+ (define-standard-binary real:+ flo:+ (copy rat:+))
+ (define-standard-binary real:- flo:- (copy rat:-))
+ (define-standard-binary real:/ flo:/ (copy rat:/))
+ (define-standard-binary real:rationalize
+ flo:rationalize
+ rat:rationalize)
+ (define-standard-binary real:rationalize->exact
+ flo:rationalize->exact
+ rat:rationalize)
+ (define-standard-binary real:simplest-rational
+ flo:simplest-rational
+ rat:simplest-rational)
+ (define-standard-binary real:simplest-exact-rational
+ flo:simplest-exact-rational
+ rat:simplest-rational))
+
+(define (real:= x y)
+ (if (flonum? x)
+ (if (flonum? y)
+ (flo:= x y)
+ (rat:= (flo:->rational x) y))
+ (if (flonum? y)
+ (rat:= x (flo:->rational y))
+ ((copy rat:=) x y))))
+
+(define (real:< x y)
+ (if (flonum? x)
+ (if (flonum? y)
+ (flo:< x y)
+ (rat:< (flo:->rational x) y))
+ (if (flonum? y)
+ (rat:< x (flo:->rational y))
+ ((copy rat:<) x y))))
+
+(define (real:max x y)
+ (if (flonum? x)
+ (if (flonum? y)
+ (if (flo:< x y) y x)
+ (if (rat:< (flo:->rational x) y) (rat:->flonum y) x))
+ (if (flonum? y)
+ (if (rat:< x (flo:->rational y)) y (rat:->flonum x))
+ (if (rat:< x y) y x))))
+
+(define (real:min x y)
+ (if (flonum? x)
+ (if (flonum? y)
+ (if (flo:< x y) x y)
+ (if (rat:< (flo:->rational x) y) x (rat:->flonum y)))
+ (if (flonum? y)
+ (if (rat:< x (flo:->rational y)) (rat:->flonum x) y)
+ (if (rat:< x y) y x))))
+(define (real:* x y)
+ (cond ((flonum? x)
+ (cond ((flonum? y) (flo:* x y))
+ ((rat:zero? y) y)
+ (else (flo:* x (rat:->flonum y)))))
+ ((rat:zero? x) x)
+ ((flonum? y) (flo:* (rat:->flonum x) y))
+ (else ((copy rat:*) x y))))
+\f
+(define (real:even? n)
+ ((copy int:even?)
+ (if (flonum? n)
+ (if (flo:integer? n)
+ (flo:->integer n)
+ (wrong-type 'EVEN? n))
+ n)))
+
+(let-syntax
+ ((define-integer-binary
+ (macro (name operator-name operator)
+ (let ((flo->int
+ (lambda (n)
+ `(IF (FLO:INTEGER? ,n)
+ (FLO:->INTEGER ,n)
+ (WRONG-TYPE ,operator-name ,n)))))
+ `(DEFINE (,name N M)
+ (IF (FLONUM? N)
+ (INT:->FLONUM
+ (,operator ,(flo->int 'N)
+ (IF (FLONUM? M)
+ ,(flo->int 'M)
+ M)))
+ (IF (FLONUM? M)
+ (INT:->FLONUM (,operator N ,(flo->int 'M)))
+ (,operator N M))))))))
+ (define-integer-binary real:quotient quotient int:quotient)
+ (define-integer-binary real:remainder remainder int:remainder)
+ (define-integer-binary real:modulo modulo int:modulo)
+ (define-integer-binary real:integer-floor integer-floor int:floor)
+ (define-integer-binary real:integer-ceiling integer-ceiling int:ceiling)
+ (define-integer-binary real:integer-round integer-round int:round)
+ (define-integer-binary real:divide integer-divide int:divide)
+ (define-integer-binary real:gcd gcd int:gcd)
+ (define-integer-binary real:lcm lcm int:lcm))
+
+(let-syntax
+ ((define-rational-unary
+ (macro (name operator)
+ `(DEFINE (,name Q)
+ (IF (FLONUM? Q)
+ (RAT:->FLONUM (,operator (FLO:->RATIONAL Q)))
+ (,operator Q))))))
+ (define-rational-unary real:numerator rat:numerator)
+ (define-rational-unary real:denominator rat:denominator))
+\f
+(let-syntax
+ ((define-transcendental-unary
+ (macro (name hole? hole-value function)
+ `(DEFINE (,name X)
+ (IF (,hole? X)
+ ,hole-value
+ (,function (REAL:->FLONUM X)))))))
+ (define-transcendental-unary real:exp real:exact0= 1 flo:exp)
+ (define-transcendental-unary real:log real:exact1= 0 flo:log)
+ (define-transcendental-unary real:sin real:exact0= 0 flo:sin)
+ (define-transcendental-unary real:cos real:exact0= 1 flo:cos)
+ (define-transcendental-unary real:tan real:exact0= 0 flo:tan)
+ (define-transcendental-unary real:asin real:exact0= 0 flo:asin)
+ (define-transcendental-unary real:acos real:exact1= 0 flo:acos)
+ (define-transcendental-unary real:atan real:exact0= 0 flo:atan))
+
+(define (real:atan2 y x)
+ (if (and (real:exact1= y)
+ (real:exact0= x))
+ 0
+ (flo:atan2 (real:->flonum y) (real:->flonum x))))
+
+(define (rat:sqrt x)
+ (let ((guess (flo:sqrt (rat:->flonum x))))
+ (if (int:integer? x)
+ (let ((n (flo:round->exact guess)))
+ (if (int:= x (int:* n n))
+ n
+ guess))
+ (let ((q (flo:->rational guess)))
+ (if (rat:= x (rat:square q))
+ q
+ guess)))))
+
+(define (real:sqrt x)
+ (if (flonum? x) (flo:sqrt x) (rat:sqrt x)))
+
+(define (real:expt x y)
+ (if (flonum? x)
+ (if (flonum? y)
+ (flo:expt x y)
+ (flo:expt x (rat:->flonum y)))
+ (if (flonum? y)
+ (flo:expt (rat:->flonum x) y)
+ (cond ((int:integer? y)
+ ((copy rat:expt) x y))
+ ((int:= 1 (rat:numerator y))
+ (let ((d (rat:denominator y)))
+ (if (int:= 2 d)
+ (rat:sqrt x)
+ (let ((guess
+ (flo:expt (rat:->flonum x) (rat:->flonum y))))
+ (let ((q
+ (if (int:integer? x)
+ (flo:round->exact guess)
+ (flo:->rational guess))))
+ (if (rat:= x (rat:expt q d))
+ q
+ guess))))))
+ (else
+ (flo:expt (rat:->flonum x) (rat:->flonum x)))))))
+
+(define (real:->flonum x)
+ (if (flonum? x)
+ x
+ (rat:->flonum x)))
+
+(define (real:->string x radix)
+ (if (flonum? x)
+ (flo:->string x radix)
+ (rat:->string x radix)))
+\f
+(define (complex:complex? object)
+ (or (recnum? object) ((copy real:real?) object)))
+
+(define (complex:real? object)
+ (if (recnum? object)
+ (real:zero? (rec:imag-part object))
+ ((copy real:real?) object)))
+
+(define (complex:rational? object)
+ (if (recnum? object)
+ (and (real:zero? (rec:imag-part object))
+ (real:rational? (rec:real-part object)))
+ ((copy real:rational?) object)))
+
+(define (complex:integer? object)
+ (if (recnum? object)
+ (and (real:zero? (rec:imag-part object))
+ (real:integer? (rec:real-part object)))
+ ((copy real:integer?) object)))
+
+(define (complex:exact? z)
+ (if (recnum? z)
+ (and (real:exact? (rec:real-part z))
+ (real:exact? (rec:imag-part z)))
+ ((copy real:exact?) z)))
+
+(define (complex:real-arg name x)
+ (if (recnum? x) (rec:real-arg name x) x))
+
+(define (rec:real-arg name x)
+ (if (real:zero? (rec:imag-part x))
+ (rec:real-part x)
+ (wrong-type name x)))
+
+(define (complex:= z1 z2)
+ (if (recnum? z1)
+ (if (recnum? z2)
+ (and (real:= (rec:real-part z1) (rec:real-part z2))
+ (real:= (rec:imag-part z1) (rec:imag-part z2)))
+ (and (real:zero? (rec:imag-part z1))
+ (real:= (rec:real-part z1) z2)))
+ (if (recnum? z2)
+ (and (real:zero? (rec:imag-part z2))
+ (real:= z1 (rec:real-part z2)))
+ ((copy real:=) z1 z2))))
+
+(define (complex:< x y)
+ (if (recnum? x)
+ (if (recnum? y)
+ (real:< (rec:real-arg '< x) (rec:real-arg '< y))
+ (real:< (rec:real-arg '< x) y))
+ (if (recnum? y)
+ (real:< x (rec:real-arg '< y))
+ ((copy real:<) x y))))
+
+(define (complex:> x y)
+ (complex:< y x))
+
+(define (complex:zero? z)
+ (if (recnum? z)
+ (and (real:zero? (rec:real-part z))
+ (real:zero? (rec:imag-part z)))
+ ((copy real:zero?) z)))
+
+(define (complex:positive? x)
+ (if (recnum? x)
+ (real:positive? (rec:real-arg 'POSITIVE? x))
+ ((copy real:positive?) x)))
+
+(define (complex:negative? x)
+ (if (recnum? x)
+ (real:negative? (rec:real-arg 'NEGATIVE? x))
+ ((copy real:negative?) x)))
+
+(define (complex:even? x)
+ (if (recnum? x) (real:even? (rec:real-arg 'EVEN? x)) ((copy real:even?) x)))
+\f
+(define (complex:max x y)
+ (if (recnum? x)
+ (if (recnum? y)
+ (real:max (rec:real-arg 'MAX x) (rec:real-arg 'MAX y))
+ (real:max (rec:real-arg 'MAX x) y))
+ (if (recnum? y)
+ (real:max x (rec:real-arg 'MAX y))
+ ((copy real:max) x y))))
+
+(define (complex:min x y)
+ (if (recnum? x)
+ (if (recnum? y)
+ (real:min (rec:real-arg 'MIN x) (rec:real-arg 'MIN y))
+ (real:min (rec:real-arg 'MIN x) y))
+ (if (recnum? y)
+ (real:min x (rec:real-arg 'MIN y))
+ ((copy real:min) x y))))
+
+(define (complex:+ z1 z2)
+ (if (recnum? z1)
+ (if (recnum? z2)
+ (complex:make-rectangular
+ (real:+ (rec:real-part z1) (rec:real-part z2))
+ (real:+ (rec:imag-part z1) (rec:imag-part z2)))
+ (make-recnum (real:+ (rec:real-part z1) z2)
+ (rec:imag-part z1)))
+ (if (recnum? z2)
+ (make-recnum (real:+ z1 (rec:real-part z2))
+ (rec:imag-part z2))
+ ((copy real:+) z1 z2))))
+
+(define (complex:1+ z)
+ (if (recnum? z)
+ (make-recnum (real:1+ (rec:real-part z)) (rec:imag-part z))
+ ((copy real:1+) z)))
+
+(define (complex:-1+ z)
+ (if (recnum? z)
+ (make-recnum (real:-1+ (rec:real-part z)) (rec:imag-part z))
+ ((copy real:-1+) z)))
+
+(define (complex:* z1 z2)
+ (if (recnum? z1)
+ (if (recnum? z2)
+ (let ((z1r (rec:real-part z1))
+ (z1i (rec:imag-part z1))
+ (z2r (rec:real-part z2))
+ (z2i (rec:imag-part z2)))
+ (complex:make-rectangular
+ (real:- (real:* z1r z2r) (real:* z1i z2i))
+ (real:+ (real:* z1r z2i) (real:* z1i z2r))))
+ (complex:make-rectangular (real:* (rec:real-part z1) z2)
+ (real:* (rec:imag-part z1) z2)))
+ (if (recnum? z2)
+ (complex:make-rectangular (real:* z1 (rec:real-part z2))
+ (real:* z1 (rec:imag-part z2)))
+ ((copy real:*) z1 z2))))
+
+(define (complex:+i* z)
+ (if (recnum? z)
+ (complex:make-rectangular (real:negate (rec:imag-part z))
+ (rec:real-part z))
+ (complex:make-rectangular 0 z)))
+
+(define (complex:-i* z)
+ (if (recnum? z)
+ (complex:make-rectangular (rec:imag-part z)
+ (real:negate (rec:real-part z)))
+ (complex:make-rectangular 0 (real:negate z))))
+\f
+(define (complex:- z1 z2)
+ (if (recnum? z1)
+ (if (recnum? z2)
+ (complex:make-rectangular
+ (real:- (rec:real-part z1) (rec:real-part z2))
+ (real:- (rec:imag-part z1) (rec:imag-part z2)))
+ (make-recnum (real:- (rec:real-part z1) z2)
+ (rec:imag-part z1)))
+ (if (recnum? z2)
+ (make-recnum (real:- z1 (rec:real-part z2))
+ (real:negate (rec:imag-part z2)))
+ ((copy real:-) z1 z2))))
+
+(define (complex:negate z)
+ (if (recnum? z)
+ (make-recnum (real:negate (rec:real-part z))
+ (real:negate (rec:imag-part z)))
+ ((copy real:negate) z)))
+
+(define (complex:conjugate z)
+ (cond ((recnum? z)
+ (make-recnum (rec:real-part z)
+ (real:negate (rec:imag-part z))))
+ ((real:real? z)
+ z)
+ (else
+ (wrong-type 'CONJUGATE z))))
+
+(define (complex:/ z1 z2)
+ (if (recnum? z1)
+ (if (recnum? z2)
+ (let ((z1r (rec:real-part z1))
+ (z1i (rec:imag-part z1))
+ (z2r (rec:real-part z2))
+ (z2i (rec:imag-part z2)))
+ (let ((d (real:+ (real:square z2r) (real:square z2i))))
+ (complex:make-rectangular
+ (real:/ (real:+ (real:* z1r z2r) (real:* z1i z2i)) d)
+ (real:/ (real:- (real:* z1i z2r) (real:* z1r z2i)) d))))
+ (make-recnum (real:/ (rec:real-part z1) z2)
+ (real:/ (rec:imag-part z1) z2)))
+ (if (recnum? z2)
+ (let ((z2r (rec:real-part z2))
+ (z2i (rec:imag-part z2)))
+ (let ((d (real:+ (real:square z2r) (real:square z2i))))
+ (complex:make-rectangular
+ (real:/ (real:* z1 z2r) d)
+ (real:/ (real:negate (real:* z1 z2i)) d))))
+ ((copy real:/) z1 z2))))
+
+(define (complex:invert z)
+ (if (recnum? z)
+ (let ((zr (rec:real-part z))
+ (zi (rec:imag-part z)))
+ (let ((d (real:+ (real:square zr) (real:square zi))))
+ (make-recnum (real:/ zr d)
+ (real:/ (real:negate zi) d))))
+ ((copy real:invert) z)))
+
+(define (complex:abs x)
+ (if (recnum? x) (real:abs (rec:real-arg 'ABS x)) ((copy real:abs) x)))
+\f
+(define (complex:quotient n d)
+ (real:quotient (complex:real-arg 'QUOTIENT n)
+ (complex:real-arg 'QUOTIENT d)))
+
+(define (complex:remainder n d)
+ (real:remainder (complex:real-arg 'REMAINDER n)
+ (complex:real-arg 'REMAINDER d)))
+
+(define (complex:modulo n d)
+ (real:modulo (complex:real-arg 'MODULO n)
+ (complex:real-arg 'MODULO d)))
+
+(define (complex:integer-floor n d)
+ (real:integer-floor (complex:real-arg 'INTEGER-FLOOR n)
+ (complex:real-arg 'INTEGER-FLOOR d)))
+
+(define (complex:integer-ceiling n d)
+ (real:integer-ceiling (complex:real-arg 'INTEGER-CEILING n)
+ (complex:real-arg 'INTEGER-CEILING d)))
+
+(define (complex:integer-round n d)
+ (real:integer-round (complex:real-arg 'INTEGER-ROUND n)
+ (complex:real-arg 'INTEGER-ROUND d)))
+
+(define (complex:divide n d)
+ (real:divide (complex:real-arg 'DIVIDE n)
+ (complex:real-arg 'DIVIDE d)))
+
+(define (complex:gcd n m)
+ (real:gcd (complex:real-arg 'GCD n)
+ (complex:real-arg 'GCD m)))
+
+(define (complex:lcm n m)
+ (real:lcm (complex:real-arg 'LCM n)
+ (complex:real-arg 'LCM m)))
+
+(define (complex:numerator q)
+ (real:numerator (complex:real-arg 'NUMERATOR q)))
+
+(define (complex:denominator q)
+ (real:denominator (complex:real-arg 'DENOMINATOR q)))
+\f
+(define (complex:floor x)
+ (if (recnum? x)
+ (real:floor (rec:real-arg 'FLOOR x))
+ ((copy real:floor) x)))
+
+(define (complex:ceiling x)
+ (if (recnum? x)
+ (real:ceiling (rec:real-arg 'CEILING x))
+ ((copy real:ceiling) x)))
+
+(define (complex:truncate x)
+ (if (recnum? x)
+ (real:truncate (rec:real-arg 'TRUNCATE x))
+ ((copy real:truncate) x)))
+
+(define (complex:round x)
+ (if (recnum? x)
+ (real:round (rec:real-arg 'ROUND x))
+ ((copy real:round) x)))
+
+(define (complex:floor->exact x)
+ (if (recnum? x)
+ (real:floor->exact (rec:real-arg 'FLOOR->EXACT x))
+ ((copy real:floor->exact) x)))
+
+(define (complex:ceiling->exact x)
+ (if (recnum? x)
+ (real:ceiling->exact (rec:real-arg 'CEILING->EXACT x))
+ ((copy real:ceiling->exact) x)))
+
+(define (complex:truncate->exact x)
+ (if (recnum? x)
+ (real:truncate->exact (rec:real-arg 'TRUNCATE->EXACT x))
+ ((copy real:truncate->exact) x)))
+
+(define (complex:round->exact x)
+ (if (recnum? x)
+ (real:round->exact (rec:real-arg 'ROUND->EXACT x))
+ ((copy real:round->exact) x)))
+
+(define (complex:rationalize x e)
+ (real:rationalize (complex:real-arg 'RATIONALIZE x)
+ (complex:real-arg 'RATIONALIZE e)))
+
+(define (complex:rationalize->exact x e)
+ (real:rationalize->exact (complex:real-arg 'RATIONALIZE x)
+ (complex:real-arg 'RATIONALIZE e)))
+
+(define (complex:simplest-rational x y)
+ (real:simplest-rational (complex:real-arg 'SIMPLEST-RATIONAL x)
+ (complex:real-arg 'SIMPLEST-RATIONAL y)))
+
+(define (complex:simplest-exact-rational x y)
+ (real:simplest-exact-rational (complex:real-arg 'SIMPLEST-RATIONAL x)
+ (complex:real-arg 'SIMPLEST-RATIONAL y)))
+\f
+(define (complex:exp z)
+ (if (recnum? z)
+ (complex:make-polar (real:exp (rec:real-part z))
+ (rec:imag-part z))
+ ((copy real:exp) z)))
+
+(define (complex:log z)
+ (cond ((recnum? z)
+ (complex:make-rectangular (real:log (complex:magnitude z))
+ (complex:angle z)))
+ ((real:negative? z)
+ (make-recnum (real:log (real:negate z)) rec:pi))
+ (else
+ ((copy real:log) z))))
+
+(define (complex:sin z)
+ (if (recnum? z)
+ (complex:/ (let ((iz (complex:+i* z)))
+ (complex:- (complex:exp iz)
+ (complex:exp (complex:negate iz))))
+ rec:+2i)
+ ((copy real:sin) z)))
+
+(define (complex:cos z)
+ (if (recnum? z)
+ (complex:/ (let ((iz (complex:+i* z)))
+ (complex:+ (complex:exp iz)
+ (complex:exp (complex:negate iz))))
+ 2)
+ ((copy real:cos) z)))
+
+(define (complex:tan z)
+ (if (recnum? z)
+ (complex:-i*
+ (let ((iz (complex:+i* z)))
+ (let ((e+iz (complex:exp iz))
+ (e-iz (complex:exp (complex:negate iz))))
+ (complex:/ (complex:- e+iz e-iz)
+ (complex:+ e+iz e-iz)))))
+ ((copy real:tan) z)))
+\f
+;;; Complex arguments -- ASIN
+;;; The danger in the complex case happens for large y when
+;;; z = iy. In this case iz + sqrt(1-z^2) --> -y + y.
+;;; A clever way out of this difficulty uses symmetry to always
+;;; take the benevolent branch of the square root.
+;;; That is, make iz and sqrt(1-z^2) always end up in the same
+;;; quadrant so catastrophic cancellation cannot occur.
+;;; This is ensured if z is in quadrants III or IV.
+
+(define (complex:asin z)
+ (if (recnum? z)
+ (let ((safe-case
+ (lambda (z)
+ (complex:-i*
+ (complex:log
+ (complex:+ (complex:+i* z)
+ (complex:sqrt (complex:- 1 (complex:* z z)))))))))
+ (if (let ((imag (rec:imag-part z)))
+ (or (real:positive? imag) ;get out of Q I and II
+ (and (real:zero? imag) ;and stay off negative reals
+ (real:negative? (rec:real-part z)))))
+ (complex:negate (safe-case (complex:negate z)))
+ (safe-case z)))
+ ((copy real:asin) z)))
+
+(define (complex:acos z)
+ (if (recnum? z)
+ (complex:- rec:pi/2 (complex:asin z))
+ ((copy real:acos) z)))
+
+(define (complex:atan z)
+ (if (recnum? z)
+ (rec:atan z)
+ ((copy real:atan) z)))
+
+(define (complex:atan2 y x)
+ (let ((rec-case
+ (lambda (y x)
+ (rec:atan (make-recnum (real:exact->inexact x)
+ (real:exact->inexact y))))))
+ (cond ((recnum? y)
+ (rec-case (rec:real-arg 'ATAN y) (complex:real-arg 'ATAN x)))
+ ((recnum? x)
+ (rec-case y (rec:real-arg 'ATAN x)))
+ (else
+ ((copy real:atan2) y x)))))
+
+(define (rec:atan z)
+ (complex:/ (let ((iz (complex:+i* z)))
+ (complex:- (complex:log (complex:1+ iz))
+ (complex:log (complex:- 1 iz))))
+ rec:+2i))
+
+(define (complex:sqrt z)
+ (cond ((recnum? z)
+ (complex:make-polar (real:sqrt (complex:magnitude z))
+ (real:/ (complex:angle z) 2)))
+ ((real:negative? z)
+ (complex:make-rectangular 0 (real:sqrt (real:negate z))))
+ (else
+ ((copy real:sqrt) z))))
+
+(define (complex:expt z1 z2)
+ (if (or (recnum? z1)
+ (recnum? z2)
+ (and (real:negative? z1)
+ (not (real:integer? z2))))
+ (complex:exp (complex:* (complex:log z1) z2))
+ ((copy real:expt) z1 z2)))
+(define (complex:make-rectangular real imag)
+ (if (real:exact0= imag)
+ real
+ (make-recnum real imag)))
+\f
+(define (complex:make-polar magnitude angle)
+ (complex:make-rectangular (real:* magnitude (real:cos angle))
+ (real:* magnitude (real:sin angle))))
+
+(define (complex:real-part z)
+ (cond ((recnum? z) (rec:real-part z))
+ ((real:real? z) z)
+ (else (wrong-type 'REAL-PART z))))
+
+(define (complex:imag-part z)
+ (cond ((recnum? z) (rec:imag-part z))
+ ((real:real? z) 0)
+ (else (wrong-type 'IMAG-PART z))))
+
+(define (complex:magnitude z)
+ (if (recnum? z)
+ (let ((ar (real:abs (rec:real-part z)))
+ (ai (real:abs (rec:imag-part z))))
+ (let ((v (real:max ar ai))
+ (w (real:min ar ai)))
+ (if (real:zero? v)
+ v
+ (real:* v (real:sqrt (real:1+ (real:square (real:/ w v))))))))
+ (real:abs z)))
+
+(define (complex:angle z)
+ (if (recnum? z)
+ (if (and (real:zero? (rec:real-part z))
+ (real:zero? (rec:imag-part z)))
+ (real:0 (complex:exact? z))
+ (real:atan2 (rec:real-part z) (rec:imag-part z))) (real:0 (real:exact? z))))
+
+(define (complex:exact->inexact z)
+ (if (recnum? z)
+ (complex:make-rectangular (real:exact->inexact (rec:real-part z))
+ (real:exact->inexact (rec:imag-part z)))
+ ((copy real:exact->inexact) z)))
+
+(define (complex:inexact->exact z)
+ (if (recnum? z)
+ (complex:make-rectangular (real:inexact->exact (rec:real-part z))
+ (real:inexact->exact (rec:imag-part z)))
+ ((copy real:inexact->exact) z)))
+
+(define (complex:->string z radix)
+ (if (recnum? z)
+ (string-append
+ (let ((r (rec:real-part z)))
+ (if (real:exact0= r)
+ ""
+ (real:->string r radix)))
+ (let ((i (rec:imag-part z))
+ (positive-case
+ (lambda (i)
+ (if (real:exact1= i)
+ ""
+ (real:->string i radix)))))
+ (if (real:positive? i)
+ (string-append "+" (positive-case i))
+ (string-append "-" (positive-case (real:negate i)))))
+ (if imaginary-unit-j? "j" "i"))
+ (real:->string z radix)))
+
+(define imaginary-unit-j? #f)
+\f
+(define number? complex:complex?)
+(define complex? complex:complex?)
+(define real? complex:real?)
+(define rational? complex:rational?)
+(define integer? complex:integer?)
+(define exact? complex:exact?)
+(define exact-rational? rat:rational?)
+(define exact-integer? int:integer?)
+
+(define (exact-nonnegative-integer? object)
+ (and (int:integer? object)
+ (not (int:negative? object))))
+
+(define (inexact? z)
+ (not (complex:exact? z)))
+
+(define (= . zs)
+ (reduce-comparator complex:= zs))
+
+(define (< . xs)
+ (reduce-comparator complex:< xs))
+
+(define (> . xs)
+ (reduce-comparator complex:> xs))
+
+(define (<= . xs)
+ (reduce-comparator (lambda (x y) (not (complex:< y x))) xs))
+
+(define (>= . xs)
+ (reduce-comparator (lambda (x y) (not (complex:< x y))) xs))
+
+(define zero? complex:zero?)
+(define positive? complex:positive?)
+(define negative? complex:negative?)
+
+(define (odd? n)
+ (not (complex:even? n)))
+
+(define even? complex:even?)
+
+(define (max x . xs)
+ (reduce-max/min complex:max x xs))
+
+(define (min x . xs)
+ (reduce-max/min complex:min x xs))
+
+(define (+ . zs)
+ (cond ((null? zs) 0)
+ ((null? (cdr zs)) (car zs))
+ ((null? (cddr zs)) (complex:+ (car zs) (cadr zs)))
+ (else
+ (complex:+ (car zs)
+ (complex:+ (cadr zs)
+ (reduce complex:+ 0 (cddr zs)))))))
+
+(define 1+ complex:1+)
+(define -1+ complex:-1+)
+
+(define (* . zs)
+ (cond ((null? zs) 1)
+ ((null? (cdr zs)) (car zs))
+ ((null? (cddr zs)) (complex:* (car zs) (cadr zs)))
+ (else
+ (complex:* (car zs)
+ (complex:* (cadr zs)
+ (reduce complex:+ 1 (cddr zs)))))))
+(define (- z1 . zs)
+ (cond ((null? zs) (complex:negate z1))
+ ((null? (cdr zs)) (complex:- z1 (car zs)))
+ (else
+ (complex:- z1
+ (complex:+ (car zs)
+ (complex:+ (cadr zs)
+ (reduce complex:+ 0 (cddr zs))))))))
+
+(define conjugate complex:conjugate)
+\f
+(define (/ z1 . zs)
+ (cond ((null? zs) (complex:invert z1))
+ ((null? (cdr zs)) (complex:/ z1 (car zs)))
+ (else
+ (complex:/ z1
+ (complex:* (car zs)
+ (complex:* (cadr zs)
+ (reduce complex:* 1 (cddr zs))))))))
+
+(define abs complex:abs)
+(define quotient complex:quotient)
+(define remainder complex:remainder)
+(define modulo complex:modulo)
+(define integer-floor complex:integer-floor)
+(define integer-ceiling complex:integer-ceiling)
+(define integer-truncate complex:quotient)
+(define integer-round complex:integer-round)
+(define integer-divide complex:divide)
+(define-integrable integer-divide-quotient car)
+(define-integrable integer-divide-remainder cdr)
+
+(define (gcd . integers)
+ (reduce complex:gcd 0 integers))
+
+(define (lcm . integers)
+ (reduce complex:lcm 1 integers))
+
+(define numerator complex:numerator)
+(define denominator complex:denominator)
+(define floor complex:floor)
+(define ceiling complex:ceiling)
+(define truncate complex:truncate)
+(define round complex:round)
+(define floor->exact complex:floor->exact)
+(define ceiling->exact complex:ceiling->exact)
+(define truncate->exact complex:truncate->exact)
+(define round->exact complex:round->exact)
+(define rationalize complex:rationalize)
+(define rationalize->exact complex:rationalize->exact)
+(define simplest-rational complex:simplest-rational)
+(define simplest-exact-rational complex:simplest-exact-rational)
+(define exp complex:exp)
+(define log complex:log)
+(define sin complex:sin)
+(define cos complex:cos)
+(define tan complex:tan)
+(define asin complex:asin)
+(define acos complex:acos)
+
+(define (atan z #!optional x)
+ (if (default-object? x)
+ (complex:atan z)
+ (complex:atan2 z x)))
+
+(define sqrt complex:sqrt)
+(define expt complex:expt)
+(define make-rectangular complex:make-rectangular)
+(define make-polar complex:make-polar)
+(define real-part complex:real-part)
+(define imag-part complex:imag-part)
+(define magnitude complex:magnitude)
+(define angle complex:angle)
+(define exact->inexact complex:exact->inexact)
+(define inexact->exact complex:inexact->exact)
+
+(define (number->string z #!optional radix)
+ (complex:->string
+ z
+ (cond ((default-object? radix) 10)
+ ((and (integer? radix)
+ (exact? radix) (<= 2 radix 36))
+ radix)
+ (else
+ (bad-range 'NUMBER->STRING radix)))))
\ No newline at end of file