Re: integer-length and integer-sqrt Aubrey Jaffer 16 Oct 2005 22:45 UTC

 | From: Bradley Lucier <xxxxxx@math.purdue.edu>
 | Date: Fri, 7 Oct 2005 12:47:01 +0200
 |
 | Jens Axel Søgaard writes:
 |
 | > I propose adding the following two operations on integers.
 | ...
 | > The second is INTEGER-SQRT, which is discussed here:
 | >
 | > <http://groups.google.com/group/comp.lang.scheme/browse_frm/thread/
 | > dc06e91e306cf488/a9cf92f425bb3db1?lnk=st&q=lucier+integer-
 | > sqrt&rnum=1&hl=en#a9cf92f425bb3db1>
 | >
 | > I consider INTEGER-SQRT just as natural an operation as GCD and LCM
 | > when it comes to number theoretical calculations.
 |
 | Agree completely.
 |
 | The following algorithm is better; it's about twice as fast and
 | Zimmermann has published a proof of correctness:

What language is this written in?

 | (define-prim (##exact-int.sqrt x)
 |
 |    ;; x is non-negative.  Returns (cons s r) where
 |    ;; x = s^2+r, x < (s+1)^2
 |
 |    ;; Derived from the paper "Karatsuba Square Root" by Paul Zimmermann,
 |    ;; INRIA technical report RR-3805, 1999.  (Used in gmp 4.*)
 |
 |    ;; Note that the statement of the theorem requires that
 |    ;; b/4 <= high-order digit of x < b which can be impossible when b is
 | a
 |    ;; power of 2; the paper later notes that it is the lower bound that
 | is
 |    ;; necessary, which we preserve.
 |
 |    (if (and (##fixnum? x)
 |             ;; we require that
 |             ;; (##< (##flonum.sqrt (- (* y y) 1)) y) => #t
 |             ;; whenever x=y^2 is in this range.  Here we assume that we
 |             ;; have at least as much precision as IEEE double precision
 | and
 |             ;; we round to nearest.
 |             (or (##not (##fixnum? 4294967296))          ; 32-bit fixnums
 |                 (##fixnum.<= x 4503599627370496)))      ; 2^52
 |        (let* ((s (##flonum.->fixnum (##flonum.sqrt (##flonum.<-fixnum
 | x))))
 |               (r (##fixnum.- x (##fixnum.* s s))))
 |          (##cons s r))
 |        (let ((length/4
 |               (##fixnum.arithmetic-shift-right
 |                (##fixnum.+ (##integer-length x) 1)
 |                2)))
 |          (let* ((s-prime&r-prime
 |                  (##exact-int.sqrt
 |                   (##arithmetic-shift
 |                    x
 |                    (##fixnum.- (##fixnum.arithmetic-shift-left length/4
 | 1)))))
 |                 (s-prime
 |                  (##car s-prime&r-prime))
 |                 (r-prime
 |                  (##cdr s-prime&r-prime)))
 |            (let* ((qu
 |                    (##exact-int.div
 |                     (##+ (##arithmetic-shift r-prime length/4)
 |                          (##extract-bit-field length/4 length/4 x))
 |                     (##arithmetic-shift s-prime 1)))
 |                   (q
 |                    (##car qu))
 |                   (u
 |                    (##cdr qu)))
 |              (let ((s
 |                     (##+ (##arithmetic-shift s-prime length/4) q))
 |                    (r
 |                     (##- (##+ (##arithmetic-shift u length/4)
 |                               (##extract-bit-field length/4 0 x))
 |                          (##* q q))))
 |                (if (##negative? r)
 |                  (##cons (##- s 1)
 |                          (##+ r
 |                               (##- (##arithmetic-shift s 1) 1)))
 |                  (##cons s
 |                          r))))))))
 |