123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- ; Part of Scheme 48 1.9. See file COPYING for notices and license.
- ; Authors: Richard Kelsey, Jonathan Rees, Martin Gasbichler, Mike Sperber
- ; These need to operate on both bignums and fixnums.
- ;bignum-add
- ;bignum-subtract
- ;bignum-multiply
- ;bignum-quotient
- ;bignum-remainder
- ;bignum-abs
- ;
- ; These only see bignums.
- ;bignum=
- ;bignum<
- ; This only sees fixnums.
- ;fixnum->bignum
- ;----------------
- (define (add-space size0 size1)
- (bignum-digits->size (+ (max size0 size1) 1)))
- ; These take care of the extra space needed for fixnum arguments (they need
- ; to be converted to bignums). SPACE-PROC takes the length of the two bignums
- ; and returns the space needed for the computation and results.
- (define (binary-space-proc space-proc)
- (lambda (x y)
- (receive (length0 extra0)
- (integer-bignum-digits x)
- (receive (length1 extra1)
- (integer-bignum-digits y)
- (+ (space-proc length0 length1)
- extra0
- extra1)))))
- (define (unary-space-proc space-proc)
- (lambda (x)
- (receive (length extra)
- (integer-bignum-digits x)
- (+ (space-proc length)
- extra))))
- ; While checking for space, which may cause a GC, we have to save the two
- ; arguments where they will be traced.
- (define (binary-bignum-op space-proc proc)
- (let ((space-proc (binary-space-proc space-proc)))
- (lambda (x y)
- (let ((needed (space-proc x y)))
- (save-temp0! x)
- (save-temp1! y)
- (ensure-bignum-space! needed)
- (let ((x (integer->external-bignum (recover-temp0!)))
- (y (integer->external-bignum (recover-temp1!))))
- (external-bignum->integer (proc x y)))))))
- ; Same again for unary procedures.
- (define (unary-bignum-op space-proc proc)
- (let ((space-proc (unary-space-proc space-proc)))
- (lambda (x)
- (let ((needed (space-proc x)))
- (save-temp0! x)
- (ensure-bignum-space! needed)
- (external-bignum->integer
- (proc (integer->external-bignum (recover-temp0!))))))))
- (define bignum-add (binary-bignum-op add-space external-bignum-add))
- (define bignum-subtract (binary-bignum-op add-space external-bignum-subtract))
- (define bignum-multiply (binary-bignum-op (lambda (size0 size1)
- (bignum-digits->size (+ size0 size1)))
- external-bignum-multiply))
- ; Three bignums whose total length is twice the numerator plus two.
- (define (divide-space numerator-size denominator-size)
- (+ (* 2 (bignum-digits->size numerator-size))
- (bignum-digits->size 2)))
- (define bignum-quotient
- (binary-bignum-op divide-space external-bignum-quotient))
- (define bignum-remainder
- (binary-bignum-op divide-space external-bignum-remainder))
- (define (bignum-divide x y)
- (let ((needed ((binary-space-proc divide-space) x y)))
- (save-temp0! x)
- (save-temp1! y)
- (ensure-bignum-space! needed)
- (let ((x (integer->external-bignum (recover-temp0!)))
- (y (integer->external-bignum (recover-temp1!))))
- (receive (div-by-zero? quot rem)
- (external-bignum-divide x y)
- (if div-by-zero?
- (values #t
- (enter-fixnum 0) ;just to have a descriptor
- (enter-fixnum 0)
- (external-bignum->integer x) (external-bignum->integer y))
- (values #f
- (external-bignum->integer quot)
- (external-bignum->integer rem)
- (external-bignum->integer x) (external-bignum->integer y)))))))
- (define (shift-space x n)
- (receive (x-size extra)
- (integer-bignum-digits x)
- (+ extra
- (if (>= n 0)
- (+ (bignum-digits->size x-size)
- (bignum-digits->size (quotient n bignum-digit-bits))
- 1)
- (+ (* 2 (not-space x-size))
- (+ (bignum-digits->size x-size) 1))))))
- (define (bignum-arithmetic-shift x y)
- (let* ((y (extract-fixnum y))
- (needed (shift-space x y)))
- (save-temp0! x)
- (ensure-bignum-space! needed)
- (let ((x (integer->external-bignum (recover-temp0!))))
- (external-bignum->integer (external-bignum-arithmetic-shift x y)))))
- ;;; bitwise-not x == (- -1 x)
- ;;; ignore that -1 is cached...
- (define (not-space size0)
- (add-space size0 fixnum-as-bignum-digits))
- (define bignum-bitwise-not
- (unary-bignum-op not-space external-bignum-bitwise-not))
- (define bignum-bit-count
- (let ((space-proc (unary-space-proc not-space)))
- (lambda (x)
- (let ((needed (space-proc x)))
- (save-temp0! x)
- (ensure-bignum-space! needed)
- (enter-fixnum
- (external-bignum-bit-count
- (integer->external-bignum (recover-temp0!))))))))
- (define (bitwise-space size0 size1)
- (bignum-digits->size (+ (max size0 size1) 1)))
- (define bignum-bitwise-and
- (binary-bignum-op bitwise-space external-bignum-bitwise-and))
- (define bignum-bitwise-ior
- (binary-bignum-op bitwise-space external-bignum-bitwise-ior))
- (define bignum-bitwise-xor
- (binary-bignum-op bitwise-space external-bignum-bitwise-xor))
- ; These are not applied to fixnums.
- (define (bignum= x y)
- (external-bignum-equal? (extract-bignum x)
- (extract-bignum y)))
- (define (bignum< x y)
- (= -1 (external-bignum-compare (extract-bignum x)
- (extract-bignum y))))
- (define bignum-abs (unary-bignum-op
- (lambda (size) size)
- (lambda (x)
- (if (= (external-bignum-test x)
- -1)
- (external-bignum-negate x)
- x))))
- (define (bignum-positive? x)
- (= (external-bignum-test (extract-bignum x)) 1))
- (define (bignum-nonnegative? x)
- (not (= (external-bignum-test (extract-bignum x)) -1)))
- ;----------------
- ; Return the number of bignum digits in an integer. For fixnums this is a
- ; fixed amount. The second return value is the amount of space needed to
- ; convert the argument into a bignum.
- (define (integer-bignum-digits x)
- (if (fixnum? x)
- (values fixnum-as-bignum-digits
- fixnum-as-bignum-size)
- (values (bignum-digits x)
- 0)))
- ; Converting back and forth between Scheme 48 integers and external bignums.
- (define (integer->external-bignum desc)
- (if (fixnum? desc)
- (long->external-bignum (extract-fixnum desc))
- (extract-bignum desc)))
- (define (long->external-bignum x)
- (external-bignum-from-long x))
- (define (unsigned-long->external-bignum x)
- (external-bignum-from-unsigned-long x))
- ; Converting between longs and bignums
- (define (long->bignum x key)
- (set-bignum-preallocation-key! key)
- (enter-bignum (long->external-bignum x)))
- (define (unsigned-long->bignum x key)
- (set-bignum-preallocation-key! key)
- (enter-bignum (unsigned-long->external-bignum x)))
- (define (external-bignum->integer external-bignum)
- (if (external-bignum-fits-in-word? external-bignum
- bits-per-fixnum
- #t)
- (enter-fixnum (external-bignum->long external-bignum))
- (enter-bignum external-bignum)))
|