109 lines
3.2 KiB
Scheme
109 lines
3.2 KiB
Scheme
; Copyright (c) 1993, 1994 Richard Kelsey and Jonathan Rees. See file COPYING.
|
|
|
|
|
|
; Inexact numbers as mere shells surrounding exact numbers.
|
|
|
|
(define-extended-number-type :innum (:inexact)
|
|
(make-innum exact)
|
|
innum?
|
|
(exact innum-exact))
|
|
|
|
(define-method &exact? ((n :innum)) #f)
|
|
|
|
(define-method &complex? ((n :innum)) (complex? (innum-exact n)))
|
|
(define-method &real? ((n :innum)) (real? (innum-exact n)))
|
|
(define-method &rational? ((n :innum)) (rational? (innum-exact n)))
|
|
(define-method &integer? ((n :innum)) (integer? (innum-exact n)))
|
|
|
|
(define-method &exact->inexact (n)
|
|
(if (innum? n)
|
|
(next-method)
|
|
(make-innum n)))
|
|
|
|
(define-method &inexact->exact ((n :innum)) (innum-exact n))
|
|
|
|
(define (inexactify n)
|
|
(if (exact? n)
|
|
(exact->inexact n)
|
|
n))
|
|
|
|
(define (define-innum-method mtable proc)
|
|
(define-method mtable ((m :innum) (n :number))
|
|
(inexactify (proc (innum-exact m) n)))
|
|
(define-method mtable ((m :number) (n :innum))
|
|
(inexactify (proc m (innum-exact n)))))
|
|
|
|
(define-innum-method &+ +)
|
|
(define-innum-method &- -)
|
|
(define-innum-method &* *)
|
|
(define-innum-method &/ /)
|
|
(define-innum-method "ient quotient)
|
|
(define-innum-method &remainder remainder)
|
|
|
|
(define (define-innum-comparison mtable proc)
|
|
(define-method mtable ((m :innum) (n :number))
|
|
(proc (innum-exact m) n))
|
|
(define-method mtable ((m :number) (n :innum))
|
|
(proc m (innum-exact n))))
|
|
|
|
(define-innum-comparison &= =)
|
|
(define-innum-comparison &< <)
|
|
|
|
(define-method &numerator ((n :innum))
|
|
(inexactify (numerator (innum-exact n))))
|
|
|
|
(define-method &denominator ((n :innum))
|
|
(inexactify (denominator (innum-exact n))))
|
|
|
|
(define-method &floor ((n :innum))
|
|
(inexactify (floor (innum-exact n))))
|
|
|
|
(define-method &number->string ((i :innum) radix)
|
|
(let ((n (innum-exact i)))
|
|
(cond ((integer? n)
|
|
(string-append (number->string n radix) "."))
|
|
((rational? n)
|
|
(let ((q (denominator n)))
|
|
(if (= radix 10)
|
|
(let ((foo (decimable? q)))
|
|
(if foo
|
|
(decimal-representation (numerator n) q foo)
|
|
(string-append "#i" (number->string n radix))))
|
|
(string-append "#i" (number->string n radix)))))
|
|
(else
|
|
(string-append "#i" (number->string n radix))))))
|
|
|
|
; The Scheme report obligates us to print inexact rationals using
|
|
; decimal points whenever this can be done without losing precision.
|
|
|
|
(define (decimal-representation p q foo)
|
|
(let ((kludge (number->string (* (car foo) (abs (remainder p q)))
|
|
10)))
|
|
(string-append (if (< p 0) "-" "")
|
|
(number->string (quotient (abs p) q) 10)
|
|
"."
|
|
(string-append (do ((i (- (cdr foo) (string-length kludge))
|
|
(- i 1))
|
|
(l '() (cons #\0 l)))
|
|
((<= i 0) (list->string l)))
|
|
kludge))))
|
|
|
|
(define (ratio-string p q radix)
|
|
(string-append (number->string p radix)
|
|
"/"
|
|
(number->string q radix)))
|
|
|
|
; (decimable? n) => non-#f iff n is a product of 2's and 5's.
|
|
; The value returned is (k . i) such that 10^i divides n * k.
|
|
|
|
(define (decimable? n)
|
|
(let loop ((n n) (d 1) (i 0))
|
|
(if (= n 1)
|
|
(cons d i)
|
|
(let ((q (quotient n 10))
|
|
(r (remainder n 10)))
|
|
(cond ((= r 0) (loop q d (+ i 1)))
|
|
((= r 5) (loop (quotient n 5) (* d 2) (+ i 1)))
|
|
((even? r) (loop (quotient n 2) (* d 5) (+ i 1)))
|
|
(else #f))))))
|