innum.scm 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Inexact numbers as mere shells surrounding exact numbers.
  3. (define-extended-number-type :innum (:inexact)
  4. (make-innum exact)
  5. innum?
  6. (exact innum-exact))
  7. (define-method &exact? ((n :innum)) #f)
  8. (define-method &complex? ((n :innum)) (complex? (innum-exact n)))
  9. (define-method &real? ((n :innum)) (real? (innum-exact n)))
  10. (define-method &rational? ((n :innum)) (rational? (innum-exact n)))
  11. (define-method &integer? ((n :innum)) (integer? (innum-exact n)))
  12. (define-method &exact->inexact ((n :number))
  13. (if (innum? n)
  14. (next-method)
  15. (make-innum n)))
  16. (define-method &inexact->exact ((n :innum)) (innum-exact n))
  17. (define (inexactify n)
  18. (if (exact? n)
  19. (exact->inexact n)
  20. n))
  21. (define (define-innum-method mtable proc)
  22. (define-method mtable ((m :innum) (n :number))
  23. (inexactify (proc (innum-exact m) n)))
  24. (define-method mtable ((m :number) (n :innum))
  25. (inexactify (proc m (innum-exact n)))))
  26. (define-innum-method &+ +)
  27. (define-innum-method &- -)
  28. (define-innum-method &* *)
  29. (define-innum-method &/ /)
  30. (define-innum-method &quotient quotient)
  31. (define-innum-method &remainder remainder)
  32. (define (define-innum-comparison mtable proc)
  33. (define-method mtable ((m :innum) (n :number))
  34. (proc (innum-exact m) n))
  35. (define-method mtable ((m :number) (n :innum))
  36. (proc m (innum-exact n))))
  37. (define-innum-comparison &= =)
  38. (define-innum-comparison &< <)
  39. (define-method &numerator ((n :innum))
  40. (inexactify (numerator (innum-exact n))))
  41. (define-method &denominator ((n :innum))
  42. (inexactify (denominator (innum-exact n))))
  43. (define-method &floor ((n :innum))
  44. (inexactify (floor (innum-exact n))))
  45. (define-method &number->string ((i :innum) radix)
  46. (let ((n (innum-exact i)))
  47. (cond ((integer? n)
  48. (string-append (number->string n radix) "."))
  49. ((rational? n)
  50. (let ((q (denominator n)))
  51. (if (= radix 10)
  52. (let ((foo (decimable? q)))
  53. (if foo
  54. (decimal-representation (numerator n) q foo)
  55. (string-append "#i" (number->string n radix))))
  56. (string-append "#i" (number->string n radix)))))
  57. (else
  58. (string-append "#i" (number->string n radix))))))
  59. ; The Scheme report obligates us to print inexact rationals using
  60. ; decimal points whenever this can be done without losing precision.
  61. (define (decimal-representation p q foo)
  62. (let ((kludge (number->string (* (car foo) (abs (remainder p q)))
  63. 10)))
  64. (string-append (if (< p 0) "-" "")
  65. (number->string (quotient (abs p) q) 10)
  66. "."
  67. (string-append (do ((i (- (cdr foo) (string-length kludge))
  68. (- i 1))
  69. (l '() (cons #\0 l)))
  70. ((<= i 0) (list->string l)))
  71. kludge))))
  72. (define (ratio-string p q radix)
  73. (string-append (number->string p radix)
  74. "/"
  75. (number->string q radix)))
  76. ; (decimable? n) => non-#f iff n is a product of 2's and 5's.
  77. ; The value returned is (k . i) such that 10^i divides n * k.
  78. (define (decimable? n)
  79. (let loop ((n n) (d 1) (i 0))
  80. (if (= n 1)
  81. (cons d i)
  82. (let ((q (quotient n 10))
  83. (r (remainder n 10)))
  84. (cond ((= r 0) (loop q d (+ i 1)))
  85. ((= r 5) (loop (quotient n 5) (* d 2) (+ i 1)))
  86. ((even? r) (loop (quotient n 2) (* d 5) (+ i 1)))
  87. (else #f))))))