ratnum.scm 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; This is file ratnum.scm.
  4. ; Rational arithmetic
  5. ; Assumes that +, -, etc. perform integer arithmetic.
  6. (define-simple-type <exact-rational> (<rational> <exact>)
  7. (lambda (n) (and (rational? n) (exact? n))))
  8. (define-extended-number-type <ratnum> (<exact-rational> <exact>) ;?
  9. (make-ratnum num den)
  10. ratnum?
  11. (num ratnum-numerator)
  12. (den ratnum-denominator))
  13. (define (integer/ m n)
  14. (cond ((< n 0)
  15. (integer/ (- 0 m) (- 0 n)))
  16. ((= n 0)
  17. (assertion-violation '/ "rational division by zero" m))
  18. ((and (exact? m) (exact? n))
  19. (let ((g (gcd m n)))
  20. (let ((m (quotient m g))
  21. (n (quotient n g)))
  22. (if (= n 1)
  23. m
  24. (make-ratnum m n)))))
  25. (else (/ m n)))) ;In case we get flonums
  26. (define (rational-numerator p)
  27. (if (ratnum? p)
  28. (ratnum-numerator p)
  29. (numerator p)))
  30. (define (rational-denominator p)
  31. (if (ratnum? p)
  32. (ratnum-denominator p)
  33. (denominator p)))
  34. ; a/b * c/d = a*c / b*d
  35. (define (rational* p q)
  36. (integer/ (* (rational-numerator p) (rational-numerator q))
  37. (* (rational-denominator p) (rational-denominator q))))
  38. ; a/b / c/d = a*d / b*c
  39. (define (rational/ p q)
  40. (integer/ (* (rational-numerator p) (rational-denominator q))
  41. (* (rational-denominator p) (rational-numerator q))))
  42. ; a/b + c/d = (a*d + b*c)/(b*d)
  43. (define (rational+ p q)
  44. (let ((b (rational-denominator p))
  45. (d (rational-denominator q)))
  46. (integer/ (+ (* (rational-numerator p) d)
  47. (* b (rational-numerator q)))
  48. (* b d))))
  49. ; a/b - c/d = (a*d - b*c)/(b*d)
  50. (define (rational- p q)
  51. (let ((b (rational-denominator p))
  52. (d (rational-denominator q)))
  53. (integer/ (- (* (rational-numerator p) d)
  54. (* b (rational-numerator q)))
  55. (* b d))))
  56. ; a/b < c/d when a*d < b*c
  57. (define (rational< p q)
  58. (< (* (rational-numerator p) (rational-denominator q))
  59. (* (rational-denominator p) (rational-numerator q))))
  60. ; a/b = c/d when a = b and c = d (always lowest terms)
  61. (define (rational= p q)
  62. (and (= (rational-numerator p) (rational-numerator q))
  63. (= (rational-denominator p) (rational-denominator q))))
  64. ; (rational-truncate p) = integer of largest magnitude <= (abs p)
  65. (define (rational-truncate p)
  66. (quotient (rational-numerator p) (rational-denominator p)))
  67. ; (floor p) = greatest integer <= p
  68. (define (rational-floor p)
  69. (let* ((n (numerator p))
  70. (q (quotient n (denominator p))))
  71. (if (>= n 0)
  72. q
  73. (- q 1))))
  74. ; Extend the generic number procedures
  75. (define-method &rational? ((n <ratnum>)) #t)
  76. (define-method &numerator ((n <ratnum>)) (ratnum-numerator n))
  77. (define-method &denominator ((n <ratnum>)) (ratnum-denominator n))
  78. (define-method &exact? ((n <ratnum>)) #t)
  79. ;(define-method &exact->inexact ((n <ratnum>))
  80. ; (/ (exact->inexact (numerator n))
  81. ; (exact->inexact (denominator n))))
  82. ;(define-method &inexact->exact ((n <rational>)) ;?
  83. ; (/ (inexact->exact (numerator n))
  84. ; (inexact->exact (denominator n))))
  85. (define-method &/ ((m <exact-integer>) (n <exact-integer>))
  86. (integer/ m n))
  87. (define (define-ratnum-method mtable proc)
  88. (define-method mtable ((m <ratnum>) (n <exact-rational>)) (proc m n))
  89. (define-method mtable ((m <exact-rational>) (n <ratnum>)) (proc m n)))
  90. (define-ratnum-method &+ rational+)
  91. (define-ratnum-method &- rational-)
  92. (define-ratnum-method &* rational*)
  93. (define-ratnum-method &/ rational/)
  94. (define-ratnum-method &= rational=)
  95. (define-ratnum-method &< rational<)
  96. (define-method &floor ((m <ratnum>)) (rational-floor m))
  97. ;(define-method &sqrt ((p <ratnum>))
  98. ; (if (< p 0)
  99. ; (next-method)
  100. ; (integer/ (sqrt (numerator p))
  101. ; (sqrt (denominator p)))))
  102. (define-method &number->string ((p <ratnum>) radix)
  103. (string-append (number->string (ratnum-numerator p) radix)
  104. "/"
  105. (number->string (ratnum-denominator p) radix)))