generic-arith.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Generic arithmetic.
  3. ; The different kinds of numbers.
  4. (define-enumeration numbers
  5. (fixnum
  6. bignum
  7. rational
  8. float
  9. complex
  10. not-a-number))
  11. ; Mapping numbers to their representation.
  12. (define stob-numbers
  13. (make-vector stob-count (enum numbers not-a-number)))
  14. ; For now all we have are bignums (and fixnums, of course).
  15. (vector-set! stob-numbers (enum stob bignum) (enum numbers bignum))
  16. (define (number->representation x)
  17. (cond ((fixnum? x)
  18. (enum numbers fixnum))
  19. ((stob? x)
  20. (vector-ref stob-numbers (header-type (stob-header x))))
  21. (else
  22. (enum numbers not-a-number))))
  23. ;----------------
  24. ; Tables for unary and binary operations. All entries initially return DEFAULT.
  25. (define (make-unary-table default)
  26. (make-vector numbers-count
  27. (lambda (x)
  28. default)))
  29. ; (unary-table-set! <table> <type> <value>)
  30. ; (unary-table-set! <table> (<type> ...) <value>)
  31. (define-syntax unary-table-set!
  32. (syntax-rules ()
  33. ((unary-table-set! ?table (?kind ...) ?value)
  34. (real-unary-table-set! ?table (list (enum numbers ?kind) ...) ?value))
  35. ((unary-table-set! ?table ?kind ?value)
  36. (real-unary-table-set! ?table (list (enum numbers ?kind)) ?value))))
  37. (define (real-unary-table-set! table kinds value)
  38. (for-each (lambda (kind)
  39. (vector-set! table kind value))
  40. kinds))
  41. (define (unary-dispatch table x)
  42. ((vector-ref table
  43. (number->representation x))
  44. x))
  45. (define (make-binary-table default)
  46. (make-vector (* numbers-count numbers-count)
  47. (lambda (x y)
  48. default)))
  49. ; Same as for unary tables, except that we have two indexes or lists of indexes.
  50. (define-syntax binary-table-set!
  51. (syntax-rules ()
  52. ((binary-table-set! ?table (?kind0 ...) (?kind1 ...) ?value)
  53. (real-binary-table-set! ?table
  54. (list (enum numbers ?kind0) ...)
  55. (list (enum numbers ?kind1) ...)
  56. ?value))
  57. ((binary-table-set! ?table (?kind0 ...) ?kind1 ?value)
  58. (real-binary-table-set! ?table
  59. (list (enum numbers ?kind0) ...)
  60. (list (enum numbers ?kind1))
  61. ?value))
  62. ((binary-table-set! ?table ?kind0 (?kind1 ...) ?value)
  63. (real-binary-table-set! ?table
  64. (list (enum numbers ?kind0))
  65. (list (enum numbers ?kind1) ...)
  66. ?value))
  67. ((binary-table-set! ?table ?kind0 ?kind1 ?value)
  68. (real-binary-table-set! ?table
  69. (list (enum numbers ?kind0))
  70. (list (enum numbers ?kind1))
  71. ?value))))
  72. (define (real-binary-table-set! table kinds0 kinds1 value)
  73. (for-each (lambda (kind0)
  74. (for-each (lambda (kind1)
  75. (vector-set! table
  76. (+ (* kind0 numbers-count)
  77. kind1)
  78. value))
  79. kinds1))
  80. kinds0))
  81. ; Does this need to be changed to get a computed goto?
  82. (define (binary-dispatch table x y)
  83. ((vector-ref table
  84. (+ (* (number->representation x)
  85. numbers-count)
  86. (number->representation y)))
  87. x
  88. y))
  89. (define (binary-lose x y)
  90. unspecific-value)
  91. ;----------------
  92. ; The actual opcodes
  93. ; Predicates
  94. (define-primitive number? (any->)
  95. (lambda (x)
  96. (not (= (number->representation x)
  97. (enum numbers not-a-number))))
  98. return-boolean)
  99. (define-primitive integer? (any->)
  100. (lambda (x)
  101. (let ((type (number->representation x)))
  102. (or (= type (enum numbers fixnum))
  103. (= type (enum numbers bignum)))))
  104. return-boolean)
  105. (define-primitive rational? (any->)
  106. (lambda (x)
  107. (let ((type (number->representation x)))
  108. (or (= type (enum numbers fixnum))
  109. (= type (enum numbers bignum))
  110. (= type (enum numbers rational)))))
  111. return-boolean)
  112. (define-primitive real? (any->)
  113. (lambda (x)
  114. (let ((type (number->representation x)))
  115. (not (or (= type (enum numbers complex))
  116. (= type (enum numbers not-a-number))))))
  117. return-boolean)
  118. (define-primitive complex? (any->)
  119. (lambda (x)
  120. (not (= (number->representation x)
  121. (enum numbers not-a-number))))
  122. return-boolean)
  123. (define-primitive exact? (any->)
  124. (lambda (x)
  125. (enum-case number (number->representation x)
  126. ((float)
  127. (goto return-boolean #f))
  128. ((complex)
  129. (goto return-boolean (not (float? (complex-real-part x)))))
  130. ((not-a-number)
  131. (raise-exception wrong-type-argument 0 x))
  132. (else
  133. (goto return-boolean #t)))))
  134. ;----------------
  135. ; Arithmetic
  136. (define-syntax define-binary-primitive
  137. (syntax-rules ()
  138. ((define-binary-primitive id table careful integer)
  139. (define table (make-binary-table binary-lose))
  140. (define-primitive id (any-> any->)
  141. (lambda (x y)
  142. (if (and (fixnum? x)
  143. (fixnum? y))
  144. (goto careful
  145. x
  146. y
  147. return
  148. (lambda (x y)
  149. (goto return (integer x y))))
  150. (let ((r (binary-dispatch table x y)))
  151. (if (vm-eq? r unspecific-value)
  152. (raise-exception wrong-type-argument 0 x y)
  153. (goto return r))))))
  154. (binary-table-set! table (fixnum bignum) (fixnum bignum) integer))))
  155. (define-binary-primitive + add-table add-carefully integer-add)
  156. (define-binary-primitive - subtract-table subtract-carefully integer-subtract)
  157. (define-binary-primitive * multiply-table multiply-carefully integer-multiply)
  158. (define-binary-primitive quotient quotient-table quotient-carefully integer-quotient)
  159. (define-binary-primitive remainder remainder-table remainder-carefully integer-remainder)
  160. (define-binary-primitive arithmetic-shift shift-table shift-carefully integer-shift)
  161. ; Hm. There is no integer-divide (obviously)
  162. (define-binary-primitive / divide-table divide-carefully integer-)
  163. ****************************************************************
  164. How to structure all this? It would be nice if the interpreter could be
  165. broken into several modules. The registers and define-primitive would
  166. need to be separated out.
  167. ;----------------
  168. ; Tower predicates.
  169. ; These need to be changed.
  170. (define-unary-opcode-extension integer? &integer? #f)
  171. (define-unary-opcode-extension rational? &rational? #f)
  172. (define-unary-opcode-extension real? &real? #f)
  173. (define-unary-opcode-extension complex? &complex? #f)
  174. (define-unary-opcode-extension number? &number? #f)
  175. (define-unary-opcode-extension exact? &exact? #f)
  176. (let ((true (lambda (x) #t)))
  177. (unary-table-set! &integer? (fixnum bignum) true)
  178. (unary-table-set! &rational? (fixnum bignum rational) true)
  179. (unary-table-set! &real? (fixnum bignum rational float) true)
  180. (unary-table-set! &complex? (fixnum bignum rational float complex) true)
  181. (unary-table-set! &number? (fixnum bignum rational float complex) true)
  182. (unary-table-set! &exact? (fixnum bignum rational) true))
  183. ; The two parts of a complex number must have the same exactness.
  184. (unary-table-set! &exact? (complex)
  185. (lambda (z)
  186. (real-part z)))
  187. ;----------------
  188. ; Imaginary operations.
  189. (define-unary-opcode-extension real-part &real-part (lambda (x) x))
  190. (define-unary-opcode-extension imag-part &imag-part (lambda (x) 0))
  191. (unary-table-set! &real-part (complex not-a-number)
  192. (lambda (x) unimplemented))
  193. (unary-table-set! &imag-part (complex not-a-number)
  194. (lambda (x) unimplemented))
  195. ;----------------
  196. ; Fractions
  197. (define-unary-opcode-extension floor &floor)
  198. (define-unary-opcode-extension numerator &numerator)
  199. (define-unary-opcode-extension denominator &denominator)
  200. (define (identity x) x)
  201. (unary-table-set! &floor (fixnum bignum) identity)
  202. (unary-table-set! &numerator (fixnum bignum) identity)
  203. (unary-table-set! &denominator (fixnum bignum) (lambda (x) 1))
  204. ;----------------
  205. ; Square root.
  206. (define-unary-opcode-extension sqrt &sqrt)
  207. ; The bignum code could whack this.
  208. ; The VM doesn't do sqrt for positive fixnums. I wonder why?
  209. ; For negative N, we lose if MAKE-RECTANGULAR loses.
  210. (unary-table-set! &sqrt (fixnum bignum)
  211. (lambda (n)
  212. (if (>= n 0)
  213. (non-negative-integer-sqrt n) ;Dubious (JAR)
  214. (let ((s (non-negative-integer-sqrt (- n))))
  215. (if (eq? s unimplemented)
  216. s
  217. (binary-dispatch &make-rectangular
  218. 0
  219. s))))))
  220. ; Courtesy of Mr. Newton.
  221. (define (non-negative-integer-sqrt n)
  222. (if (<= n 1) ; for both 0 and 1
  223. n
  224. (let loop ((m (quotient n 2)))
  225. (let ((m1 (quotient n m)))
  226. (cond ((< m1 m)
  227. (loop (quotient (+ m m1) 2)))
  228. ((= n (* m m))
  229. m)
  230. (else
  231. unimplemented))))))
  232. ;----------------
  233. ; Make sure this has very low priority, so that it's only tried as a
  234. ; last resort.
  235. ;
  236. ; In fact, I'll comment it out completely. -RK
  237. ;(define-method &/ (m n)
  238. ; (if (and (integer? m) (integer? n))
  239. ; (if (= 0 (remainder m n))
  240. ; (quotient m n)
  241. ; (let ((z (abs (quotient n 2))))
  242. ; (set-exactness (quotient (if (< m 0)
  243. ; (- m z)
  244. ; (+ m z))
  245. ; n)
  246. ; #f)))
  247. ; (next-method)))
  248. ;----------------
  249. ; The rest have no useful defaults.
  250. (define-unary-opcode-extension exact->inexact &exact->inexact)
  251. (define-unary-opcode-extension inexact->exact &inexact->exact)
  252. (define-binary-opcode-extension + &+)
  253. (define-binary-opcode-extension - &-)
  254. (define-binary-opcode-extension * &*)
  255. (define-binary-opcode-extension / &/)
  256. (define-binary-opcode-extension = &=)
  257. (define-binary-opcode-extension < &<)
  258. (define-binary-opcode-extension quotient &quotient)
  259. (define-binary-opcode-extension remainder &remainder)
  260. (define-binary-opcode-extension make-rectangular &make-rectangular)
  261. (define-unary-opcode-extension exp &exp)
  262. (define-unary-opcode-extension log &log)
  263. (define-unary-opcode-extension sin &sin)
  264. (define-unary-opcode-extension cos &cos)
  265. (define-unary-opcode-extension tan &tan)
  266. (define-unary-opcode-extension asin &asin)
  267. (define-unary-opcode-extension acos &acos)
  268. (define-unary-opcode-extension atan &atan)
  269. ; >, <=, and >= are all extended using the table for <.
  270. (extend-opcode! (enum op >)
  271. (lambda (lose)
  272. (lambda (reason arg0 arg1)
  273. (let ((res (binary-dispatch &< arg1 arg0)))
  274. (if (eq? res unimplemented)
  275. (lose reason arg0 arg1)
  276. res)))))
  277. (extend-opcode! (enum op <=)
  278. (lambda (lose)
  279. (lambda (reason arg0 arg1)
  280. (let ((res (binary-dispatch &< arg1 arg0)))
  281. (if (eq? res unimplemented)
  282. (lose reason arg0 arg1)
  283. (not res))))))
  284. (extend-opcode! (enum op >=)
  285. (lambda (lose)
  286. (lambda (reason arg0 arg1)
  287. (let ((res (binary-dispatch &< arg0 arg1)))
  288. (if (eq? res unimplemented)
  289. (lose reason arg0 arg1)
  290. (not res))))))