ratnum.scm 3.7 KB

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