bignum-arith.scm 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Martin Gasbichler, Mike Sperber
  3. ; These need to operate on both bignums and fixnums.
  4. ;bignum-add
  5. ;bignum-subtract
  6. ;bignum-multiply
  7. ;bignum-quotient
  8. ;bignum-remainder
  9. ;bignum-abs
  10. ;
  11. ; These only see bignums.
  12. ;bignum=
  13. ;bignum<
  14. ; This only sees fixnums.
  15. ;fixnum->bignum
  16. ;----------------
  17. (define (add-space size0 size1)
  18. (bignum-digits->size (+ (max size0 size1) 1)))
  19. ; These take care of the extra space needed for fixnum arguments (they need
  20. ; to be converted to bignums). SPACE-PROC takes the length of the two bignums
  21. ; and returns the space needed for the computation and results.
  22. (define (binary-space-proc space-proc)
  23. (lambda (x y)
  24. (receive (length0 extra0)
  25. (integer-bignum-digits x)
  26. (receive (length1 extra1)
  27. (integer-bignum-digits y)
  28. (+ (space-proc length0 length1)
  29. extra0
  30. extra1)))))
  31. (define (unary-space-proc space-proc)
  32. (lambda (x)
  33. (receive (length extra)
  34. (integer-bignum-digits x)
  35. (+ (space-proc length)
  36. extra))))
  37. ; While checking for space, which may cause a GC, we have to save the two
  38. ; arguments where they will be traced.
  39. (define (binary-bignum-op space-proc proc)
  40. (let ((space-proc (binary-space-proc space-proc)))
  41. (lambda (x y)
  42. (let ((needed (space-proc x y)))
  43. (save-temp0! x)
  44. (save-temp1! y)
  45. (ensure-bignum-space! needed)
  46. (let ((x (integer->external-bignum (recover-temp0!)))
  47. (y (integer->external-bignum (recover-temp1!))))
  48. (external-bignum->integer (proc x y)))))))
  49. ; Same again for unary procedures.
  50. (define (unary-bignum-op space-proc proc)
  51. (let ((space-proc (unary-space-proc space-proc)))
  52. (lambda (x)
  53. (let ((needed (space-proc x)))
  54. (save-temp0! x)
  55. (ensure-bignum-space! needed)
  56. (external-bignum->integer
  57. (proc (integer->external-bignum (recover-temp0!))))))))
  58. (define bignum-add (binary-bignum-op add-space external-bignum-add))
  59. (define bignum-subtract (binary-bignum-op add-space external-bignum-subtract))
  60. (define bignum-multiply (binary-bignum-op (lambda (size0 size1)
  61. (bignum-digits->size (+ size0 size1)))
  62. external-bignum-multiply))
  63. ; Three bignums whose total length is twice the numerator plus two.
  64. (define (divide-space numerator-size denominator-size)
  65. (+ (* 2 (bignum-digits->size numerator-size))
  66. (bignum-digits->size 2)))
  67. (define bignum-quotient
  68. (binary-bignum-op divide-space external-bignum-quotient))
  69. (define bignum-remainder
  70. (binary-bignum-op divide-space external-bignum-remainder))
  71. (define (bignum-divide x y)
  72. (let ((needed ((binary-space-proc divide-space) x y)))
  73. (save-temp0! x)
  74. (save-temp1! y)
  75. (ensure-bignum-space! needed)
  76. (let ((x (integer->external-bignum (recover-temp0!)))
  77. (y (integer->external-bignum (recover-temp1!))))
  78. (receive (div-by-zero? quot rem)
  79. (external-bignum-divide x y)
  80. (if div-by-zero?
  81. (values #t
  82. (enter-fixnum 0) ;just to have a descriptor
  83. (enter-fixnum 0)
  84. (external-bignum->integer x) (external-bignum->integer y))
  85. (values #f
  86. (external-bignum->integer quot)
  87. (external-bignum->integer rem)
  88. (external-bignum->integer x) (external-bignum->integer y)))))))
  89. (define (shift-space x n)
  90. (receive (x-size extra)
  91. (integer-bignum-digits x)
  92. (+ extra
  93. (if (>= n 0)
  94. (+ (bignum-digits->size x-size)
  95. (bignum-digits->size (quotient n bignum-digit-bits))
  96. 1)
  97. (+ (* 2 (not-space x-size))
  98. (+ (bignum-digits->size x-size) 1))))))
  99. (define (bignum-arithmetic-shift x y)
  100. (let* ((y (extract-fixnum y))
  101. (needed (shift-space x y)))
  102. (save-temp0! x)
  103. (ensure-bignum-space! needed)
  104. (let ((x (integer->external-bignum (recover-temp0!))))
  105. (external-bignum->integer (external-bignum-arithmetic-shift x y)))))
  106. ;;; bitwise-not x == (- -1 x)
  107. ;;; ignore that -1 is cached...
  108. (define (not-space size0)
  109. (add-space size0 fixnum-as-bignum-digits))
  110. (define bignum-bitwise-not
  111. (unary-bignum-op not-space external-bignum-bitwise-not))
  112. (define bignum-bit-count
  113. (let ((space-proc (unary-space-proc not-space)))
  114. (lambda (x)
  115. (let ((needed (space-proc x)))
  116. (save-temp0! x)
  117. (ensure-bignum-space! needed)
  118. (enter-fixnum
  119. (external-bignum-bit-count
  120. (integer->external-bignum (recover-temp0!))))))))
  121. (define (bitwise-space size0 size1)
  122. (bignum-digits->size (+ (max size0 size1) 1)))
  123. (define bignum-bitwise-and
  124. (binary-bignum-op bitwise-space external-bignum-bitwise-and))
  125. (define bignum-bitwise-ior
  126. (binary-bignum-op bitwise-space external-bignum-bitwise-ior))
  127. (define bignum-bitwise-xor
  128. (binary-bignum-op bitwise-space external-bignum-bitwise-xor))
  129. ; These are not applied to fixnums.
  130. (define (bignum= x y)
  131. (external-bignum-equal? (extract-bignum x)
  132. (extract-bignum y)))
  133. (define (bignum< x y)
  134. (= -1 (external-bignum-compare (extract-bignum x)
  135. (extract-bignum y))))
  136. (define bignum-abs (unary-bignum-op
  137. (lambda (size) size)
  138. (lambda (x)
  139. (if (= (external-bignum-test x)
  140. -1)
  141. (external-bignum-negate x)
  142. x))))
  143. (define (bignum-positive? x)
  144. (= (external-bignum-test (extract-bignum x)) 1))
  145. (define (bignum-nonnegative? x)
  146. (not (= (external-bignum-test (extract-bignum x)) -1)))
  147. ;----------------
  148. ; Return the number of bignum digits in an integer. For fixnums this is a
  149. ; fixed amount. The second return value is the amount of space needed to
  150. ; convert the argument into a bignum.
  151. (define (integer-bignum-digits x)
  152. (if (fixnum? x)
  153. (values fixnum-as-bignum-digits
  154. fixnum-as-bignum-size)
  155. (values (bignum-digits x)
  156. 0)))
  157. ; Converting back and forth between Scheme 48 integers and external bignums.
  158. (define (integer->external-bignum desc)
  159. (if (fixnum? desc)
  160. (long->external-bignum (extract-fixnum desc))
  161. (extract-bignum desc)))
  162. (define (long->external-bignum x)
  163. (external-bignum-from-long x))
  164. (define (unsigned-long->external-bignum x)
  165. (external-bignum-from-unsigned-long x))
  166. ; Converting between longs and bignums
  167. (define (long->bignum x key)
  168. (set-bignum-preallocation-key! key)
  169. (enter-bignum (long->external-bignum x)))
  170. (define (unsigned-long->bignum x key)
  171. (set-bignum-preallocation-key! key)
  172. (enter-bignum (unsigned-long->external-bignum x)))
  173. (define (external-bignum->integer external-bignum)
  174. (if (external-bignum-fits-in-word? external-bignum
  175. bits-per-fixnum
  176. #t)
  177. (enter-fixnum (external-bignum->long external-bignum))
  178. (enter-bignum external-bignum)))