recnum.scm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Rectangular complex arithmetic built on real arithmetic.
  3. (define-extended-number-type :recnum (:complex)
  4. (make-recnum real imag)
  5. recnum?
  6. (real recnum-real-part)
  7. (imag recnum-imag-part))
  8. (define (rectangulate x y) ; Assumes (eq? (exact? x) (exact? y))
  9. (if (= y 0)
  10. x
  11. (make-recnum x y)))
  12. (define (rectangular-real-part z)
  13. (if (recnum? z)
  14. (recnum-real-part z)
  15. (real-part z)))
  16. (define (rectangular-imag-part z)
  17. (if (recnum? z)
  18. (recnum-imag-part z)
  19. (imag-part z)))
  20. (define (rectangular+ a b)
  21. (rectangulate (+ (rectangular-real-part a) (rectangular-real-part b))
  22. (+ (rectangular-imag-part a) (rectangular-imag-part b))))
  23. (define (rectangular- a b)
  24. (rectangulate (- (rectangular-real-part a) (rectangular-real-part b))
  25. (- (rectangular-imag-part a) (rectangular-imag-part b))))
  26. (define (rectangular* a b)
  27. (let ((a1 (rectangular-real-part a))
  28. (a2 (rectangular-imag-part a))
  29. (b1 (rectangular-real-part b))
  30. (b2 (rectangular-imag-part b)))
  31. (rectangulate (- (* a1 b1) (* a2 b2))
  32. (+ (* a1 b2) (* a2 b1)))))
  33. (define (rectangular/ a b)
  34. (let ((a1 (rectangular-real-part a))
  35. (a2 (rectangular-imag-part a))
  36. (b1 (rectangular-real-part b))
  37. (b2 (rectangular-imag-part b)))
  38. (let ((d (+ (* b1 b1) (* b2 b2))))
  39. (rectangulate (/ (+ (* a1 b1) (* a2 b2)) d)
  40. (/ (- (* a2 b1) (* a1 b2)) d)))))
  41. (define (rectangular= a b)
  42. (let ((a1 (rectangular-real-part a))
  43. (a2 (rectangular-imag-part a))
  44. (b1 (rectangular-real-part b))
  45. (b2 (rectangular-imag-part b)))
  46. (and (= a1 b1) (= a2 b2))))
  47. ; Methods
  48. (define-method &complex? ((z :recnum)) #t)
  49. (define-method &real-part ((z :recnum)) (recnum-real-part z))
  50. (define-method &imag-part ((z :recnum)) (recnum-imag-part z))
  51. (define-method &magnitude ((z :recnum))
  52. (let ((r (recnum-real-part z))
  53. (i (recnum-imag-part z)))
  54. (sqrt (+ (* r r) (* i i)))))
  55. (define-method &angle ((z :recnum))
  56. (atan (recnum-imag-part z)
  57. (recnum-real-part z)))
  58. ; Methods on complexes in terms of real-part and imag-part
  59. (define-method &exact? ((z :recnum))
  60. (exact? (recnum-real-part z)))
  61. (define-method &inexact->exact ((z :recnum))
  62. (make-recnum (inexact->exact (recnum-real-part z))
  63. (inexact->exact (recnum-imag-part z))))
  64. (define-method &exact->inexact ((z :recnum))
  65. (make-recnum (exact->inexact (recnum-real-part z))
  66. (exact->inexact (recnum-imag-part z))))
  67. (define (define-recnum-method mtable proc)
  68. (define-method mtable ((m :recnum) (n :complex)) (proc m n))
  69. (define-method mtable ((m :complex) (n :recnum)) (proc m n)))
  70. (define-recnum-method &+ rectangular+)
  71. (define-recnum-method &- rectangular-)
  72. (define-recnum-method &* rectangular*)
  73. (define-recnum-method &/ rectangular/)
  74. (define-recnum-method &= rectangular=)
  75. (define-method &sqrt ((n :real))
  76. (if (< n 0)
  77. (make-rectangular 0 (sqrt (- 0 n)))
  78. (next-method))) ; not that we have to
  79. (define-method &sqrt ((z :recnum))
  80. (exp (/ (log z) 2)))
  81. (define plus-i (make-recnum 0 1)) ; we can't read +i yet
  82. (define minus-i (make-recnum 0 -1))
  83. (define-method &exp ((z :recnum))
  84. (let ((i (imag-part z)))
  85. (* (exp (real-part z))
  86. (+ (cos i) (* plus-i (sin i))))))
  87. (define-method &log ((z :recnum))
  88. (+ (log (magnitude z)) (* plus-i (angle z))))
  89. (define pi (delay (* 2 (asin 1)))) ; can't compute at build time
  90. (define-method &log ((n :real))
  91. (if (< n 0)
  92. (make-rectangular (log (- 0 n)) (force pi))
  93. (next-method)))
  94. (define-method &sin ((c :recnum))
  95. (let ((i-c (* c plus-i)))
  96. (/ (- (exp i-c)
  97. (exp (- 0 i-c)))
  98. (* 2 plus-i))))
  99. (define-method &cos ((c :recnum))
  100. (let ((i-c (* c plus-i)))
  101. (/ (+ (exp i-c)
  102. (exp (- 0 i-c)))
  103. 2)))
  104. (define-method &tan ((c :recnum))
  105. (/ (sin c) (cos c)))
  106. (define-method &asin ((c :recnum))
  107. (* minus-i
  108. (log (+ (* c plus-i)
  109. (sqrt (- 1 (* c c)))))))
  110. (define-method &acos ((c :recnum))
  111. (* minus-i
  112. (log (+ c
  113. (* plus-i (sqrt (- 1 (* c c))))))))
  114. ; kludge; we can't read floating point yet
  115. (define infinity (delay (expt (exact->inexact 2) (exact->inexact 1500))))
  116. (define-method &atan1 ((c :recnum))
  117. (if (or (= c plus-i)
  118. (= c minus-i))
  119. (- 0 (force infinity))
  120. (* plus-i
  121. (/ (log (/ (+ plus-i c)
  122. (+ plus-i (- 0 c))))
  123. 2))))
  124. ; Gleep! Can we do quotient and remainder on Gaussian integers?
  125. ; Can we do numerator and denominator on complex rationals?
  126. (define-method &number->string ((z :recnum) radix)
  127. (let ((x (real-part z))
  128. (y (imag-part z)))
  129. (let ((r (number->string x radix))
  130. (i (number->string (abs y) radix))
  131. (& (if (< y 0) "-" "+")))
  132. (if (and (inexact? y) ;gross
  133. (char=? (string-ref i 0) #\#))
  134. (string-append (if (char=? (string-ref r 0) #\#)
  135. ""
  136. "#i")
  137. r &
  138. (substring i 2 (string-length i))
  139. "i")
  140. (string-append r & i "i")))))
  141. (define-method &make-rectangular ((x :real) (y :real))
  142. (if (eq? (exact? x) (exact? y))
  143. (rectangulate x y)
  144. (rectangulate (if (exact? x) (exact->inexact x) x)
  145. (if (exact? y) (exact->inexact y) y))))