generic-arith.scm 10 KB

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