123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- ; Part of Scheme 48 1.9. See file COPYING for notices and license.
- ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
- ; This is file xnum.scm.
- ;;;; Extended number support
- (define-simple-type <extended-number> (<number>) extended-number?)
- (define-record-type extended-number-type :extended-number-type
- (really-make-extended-number-type field-names supers priority predicate id)
- extended-number-type?
- (field-names extended-number-type-field-names)
- (supers extended-number-type-supers)
- (priority extended-number-type-priority)
- (predicate extended-number-predicate)
- (id extended-number-type-identity))
- (define-record-discloser :extended-number-type
- (lambda (e-n-t)
- (list 'extended-number-type (extended-number-type-identity e-n-t))))
- (define (make-extended-number-type field-names supers id)
- (letrec ((t (really-make-extended-number-type
- field-names
- supers
- (+ (apply max
- (map type-priority
- (cons <extended-number> supers)))
- 10)
- (lambda (x)
- (and (extended-number? x)
- (eq? (extended-number-type x) t)))
- id)))
- t))
- (define (extended-number-type x) (extended-number-ref x 0))
- ; DEFINE-EXTENDED-NUMBER-TYPE macro
- (define-syntax define-extended-number-type
- (syntax-rules ()
- ((define-extended-number-type ?type (?super ...)
- (?constructor ?arg1 ?arg ...)
- ?predicate
- (?field ?accessor)
- ...)
- (begin (define ?type
- (make-extended-number-type '(?field ...)
- (list ?super ...)
- '?type))
- (define ?constructor
- (let ((args '(?arg1 ?arg ...)))
- (if (equal? args
- (extended-number-type-field-names ?type))
- (let ((k (+ (length args) 1)))
- (lambda (?arg1 ?arg ...)
- (let ((n (make-extended-number k #f))
- (i 1))
- (extended-number-set! n 0 ?type)
- (extended-number-set! n 1 ?arg1)
- (begin (set! i (+ i 1))
- (extended-number-set! n i ?arg))
- ...
- n)))
- (assertion-violation 'define-extended-number-type
- "ill-formed DEFINE-EXTENDED-NUMBER-TYPE" '?type))))
- (define (?predicate x)
- (and (extended-number? x)
- (eq? (extended-number-type x) ?type)))
- (define-extended-number-accessors ?accessor ...)))))
- (define-syntax define-extended-number-accessors
- (syntax-rules ()
- ((define-extended-number-accessors ?accessor)
- (define (?accessor n) (extended-number-ref n 1)))
- ((define-extended-number-accessors ?accessor1 ?accessor2)
- (begin (define (?accessor1 n) (extended-number-ref n 1))
- (define (?accessor2 n) (extended-number-ref n 2))))
- ((define-extended-number-accessors ?accessor1 ?accessor2 ?accessor3)
- (begin (define (?accessor1 n) (extended-number-ref n 1))
- (define (?accessor2 n) (extended-number-ref n 2))
- (define (?accessor3 n) (extended-number-ref n 3))))))
- (define-method &type-priority ((t :extended-number-type))
- (extended-number-type-priority t))
- (define-method &type-predicate ((t :extended-number-type))
- (extended-number-predicate t))
- ; Make all the numeric instructions be extensible.
- (define (make-opcode-generic! opcode mtable)
- (let ((perform (method-table-get-perform mtable)))
- (extend-opcode! opcode
- (lambda (lose)
- (set-final-method! mtable
- (lambda (next-method . args)
- (apply lose (enum exception wrong-type-argument) args)))
- (lambda args
- ((perform) args))))))
-
- (define-syntax define-opcode-extension
- (syntax-rules ()
- ((define-opcode-extension ?name ?table-name)
- (begin (define ?table-name (make-method-table '?name))
- (make-opcode-generic! (enum op ?name) ?table-name)))))
- (define-opcode-extension + &+)
- (define-opcode-extension - &-)
- (define-opcode-extension * &*)
- (define-opcode-extension / &/)
- (define-opcode-extension = &=)
- (define-opcode-extension < &<)
- (define-opcode-extension quotient "ient)
- (define-opcode-extension remainder &remainder)
-
- (define-opcode-extension integer? &integer?)
- (define-opcode-extension rational? &rational?)
- (define-opcode-extension real? &real?)
- (define-opcode-extension complex? &complex?)
- (define-opcode-extension number? &number?)
- (define-opcode-extension exact? &exact?)
- (define-opcode-extension exact->inexact &exact->inexact)
- (define-opcode-extension inexact->exact &inexact->exact)
- (define-opcode-extension real-part &real-part)
- (define-opcode-extension imag-part &imag-part)
- (define-opcode-extension angle &angle)
- (define-opcode-extension magnitude &magnitude)
- (define-opcode-extension floor &floor)
- (define-opcode-extension numerator &numerator)
- (define-opcode-extension denominator &denominator)
- (define-opcode-extension make-rectangular &make-rectangular)
- (define-opcode-extension make-polar &make-polar)
- (define-opcode-extension exp &exp)
- (define-opcode-extension log &log)
- (define-opcode-extension sin &sin)
- (define-opcode-extension cos &cos)
- (define-opcode-extension tan &tan)
- (define-opcode-extension asin &asin)
- (define-opcode-extension acos &acos)
- (define-opcode-extension atan1 &atan1)
- (define-opcode-extension atan2 &atan2)
- (define-opcode-extension sqrt &sqrt)
- ; >, <=, and >= are all extended using the table for <.
- (let ((perform (method-table-get-perform &<)))
- (extend-opcode! (enum op >)
- (lambda (lose)
- (lambda (x y)
- ((perform) (list y x)))))
- (extend-opcode! (enum op <=)
- (lambda (lose)
- (lambda (x y)
- (not ((perform) (list y x))))))
- (extend-opcode! (enum op >=)
- (lambda (lose)
- (lambda (x y)
- (not ((perform) (list x y)))))))
-
- ; Default methods.
- (define-method &integer? (x) #f)
- (define-method &rational? (x) (integer? x))
- (define-method &real? (x) (rational? x))
- (define-method &complex? (x) (real? x))
- (define-method &number? (x) (complex? x))
- (define-method &real-part ((x <real>)) x)
- (define-method &imag-part ((x <real>))
- (if (exact? x) 0 (exact->inexact 0)))
- (define-method &magnitude ((x <real>))
- (abs x))
- (define pi (delay (* 2 (asin 1)))) ; can't compute at build time
- (define-method &angle ((x <real>))
- (cond
- ((positive? x)
- (if (exact? x)
- 0
- (exact->inexact 0)))
- ((negative? x) (force pi))
- ((exact? x) (assertion-violation 'angle "invalid argument to angle" x))
- (else x)))
- (define-method &floor ((n <integer>)) n)
- (define-method &numerator ((n <integer>)) n)
- (define-method &denominator ((n <integer>))
- (if (exact? n) 1 (exact->inexact 1)))
- ; Make sure this has very low priority, so that it's only tried as a
- ; last resort.
- (define-method &/ (m n)
- (if (and (integer? m) (integer? n))
- (if (= 0 (remainder m n))
- (quotient m n)
- (let ((z (abs (quotient n 2))))
- (set-exactness (quotient (if (< m 0)
- (- m z)
- (+ m z))
- n)
- #f)))
- (next-method)))
- (define-method &sqrt (n)
- (if (and (integer? n)
- (>= n 0))
- (non-negative-integer-sqrt n)
- (next-method)))
- (define (non-negative-integer-sqrt n)
- (cond ((<= n 1) ; for both 0 and 1
- n)
- ;; ((< n 0)
- ;; (make-rectangular 0 (integer-sqrt (- 0 n))))
- (else
- (let loop ((m (quotient n 2)))
- (let ((m1 (quotient n m)))
- (cond ((< m1 m)
- (loop (quotient (+ m m1) 2)))
- ((= n (* m m))
- m)
- ((exact? m)
- (exact->inexact m))
- (else m)))))))
- (define-simple-type <exact> (<number>)
- (lambda (n) (and (number? n) (exact? n))))
- (define-method &inexact->exact ((n <exact>)) n)
- (define-simple-type <inexact> (<number>)
- (lambda (n) (and (number? n) (inexact? n))))
- (define-method &exact->inexact ((n <inexact>)) n)
- ; Whattakludge.
- ; Replace the default method (which in the initial image always returns #f).
- (define-method &really-string->number (s radix xact?)
- (let ((len (string-length s)))
- (cond ((<= len 1) #f)
- ((char=? (string-ref s (- len 1)) #\i)
- (parse-rectangular s radix xact?))
- ((string-position #\@ s)
- => (lambda (at)
- (let ((r (really-string->number (substring s 0 at)
- radix xact?))
- (theta (really-string->number (substring s (+ at 1) len)
- radix xact?)))
- (if (and (real? r) (real? theta))
- (make-polar r theta)))))
- ((string-position #\/ s)
- => (lambda (slash)
- (let ((m (string->integer (substring s 0 slash) radix))
- (n (string->integer (substring s (+ slash 1) len)
- radix)))
- (if (and m n (not (zero? n)))
- (set-exactness (/ m n) xact?)
- #f))))
- ((string-position #\# s)
- (if xact?
- #f
- (really-string->number
- (list->string (map (lambda (c) (if (char=? c #\#) #\5 c))
- (string->list s)))
- radix
- xact?)))
- ((and (= radix 10)
- (string-position #\e s))
- => (lambda (e)
- (parse-with-exponent s xact? e)))
- ((string-position #\. s)
- => (lambda (dot)
- (parse-decimal s radix xact? dot)))
- (else #f))))
- (define (parse-decimal s radix xact? dot)
- ;; Talk about kludges. This is REALLY kludgey.
- (let* ((len (string-length s))
- (j (if (or (char=? (string-ref s 0) #\+)
- (char=? (string-ref s 0) #\-))
- 1
- 0))
- (m (if (= dot j)
- 0
- (string->integer (substring s j dot)
- radix)))
- (n (if (= dot (- len 1))
- 0
- (string->integer (substring s (+ dot 1) len)
- radix))))
- (if (and m n)
- (let ((n (+ m (/ n (expt radix
- (- len (+ dot 1)))))))
- (set-exactness (if (char=? (string-ref s 0) #\-)
- (- 0 n)
- n)
- xact?))
- #f)))
- (define (parse-with-exponent s xact? e)
- (let ((len (string-length s)))
- (cond
- ((string->integer (substring s (+ e 1) len) 10)
- => (lambda (exp)
- (cond
- ((really-string->number (substring s 0 e) 10 xact?)
- => (lambda (significand)
- (* significand
- (expt 10 exp))))
- (else #f))))
- (else #f))))
-
- (define (parse-rectangular s radix xact?)
- (let ((len (string-length s)))
- (let loop ((i (- len 2)))
- (if (< i 0)
- #f
- (let ((c (string-ref s i)))
- (if (or (char=? c #\+)
- (char=? c #\-))
- (let ((x (if (= i 0)
- 0
- (really-string->number (substring s 0 i)
- radix xact?)))
- (y (if (= i (- len 2))
- (if (char=? c #\+) 1 -1)
- (really-string->number (substring s i (- len 1))
- radix xact?))))
- (if (and (real? x) (real? y))
- (make-rectangular x y)
- #f))
- (loop (- i 1))))))))
- (define (set-exactness n xact?)
- (if (exact? n)
- (if xact? n (exact->inexact n))
- ;; ?what to do? (if xact? (inexact->exact n) n)
- n))
- ; Utility
- (define (string-position c s)
- (let loop ((i 0))
- (if (>= i (string-length s))
- #f
- (if (char=? c (string-ref s i))
- i
- (loop (+ i 1))))))
|