Permalink
Cannot retrieve contributors at this time
| ;;;============================================================================ | |
| ;;; File: "_num.scm" | |
| ;;; Copyright (c) 1994-2016 by Marc Feeley, All Rights Reserved. | |
| ;;; Copyright (c) 2004-2016 by Brad Lucier, All Rights Reserved. | |
| ;;;============================================================================ | |
| (macro-case-target | |
| ((C) | |
| (c-declare "#include \"mem.h\"") | |
| (##define-macro (use-fast-bignum-algorithms) #t)) | |
| (else | |
| (##define-macro (use-fast-bignum-algorithms) #f))) | |
| ;;;============================================================================ | |
| ;;; Implementation of exceptions. | |
| (implement-library-type-range-exception) | |
| (define-prim (##raise-range-exception arg-num proc . args) | |
| (##extract-procedure-and-arguments | |
| proc | |
| args | |
| arg-num | |
| #f | |
| #f | |
| (lambda (procedure arguments arg-num dummy1 dummy2) | |
| (macro-raise | |
| (macro-make-range-exception procedure arguments arg-num))))) | |
| (implement-library-type-divide-by-zero-exception) | |
| (define-prim (##raise-divide-by-zero-exception proc . args) | |
| (##extract-procedure-and-arguments | |
| proc | |
| args | |
| #f | |
| #f | |
| #f | |
| (lambda (procedure arguments dummy1 dummy2 dummy3) | |
| (macro-raise | |
| (macro-make-divide-by-zero-exception procedure arguments))))) | |
| (implement-library-type-fixnum-overflow-exception) | |
| (define-prim (##raise-fixnum-overflow-exception proc . args) | |
| (##extract-procedure-and-arguments | |
| proc | |
| args | |
| #f | |
| #f | |
| #f | |
| (lambda (procedure arguments dummy1 dummy2 dummy3) | |
| (macro-raise | |
| (macro-make-fixnum-overflow-exception procedure arguments))))) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Define type checking procedures. | |
| (define-fail-check-type exact-signed-int8 'exact-signed-int8) | |
| (define-fail-check-type exact-signed-int8-list 'exact-signed-int8-list) | |
| (define-fail-check-type exact-unsigned-int8 'exact-unsigned-int8) | |
| (define-fail-check-type exact-unsigned-int8-list 'exact-unsigned-int8-list) | |
| (define-fail-check-type exact-signed-int16 'exact-signed-int16) | |
| (define-fail-check-type exact-signed-int16-list 'exact-signed-int16-list) | |
| (define-fail-check-type exact-unsigned-int16 'exact-unsigned-int16) | |
| (define-fail-check-type exact-unsigned-int16-list 'exact-unsigned-int16-list) | |
| (define-fail-check-type exact-signed-int32 'exact-signed-int32) | |
| (define-fail-check-type exact-signed-int32-list 'exact-signed-int32-list) | |
| (define-fail-check-type exact-unsigned-int32 'exact-unsigned-int32) | |
| (define-fail-check-type exact-unsigned-int32-list 'exact-unsigned-int32-list) | |
| (define-fail-check-type exact-signed-int64 'exact-signed-int64) | |
| (define-fail-check-type exact-signed-int64-list 'exact-signed-int64-list) | |
| (define-fail-check-type exact-unsigned-int64 'exact-unsigned-int64) | |
| (define-fail-check-type exact-unsigned-int64-list 'exact-unsigned-int64-list) | |
| (define-fail-check-type inexact-real 'inexact-real) | |
| (define-fail-check-type inexact-real-list 'inexact-real-list) | |
| (define-fail-check-type number 'number) | |
| (define-fail-check-type real 'real) | |
| (define-fail-check-type finite-real 'finite-real) | |
| (define-fail-check-type rational 'rational) | |
| (define-fail-check-type integer 'integer) | |
| (define-fail-check-type exact-integer 'exact-integer) | |
| (define-fail-check-type fixnum 'fixnum) | |
| (define-fail-check-type flonum 'flonum) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Numerical type predicates. | |
| (define-prim (##number? x) | |
| (##complex? x)) | |
| (define-prim (##complex? x) | |
| (macro-number-dispatch x #f | |
| #t ;; x = fixnum | |
| #t ;; x = bignum | |
| #t ;; x = ratnum | |
| #t ;; x = flonum | |
| #t)) ;; x = cpxnum | |
| (define-prim (number? x) | |
| (macro-force-vars (x) | |
| (##number? x))) | |
| (define-prim (complex? x) | |
| (macro-force-vars (x) | |
| (##complex? x))) | |
| (define-prim (##real? x) | |
| (macro-number-dispatch x #f | |
| #t ;; x = fixnum | |
| #t ;; x = bignum | |
| #t ;; x = ratnum | |
| #t ;; x = flonum | |
| (macro-cpxnum-real? x))) ;; x = cpxnum | |
| (define-prim (real? x) | |
| (macro-force-vars (x) | |
| (##real? x))) | |
| (define-prim (##rational? x) | |
| (macro-number-dispatch x #f | |
| #t ;; x = fixnum | |
| #t ;; x = bignum | |
| #t ;; x = ratnum | |
| (macro-flonum-rational? x) ;; x = flonum | |
| (macro-cpxnum-rational? x))) ;; x = cpxnum | |
| (define-prim (rational? x) | |
| (macro-force-vars (x) | |
| (##rational? x))) | |
| (define-prim (##integer? x) | |
| (macro-number-dispatch x #f | |
| #t ;; x = fixnum | |
| #t ;; x = bignum | |
| #f ;; x = ratnum | |
| (macro-flonum-int? x) ;; x = flonum | |
| (macro-cpxnum-int? x))) ;; x = cpxnum | |
| (define-prim (integer? x) | |
| (macro-force-vars (x) | |
| (##integer? x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Exactness predicates. | |
| (define-prim (##exact? x) | |
| (define (type-error) #f) | |
| (macro-number-dispatch x (type-error) | |
| #t ;; x = fixnum | |
| #t ;; x = bignum | |
| #t ;; x = ratnum | |
| #f ;; x = flonum | |
| (and (##not (##flonum? (macro-cpxnum-real x))) ;; x = cpxnum | |
| (##not (##flonum? (macro-cpxnum-imag x)))))) | |
| (define-prim (exact? x) | |
| (macro-force-vars (x) | |
| (let () | |
| (define (type-error) | |
| (##fail-check-number 1 exact? x)) | |
| (macro-number-dispatch x (type-error) | |
| #t ;; x = fixnum | |
| #t ;; x = bignum | |
| #t ;; x = ratnum | |
| #f ;; x = flonum | |
| (and (##not (##flonum? (macro-cpxnum-real x))) ;; x = cpxnum | |
| (##not (##flonum? (macro-cpxnum-imag x)))))))) | |
| (define-prim (##inexact? x) | |
| (define (type-error) #f) | |
| (macro-number-dispatch x (type-error) | |
| #f ;; x = fixnum | |
| #f ;; x = bignum | |
| #f ;; x = ratnum | |
| #t ;; x = flonum | |
| (or (##flonum? (macro-cpxnum-real x)) ;; x = cpxnum | |
| (##flonum? (macro-cpxnum-imag x))))) | |
| (define-prim (inexact? x) | |
| (macro-force-vars (x) | |
| (let () | |
| (define (type-error) | |
| (##fail-check-number 1 inexact? x)) | |
| (macro-number-dispatch x (type-error) | |
| #f ;; x = fixnum | |
| #f ;; x = bignum | |
| #f ;; x = ratnum | |
| #t ;; x = flonum | |
| (or (##flonum? (macro-cpxnum-real x)) ;; x = cpxnum | |
| (##flonum? (macro-cpxnum-imag x))))))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Comparison predicates. | |
| (define-prim (##= x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (##fx= x y) | |
| #f | |
| #f | |
| (if (##fixnum->flonum-exact? x) | |
| (##fl= (##fixnum->flonum x) y) | |
| (and (##flfinite? y) | |
| (##ratnum.= (##exact-int->ratnum x) (##flonum->ratnum y)))) | |
| (##cpxnum.= (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| #f | |
| (or (##eq? x y) | |
| (##exact-int.= x y)) | |
| #f | |
| (and (##flfinite? y) | |
| (##ratnum.= (##exact-int->ratnum x) (##flonum->ratnum y))) | |
| (##cpxnum.= (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| #f | |
| #f | |
| (or (##eq? x y) | |
| (##ratnum.= x y)) | |
| (and (##flfinite? y) | |
| (##ratnum.= x (##flonum->ratnum y))) | |
| (##cpxnum.= (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (if (##fixnum->flonum-exact? y) | |
| (##fl= x (##fixnum->flonum y)) | |
| (and (##flfinite? x) | |
| (##ratnum.= (##flonum->ratnum x) (##exact-int->ratnum y)))) | |
| (and (##flfinite? x) | |
| (##ratnum.= (##flonum->ratnum x) (##exact-int->ratnum y))) | |
| (and (##flfinite? x) | |
| (##ratnum.= (##flonum->ratnum x) y)) | |
| (##fl= x y) | |
| (##cpxnum.= (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = cpxnum | |
| (##cpxnum.= x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.= x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.= x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.= x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.= x y)))) | |
| (define-prim-nary-bool (= x y) | |
| #t | |
| (if (##number? x) #t '(1)) | |
| (##= x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-number)) | |
| (define-prim (##< x y #!optional (nan-result #f)) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (##fx< x y) | |
| (##not (##bignum.negative? y)) | |
| (##ratnum.< (##exact-int->ratnum x) y) | |
| (cond ((##flfinite? y) | |
| (if (##fixnum->flonum-exact? x) | |
| (##fl< (##fixnum->flonum x) y) | |
| (##ratnum.< (##exact-int->ratnum x) (##flonum->ratnum y)))) | |
| ((##flnan? y) | |
| nan-result) | |
| (else | |
| (##flpositive? y))) | |
| (if (macro-cpxnum-real? y) | |
| (##< x (macro-cpxnum-real y) nan-result) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| (##bignum.negative? x) | |
| (##exact-int.< x y) | |
| (##ratnum.< (##exact-int->ratnum x) y) | |
| (cond ((##flfinite? y) | |
| (##ratnum.< (##exact-int->ratnum x) (##flonum->ratnum y))) | |
| ((##flnan? y) | |
| nan-result) | |
| (else | |
| (##flpositive? y))) | |
| (if (macro-cpxnum-real? y) | |
| (##< x (macro-cpxnum-real y) nan-result) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| (##ratnum.< x (##exact-int->ratnum y)) | |
| (##ratnum.< x (##exact-int->ratnum y)) | |
| (##ratnum.< x y) | |
| (cond ((##flfinite? y) | |
| (##ratnum.< x (##flonum->ratnum y))) | |
| ((##flnan? y) | |
| nan-result) | |
| (else | |
| (##flpositive? y))) | |
| (if (macro-cpxnum-real? y) | |
| (##< x (macro-cpxnum-real y) nan-result) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (cond ((##flfinite? x) | |
| (if (##fixnum->flonum-exact? y) | |
| (##fl< x (##fixnum->flonum y)) | |
| (##ratnum.< (##flonum->ratnum x) (##exact-int->ratnum y)))) | |
| ((##flnan? x) | |
| nan-result) | |
| (else | |
| (##flnegative? x))) | |
| (cond ((##flfinite? x) | |
| (##ratnum.< (##flonum->ratnum x) (##exact-int->ratnum y))) | |
| ((##flnan? x) | |
| nan-result) | |
| (else | |
| (##flnegative? x))) | |
| (cond ((##flfinite? x) | |
| (##ratnum.< (##flonum->ratnum x) y)) | |
| ((##flnan? x) | |
| nan-result) | |
| (else | |
| (##flnegative? x))) | |
| (if (or (##flnan? x) (##flnan? y)) | |
| nan-result | |
| (##fl< x y)) | |
| (if (macro-cpxnum-real? y) | |
| (##< x (macro-cpxnum-real y) nan-result) | |
| (type-error-on-y))) | |
| (if (macro-cpxnum-real? x) ;; x = cpxnum | |
| (macro-number-dispatch y (type-error-on-y) | |
| (##< (macro-cpxnum-real x) y nan-result) | |
| (##< (macro-cpxnum-real x) y nan-result) | |
| (##< (macro-cpxnum-real x) y nan-result) | |
| (##< (macro-cpxnum-real x) y nan-result) | |
| (if (macro-cpxnum-real? y) | |
| (##< (macro-cpxnum-real x) (macro-cpxnum-real y) nan-result) | |
| (type-error-on-y))) | |
| (type-error-on-x)))) | |
| (define-prim-nary-bool (< x y) | |
| #t | |
| (if (##real? x) #t '(1)) | |
| (##< x y #f) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-real)) | |
| (define-prim-nary-bool (> x y) | |
| #t | |
| (if (##real? x) #t '(1)) | |
| (##< y x #f) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-real)) | |
| (define-prim-nary-bool (<= x y) | |
| #t | |
| (if (##real? x) #t '(1)) | |
| (##not (##< y x #t)) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-real)) | |
| (define-prim-nary-bool (>= x y) | |
| #t | |
| (if (##real? x) #t '(1)) | |
| (##not (##< x y #t)) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-real)) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Numerical property predicates. | |
| (define-prim (##zero? x) | |
| (define (type-error) | |
| (##fail-check-number 1 zero? x)) | |
| (macro-number-dispatch x (type-error) | |
| (##fxzero? x) | |
| #f | |
| #f | |
| (##flzero? x) | |
| (and (let ((imag (macro-cpxnum-imag x))) | |
| (and (##flonum? imag) (##flzero? imag))) | |
| (let ((real (macro-cpxnum-real x))) | |
| (if (##fixnum? real) | |
| (##fxzero? real) | |
| (and (##flonum? real) (##flzero? real))))))) | |
| (define-prim (zero? x) | |
| (macro-force-vars (x) | |
| (##zero? x))) | |
| (define-prim (##positive? x) | |
| (define (type-error) | |
| (##fail-check-real 1 positive? x)) | |
| (macro-number-dispatch x (type-error) | |
| (##fxpositive? x) | |
| (##not (##bignum.negative? x)) | |
| (##positive? (macro-ratnum-numerator x)) | |
| (##flpositive? x) | |
| (if (macro-cpxnum-real? x) | |
| (##positive? (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (positive? x) | |
| (macro-force-vars (x) | |
| (##positive? x))) | |
| (define-prim (##negative? x) | |
| (define (type-error) | |
| (##fail-check-real 1 negative? x)) | |
| (macro-number-dispatch x (type-error) | |
| (##fxnegative? x) | |
| (##bignum.negative? x) | |
| (##negative? (macro-ratnum-numerator x)) | |
| (##flnegative? x) | |
| (if (macro-cpxnum-real? x) | |
| (##negative? (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (negative? x) | |
| (macro-force-vars (x) | |
| (##negative? x))) | |
| (define-prim (##odd? x) | |
| (define (type-error) | |
| (##fail-check-integer 1 odd? x)) | |
| (macro-number-dispatch x (type-error) | |
| (##fxodd? x) | |
| (macro-bignum-odd? x) | |
| (type-error) | |
| (if (macro-flonum-int? x) | |
| (##odd? (##flonum->exact-int x)) | |
| (type-error)) | |
| (if (macro-cpxnum-int? x) | |
| (##odd? (##inexact->exact (macro-cpxnum-real x))) | |
| (type-error)))) | |
| (define-prim (odd? x) | |
| (macro-force-vars (x) | |
| (##odd? x))) | |
| (define-prim (##even? x) | |
| (define (type-error) | |
| (##fail-check-integer 1 even? x)) | |
| (macro-number-dispatch x (type-error) | |
| (##not (##fxodd? x)) | |
| (##not (macro-bignum-odd? x)) | |
| (type-error) | |
| (if (macro-flonum-int? x) | |
| (##even? (##flonum->exact-int x)) | |
| (type-error)) | |
| (if (macro-cpxnum-int? x) | |
| (##even? (##inexact->exact (macro-cpxnum-real x))) | |
| (type-error)))) | |
| (define-prim (even? x) | |
| (macro-force-vars (x) | |
| (##even? x))) | |
| (define-prim (##finite? x) | |
| (define (type-error) | |
| (##fail-check-real 1 finite? x)) | |
| (macro-number-dispatch x (type-error) | |
| #t | |
| #t | |
| #t | |
| (##flfinite? x) | |
| (if (macro-cpxnum-real? x) | |
| (let ((real (macro-cpxnum-real x))) | |
| (or (##not (##flonum? real)) | |
| (##flfinite? real))) | |
| (type-error)))) | |
| (define-prim (finite? x) | |
| (macro-force-vars (x) | |
| (##finite? x))) | |
| (define-prim (##infinite? x) | |
| (define (type-error) | |
| (##fail-check-real 1 infinite? x)) | |
| (macro-number-dispatch x (type-error) | |
| #f | |
| #f | |
| #f | |
| (##flinfinite? x) | |
| (if (macro-cpxnum-real? x) | |
| (let ((real (macro-cpxnum-real x))) | |
| (and (##flonum? real) | |
| (##flinfinite? real))) | |
| (type-error)))) | |
| (define-prim (infinite? x) | |
| (macro-force-vars (x) | |
| (##infinite? x))) | |
| (define-prim (##nan? x) | |
| (define (type-error) | |
| (##fail-check-real 1 nan? x)) | |
| (macro-number-dispatch x (type-error) | |
| #f | |
| #f | |
| #f | |
| (##flnan? x) | |
| (if (macro-cpxnum-real? x) | |
| (let ((real (macro-cpxnum-real x))) | |
| (and (##flonum? real) | |
| (##flnan? real))) | |
| (type-error)))) | |
| (define-prim (nan? x) | |
| (macro-force-vars (x) | |
| (##nan? x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Max and min. | |
| (define-prim (##max x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (##fxmax x y) | |
| (if (##< x y) y x) | |
| (if (##< x y) y x) | |
| (##flmax (##fixnum->flonum x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##max x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| (if (##< x y) y x) | |
| (if (##< x y) y x) | |
| (if (##< x y) y x) | |
| (##flmax (##exact-int->flonum x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##max x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| (if (##< x y) y x) | |
| (if (##< x y) y x) | |
| (if (##< x y) y x) | |
| (##flmax (##ratnum->flonum x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##max x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (##flmax x (##fixnum->flonum y)) | |
| (##flmax x (##exact-int->flonum y)) | |
| (##flmax x (##ratnum->flonum y)) | |
| (##flmax x y) | |
| (if (macro-cpxnum-real? y) | |
| (##max x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (if (macro-cpxnum-real? x) ;; x = cpxnum | |
| (macro-number-dispatch y (type-error-on-y) | |
| (##max (macro-cpxnum-real x) y) | |
| (##max (macro-cpxnum-real x) y) | |
| (##max (macro-cpxnum-real x) y) | |
| (##max (macro-cpxnum-real x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##max (macro-cpxnum-real x) (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (type-error-on-x)))) | |
| (define-prim-nary (max x y) | |
| () | |
| (if (##real? x) x '(1)) | |
| (##max x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-real)) | |
| (define-prim (##min x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (##fxmin x y) | |
| (if (##< x y) x y) | |
| (if (##< x y) x y) | |
| (##flmin (##fixnum->flonum x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##min x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| (if (##< x y) x y) | |
| (if (##< x y) x y) | |
| (if (##< x y) x y) | |
| (##flmin (##exact-int->flonum x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##min x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| (if (##< x y) x y) | |
| (if (##< x y) x y) | |
| (if (##< x y) x y) | |
| (##flmin (##ratnum->flonum x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##min x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (##flmin x (##fixnum->flonum y)) | |
| (##flmin x (##exact-int->flonum y)) | |
| (##flmin x (##ratnum->flonum y)) | |
| (##flmin x y) | |
| (if (macro-cpxnum-real? y) | |
| (##min x (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (if (macro-cpxnum-real? x) ;; x = cpxnum | |
| (macro-number-dispatch y (type-error-on-y) | |
| (##min (macro-cpxnum-real x) y) | |
| (##min (macro-cpxnum-real x) y) | |
| (##min (macro-cpxnum-real x) y) | |
| (##min (macro-cpxnum-real x) y) | |
| (if (macro-cpxnum-real? y) | |
| (##min (macro-cpxnum-real x) (macro-cpxnum-real y)) | |
| (type-error-on-y))) | |
| (type-error-on-x)))) | |
| (define-prim-nary (min x y) | |
| () | |
| (if (##real? x) x '(1)) | |
| (##min x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-real)) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; +, *, -, / | |
| (define-prim (##+ x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (or (##fx+? x y) | |
| (##bignum.+ (##fixnum->bignum x) (##fixnum->bignum y))) | |
| (if (##fxzero? x) | |
| y | |
| (##bignum.+ (##fixnum->bignum x) y)) | |
| (if (##fxzero? x) | |
| y | |
| (##ratnum.+ (##exact-int->ratnum x) y)) | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? x)) | |
| y | |
| (##fl+ (##fixnum->flonum x) y)) | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? x)) | |
| y | |
| (##cpxnum.+ (##noncpxnum->cpxnum x) y))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| (if (##fxzero? y) | |
| x | |
| (##bignum.+ x (##fixnum->bignum y))) | |
| (##bignum.+ x y) | |
| (##ratnum.+ (##exact-int->ratnum x) y) | |
| (##fl+ (##exact-int->flonum x) y) | |
| (##cpxnum.+ (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| (if (##fxzero? y) | |
| x | |
| (##ratnum.+ x (##exact-int->ratnum y))) | |
| (##ratnum.+ x (##exact-int->ratnum y)) | |
| (##ratnum.+ x y) | |
| (##fl+ (##ratnum->flonum x) y) | |
| (##cpxnum.+ (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? y)) | |
| x | |
| (##fl+ x (##fixnum->flonum y))) | |
| (##fl+ x (##exact-int->flonum y)) | |
| (##fl+ x (##ratnum->flonum y)) | |
| (##fl+ x y) | |
| (##cpxnum.+ (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = cpxnum | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? y)) | |
| x | |
| (##cpxnum.+ x (##noncpxnum->cpxnum y))) | |
| (##cpxnum.+ x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.+ x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.+ x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.+ x y)))) | |
| (define-prim-nary (+ x y) | |
| 0 | |
| (if (##number? x) x '(1)) | |
| (##+ x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-number)) | |
| (define-prim (##* x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (cond ((##fx= y 0) | |
| 0) | |
| ((if (##fx= y -1) | |
| (##fx-? x) | |
| (##fx*? x y)) | |
| => (lambda (result) result)) | |
| (else | |
| (##bignum.* (##fixnum->bignum x) (##fixnum->bignum y)))) | |
| (cond ((##fxzero? x) | |
| 0) | |
| ((##fx= x 1) | |
| y) | |
| ((##fx= x -1) | |
| (##negate y)) | |
| (else | |
| (##bignum.* (##fixnum->bignum x) y))) | |
| (cond ((##fxzero? x) | |
| 0) | |
| ((##fx= x 1) | |
| y) | |
| ((##fx= x -1) | |
| (##negate y)) | |
| (else | |
| (##ratnum.* (##exact-int->ratnum x) y))) | |
| (cond ((and (macro-special-case-exact-zero?) | |
| (##fxzero? x)) | |
| 0) | |
| ((##fx= x 1) | |
| y) | |
| (else | |
| (##fl* (##fixnum->flonum x) y))) | |
| (cond ((and (macro-special-case-exact-zero?) | |
| (##fxzero? x)) | |
| 0) | |
| ((##fx= x 1) | |
| y) | |
| (else | |
| (##cpxnum.* (##noncpxnum->cpxnum x) y)))) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| (cond ((##fx= y 0) | |
| 0) | |
| ((##fx= y 1) | |
| x) | |
| ((##fx= y -1) | |
| (##negate x)) | |
| (else | |
| (##bignum.* x (##fixnum->bignum y)))) | |
| (##bignum.* x y) | |
| (##ratnum.* (##exact-int->ratnum x) y) | |
| (##fl* (##exact-int->flonum x) y) | |
| (##cpxnum.* (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| (cond ((##fxzero? y) | |
| 0) | |
| ((##fx= y 1) | |
| x) | |
| ((##fx= y -1) | |
| (##negate x)) | |
| (else | |
| (##ratnum.* x (##exact-int->ratnum y)))) | |
| (##ratnum.* x (##exact-int->ratnum y)) | |
| (##ratnum.* x y) | |
| (##fl* (##ratnum->flonum x) y) | |
| (##cpxnum.* (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (cond ((and (macro-special-case-exact-zero?) (##fxzero? y)) | |
| 0) | |
| ((##fx= y 1) | |
| x) | |
| (else | |
| (##fl* x (##fixnum->flonum y)))) | |
| (##fl* x (##exact-int->flonum y)) | |
| (##fl* x (##ratnum->flonum y)) | |
| (##fl* x y) | |
| (##cpxnum.* (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = cpxnum | |
| (cond ((and (macro-special-case-exact-zero?) (##fxzero? y)) | |
| 0) | |
| ((##fx= y 1) | |
| x) | |
| (else | |
| (##cpxnum.* x (##noncpxnum->cpxnum y)))) | |
| (##cpxnum.* x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.* x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.* x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.* x y)))) | |
| (define-prim-nary (* x y) | |
| 1 | |
| (if (##number? x) x '(1)) | |
| (##* x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-number)) | |
| (define-prim (##square x) | |
| (define (type-error) | |
| (##fail-check-number 1 square x)) | |
| (macro-number-dispatch x (type-error) | |
| (or (##fxsquare? x) | |
| (let ((x (##fixnum->bignum x))) | |
| (##bignum.* x x))) | |
| (##bignum.* x x) | |
| (##ratnum.* x x) | |
| (##fl* x x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (or (##eqv? real 0) | |
| (##exact? x)) | |
| (##make-rectangular (##* (##- real imag) (##+ real imag)) | |
| (##* 2 (##* real imag))) | |
| (##csquare (##exact->inexact x)))))) | |
| (define-prim (square x) | |
| (macro-force-vars (x) | |
| (##square x))) | |
| (define-prim (##negate x) | |
| (##define-macro (type-error) `'(1)) | |
| (macro-number-dispatch x (type-error) | |
| (or (##fx-? x) | |
| (##bignum.- (##fixnum->bignum 0) (##fixnum->bignum ##min-fixnum))) | |
| (##bignum.- (##fixnum->bignum 0) x) | |
| (macro-ratnum-make (##negate (macro-ratnum-numerator x)) | |
| (macro-ratnum-denominator x)) | |
| (##fl- x) | |
| (##make-rectangular (##negate (macro-cpxnum-real x)) | |
| (##negate (macro-cpxnum-imag x))))) | |
| (define-prim (##- x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (macro-number-dispatch x (type-error-on-x) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = fixnum | |
| (or (##fx-? x y) | |
| (##bignum.- (##fixnum->bignum x) (##fixnum->bignum y))) | |
| (##bignum.- (##fixnum->bignum x) y) | |
| (if (##fxzero? x) | |
| (##negate y) | |
| (##ratnum.- (##exact-int->ratnum x) y)) | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? x)) | |
| (##fl- y) | |
| (##fl- (##fixnum->flonum x) y)) | |
| (##cpxnum.- (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = bignum | |
| (if (##fxzero? y) | |
| x | |
| (##bignum.- x (##fixnum->bignum y))) | |
| (##bignum.- x y) | |
| (##ratnum.- (##exact-int->ratnum x) y) | |
| (##fl- (##exact-int->flonum x) y) | |
| (##cpxnum.- (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = ratnum | |
| (if (##fxzero? y) | |
| x | |
| (##ratnum.- x (##exact-int->ratnum y))) | |
| (##ratnum.- x (##exact-int->ratnum y)) | |
| (##ratnum.- x y) | |
| (##fl- (##ratnum->flonum x) y) | |
| (##cpxnum.- (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = flonum | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? y)) | |
| x | |
| (##fl- x (##fixnum->flonum y))) | |
| (##fl- x (##exact-int->flonum y)) | |
| (##fl- x (##ratnum->flonum y)) | |
| (##fl- x y) | |
| (##cpxnum.- (##noncpxnum->cpxnum x) y)) | |
| (macro-number-dispatch y (type-error-on-y) ;; x = cpxnum | |
| (if (and (macro-special-case-exact-zero?) (##fxzero? y)) | |
| x | |
| (##cpxnum.- x (##noncpxnum->cpxnum y))) | |
| (##cpxnum.- x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.- x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.- x (##noncpxnum->cpxnum y)) | |
| (##cpxnum.- x y)))) | |
| (define-prim-nary (- x y) | |
| () | |
| (##negate x) | |
| (##- x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-number)) | |
| (define-prim (##inverse x) | |
| (##define-macro (type-error) `'(1)) | |
| (define (divide-by-zero-error) #f) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| (divide-by-zero-error) | |
| (if (##fxnegative? x) | |
| (if (##fx= x -1) | |
| x | |
| (macro-ratnum-make -1 (##negate x))) | |
| (if (##fx= x 1) | |
| x | |
| (macro-ratnum-make 1 x)))) | |
| (if (##bignum.negative? x) | |
| (macro-ratnum-make -1 (##negate x)) | |
| (macro-ratnum-make 1 x)) | |
| (let ((num (macro-ratnum-numerator x)) | |
| (den (macro-ratnum-denominator x))) | |
| (cond ((##fx= num 1) | |
| den) | |
| ((##fx= num -1) | |
| (##negate den)) | |
| (else | |
| (if (##negative? num) | |
| (macro-ratnum-make (##negate den) (##negate num)) | |
| (macro-ratnum-make den num))))) | |
| (##fl/ (macro-inexact-+1) x) | |
| (##cpxnum./ (##noncpxnum->cpxnum 1) x))) | |
| (define-prim (##/ x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (define (divide-by-zero-error) #f) | |
| (macro-number-dispatch y (type-error-on-y) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = fixnum | |
| (cond ((##fxzero? y) | |
| (divide-by-zero-error)) | |
| ((##fx= y 1) | |
| x) | |
| ((##fx= y -1) | |
| (##negate x)) | |
| ((##fxzero? x) | |
| 0) | |
| ((##fx= x 1) | |
| (##inverse y)) | |
| (else | |
| (##ratnum./ (##exact-int->ratnum x) (##exact-int->ratnum y)))) | |
| (cond ((##fxzero? y) | |
| (divide-by-zero-error)) | |
| ((##fx= y 1) | |
| x) | |
| ((##fx= y -1) | |
| (##negate x)) | |
| (else | |
| (##ratnum./ (##exact-int->ratnum x) (##exact-int->ratnum y)))) | |
| (cond ((##fxzero? y) | |
| (divide-by-zero-error)) | |
| ((##fx= y 1) | |
| x) | |
| ((##fx= y -1) | |
| (##negate x)) | |
| (else | |
| (##ratnum./ x (##exact-int->ratnum y)))) | |
| (cond ((##fxzero? y) | |
| (divide-by-zero-error)) | |
| ((##fx= y 1) | |
| x) | |
| (else | |
| (##fl/ x (##fixnum->flonum y)))) | |
| (cond ((##fxzero? y) | |
| (divide-by-zero-error)) | |
| ((##fx= y 1) | |
| x) | |
| (else | |
| (##cpxnum./ x (##noncpxnum->cpxnum y))))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = bignum | |
| (cond ((##fxzero? x) | |
| 0) | |
| ((##fx= x 1) | |
| (##inverse y)) | |
| (else | |
| (##ratnum./ (##exact-int->ratnum x) (##exact-int->ratnum y)))) | |
| (##ratnum./ (##exact-int->ratnum x) (##exact-int->ratnum y)) | |
| (##ratnum./ x (##exact-int->ratnum y)) | |
| (##fl/ x (##exact-int->flonum y)) | |
| (##cpxnum./ x (##noncpxnum->cpxnum y))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = ratnum | |
| (cond ((##fxzero? x) | |
| 0) | |
| ((##fx= x 1) | |
| (##inverse y)) | |
| (else | |
| (##ratnum./ (##exact-int->ratnum x) y))) | |
| (##ratnum./ (##exact-int->ratnum x) y) | |
| (##ratnum./ x y) | |
| (##fl/ x (##ratnum->flonum y)) | |
| (##cpxnum./ x (##noncpxnum->cpxnum y))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = flonum, no error possible | |
| (##fl/ (##fixnum->flonum x) y) | |
| (##fl/ (##exact-int->flonum x) y) | |
| (##fl/ (##ratnum->flonum x) y) | |
| (##fl/ x y) | |
| (##cpxnum./ x (##noncpxnum->cpxnum y))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = cpxnum | |
| (##cpxnum./ (##noncpxnum->cpxnum x) y) | |
| (##cpxnum./ (##noncpxnum->cpxnum x) y) | |
| (##cpxnum./ (##noncpxnum->cpxnum x) y) | |
| (##cpxnum./ (##noncpxnum->cpxnum x) y) | |
| (##cpxnum./ x y)))) | |
| (define-prim-nary (/ x y) | |
| () | |
| (##inverse x) | |
| (##/ x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-number) | |
| (##not ##raise-divide-by-zero-exception)) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; abs | |
| (define-prim (##exact-int.negative? x) | |
| (if (##fixnum? x) | |
| (##fxnegative? x) | |
| (##bignum.negative? x))) | |
| (define-prim (##abs x) | |
| (define (type-error) | |
| (##fail-check-real 1 abs x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxnegative? x) (##negate x) x) | |
| (if (##bignum.negative? x) (##negate x) x) | |
| (if (##exact-int.negative? (macro-ratnum-numerator x)) | |
| (macro-ratnum-make (##negate (macro-ratnum-numerator x)) | |
| (macro-ratnum-denominator x)) | |
| x) | |
| (##flabs x) | |
| (if (macro-cpxnum-real? x) | |
| (##make-rectangular (##abs (macro-cpxnum-real x)) | |
| (##abs (macro-cpxnum-imag x))) | |
| (type-error)))) | |
| (define-prim (abs x) | |
| (macro-force-vars (x) | |
| (##abs x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; quotient, remainder, modulo | |
| (define-prim (##quotient x y) | |
| (define (type-error-on-x) | |
| (##fail-check-integer 1 quotient x y)) | |
| (define (type-error-on-y) | |
| (##fail-check-integer 2 quotient x y)) | |
| (define (divide-by-zero-error) | |
| (##raise-divide-by-zero-exception quotient x y)) | |
| (define (exact-quotient x y) | |
| (##car (##exact-int.div x y))) | |
| (define (inexact-quotient x y) | |
| (let ((exact-y (##inexact->exact y))) | |
| (if (##eqv? exact-y 0) | |
| (divide-by-zero-error) | |
| (##exact->inexact | |
| (##quotient (##inexact->exact x) exact-y))))) | |
| (macro-number-dispatch y (type-error-on-y) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = fixnum | |
| (cond ((##fx= y 0) | |
| (divide-by-zero-error)) | |
| ((##fx= y -1) ;; (quotient ##min-fixnum -1) is a bignum | |
| (##negate x)) | |
| (else | |
| (##fxquotient x y))) | |
| (cond ((##fx= y 0) | |
| (divide-by-zero-error)) | |
| (else | |
| (exact-quotient x y))) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-quotient x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-quotient x y) | |
| (type-error-on-x))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = bignum | |
| (exact-quotient x y) | |
| (exact-quotient x y) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-quotient x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-quotient x y) | |
| (type-error-on-x))) | |
| (type-error-on-y) ;; y = ratnum | |
| (macro-number-dispatch x (type-error-on-x) ;; y = flonum | |
| (if (macro-flonum-int? y) | |
| (inexact-quotient x y) | |
| (type-error-on-y)) | |
| (if (macro-flonum-int? y) | |
| (inexact-quotient x y) | |
| (type-error-on-y)) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (if (macro-flonum-int? y) | |
| (inexact-quotient x y) | |
| (type-error-on-y)) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (if (macro-flonum-int? y) | |
| (inexact-quotient x y) | |
| (type-error-on-y)) | |
| (type-error-on-x))) | |
| (if (macro-cpxnum-int? y) ;; y = cpxnum | |
| (macro-number-dispatch x (type-error-on-x) | |
| (inexact-quotient x y) | |
| (inexact-quotient x y) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-quotient x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-quotient x y) | |
| (type-error-on-x))) | |
| (type-error-on-y)))) | |
| (define-prim (quotient x y) | |
| (macro-force-vars (x y) | |
| (##quotient x y))) | |
| (define-prim (##remainder x y) | |
| (define (type-error-on-x) | |
| (##fail-check-integer 1 remainder x y)) | |
| (define (type-error-on-y) | |
| (##fail-check-integer 2 remainder x y)) | |
| (define (divide-by-zero-error) | |
| (##raise-divide-by-zero-exception remainder x y)) | |
| (define (exact-remainder x y) | |
| (##cdr (##exact-int.div x y | |
| #f ;; need-quotient? | |
| #t ;; keep-dividend? | |
| ))) | |
| (define (inexact-remainder x y) | |
| (let ((exact-y (##inexact->exact y))) | |
| (if (##eqv? exact-y 0) | |
| (divide-by-zero-error) | |
| (##exact->inexact | |
| (##remainder (##inexact->exact x) exact-y))))) | |
| (macro-number-dispatch y (type-error-on-y) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = fixnum | |
| (cond ((##fx= y 0) | |
| (divide-by-zero-error)) | |
| (else | |
| (##fxremainder x y))) | |
| (cond ((##fx= y 0) | |
| (divide-by-zero-error)) | |
| (else | |
| (exact-remainder x y))) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-remainder x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-remainder x y) | |
| (type-error-on-x))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = bignum | |
| (exact-remainder x y) | |
| (exact-remainder x y) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-remainder x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-remainder x y) | |
| (type-error-on-x))) | |
| (type-error-on-y) ;; y = ratnum | |
| (macro-number-dispatch x (type-error-on-x) ;; y = flonum | |
| (if (macro-flonum-int? y) | |
| (inexact-remainder x y) | |
| (type-error-on-y)) | |
| (if (macro-flonum-int? y) | |
| (inexact-remainder x y) | |
| (type-error-on-y)) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (if (macro-flonum-int? y) | |
| (inexact-remainder x y) | |
| (type-error-on-y)) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (if (macro-flonum-int? y) | |
| (inexact-remainder x y) | |
| (type-error-on-y)) | |
| (type-error-on-x))) | |
| (if (macro-cpxnum-int? y) ;; y = cpxnum | |
| (macro-number-dispatch x (type-error-on-x) | |
| (inexact-remainder x y) | |
| (inexact-remainder x y) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-remainder x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-remainder x y) | |
| (type-error-on-x))) | |
| (type-error-on-y)))) | |
| (define-prim (remainder x y) | |
| (macro-force-vars (x y) | |
| (##remainder x y))) | |
| (define-prim (##modulo x y) | |
| (define (type-error-on-x) | |
| (##fail-check-integer 1 modulo x y)) | |
| (define (type-error-on-y) | |
| (##fail-check-integer 2 modulo x y)) | |
| (define (divide-by-zero-error) | |
| (##raise-divide-by-zero-exception modulo x y)) | |
| (define (exact-modulo x y) | |
| (let ((r (##cdr (##exact-int.div x | |
| y | |
| #f ;; need-quotient? | |
| #t ;; keep-dividend? | |
| )))) | |
| (if (##eqv? r 0) | |
| 0 | |
| (if (##eq? (##negative? x) (##negative? y)) | |
| r | |
| (##+ r y))))) | |
| (define (inexact-modulo x y) | |
| (let ((exact-y (##inexact->exact y))) | |
| (if (##eqv? exact-y 0) | |
| (divide-by-zero-error) | |
| (##exact->inexact | |
| (##modulo (##inexact->exact x) exact-y))))) | |
| (macro-number-dispatch y (type-error-on-y) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = fixnum | |
| (cond ((##fx= y 0) | |
| (divide-by-zero-error)) | |
| (else | |
| (##fxmodulo x y))) | |
| (cond ((##fx= y 0) | |
| (divide-by-zero-error)) | |
| (else | |
| (exact-modulo x y))) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-modulo x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-modulo x y) | |
| (type-error-on-x))) | |
| (macro-number-dispatch x (type-error-on-x) ;; y = bignum | |
| (exact-modulo x y) | |
| (exact-modulo x y) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-modulo x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-modulo x y) | |
| (type-error-on-x))) | |
| (type-error-on-y) ;; y = ratnum | |
| (macro-number-dispatch x (type-error-on-x) ;; y = flonum | |
| (if (macro-flonum-int? y) | |
| (inexact-modulo x y) | |
| (type-error-on-y)) | |
| (if (macro-flonum-int? y) | |
| (inexact-modulo x y) | |
| (type-error-on-y)) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (if (macro-flonum-int? y) | |
| (inexact-modulo x y) | |
| (type-error-on-y)) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (if (macro-flonum-int? y) | |
| (inexact-modulo x y) | |
| (type-error-on-y)) | |
| (type-error-on-x))) | |
| (if (macro-cpxnum-int? y) ;; y = cpxnum | |
| (macro-number-dispatch x (type-error-on-x) | |
| (inexact-modulo x y) | |
| (inexact-modulo x y) | |
| (type-error-on-x) | |
| (if (macro-flonum-int? x) | |
| (inexact-modulo x y) | |
| (type-error-on-x)) | |
| (if (macro-cpxnum-int? x) | |
| (inexact-modulo x y) | |
| (type-error-on-x))) | |
| (type-error-on-y)))) | |
| (define-prim (modulo x y) | |
| (macro-force-vars (x y) | |
| (##modulo x y))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; gcd, lcm | |
| (define-prim (##gcd x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (define (##fast-gcd u v) | |
| ;; See the paper "Fast Reduction and Composition of Binary | |
| ;; Quadratic Forms" by Arnold Schoenhage. His algorithm and proof | |
| ;; are derived from, and basically the same for, his Controlled | |
| ;; Euclidean Descent algorithm for gcd, which he has never | |
| ;; published. This algorithm has complexity log N times a | |
| ;; constant times the complexity of a multiplication of the same | |
| ;; size. We don't use it until we get to about 6800 bits. Note | |
| ;; that this is the same place that we start using FFT | |
| ;; multiplication and fast division with Newton's method for | |
| ;; finding inverses. | |
| ;; Niels Mo"ller has written two papers about an improved version | |
| ;; of this algorithm. | |
| ;; assumes u and v are nonnegative exact ints | |
| (define (make-gcd-matrix A_11 A_12 | |
| A_21 A_22) | |
| (##vector A_11 A_12 | |
| A_21 A_22)) | |
| (define (gcd-matrix_11 A) | |
| (##vector-ref A 0)) | |
| (define (gcd-matrix_12 A) | |
| (##vector-ref A 1)) | |
| (define (gcd-matrix_21 A) | |
| (##vector-ref A 2)) | |
| (define (gcd-matrix_22 A) | |
| (##vector-ref A 3)) | |
| (define (make-gcd-vector v_1 v_2) | |
| (##vector v_1 v_2)) | |
| (define (gcd-vector_1 v) | |
| (##vector-ref v 0)) | |
| (define (gcd-vector_2 v) | |
| (##vector-ref v 1)) | |
| (define gcd-matrix-identity '#(1 0 | |
| 0 1)) | |
| (define (gcd-matrix-multiply A B) | |
| (cond ((##eq? A gcd-matrix-identity) | |
| B) | |
| ((##eq? B gcd-matrix-identity) | |
| A) | |
| (else | |
| (let ((A_11 (gcd-matrix_11 A)) (A_12 (gcd-matrix_12 A)) | |
| (A_21 (gcd-matrix_21 A)) (A_22 (gcd-matrix_22 A)) | |
| (B_11 (gcd-matrix_11 B)) (B_12 (gcd-matrix_12 B)) | |
| (B_21 (gcd-matrix_21 B)) (B_22 (gcd-matrix_22 B))) | |
| (make-gcd-matrix (##+ (##* A_11 B_11) | |
| (##* A_12 B_21)) | |
| (##+ (##* A_11 B_12) | |
| (##* A_12 B_22)) | |
| (##+ (##* A_21 B_11) | |
| (##* A_22 B_21)) | |
| (##+ (##* A_21 B_12) | |
| (##* A_22 B_22))))))) | |
| (define (gcd-matrix-multiply-strassen A B) | |
| ;; from http://mathworld.wolfram.com/StrassenFormulas.html | |
| (cond ((##eq? A gcd-matrix-identity) | |
| B) | |
| ((##eq? B gcd-matrix-identity) | |
| A) | |
| (else | |
| (let ((A_11 (gcd-matrix_11 A)) (A_12 (gcd-matrix_12 A)) | |
| (A_21 (gcd-matrix_21 A)) (A_22 (gcd-matrix_22 A)) | |
| (B_11 (gcd-matrix_11 B)) (B_12 (gcd-matrix_12 B)) | |
| (B_21 (gcd-matrix_21 B)) (B_22 (gcd-matrix_22 B))) | |
| (let ((Q_1 (##* (##+ A_11 A_22) (##+ B_11 B_22))) | |
| (Q_2 (##* (##+ A_21 A_22) B_11)) | |
| (Q_3 (##* A_11 (##- B_12 B_22))) | |
| (Q_4 (##* A_22 (##- B_21 B_11))) | |
| (Q_5 (##* (##+ A_11 A_12) B_22)) | |
| (Q_6 (##* (##- A_21 A_11) (##+ B_11 B_12))) | |
| (Q_7 (##* (##- A_12 A_22) (##+ B_21 B_22)))) | |
| (make-gcd-matrix (##+ (##+ Q_1 Q_4) (##- Q_7 Q_5)) | |
| (##+ Q_3 Q_5) | |
| (##+ Q_2 Q_4) | |
| (##+ (##+ Q_1 Q_3) (##- Q_6 Q_2)))))))) | |
| (define (gcd-matrix-solve A y) | |
| (let ((y_1 (gcd-vector_1 y)) | |
| (y_2 (gcd-vector_2 y))) | |
| (make-gcd-vector (##- (##* y_1 (gcd-matrix_22 A)) | |
| (##* y_2 (gcd-matrix_12 A))) | |
| (##- (##* y_2 (gcd-matrix_11 A)) | |
| (##* y_1 (gcd-matrix_21 A)))))) | |
| (define (x>=2^n x n) | |
| (##fx< n (##integer-length x))) | |
| (define (determined-minimal? u v s) | |
| ;; assumes 2^s <= u , v; s>= 0 fixnum | |
| ;; returns #t if we can determine that |u-v|<2^s | |
| ;; at least one of u and v is a bignum | |
| (let ((u (if (##fixnum? u) (##fixnum->bignum u) u)) | |
| (v (if (##fixnum? v) (##fixnum->bignum v) v))) | |
| (let ((u-length (##bignum.mdigit-length u))) | |
| (and (##fx= u-length (##bignum.mdigit-length v)) | |
| (let loop ((i (##fx- u-length 1))) | |
| (let ((v-digit (##bignum.mdigit-ref v i)) | |
| (u-digit (##bignum.mdigit-ref u i))) | |
| (if (and (##fxzero? u-digit) | |
| (##fxzero? v-digit)) | |
| (loop (##fx- i 1)) | |
| (and (##fx= (##fxquotient s ##bignum.mdigit-width) | |
| i) | |
| (##fx< (##fxmax (##fx- u-digit v-digit) | |
| (##fx- v-digit u-digit)) | |
| (##fxarithmetic-shift-left | |
| 1 | |
| (##fxremainder s ##bignum.mdigit-width))))))))))) | |
| (define (gcd-small-step cont M u v s) | |
| ;; u, v >= 2^s | |
| ;; M is the matrix product of the partial sums of | |
| ;; the continued fraction representation of a/b so far | |
| ;; returns updated M, u, v, and a truth value | |
| ;; u, v >= 2^s and | |
| ;; if last return value is #t, we know that | |
| ;; (- (max u v) (min u v)) < 2^s, i.e, u, v are minimal above 2^s | |
| (define (gcd-matrix-multiply-low M q) | |
| (let ((M_11 (gcd-matrix_11 M)) | |
| (M_12 (gcd-matrix_12 M)) | |
| (M_21 (gcd-matrix_21 M)) | |
| (M_22 (gcd-matrix_22 M))) | |
| (make-gcd-matrix (##+ M_11 (##* q M_12)) M_12 | |
| (##+ M_21 (##* q M_22)) M_22))) | |
| (define (gcd-matrix-multiply-high M q) | |
| (let ((M_11 (gcd-matrix_11 M)) | |
| (M_12 (gcd-matrix_12 M)) | |
| (M_21 (gcd-matrix_21 M)) | |
| (M_22 (gcd-matrix_22 M))) | |
| (make-gcd-matrix M_11 (##+ (##* q M_11) M_12) | |
| M_21 (##+ (##* q M_21) M_22)))) | |
| (if (or (##bignum? u) | |
| (##bignum? v)) | |
| ;; if u and v are nearly equal bignums, the two ##< | |
| ;; following this condition could take O(N) time to compute. | |
| ;; When this happens, however, it will be likely that | |
| ;; determined-minimal? will return true. | |
| (cond ((determined-minimal? u v s) | |
| (cont M | |
| u | |
| v | |
| #t)) | |
| ((##< u v) | |
| (let* ((qr (##exact-int.div v u)) | |
| (q (##car qr)) | |
| (r (##cdr qr))) | |
| (cond ((x>=2^n r s) | |
| (cont (gcd-matrix-multiply-low M q) | |
| u | |
| r | |
| #f)) | |
| ((##eqv? q 1) | |
| (cont M | |
| u | |
| v | |
| #t)) | |
| (else | |
| (cont (gcd-matrix-multiply-low M (##- q 1)) | |
| u | |
| (##+ r u) | |
| #t))))) | |
| ((##< v u) | |
| (let* ((qr (##exact-int.div u v)) | |
| (q (##car qr)) | |
| (r (##cdr qr))) | |
| (cond ((x>=2^n r s) | |
| (cont (gcd-matrix-multiply-high M q) | |
| r | |
| v | |
| #f)) | |
| ((##eqv? q 1) | |
| (cont M | |
| u | |
| v | |
| #t)) | |
| (else | |
| (cont (gcd-matrix-multiply-high M (##- q 1)) | |
| (##+ r v) | |
| v | |
| #t))))) | |
| (else | |
| (cont M | |
| u | |
| v | |
| #t))) | |
| ;; here u and v are fixnums, so 2^s, which is <= u and v, is | |
| ;; also a fixnum | |
| (let ((two^s (##fxarithmetic-shift-left 1 s))) | |
| (if (##fx< u v) | |
| (if (##fx< (##fx- v u) two^s) | |
| (cont M | |
| u | |
| v | |
| #t) | |
| (let ((r (##fxremainder v u)) | |
| (q (##fxquotient v u))) | |
| (if (##fx>= r two^s) | |
| (cont (gcd-matrix-multiply-low M q) | |
| u | |
| r | |
| #f) | |
| ;; the case when q is one and the remainder is < two^s | |
| ;; is covered in the first test | |
| (cont (gcd-matrix-multiply-low M (##fx- q 1)) | |
| u | |
| (##fx+ r u) | |
| #t)))) | |
| ;; here u >= v, but the case u = v is covered by the first test | |
| (if (##fx< (##fx- u v) two^s) | |
| (cont M | |
| u | |
| v | |
| #t) | |
| (let ((r (##fxremainder u v)) | |
| (q (##fxquotient u v))) | |
| (if (##fx>= r two^s) | |
| (cont (gcd-matrix-multiply-high M q) | |
| r | |
| v | |
| #f) | |
| ;; the case when q is one and the remainder is < two^s | |
| ;; is covered in the first test | |
| (cont (gcd-matrix-multiply-high M (##fx- q 1)) | |
| (##fx+ r v) | |
| v | |
| #t)))))))) | |
| (define (gcd-middle-step cont a b h m-prime cont-needs-M?) | |
| ((lambda (cont) | |
| (if (and (x>=2^n a h) | |
| (x>=2^n b h)) | |
| (MR cont a b h cont-needs-M?) | |
| (cont gcd-matrix-identity a b))) | |
| (lambda (M x y) | |
| (let loop ((M M) | |
| (x x) | |
| (y y)) | |
| (if (or (x>=2^n x h) | |
| (x>=2^n y h)) | |
| ((lambda (cont) (gcd-small-step cont M x y m-prime)) | |
| (lambda (M x y minimal?) | |
| (if minimal? | |
| (cont M x y) | |
| (loop M x y)))) | |
| ((lambda (cont) (MR cont x y m-prime cont-needs-M?)) | |
| (lambda (M-prime alpha beta) | |
| (cont (if cont-needs-M? | |
| (if (##fx> (##fx- h m-prime) 1024) | |
| ;; here we trade off 1 multiplication | |
| ;; for 21 additions | |
| (gcd-matrix-multiply-strassen M M-prime) | |
| (gcd-matrix-multiply M M-prime)) | |
| gcd-matrix-identity) | |
| alpha | |
| beta)))))))) | |
| (define (MR cont a b m cont-needs-M?) | |
| ((lambda (cont) | |
| (if (and (x>=2^n a (##fx+ m 2)) | |
| (x>=2^n b (##fx+ m 2))) | |
| (let ((n (##fx- (##fxmax (##integer-length a) | |
| (##integer-length b)) | |
| m))) | |
| ((lambda (cont) | |
| (if (##fx<= m n) | |
| (cont m 0) | |
| (cont n (##fx- (##fx+ m 1) n)))) | |
| (lambda (m-prime p) | |
| (let ((h (##fx+ m-prime (##fxquotient n 2)))) | |
| (if (##fx< 0 p) | |
| (let ((a (##arithmetic-shift a (##fx- p))) | |
| (b (##arithmetic-shift b (##fx- p))) | |
| (a_0 (##extract-bit-field p 0 a)) | |
| (b_0 (##extract-bit-field p 0 b))) | |
| ((lambda (cont) | |
| (gcd-middle-step cont a b h m-prime #t)) | |
| (lambda (M alpha beta) | |
| (let ((M-inverse-v_0 (gcd-matrix-solve M (make-gcd-vector a_0 b_0)))) | |
| (cont (if cont-needs-M? M gcd-matrix-identity) | |
| (##+ (##arithmetic-shift alpha p) | |
| (gcd-vector_1 M-inverse-v_0)) | |
| (##+ (##arithmetic-shift beta p) | |
| (gcd-vector_2 M-inverse-v_0))))))) | |
| (gcd-middle-step cont a b h m-prime cont-needs-M?)))))) | |
| (cont gcd-matrix-identity | |
| a | |
| b))) | |
| (lambda (M alpha beta) | |
| (let loop ((M M) | |
| (alpha alpha) | |
| (beta beta) | |
| (minimal? #f)) | |
| (if minimal? | |
| (cont M alpha beta) | |
| (gcd-small-step loop M alpha beta m)))))) | |
| ((lambda (cont) | |
| (if (and (use-fast-bignum-algorithms) | |
| (##bignum? u) | |
| (##bignum? v) | |
| (x>=2^n u ##bignum.fast-gcd-size) | |
| (x>=2^n v ##bignum.fast-gcd-size)) | |
| (MR cont u v ##bignum.fast-gcd-size #f) | |
| (cont 0 u v))) | |
| (lambda (M a b) | |
| (general-base a b)))) | |
| (define (general-base a b) | |
| (if (##eqv? b 0) | |
| a | |
| (let ((rem (cdr (##exact-int.div a b ;; calculate (remainder a b) | |
| #f ;; need-quotient? | |
| #f ;; keep-dividend? | |
| )))) | |
| (if (##fixnum? b) | |
| (fixnum-base b rem) | |
| (general-base b rem))))) | |
| (define (fixnum-base a b) | |
| (##declare (not interrupts-enabled)) | |
| (if (##eqv? b 0) | |
| a | |
| (let ((a b) | |
| (b (##fxremainder a b))) | |
| (if (##eqv? b 0) | |
| a | |
| (fixnum-base b (##fxremainder a b)))))) | |
| (define (exact-gcd x y) | |
| ;; always returns an exact result, even with inexact arguments. | |
| (let ((x (cond ((##inexact? x) | |
| (##inexact->exact (##flabs x))) | |
| ((##negative? x) | |
| (##negate x)) | |
| ((##bignum? x) | |
| (##bignum.copy x)) | |
| (else ;; nonnegative fixnum | |
| x))) | |
| (y (cond ((##inexact? y) | |
| (##inexact->exact (##flabs y))) | |
| ((##negative? y) | |
| (##negate y)) | |
| ((##bignum? y) | |
| (##bignum.copy y)) | |
| (else ;; nonnegative fixnum | |
| y)))) | |
| ;; now x and y are newly allocated, so we can overwrite them if | |
| ;; necessary in general-base | |
| (cond ((##eqv? x 0) | |
| y) | |
| ((##eqv? y 0) | |
| x) | |
| ((and (##fixnum? x) (##fixnum? y)) | |
| (fixnum-base x y)) | |
| (else | |
| (##fast-gcd x y))))) | |
| (cond ((##not (##integer? x)) | |
| (type-error-on-x)) | |
| ((##not (##integer? y)) | |
| (type-error-on-y)) | |
| ((##eq? x y) | |
| (##abs x)) | |
| (else | |
| (if (and (##exact? x) (##exact? y)) | |
| (exact-gcd x y) | |
| (##exact->inexact (exact-gcd x y)))))) | |
| (define-prim-nary (gcd x y) | |
| 0 | |
| (if (##integer? x) (##abs x) '(1)) | |
| (##gcd x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-integer)) | |
| (define-prim (##lcm x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (define (exact-lcm x y) | |
| (if (or (##eqv? x 0) (##eqv? y 0)) | |
| 0 | |
| (##abs (##* (##quotient x (##gcd x y)) | |
| y)))) | |
| (define (inexact-lcm x y) | |
| (##exact->inexact | |
| (exact-lcm (##inexact->exact x) | |
| (##inexact->exact y)))) | |
| (cond ((##not (##integer? x)) | |
| (type-error-on-x)) | |
| ((##not (##integer? y)) | |
| (type-error-on-y)) | |
| (else | |
| (if (and (##exact? x) (##exact? y)) | |
| (exact-lcm x y) | |
| (inexact-lcm x y))))) | |
| (define-prim-nary (lcm x y) | |
| 1 | |
| (if (##integer? x) (##abs x) '(1)) | |
| (##lcm x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-integer)) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; numerator, denominator | |
| (define-prim (##numerator x) | |
| (define (type-error) | |
| (##fail-check-rational 1 numerator x)) | |
| (macro-number-dispatch x (type-error) | |
| x | |
| x | |
| (macro-ratnum-numerator x) | |
| (cond ((##flzero? x) | |
| x) | |
| ((macro-flonum-rational? x) | |
| (##exact->inexact (##numerator (##flonum->exact x)))) | |
| (else | |
| (type-error))) | |
| (if (macro-cpxnum-rational? x) | |
| (##numerator (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (numerator x) | |
| (macro-force-vars (x) | |
| (##numerator x))) | |
| (define-prim (##denominator x) | |
| (define (type-error) | |
| (##fail-check-rational 1 denominator x)) | |
| (macro-number-dispatch x (type-error) | |
| 1 | |
| 1 | |
| (macro-ratnum-denominator x) | |
| (if (macro-flonum-rational? x) | |
| (##exact->inexact (##denominator (##flonum->exact x))) | |
| (type-error)) | |
| (if (macro-cpxnum-rational? x) | |
| (##denominator (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (denominator x) | |
| (macro-force-vars (x) | |
| (##denominator x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; floor, ceiling, truncate, round | |
| (define-prim (##floor x) | |
| (define (type-error) | |
| (##fail-check-finite-real 1 floor x)) | |
| (macro-number-dispatch x (type-error) | |
| x | |
| x | |
| (let ((num (macro-ratnum-numerator x)) | |
| (den (macro-ratnum-denominator x))) | |
| (if (##negative? num) | |
| (##quotient (##- num (##- den 1)) den) | |
| (##quotient num den))) | |
| (if (##flfinite? x) | |
| (##flfloor x) | |
| (type-error)) | |
| (if (macro-cpxnum-real? x) | |
| (##floor (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (floor x) | |
| (macro-force-vars (x) | |
| (##floor x))) | |
| (define-prim (##ceiling x) | |
| (define (type-error) | |
| (##fail-check-finite-real 1 ceiling x)) | |
| (macro-number-dispatch x (type-error) | |
| x | |
| x | |
| (let ((num (macro-ratnum-numerator x)) | |
| (den (macro-ratnum-denominator x))) | |
| (if (##negative? num) | |
| (##quotient num den) | |
| (##quotient (##+ num (##- den 1)) den))) | |
| (if (##flfinite? x) | |
| (##flceiling x) | |
| (type-error)) | |
| (if (macro-cpxnum-real? x) | |
| (##ceiling (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (ceiling x) | |
| (macro-force-vars (x) | |
| (##ceiling x))) | |
| (define-prim (##truncate x) | |
| (define (type-error) | |
| (##fail-check-finite-real 1 truncate x)) | |
| (macro-number-dispatch x (type-error) | |
| x | |
| x | |
| (##quotient (macro-ratnum-numerator x) | |
| (macro-ratnum-denominator x)) | |
| (if (##flfinite? x) | |
| (##fltruncate x) | |
| (type-error)) | |
| (if (macro-cpxnum-real? x) | |
| (##truncate (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (truncate x) | |
| (macro-force-vars (x) | |
| (##truncate x))) | |
| (define-prim (##round x) | |
| (define (type-error) | |
| (##fail-check-finite-real 1 round x)) | |
| (macro-number-dispatch x (type-error) | |
| x | |
| x | |
| (##ratnum.round x) | |
| (if (##flfinite? x) | |
| (##flround x) | |
| (type-error)) | |
| (if (macro-cpxnum-real? x) | |
| (##round (macro-cpxnum-real x)) | |
| (type-error)))) | |
| (define-prim (round x) | |
| (macro-force-vars (x) | |
| (##round x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; rationalize | |
| (define-prim (##rationalize x y) | |
| (define (simplest-rational1 x y) | |
| (if (##< y x) | |
| (simplest-rational2 y x) | |
| (simplest-rational2 x y))) | |
| (define (simplest-rational2 x y) | |
| (cond ((##not (##< x y)) | |
| x) | |
| ((##positive? x) | |
| (simplest-rational3 x y)) | |
| ((##negative? y) | |
| (##negate (simplest-rational3 (##negate y) (##negate x)))) | |
| (else | |
| 0))) | |
| (define (simplest-rational3 x y) | |
| (let ((fx (##floor x)) | |
| (fy (##floor y))) | |
| (cond ((##not (##< fx x)) | |
| fx) | |
| ((##= fx fy) | |
| (##+ fx | |
| (##inverse | |
| (simplest-rational3 | |
| (##inverse (##- y fy)) | |
| (##inverse (##- x fx)))))) | |
| (else | |
| (##+ fx 1))))) | |
| (cond ((##not (##rational? x)) | |
| (##fail-check-finite-real 1 rationalize x y)) | |
| ((and (##flonum? y) | |
| (##fl= y (macro-inexact-+inf))) | |
| (macro-inexact-+0)) | |
| ((##not (##rational? y)) | |
| (##fail-check-real 2 rationalize x y)) | |
| ((##negative? y) | |
| (##raise-range-exception 2 rationalize x y)) | |
| ((and (##exact? x) (##exact? y)) | |
| (simplest-rational1 (##- x y) (##+ x y))) | |
| (else | |
| (let ((exact-x (##inexact->exact x)) | |
| (exact-y (##inexact->exact y))) | |
| (##exact->inexact | |
| (simplest-rational1 (##- exact-x exact-y) | |
| (##+ exact-x exact-y))))))) | |
| (define-prim (rationalize x y) | |
| (macro-force-vars (x y) | |
| (##rationalize x y))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; trigonometry and complex numbers | |
| #| | |
| The next functions are from | |
| Functions from | |
| Branch Cuts for Complex Elementary Functions | |
| or | |
| Much Ado About Nothing's Sign Bit | |
| by W. Kahan | |
| Full reference: | |
| Kahan, W: Branch cuts for complex elementary functions; or, Much ado about nothing’s sign bit. In Iserles, A., and Powell, M. (eds.), The state of the art in numerical analysis. Clarendon Press (1987) pp 165-211. | |
| Note that Kahan's paper contains two treatments of branch cuts---Section 4, which deals with arithmetic with signed zeros (like IEEE arithmetic) and Section 5, which deals with arithmetic with only unsigned zeros. The codes in the paper are only for IEEE-style arithmetic. | |
| Gambit Scheme is in a funny position, as it allows mixed-exactness complex numbers. We'll consider inexact real zeros (+0., -0.) as signed (of course), but we'll interpret exact zero (0) as unsigned. | |
| The branch cuts of all the functions considered here lie on the exact real axis or the exact imaginary axis. | |
| All of the inverse functions are defined in terms of log and sqrt, and the side of the continuity at the branch cuts is determined by the sides of continuity of those two functions. | |
| I believe that this is the same as the continuity rules that the CLHS gives for atan, asin, acos, etc., along branch cuts. | |
| Thanks to Raymond Toy for email discussions and for the code for cmucl, which gets this stuff right in the Common Lisp context. | |
| See | |
| http://140.177.205.23/InverseHyperbolicFunctions.html | |
| for a discussion of branch cuts. | |
| |# | |
| (define-prim (##cabs z) | |
| ;; As far as I can tell, this is just magic. It works, and I'm not | |
| ;; going to touch it. | |
| #| | |
| Code to compute the constants using my computable reals package. | |
| (load "exact-reals") | |
| (define r2-exact | |
| (computable-sqrt (exact->computable 2))) | |
| (define r2p1-exact | |
| (computable-+ r2-exact (exact->computable 1))) | |
| (define r2p1 | |
| (computable->inexact r2p1-exact)) | |
| (define t2p1-exact | |
| (computable-- r2p1-exact (exact->computable (inexact->exact r2p1)))) | |
| (define r2 | |
| (computable->inexact r2-exact)) | |
| (define t2p1 | |
| (computable->inexact t2p1-exact)) | |
| (for-each pretty-print | |
| `((define r2 ,r2) (define r2p1 ,r2p1) (define t2p1 ,t2p1))) | |
| |# | |
| (define r2 1.4142135623730951) | |
| (define r2p1 2.414213562373095) | |
| (define t2p1 1.2537167179050217e-16) | |
| (let ((x (##flabs (macro-cpxnum-real z))) | |
| (y (##flabs (macro-cpxnum-imag z)))) | |
| (define (continue x y) | |
| (let* ((x (if (##flinfinite? y) y x)) | |
| (t (##fl- x y))) | |
| (if (and (##not (##fl= x +inf.0)) | |
| (##not (##fl= t x))) | |
| (if (##fl> t y) | |
| (let* ((s (##fl/ x y)) | |
| (s (##fl+ s (##flsqrt (##fl+ 1.0 (##fl* s s)))))) | |
| (##fl+ x (##fl/ y s))) | |
| (let* ((s (##fl/ t y)) | |
| (t (##fl* (##fl+ 2.0 s) s)) | |
| (s (##fl+ r2p1 | |
| (##fl+ s | |
| (##fl+ t2p1 | |
| (##fl/ t | |
| (##fl+ r2 (##flsqrt (##fl+ 2.0 t))))))))) | |
| (##fl+ x (##fl/ y s)))) | |
| x))) | |
| (if (##fl< x y) | |
| (continue y x) | |
| (continue x y)))) | |
| (define-prim (##carg z) | |
| (##angle z)) | |
| (define-prim (##csquare xi+ieta) | |
| (let ((xi (macro-cpxnum-real xi+ieta)) | |
| (eta (macro-cpxnum-imag xi+ieta))) | |
| (let ((x (##fl* (##fl- xi eta) (##fl+ xi eta))) | |
| (y (##fl* 2.0 xi eta))) | |
| (cond ((##flnan? x) | |
| (cond ((##flinfinite? y) | |
| (macro-cpxnum-make (##flcopysign (macro-inexact-+0) xi) y)) | |
| ((##flinfinite? eta) | |
| (macro-cpxnum-make (macro-inexact--inf) y)) | |
| ((##flinfinite? xi) | |
| (macro-cpxnum-make (macro-inexact-+inf) y)) | |
| (else | |
| (macro-cpxnum-make x y)))) | |
| ((and (##flnan? y) | |
| (##flinfinite? x)) | |
| (macro-cpxnum-make x (##flcopysign (macro-inexact-+0) y))) | |
| (else | |
| (macro-cpxnum-make x y)))))) | |
| (define-prim (##cssqs x+iy) | |
| (let ((x (macro-cpxnum-real x+iy)) | |
| (y (macro-cpxnum-imag x+iy))) | |
| (cond ((or (##flinfinite? x) | |
| (##flinfinite? y)) | |
| (##cons (macro-inexact-+inf) 0)) | |
| ((and (##flzero? x) | |
| (##flzero? y)) | |
| (##cons 0. 0)) | |
| (else | |
| ;; from now on, neither x nor y are infinite, and one is non-zero | |
| (let* ((x^2 (##flsquare x)) | |
| (y^2 (##flsquare y)) | |
| (rho (##fl+ x^2 y^2))) | |
| (if (or (##flinfinite? rho) ;; if rho is NaN, this is false | |
| (and (or (##fl< x^2 (macro-inexact-lambda)) ;; poor man's way to see whether underflow flag was set | |
| (##fl< y^2 (macro-inexact-lambda))) | |
| (##fl< rho (##fl/ (macro-inexact-lambda) (macro-inexact-epsilon))))) ;; if rho is NaN, this is false | |
| ;; rho is not NaN, so x and y are not NaN, and x and y are not infinite. Whew. | |
| (let ((k (##flilogb (##flmax (##flabs x) (##flabs y))))) | |
| (##cons (##fl+ (##flsquare (##flscalbn x (##fx- k))) | |
| (##flsquare (##flscalbn y (##fx- k)))) | |
| k)) | |
| (##cons rho 0))))))) | |
| (define-prim (##csqrt x+iy) | |
| (let* ((x (macro-cpxnum-real x+iy)) | |
| (y (macro-cpxnum-imag x+iy)) | |
| (rho+ik (##cssqs x+iy)) | |
| (rho (##car rho+ik)) | |
| (k (##cdr rho+ik)) | |
| (rho (if (##flnan? x) | |
| rho | |
| (##fl+ (##flscalbn (##flabs x) (##fx- k)) | |
| (##flsqrt rho)))) | |
| (rho (if (##fxodd? k) | |
| (##flscalbn (##flsqrt rho) (##fxquotient (##fx- k 1) 2)) | |
| (##flscalbn (##flsqrt (##fl* 2.0 rho)) (##fx- (##fxquotient k 2) 1)))) | |
| (xi rho) | |
| (eta y)) | |
| (if (##not (##fl= rho 0.0)) | |
| (let ((eta (if (##not (##flinfinite? (##flabs eta))) | |
| (##fl/ (##fl/ eta rho) 2.0) | |
| eta))) | |
| (if (##flnegative? x) | |
| (macro-cpxnum-make (##flabs eta) (##flcopysign rho y)) | |
| (macro-cpxnum-make xi eta))) | |
| (macro-cpxnum-make xi eta)))) | |
| (define-prim (##cacos z) | |
| (##- (macro-inexact-+pi/2) (##casin z))) | |
| (define-prim (##cacosh z) | |
| (let ((sqrt-z-1 (##sqrt (##- z 1))) | |
| (sqrt-z+1 (##sqrt (##+ z 1)))) | |
| ;; if z is real and > 1, then the imaginary part of the next expression can be | |
| ;; inexact 0, but that's OK because this routine is not called in this case. | |
| (##make-rectangular (##asinh (##real-part (##* (##conjugate sqrt-z-1) sqrt-z+1))) | |
| (##* 2 (##atan2 (##imag-part sqrt-z-1) (##real-part sqrt-z+1)))))) | |
| (define-prim (##casin z) | |
| ;; if (##real-part z) is exact zero, then there is a correlation of errors in sqrt-1-z and sqrt-1+z that | |
| ;; allows the next substitution | |
| (let ((x (##real-part z))) | |
| (if (##eqv? x 0) | |
| (##make-rectangular 0 (##asinh (##imag-part z))) | |
| (let ((sqrt-1-z (##sqrt (##- 1 z))) | |
| (sqrt-1+z (##sqrt (##+ 1 z)))) | |
| (##make-rectangular (##atan2 x (##real-part (##* sqrt-1-z sqrt-1+z))) | |
| (##asinh (##imag-part (##* (##conjugate sqrt-1-z) sqrt-1+z)))))))) | |
| (define-prim (##casinh z) | |
| (##* -i (##casin (##* +i z)))) | |
| (define-prim (##catanh x+iy) | |
| (define (x/x^2+y^2 x y) | |
| (if (##fl< (##flabs y) (##flabs x)) | |
| (##fl/ 1. (##fl+ x (##fl* (##fl/ y x) y))) | |
| (let ((x/y (##fl/ x y))) | |
| (##fl/ x/y (##fl+ (##fl* x x/y) y))))) | |
| (define (##->exact-sign x) | |
| ;; returns an exact number with the same sign as x, returns 1 if x is exact zero | |
| (if (##flonum? x) | |
| (##inexact->exact (##flcopysign 1. x)) | |
| (if (##negative? x) -1 1))) | |
| (let* ((pi/2 (##* 2 (##atan 1))) | |
| (theta (##fl/ (##flsqrt (macro-inexact-omega)) 4.)) | |
| (rho (##fl/ theta)) | |
| (beta (##->exact-sign (##real-part x+iy))) ;; beta is exact | |
| (x+iy (##* beta (##conjugate x+iy))) | |
| (x (##real-part x+iy)) | |
| (y (##imag-part x+iy)) | |
| (inexact-x (##exact->inexact x)) | |
| (inexact-y (##exact->inexact y)) | |
| (abs-y (##flabs inexact-y)) | |
| (zeta (cond ((or (##fl< theta inexact-x) | |
| (##fl< theta abs-y)) | |
| (macro-cpxnum-make (##exact->inexact (x/x^2+y^2 inexact-x inexact-y)) | |
| (##flcopysign pi/2 inexact-y))) | |
| ((##fl= inexact-x 1.) | |
| (macro-cpxnum-make (##fllog (##fl/ (##flsqrt (##flsqrt (##fl+ 4. (##flsquare abs-y)))) | |
| (##flsqrt (##fl+ abs-y rho)))) | |
| (##fl/ (##flcopysign (##fl+ pi/2 (##flatan (##fl/ (##fl+ abs-y rho) 2.0))) | |
| inexact-y) | |
| 2.))) | |
| (else | |
| (macro-cpxnum-make (if (##eqv? x 0) | |
| ;; if rho and abs-y were exact in the next expression (no matter their values) | |
| ;; then the argument to fllog1p would be exact 0, so the result would be exact 0. | |
| 0 | |
| (##fl/ (##fllog1p (##fl/ (##fl* 4. inexact-x) ;; was (##* 4 x) originally | |
| (##fl+ (##flsquare (##fl- 1. inexact-x)) | |
| (##flsquare (##fl+ abs-y rho))))) | |
| 4.)) | |
| (##fl/ (##carg (macro-cpxnum-make (##fl- (##fl* (##fl- 1. inexact-x) | |
| (##fl+ 1. inexact-x)) | |
| (##flsquare (##fl+ abs-y rho))) | |
| (##fl* 2. inexact-y))) | |
| 2.0)))))) | |
| (##* beta (##conjugate zeta)))) | |
| (define-prim (##ctanh xi+ieta) | |
| ;; we assume that neither xi nor eta can be exact 0 | |
| (let* ((xi (macro-cpxnum-real xi+ieta)) | |
| (eta (macro-cpxnum-imag xi+ieta))) | |
| (if (##< (##fl/ (##flasinh (macro-inexact-omega)) 4.) | |
| (##abs xi)) | |
| (macro-cpxnum-make (##flcopysign 1. (##exact->inexact xi)) ;; xi cannot be exact 0 | |
| (##flcopysign 0. (##exact->inexact eta))) ;; eta cannot be exact 0 | |
| (let* ((t (##tan eta)) ;; sin(eta)/cos(eta), can't be exact 0, so can't be exact | |
| (beta (##fl+ 1. (##flsquare t))) ;; 1/cos^2(eta), can't be exact | |
| (s (##sinh xi)) ;; sinh(xi), can't be exact zero, so can't be exact | |
| (rho (##flsqrt (##fl+ 1. (##flsquare s))))) ;; cosh(xi), can't be exact | |
| (if (##infinite? t) ;; if sin(eta)/cos(eta) = infinity (how, I don't know) | |
| (macro-cpxnum-make (##fl/ rho s) | |
| (##fl/ t)) | |
| (let ((one+beta*s^2 (##fl+ 1. (##fl* beta (##flsquare s))))) | |
| (macro-cpxnum-make (##fl/ (##fl* beta (##fl* rho s)) | |
| one+beta*s^2) | |
| (##fl/ t | |
| one+beta*s^2)))))))) | |
| (define-prim (##ctan zeta) | |
| (##* -i (##ctanh (##* +i zeta)))) | |
| ;;; End of Kahan's functions | |
| (define-prim (##conjugate x) | |
| (define (type-error) | |
| (##fail-check-number 1 conjugate x)) | |
| (macro-number-dispatch x (type-error) | |
| x x x x (macro-cpxnum-make (macro-cpxnum-real x) | |
| (##negate (macro-cpxnum-imag x))))) | |
| (define-prim (conjugate x) | |
| (macro-force-vars (x) | |
| (##conjugate x))) | |
| (define-prim (##exp x) | |
| (define (type-error) | |
| (##fail-check-number 1 exp x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 1 | |
| (##flexp (##fixnum->flonum x))) | |
| (##flexp (##exact-int->flonum x)) | |
| (##flexp (##ratnum->flonum x)) | |
| (##flexp x) | |
| (##make-polar (##exp (macro-cpxnum-real x)) | |
| (macro-cpxnum-imag x)))) | |
| (define-prim (exp x) | |
| (macro-force-vars (x) | |
| (##exp x))) | |
| (define-prim (##flonum-full-precision? x) | |
| (let ((y (##flabs x))) | |
| (and (##fl< y (macro-inexact-+inf)) | |
| (##fl<= (macro-flonum-min-normal) y)))) | |
| (define-prim (##log x) | |
| (define (type-error) | |
| (##fail-check-number 1 log x)) | |
| (define (range-error) | |
| (##raise-range-exception 1 log x)) | |
| (define (negative-log x) | |
| (##make-rectangular (##log (##negate x)) (macro-inexact-+pi))) | |
| (define (exact-log x) | |
| ;; x is positive, x is not 1. | |
| ;; There are three places where just converting to a flonum and | |
| ;; taking the flonum logarithm doesn't work well. | |
| ;; 1. Overflow in the conversion | |
| ;; 2. Underflow in the conversion (or even loss of precision | |
| ;; because of a denormalized conversion result) | |
| ;; 3. When the number is close to 1. | |
| (let ((float-x (##exact->inexact x))) | |
| (cond ((##= x float-x) | |
| (##fllog float-x)) ;; first, we trust the builtin flonum log | |
| ((##not (##flonum-full-precision? float-x)) | |
| ;; direct conversion to flonum could incur massive relative | |
| ;; rounding errors, or would just lead to an infinite result | |
| ;; so we tolerate more than one rounding error in the calculation | |
| (let* ((wn (##integer-length (##numerator x))) | |
| (wd (##integer-length (##denominator x))) | |
| (p (##fx- wn wd)) | |
| (float-p (##fixnum->flonum p)) | |
| (partial-result (##fllog | |
| (##exact->inexact | |
| (##* x (##expt 2 (##fx- p))))))) | |
| (##fl+ (##fl* float-p | |
| (macro-inexact-log-2)) | |
| partial-result))) | |
| ((or (##fl< (macro-inexact-exp-+1/2) float-x) | |
| (##fl< float-x (macro-inexact-exp--1/2))) | |
| ;; here the absolute value of the logarithm is at least 0.5, | |
| ;; so there is less rounding error in the final result. | |
| (##fllog float-x)) | |
| (else | |
| ;; use ln1p for arguments near one. | |
| (##fllog1p (##exact->inexact (##- x 1))))))) | |
| (define (complex-log-magnitude x) | |
| (define (log-mag a b) | |
| ;; both are finite, 0 <= a <= b, b is nonzero | |
| (let* ((c (##/ a b)) | |
| (approx-mag (##* b (##sqrt (##+ 1 (##* c c)))))) | |
| (if (or (##exact? approx-mag) | |
| (and (##flonum-full-precision? approx-mag) | |
| (or (##fl< (macro-inexact-exp-+1/2) approx-mag) | |
| (##fl< approx-mag (macro-inexact-exp--1/2))))) | |
| ;; log composed with magnitude will compute a relatively accurate answer | |
| (##log approx-mag) | |
| (let ((a (##inexact->exact a)) | |
| (b (##inexact->exact b))) | |
| (##* 1/2 (exact-log (##+ (##* a a) (##* b b)))))))) | |
| (let ((abs-r (##abs (##real-part x))) | |
| (abs-i (##abs (##imag-part x)))) | |
| ;; abs-i is not exact 0 | |
| (cond ((or (and (##flonum? abs-r) | |
| (##fl= abs-r (macro-inexact-+inf))) | |
| (and (##flonum? abs-i) | |
| (##fl= abs-i (macro-inexact-+inf)))) | |
| (macro-inexact-+inf)) | |
| ;; neither abs-r or abs-i is infinite | |
| ((and (##flonum? abs-r) | |
| (##flnan? abs-r)) | |
| abs-r) | |
| ;; abs-r is not a NaN | |
| ((and (##flonum? abs-i) | |
| (##flnan? abs-i)) | |
| abs-i) | |
| ;; abs-i is not a NaN | |
| ((##eqv? abs-r 0) | |
| (##log abs-i)) | |
| ;; abs-r is not exact 0 | |
| ((and (##zero? abs-r) | |
| (##zero? abs-i)) | |
| (macro-inexact--inf)) | |
| ;; abs-i and abs-r are not both zero | |
| (else | |
| (if (##< abs-r abs-i) | |
| (log-mag abs-r abs-i) | |
| (log-mag abs-i abs-r)))))) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| (range-error) | |
| (if (##fxnegative? x) | |
| (negative-log x) | |
| (if (##eqv? x 1) | |
| 0 | |
| (exact-log x)))) | |
| (if (##bignum.negative? x) | |
| (negative-log x) | |
| (exact-log x)) | |
| (if (##negative? (macro-ratnum-numerator x)) | |
| (negative-log x) | |
| (exact-log x)) | |
| (if (or (##flnan? x) | |
| (##not (##flnegative? | |
| (##flcopysign (macro-inexact-+1) x)))) | |
| (##fllog x) | |
| (negative-log x)) | |
| (##make-rectangular (complex-log-magnitude x) (##angle x)))) | |
| (define-prim (log x) | |
| (macro-force-vars (x) | |
| (##log x))) | |
| (define-prim (##sin x) | |
| (define (type-error) | |
| (##fail-check-number 1 sin x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 0 | |
| (##flsin (##fixnum->flonum x))) | |
| (##flsin (##exact-int->flonum x)) | |
| (##flsin (##ratnum->flonum x)) | |
| (##flsin x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (and (##flonum? real) | |
| (##flonum? imag)) | |
| ;; fast path for flonums case | |
| (macro-cpxnum-make (##fl* (##flsin real) (##flcosh imag)) | |
| (##fl* (##flcos real) (##flsinh imag))) | |
| (##make-rectangular (##* (##sin real) (##cosh imag)) | |
| (##* (##cos real) (##sinh imag))))))) | |
| (define-prim (sin x) | |
| (macro-force-vars (x) | |
| (##sin x))) | |
| (define-prim (##cos x) | |
| (define (type-error) | |
| (##fail-check-number 1 cos x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 1 | |
| (##flcos (##fixnum->flonum x))) | |
| (##flcos (##exact-int->flonum x)) | |
| (##flcos (##ratnum->flonum x)) | |
| (##flcos x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (and (##flonum? real) | |
| (##flonum? imag)) | |
| ;; fast path for flonums case | |
| (macro-cpxnum-make (##fl* (##flcos real) (##flcosh imag)) | |
| (##fl- (##fl* (##flsin real) (##flsinh imag)))) | |
| (##make-rectangular (##* (##cos real) (##cosh imag)) | |
| (##negate (##* (##sin real) (##sinh imag)))))))) | |
| (define-prim (cos x) | |
| (macro-force-vars (x) | |
| (##cos x))) | |
| (define-prim (##tan x) | |
| (define (type-error) | |
| (##fail-check-number 1 tan x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 0 | |
| (##fltan (##fixnum->flonum x))) | |
| (##fltan (##exact-int->flonum x)) | |
| (##fltan (##ratnum->flonum x)) | |
| (##fltan x) | |
| ;; complex ##tanh is the basic one here. | |
| (##* -i (##tanh (##* +i x))))) | |
| (define-prim (tan x) | |
| (macro-force-vars (x) | |
| (##tan x))) | |
| (define-prim (##asin x) | |
| (define (type-error) | |
| (##fail-check-number 1 asin x)) | |
| (define (real-case x) | |
| (if (or (##< 1 x) | |
| (##< x -1)) | |
| (##casin (macro-cpxnum-make x 0)) | |
| (##flasin (##exact->inexact x)))) | |
| (macro-number-dispatch x (type-error) | |
| (if (##eqv? x 0) | |
| 0 | |
| (real-case x)) | |
| (real-case x) | |
| (real-case x) | |
| (real-case x) | |
| (##casin x))) | |
| (define-prim (asin x) | |
| (macro-force-vars (x) | |
| (##asin x))) | |
| (define-prim (##acos x) | |
| (define (type-error) | |
| (##fail-check-number 1 acos x)) | |
| (define (real-case x) | |
| (if (or (##< 1 x) | |
| (##< x -1)) | |
| (##cacos (macro-cpxnum-make x 0)) | |
| (##flacos (##exact->inexact x)))) | |
| (macro-number-dispatch x (type-error) | |
| (if (##eqv? x 1) | |
| 0 | |
| (real-case x)) | |
| (real-case x) | |
| (real-case x) | |
| (real-case x) | |
| (##cacos x))) | |
| (define-prim (acos x) | |
| (macro-force-vars (x) | |
| (##acos x))) | |
| (define-prim (##atan x) | |
| (define (type-error) | |
| (##fail-check-number 1 atan x)) | |
| (define (range-error) | |
| (##raise-range-exception 1 atan x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 0 | |
| (##flatan (##fixnum->flonum x))) | |
| (##flatan (##exact-int->flonum x)) | |
| (##flatan (##ratnum->flonum x)) | |
| (##flatan x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (and (##eqv? real 0) | |
| (or (##eqv? imag 1) | |
| (##eqv? imag -1))) | |
| (range-error) | |
| (##* -i (##atanh (##* +i x))))))) | |
| (define-prim (##atan2 y x) | |
| (cond ((or (and (##flonum? x) (##flnan? x)) | |
| (and (##flonum? y) (##flnan? y))) | |
| +nan.0) | |
| ((##eqv? 0 y) | |
| (if (##exact? x) | |
| (if (##negative? x) | |
| (macro-inexact-+pi) | |
| 0) | |
| (if (##negative? (##flcopysign (macro-inexact-+1) x)) | |
| (macro-inexact-+pi) | |
| 0.))) | |
| ((and (##not (##finite? x)) | |
| (##not (##finite? y))) | |
| (if (##positive? x) | |
| (##flcopysign (macro-inexact-+pi/4) y) | |
| (##flcopysign (macro-inexact-+3pi/4) y))) | |
| (else | |
| (let ((inexact-x (##exact->inexact x)) | |
| (inexact-y (##exact->inexact y))) | |
| (if (and (or (##flonum? x) | |
| (##flonum-full-precision? inexact-x) | |
| (##= x inexact-x)) | |
| (or (##flonum? y) | |
| (##flonum-full-precision? inexact-y) | |
| (##= y inexact-y))) | |
| (##flatan inexact-y inexact-x) | |
| ;; at least one of x or y is nonzero | |
| ;; and at least one of them is not a flonum | |
| (let* ((exact-x (##inexact->exact x)) | |
| (exact-y (##inexact->exact y)) | |
| (max-arg (##max (##abs exact-x) | |
| (##abs exact-y))) | |
| (normalizer (##expt 2 (##- (##integer-length (##denominator max-arg)) | |
| (##integer-length (##numerator max-arg)))))) | |
| ;; now the largest argument will be about 1. | |
| (##flatan (##exact->inexact (##* normalizer exact-y)) | |
| (##exact->inexact (##* normalizer exact-x))))))))) | |
| (define-prim (atan x #!optional (y (macro-absent-obj))) | |
| (macro-force-vars (x) | |
| (if (##eq? y (macro-absent-obj)) | |
| (##atan x) | |
| (macro-force-vars (y) | |
| (cond ((##not (##real? x)) | |
| (##fail-check-real 1 atan x y)) | |
| ((##not (##real? y)) | |
| (##fail-check-real 2 atan x y)) | |
| (else | |
| (##atan2 x y))))))) | |
| ;;; Hyperbolic functions | |
| (define-prim (##sinh x) | |
| (define (type-error) | |
| (##fail-check-number 1 sinh x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 0 | |
| (##flsinh (##fixnum->flonum x))) | |
| (##flsinh (##exact-int->flonum x)) | |
| (##flsinh (##ratnum->flonum x)) | |
| (##flsinh x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (and (##flonum? real) (##flonum? imag)) | |
| ;; fast path for flonum case | |
| (macro-cpxnum-make (##fl* (##flsinh real) (##flcos imag)) | |
| (##fl* (##flcosh real) (##flsin imag))) | |
| (macro-cpxnum-make (##* (##sinh real) (##cos imag)) | |
| (##* (##cosh real) (##sin imag))))))) | |
| (define-prim (sinh x) | |
| (macro-force-vars (x) | |
| (##sinh x))) | |
| (define-prim (##cosh x) | |
| (define (type-error) | |
| (##fail-check-number 1 cosh x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 1 | |
| (##flcosh (##fixnum->flonum x))) | |
| (##flcosh (##exact-int->flonum x)) | |
| (##flcosh (##ratnum->flonum x)) | |
| (##flcosh x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (and (##flonum? real) (##flonum? imag)) | |
| ;; fast path for flonum case | |
| (macro-cpxnum-make (##fl* (##flcosh real) (##flcos imag)) | |
| (##fl* (##flsinh real) (##flsin imag))) | |
| (macro-cpxnum-make (##* (##cosh real) (##cos imag)) | |
| (##* (##sinh real) (##sin imag))))))) | |
| (define-prim (cosh x) | |
| (macro-force-vars (x) | |
| (##cosh x))) | |
| (define-prim (##tanh x) | |
| (define (type-error) | |
| (##fail-check-number 1 tanh x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 0 | |
| (##fltanh (##fixnum->flonum x))) | |
| (##fltanh (##exact-int->flonum x)) | |
| (##fltanh (##ratnum->flonum x)) | |
| (##fltanh x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (##eqv? real 0) | |
| ;; the argument of the next ##tan is real | |
| ;; (##* +i (##tan (##* -i x))) | |
| (macro-cpxnum-make 0 (##tan imag)) | |
| (##ctanh x))))) | |
| (define-prim (tanh x) | |
| (macro-force-vars (x) | |
| (##tanh x))) | |
| ;;; Inverse hyperbolic functions | |
| (define-prim (##asinh x) | |
| (define (type-error) | |
| (##fail-check-number 1 asinh x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxzero? x) | |
| 0 | |
| (##flasinh (##fixnum->flonum x))) | |
| (##flasinh (##exact-int->flonum x)) | |
| (##flasinh (##ratnum->flonum x)) | |
| (##flasinh x) | |
| (##casinh x))) | |
| (define-prim (asinh x) | |
| (macro-force-vars (x) | |
| (##asinh x))) | |
| (define-prim (##acosh x) | |
| (define (type-error) | |
| (##fail-check-number 1 acosh x)) | |
| (define (real-case x) | |
| (if (##< x 1) | |
| (##cacosh (macro-cpxnum-make x 0)) | |
| (##flacosh (##exact->inexact x)))) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fx= x 1) | |
| 0 | |
| (real-case x)) | |
| (real-case x) | |
| (real-case x) | |
| (real-case x) | |
| (##cacosh x))) | |
| (define-prim (acosh x) | |
| (macro-force-vars (x) | |
| (##acosh x))) | |
| (define-prim (##atanh x) | |
| (define (type-error) | |
| (##fail-check-number 1 atanh x)) | |
| (define (range-error) | |
| (##raise-range-exception 1 atanh x)) | |
| (define (real-case x) | |
| (cond ((##< 1 x) | |
| (##negate (real-case (##negate x)))) | |
| ((##< x -1) | |
| (##make-rectangular (##fl/ (##fllog1p (##exact->inexact (##/ (##* 4 x) | |
| (##square (##- x 1))))) | |
| 4.) | |
| (macro-inexact-+pi/2))) | |
| (else | |
| (##flatanh (##exact->inexact x))))) | |
| (macro-number-dispatch x (type-error) | |
| (case x | |
| ((0) | |
| 0) | |
| ((-1 1) | |
| (range-error)) | |
| (else | |
| (real-case x))) | |
| (real-case x) | |
| (real-case x) | |
| (real-case x) | |
| (##catanh x))) | |
| (define-prim (atanh x) | |
| (macro-force-vars (x) | |
| (##atanh x))) | |
| (define-prim (##sqrt x) | |
| (define (type-error) | |
| (##fail-check-number 1 sqrt x)) | |
| (define (exact-int-sqrt x) | |
| (if (##negative? x) | |
| (##make-rectangular 0 (exact-int-sqrt (##negate x))) | |
| (let ((y (##exact-int.sqrt x))) | |
| (cond ((##eqv? (##cdr y) 0) | |
| (##car y)) | |
| ((##not (##exact-int.< (macro-flonum-+m-max-plus-1) x)) | |
| ;; 0 <= x <= (macro-flonum-+m-max-plus-1), can be | |
| ;; converted to flonum exactly so avoids double | |
| ;; rounding in next expression. This has a relatively | |
| ;; fast path for small integers. | |
| (##flsqrt (##exact-int->flonum x))) | |
| ((##not (##< (##car y) (macro-flonum-+m-max-plus-1))) | |
| ;; ##exact-int->flonum uses second argument correctly | |
| (##exact-int->flonum (##car y) #t)) | |
| (else | |
| ;; The integer part of y does not have enough bits accuracy | |
| ;; to round it correctly to a flonum, so to | |
| ;; make sure (##car y) is big enough in the next call we | |
| ;; multiply by (expt 2 (macro-flonum-m-bits-plus-1*2)), | |
| ;; which is somewhat extravagant; | |
| ;; (expt 2 (+ 1 (macro-flonum-m-bits-plus-1))) should | |
| ;; work fine. | |
| (##fl* (macro-flonum-inverse-+m-max-plus-1-inexact) | |
| (exact-int-sqrt | |
| (##arithmetic-shift | |
| x | |
| (macro-flonum-m-bits-plus-1*2))))))))) | |
| (define (ratnum-sqrt x) | |
| (if (##negative? x) | |
| (##make-rectangular 0 (ratnum-sqrt (##negate x))) | |
| (let ((p (macro-ratnum-numerator x)) | |
| (q (macro-ratnum-denominator x))) | |
| (let ((sqrt-p (##exact-int.sqrt p)) | |
| (sqrt-q (##exact-int.sqrt q))) | |
| (if (and (##zero? (##cdr sqrt-p)) | |
| (##zero? (##cdr sqrt-q))) | |
| ;; both (abs p) and q are perfect squares and | |
| ;; their square roots do not have any common factors | |
| (macro-ratnum-make (##car sqrt-p) | |
| (##car sqrt-q)) | |
| (let ((wp (##integer-length p)) | |
| (wq (##integer-length q))) | |
| ;; for IEEE 754 double precision, we need at least | |
| ;; 53 or 54 (I can't seem to work it out) of the | |
| ;; leading bits of (sqrt (/ p q)). Here we get | |
| ;; about 64 leading bits. We just shift p (either | |
| ;; right or left) until it is about 128 bits longer | |
| ;; than q (shift must be even), then take the | |
| ;; integer square root of the result. | |
| (let* ((shift | |
| (##fxarithmetic-shift-left | |
| (##fxarithmetic-shift-right | |
| (##fx- 128 (##fx- wp wq)) | |
| 1) | |
| 1)) | |
| (leading-bits | |
| (##car | |
| (##exact-int.sqrt | |
| (##quotient | |
| (##arithmetic-shift p shift) | |
| q)))) | |
| (pre-rounded-result | |
| (if (##fxnegative? shift) | |
| (##arithmetic-shift | |
| leading-bits | |
| (##fx- | |
| (##fxarithmetic-shift-right | |
| shift | |
| 1))) | |
| (##ratnum.normalize | |
| leading-bits | |
| (##arithmetic-shift | |
| 1 | |
| (##fxarithmetic-shift-right | |
| shift | |
| 1)))))) | |
| (if (##ratnum? pre-rounded-result) | |
| (##ratnum->flonum pre-rounded-result #t) | |
| (##exact-int->flonum pre-rounded-result #t))))))))) | |
| (macro-number-dispatch x (type-error) | |
| (exact-int-sqrt x) | |
| (exact-int-sqrt x) | |
| (ratnum-sqrt x) | |
| (if (##flnegative? x) | |
| (##make-rectangular 0 (##flsqrt (##fl- x))) | |
| (##flsqrt x)) | |
| (let ((real (##real-part x)) | |
| (imag (##imag-part x))) | |
| (cond ((and (##exact? real) | |
| (##exact? imag) | |
| (let ((discriminant (##sqrt (##+ (##* real real) | |
| (##* imag imag))))) | |
| (and (##exact? discriminant) | |
| (let ((result-real (##sqrt (##/ (##+ real discriminant) 2)))) | |
| (and (##exact? result-real) | |
| (##make-rectangular result-real (##/ imag (##* 2 result-real)))))))) | |
| => | |
| values) | |
| (else | |
| (##csqrt (##exact->inexact x))))))) | |
| (define-prim (sqrt x) | |
| (macro-force-vars (x) | |
| (##sqrt x))) | |
| (define-prim (##expt x y) | |
| (define (exact-int-expt x y) | |
| (define (positive-int-expt x y) | |
| ;; x is an exact number and y is a positive exact integer | |
| (define (square x) | |
| (##* x x)) | |
| (define (expt-aux x y) | |
| ;; x is an exact integer (not 0 or 1) and y is a nonzero exact integer | |
| (if (##eqv? y 1) | |
| x | |
| (let ((temp (square (expt-aux x (##arithmetic-shift y -1))))) | |
| (if (##even? y) | |
| temp | |
| (##* x temp))))) | |
| (cond ((or (##eqv? x 0) | |
| (##eqv? x 1)) | |
| x) | |
| ((eqv? x -1) | |
| (if (##odd? y) | |
| -1 | |
| 1)) | |
| ((##ratnum? x) | |
| (macro-ratnum-make | |
| (exact-int-expt (macro-ratnum-numerator x) y) | |
| (exact-int-expt (macro-ratnum-denominator x) y))) | |
| (else | |
| (expt-aux x y)))) | |
| (define (invert z) | |
| ;; z is exact | |
| (let ((result (##inverse z))) | |
| (if (##not result) | |
| (##raise-range-exception 1 expt x y) | |
| result))) | |
| (if (##negative? y) | |
| (invert (positive-int-expt x (##negate y))) | |
| (positive-int-expt x y))) | |
| (define (complex-expt x y) | |
| (##exp (##* (##log x) y))) | |
| (define (ratnum-expt x y) | |
| ;; x is exact-int or ratnum | |
| (cond ((##eqv? x 0) | |
| (if (##negative? y) | |
| (##raise-range-exception 1 expt x y) | |
| 0)) | |
| ((##eqv? x 1) | |
| 1) | |
| ((##negative? x) | |
| ;; We'll do some nice multiples of angles of pi carefully | |
| (case (macro-ratnum-denominator y) | |
| ((2) | |
| (##* (##expt (##negate x) y) | |
| (case (##modulo (macro-ratnum-numerator y) 4) | |
| ((1) | |
| (macro-cpxnum-+i)) | |
| (else ;; (3) | |
| (macro-cpxnum--i))))) | |
| ((3) | |
| (##* (##expt (##negate x) y) | |
| (case (##modulo (macro-ratnum-numerator y) 6) | |
| ((1) | |
| (macro-cpxnum-+1/2+sqrt3/2i)) | |
| ((2) | |
| (macro-cpxnum--1/2+sqrt3/2i)) | |
| ((4) | |
| (macro-cpxnum--1/2-sqrt3/2i)) | |
| (else ;; (5) | |
| (macro-cpxnum-+1/2-sqrt3/2i))))) | |
| ((6) | |
| (##* (##expt (##negate x) y) | |
| (case (##modulo (macro-ratnum-numerator y) 12) | |
| ((1) | |
| (macro-cpxnum-+sqrt3/2+1/2i)) | |
| ((5) | |
| (macro-cpxnum--sqrt3/2+1/2i)) | |
| ((7) | |
| (macro-cpxnum--sqrt3/2-1/2i)) | |
| (else ;; (11) | |
| (macro-cpxnum-+sqrt3/2-1/2i))))) | |
| ;; otherwise, we punt | |
| (else | |
| (complex-expt x y)))) | |
| ((or (##fixnum? x) | |
| (##bignum? x)) | |
| (let* ((y-den (macro-ratnum-denominator y)) | |
| (temp (##exact-int.nth-root x y-den))) | |
| (if (##= x (exact-int-expt temp y-den)) | |
| (exact-int-expt temp (macro-ratnum-numerator y)) | |
| (##flexpt (##exact-int->flonum x) | |
| (##ratnum->flonum y))))) | |
| (else | |
| ;; x is a ratnum | |
| (let ((x-num (macro-ratnum-numerator x)) | |
| (x-den (macro-ratnum-denominator x)) | |
| (y-num (macro-ratnum-numerator y)) | |
| (y-den (macro-ratnum-denominator y))) | |
| (let ((temp-num (##exact-int.nth-root x-num y-den))) | |
| (if (##= (exact-int-expt temp-num y-den) x-num) | |
| (let ((temp-den (##exact-int.nth-root x-den y-den))) | |
| (if (##= (exact-int-expt temp-den y-den) x-den) | |
| (exact-int-expt (macro-ratnum-make temp-num temp-den) | |
| y-num) | |
| (##flexpt (##ratnum->flonum x) | |
| (##ratnum->flonum y)))) | |
| (##flexpt (##ratnum->flonum x) | |
| (##ratnum->flonum y)))))))) | |
| (macro-number-dispatch y (##fail-check-number 2 expt x y) | |
| (macro-number-dispatch x (##fail-check-number 1 expt x y) ;; y a fixnum | |
| (if (##fx= y 0) | |
| 1 | |
| (exact-int-expt x y)) | |
| (if (##fx= y 0) | |
| 1 | |
| (exact-int-expt x y)) | |
| (if (##fx= y 0) | |
| 1 | |
| (exact-int-expt x y)) | |
| (cond ((##fx= y 0) | |
| 1) | |
| ((##flnan? x) | |
| x) | |
| ((##flnegative? x) | |
| ;; we do this because (##fixnum->flonum y) is always | |
| ;; even for large enough y on 64-bit machines | |
| (let ((abs-result | |
| (##flexpt (##fl- x) (##fixnum->flonum y)))) | |
| (if (##fxodd? y) | |
| (##fl- abs-result) | |
| abs-result))) | |
| (else | |
| (##flexpt x (##fixnum->flonum y)))) | |
| (cond ((##fx= y 0) | |
| 1) | |
| ((##fx= y 1) | |
| x) | |
| ((##exact? x) | |
| (exact-int-expt x y)) | |
| (else | |
| (complex-expt x y)))) | |
| (macro-number-dispatch x (##fail-check-number 1 expt x y) ;; y a bignum | |
| (exact-int-expt x y) | |
| (exact-int-expt x y) | |
| (exact-int-expt x y) | |
| (cond ((##flnan? x) | |
| x) | |
| ((##flnegative? x) | |
| ;; we do this because (##exact-int->flonum y) is always | |
| ;; even for large enough y | |
| (let ((abs-result | |
| (##flexpt (##fl- x) (##exact-int->flonum y)))) | |
| (if (##odd? y) | |
| (##fl- abs-result) | |
| abs-result))) | |
| (else | |
| (##flexpt x (##exact-int->flonum y)))) | |
| (if (##exact? x) | |
| (exact-int-expt x y) | |
| (complex-expt x y))) | |
| (macro-number-dispatch x (##fail-check-number 1 expt x y) ;; y a ratnum | |
| (ratnum-expt x y) | |
| (ratnum-expt x y) | |
| (ratnum-expt x y) | |
| (cond ((##flnan? x) | |
| x) | |
| ((##flnegative? x) | |
| (if (##eqv? 2 (macro-ratnum-denominator y)) | |
| (let ((magnitude (##flexpt (##fl- x) (##ratnum->flonum y)))) | |
| (if (##eqv? 1 (##modulo (macro-ratnum-numerator y) 4)) | |
| ;; multiple of i | |
| (macro-cpxnum-make 0 magnitude) | |
| ;; multiple of -i | |
| (macro-cpxnum-make 0 (##fl- magnitude)))) | |
| (complex-expt x y))) | |
| (else | |
| (##flexpt x (##ratnum->flonum y)))) | |
| (or (and (##eqv? 2 (macro-ratnum-denominator y)) | |
| (or (and (##eqv? 1 (macro-ratnum-numerator y)) | |
| (##sqrt x)) | |
| (and (##exact? x) | |
| (let ((sqrt-x (##sqrt x))) | |
| (and (##exact? sqrt-x) | |
| (##* sqrt-x (##expt x (##quotient (##- (macro-ratnum-numerator y) 1) 2)))))))) | |
| (complex-expt x y))) | |
| (macro-number-dispatch x (##fail-check-number 1 expt x y) ;; y a flonum | |
| (cond ((##flnan? y) | |
| y) | |
| ((##eqv? x 0) | |
| (if (##flnegative? y) | |
| (##raise-range-exception 1 expt x y) | |
| 0.)) | |
| ((or (##fxpositive? x) | |
| (macro-flonum-int? y)) | |
| (##flexpt (##fixnum->flonum x) y)) | |
| (else | |
| (complex-expt x y))) | |
| (cond ((##flnan? y) | |
| y) | |
| ((or (##positive? x) | |
| (macro-flonum-int? y)) | |
| (##flexpt (##exact-int->flonum x) y)) | |
| (else | |
| (complex-expt x y))) | |
| (cond ((##flnan? y) | |
| y) | |
| ((or (##positive? x) | |
| (macro-flonum-int? y)) | |
| (##flexpt (##ratnum->flonum x) y)) | |
| (else | |
| (complex-expt x y))) | |
| (cond ((##flnan? x) | |
| x) | |
| ((##flnan? y) | |
| y) | |
| ((or (##flpositive? x) | |
| (macro-flonum-int? y)) | |
| (##flexpt x y)) | |
| (else | |
| (complex-expt x y))) | |
| (cond ((##flnan? y) | |
| y) | |
| (else | |
| (complex-expt x y)))) | |
| (macro-number-dispatch x (##fail-check-number 1 expt x y) ;; y a cpxnum | |
| (if (##eqv? x 0) | |
| (let ((real (##real-part y))) | |
| (if (##positive? real) | |
| 0 | |
| ;; If we call (complex-expt 0 y), | |
| ;; we'll try to take (##log 0) in complex-expt, | |
| ;; so we raise the exception here. | |
| (##raise-range-exception 1 expt x y))) | |
| (complex-expt x y)) | |
| (complex-expt x y) | |
| (complex-expt x y) | |
| (complex-expt x y) | |
| (complex-expt x y)))) | |
| (define-prim (expt x y) | |
| (macro-force-vars (x y) | |
| (##expt x y))) | |
| (define-prim (##make-rectangular x y) | |
| (cond ((##not (##real? x)) | |
| (##fail-check-real 1 make-rectangular x y)) | |
| ((##not (##real? y)) | |
| (##fail-check-real 2 make-rectangular x y)) | |
| (else | |
| (let ((real (##real-part x)) | |
| (imag (##real-part y))) | |
| (if (##eqv? imag 0) | |
| real | |
| (macro-cpxnum-make real imag)))))) | |
| (define-prim (make-rectangular x y) | |
| (macro-force-vars (x y) | |
| (##make-rectangular x y))) | |
| (define-prim (##make-polar x y) | |
| (cond ((##not (##real? x)) | |
| (##fail-check-real 1 make-polar x y)) | |
| ((##not (##real? y)) | |
| (##fail-check-real 2 make-polar x y)) | |
| (else | |
| (let ((real-x (##real-part x)) | |
| (real-y (##real-part y))) | |
| (##make-rectangular (##* real-x (##cos real-y)) | |
| (##* real-x (##sin real-y))))))) | |
| (define-prim (make-polar x y) | |
| (macro-force-vars (x y) | |
| (##make-polar x y))) | |
| (define-prim (##real-part x) | |
| (define (type-error) | |
| (##fail-check-number 1 real-part x)) | |
| (macro-number-dispatch x (type-error) | |
| x x x x (macro-cpxnum-real x))) | |
| (define-prim (real-part x) | |
| (macro-force-vars (x) | |
| (##real-part x))) | |
| (define-prim (##imag-part x) | |
| (define (type-error) | |
| (##fail-check-number 1 imag-part x)) | |
| (macro-number-dispatch x (type-error) | |
| 0 0 0 0 (macro-cpxnum-imag x))) | |
| (define-prim (imag-part x) | |
| (macro-force-vars (x) | |
| (##imag-part x))) | |
| (define-prim (##magnitude x) | |
| (define (type-error) | |
| (##fail-check-number 1 magnitude x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxnegative? x) (##negate x) x) | |
| (if (##bignum.negative? x) (##negate x) x) | |
| (if (##exact-int.negative? (macro-ratnum-numerator x)) | |
| (macro-ratnum-make (##negate (macro-ratnum-numerator x)) | |
| (macro-ratnum-denominator x)) | |
| x) | |
| (##flabs x) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (cond ((and (##flonum? real) (##flonum? imag)) | |
| (##cabs x)) | |
| ;; at least one of real or imag is exact | |
| ((and (##exact? real) (##exact? imag)) | |
| (##sqrt (##+ (##square real) (##square imag)))) | |
| ;; one is exact, other is inexact | |
| ((and (##finite? real) (##finite? imag)) | |
| (##exact->inexact (##sqrt (##+ (##square (##inexact->exact real)) | |
| (##square (##inexact->exact imag)))))) | |
| ;; one is exact, other is not finite inexact | |
| (else | |
| (##cabs (macro-cpxnum-make (##exact->inexact real) | |
| (##exact->inexact imag)))))))) | |
| (define-prim (magnitude x) | |
| (macro-force-vars (x) | |
| (##magnitude x))) | |
| (define-prim (##angle x) | |
| (define (type-error) | |
| (##fail-check-number 1 angle x)) | |
| (macro-number-dispatch x (type-error) | |
| (if (##fxnegative? x) | |
| (macro-inexact-+pi) | |
| 0) | |
| (if (##bignum.negative? x) | |
| (macro-inexact-+pi) | |
| 0) | |
| (if (##negative? (macro-ratnum-numerator x)) | |
| (macro-inexact-+pi) | |
| 0) | |
| (if (##flnegative? (##flcopysign (macro-inexact-+1) x)) | |
| (macro-inexact-+pi) | |
| (macro-inexact-+0)) | |
| (##atan2 (macro-cpxnum-imag x) (macro-cpxnum-real x)))) | |
| (define-prim (angle x) | |
| (macro-force-vars (x) | |
| (##angle x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; exact->inexact, inexact->exact | |
| (define-prim (##exact->inexact x) | |
| (define (type-error) | |
| (##fail-check-number 1 exact->inexact x)) | |
| (macro-number-dispatch x (type-error) | |
| (##fixnum->flonum x) | |
| (##exact-int->flonum x) | |
| (##ratnum->flonum x) | |
| x | |
| (##make-rectangular (##exact->inexact (macro-cpxnum-real x)) | |
| (##exact->inexact (macro-cpxnum-imag x))))) | |
| (define-prim (exact->inexact x) | |
| (macro-force-vars (x) | |
| (##exact->inexact x))) | |
| (define-prim (##inexact->exact x) | |
| (define (type-error) | |
| (##fail-check-number 1 inexact->exact x)) | |
| (define (range-error) | |
| (##raise-range-exception 1 inexact->exact x)) | |
| (macro-number-dispatch x (type-error) | |
| x | |
| x | |
| x | |
| (if (macro-flonum-rational? x) | |
| (##flonum->exact x) | |
| (range-error)) | |
| (let ((real (macro-cpxnum-real x)) | |
| (imag (macro-cpxnum-imag x))) | |
| (if (and (macro-noncpxnum-rational? real) | |
| (macro-noncpxnum-rational? imag)) | |
| (##make-rectangular (##inexact->exact real) | |
| (##inexact->exact imag)) | |
| (range-error))))) | |
| (define-prim (inexact->exact x) | |
| (macro-force-vars (x) | |
| (##inexact->exact x))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; number->string, string->number | |
| (define-prim (##exact-int->string x rad force-sign?) | |
| (##define-macro (macro-make-block-size) | |
| (let* ((max-rad 16) | |
| (t (make-vector (+ max-rad 1) 0))) | |
| (define max-fixnum 536870911) ;; OK to be conservative | |
| (define (block-size-for rad) | |
| (let loop ((i 0) (rad^i 1)) | |
| (let ((new-rad^i (* rad^i rad))) | |
| (if (<= new-rad^i max-fixnum) | |
| (loop (+ i 1) new-rad^i) | |
| i)))) | |
| (let loop ((i max-rad)) | |
| (if (< 1 i) | |
| (begin | |
| (vector-set! t i (block-size-for i)) | |
| (loop (- i 1))))) | |
| `',t)) | |
| (define block-size (macro-make-block-size)) | |
| (##define-macro (macro-make-rad^block-size) | |
| (let* ((max-rad 16) | |
| (t (make-vector (+ max-rad 1) 0))) | |
| (define max-fixnum 536870911) ;; OK to be conservative | |
| (define (rad^block-size-for rad) | |
| (let loop ((i 0) (rad^i 1)) | |
| (let ((new-rad^i (* rad^i rad))) | |
| (if (<= new-rad^i max-fixnum) | |
| (loop (+ i 1) new-rad^i) | |
| rad^i)))) | |
| (let loop ((i max-rad)) | |
| (if (< 1 i) | |
| (begin | |
| (vector-set! t i (rad^block-size-for i)) | |
| (loop (- i 1))))) | |
| `',t)) | |
| (define rad^block-size (macro-make-rad^block-size)) | |
| (define (make-string-from-last-fixnum rad x len pos) | |
| (let loop ((x x) (len len) (pos pos)) | |
| (if (##fx= x 0) | |
| (##make-string len) | |
| (let* ((new-pos | |
| (##fx+ pos 1)) | |
| (s | |
| (loop (##fxquotient x rad) | |
| (##fx+ len 1) | |
| new-pos))) | |
| (##string-set! | |
| s | |
| (##fx- (##string-length s) new-pos) | |
| (##string-ref ##digit-to-char-table | |
| (##fx- (##fxremainder x rad)))) | |
| s)))) | |
| (define (convert-non-last-fixnum s rad x pos) | |
| (let loop ((x x) | |
| (size (##vector-ref block-size rad)) | |
| (i (##fx- (##string-length s) pos))) | |
| (if (##fx< 0 size) | |
| (let ((new-i (##fx- i 1))) | |
| (##string-set! | |
| s | |
| new-i | |
| (##string-ref ##digit-to-char-table | |
| (##fxremainder x rad))) | |
| (loop (##fxquotient x rad) | |
| (##fx- size 1) | |
| new-i))))) | |
| (define (make-string-from-fixnums rad lst len pos) | |
| (let loop ((lst lst) (pos pos)) | |
| (let ((new-lst (##cdr lst))) | |
| (if (##null? new-lst) | |
| (make-string-from-last-fixnum | |
| rad | |
| (##fx- (##car lst)) | |
| (##fx+ len pos) | |
| pos) | |
| (let* ((size | |
| (##vector-ref block-size rad)) | |
| (new-pos | |
| (##fx+ pos size)) | |
| (s | |
| (loop new-lst new-pos))) | |
| (convert-non-last-fixnum s rad (##car lst) pos) | |
| s))))) | |
| (define (uinteger->fixnums level sqs x lst) | |
| (cond ((and (##null? lst) (##eqv? x 0)) | |
| lst) | |
| ((##fx= level 0) | |
| (##cons x lst)) | |
| (else | |
| (let* ((qr (##exact-int.div x (##car sqs))) | |
| (new-level (##fx- level 1)) | |
| (new-sqs (##cdr sqs)) | |
| (q (##car qr)) | |
| (r (##cdr qr))) | |
| (uinteger->fixnums | |
| new-level | |
| new-sqs | |
| r | |
| (uinteger->fixnums new-level new-sqs q lst)))))) | |
| (define (uinteger->string x rad len) | |
| (make-string-from-fixnums | |
| rad | |
| (let ((rad^size | |
| (##vector-ref rad^block-size rad)) | |
| (x-length | |
| (##integer-length x))) | |
| (let loop ((level 0) | |
| (sqs '()) | |
| (rad^size^2^level rad^size)) | |
| (let ((new-level | |
| (##fx+ level 1)) | |
| (new-sqs | |
| (##cons rad^size^2^level sqs))) | |
| (if (##fx< x-length | |
| (##fx- | |
| (##fx* (##integer-length rad^size^2^level) 2) | |
| 1)) | |
| (uinteger->fixnums new-level new-sqs x '()) | |
| (let ((new-rad^size^2^level | |
| (##exact-int.square rad^size^2^level))) | |
| (if (##< x new-rad^size^2^level) | |
| (uinteger->fixnums new-level new-sqs x '()) | |
| (loop new-level | |
| new-sqs | |
| new-rad^size^2^level))))))) | |
| len | |
| 0)) | |
| (if (##fixnum? x) | |
| (cond ((##fxnegative? x) | |
| (let ((s (make-string-from-last-fixnum rad x 1 0))) | |
| (##string-set! s 0 #\-) | |
| s)) | |
| ((##fxzero? x) | |
| (if force-sign? | |
| (##string #\+ #\0) | |
| (##string #\0))) | |
| (else | |
| (if force-sign? | |
| (let ((s (make-string-from-last-fixnum rad (##fx- x) 1 0))) | |
| (##string-set! s 0 #\+) | |
| s) | |
| (make-string-from-last-fixnum rad (##fx- x) 0 0)))) | |
| (cond ((##bignum.negative? x) | |
| (let ((s (uinteger->string (##negate x) rad 1))) | |
| (##string-set! s 0 #\-) | |
| s)) | |
| (else | |
| (if force-sign? | |
| (let ((s (uinteger->string x rad 1))) | |
| (##string-set! s 0 #\+) | |
| s) | |
| (uinteger->string x rad 0)))))) | |
| (define ##digit-to-char-table "0123456789abcdefghijklmnopqrstuvwxyz") | |
| (define-prim (##ratnum->string x rad force-sign?) | |
| (##string-append | |
| (##exact-int->string (macro-ratnum-numerator x) rad force-sign?) | |
| "/" | |
| (##exact-int->string (macro-ratnum-denominator x) rad #f))) | |
| (##define-macro (macro-r6rs-fp-syntax) #t) | |
| (##define-macro (macro-chez-fp-syntax) #f) | |
| (##define-macro (macro-make-10^constants) | |
| (define n 326) | |
| (let ((v (make-vector n))) | |
| (let loop ((i 0) (x 1)) | |
| (if (< i n) | |
| (begin | |
| (vector-set! v i x) | |
| (loop (+ i 1) (* x 10))))) | |
| `',v)) | |
| (define ##10^-constants | |
| (if (use-fast-bignum-algorithms) | |
| (macro-make-10^constants) | |
| #f)) | |
| (define-prim (##flonum-printout v sign-prefix) | |
| ;; This algorithm is derived from the paper "Printing Floating-Point | |
| ;; Numbers Quickly and Accurately" by Robert G. Burger and R. Kent Dybvig, | |
| ;; SIGPLAN'96 Conference on Programming Language Design an Implementation. | |
| ;; v is a flonum | |
| ;; f is an exact integer (fixnum or bignum) | |
| ;; e is an exact integer (fixnum only) | |
| (define (10^ n) ;; 0 <= n < 326 | |
| (if (use-fast-bignum-algorithms) | |
| (##vector-ref ##10^-constants n) | |
| (##expt 10 n))) | |
| (define (base-10-log x) | |
| (##define-macro (1/log10) `',(/ (log 10))) | |
| (##fl* (##fllog x) (1/log10))) | |
| (##define-macro (epsilon) | |
| 1e-10) | |
| (define (scale r s m+ m- round? v) | |
| ;; r is an exact integer (fixnum or bignum) | |
| ;; s is an exact integer (fixnum or bignum) | |
| ;; m+ is an exact integer (fixnum or bignum) | |
| ;; m- is an exact integer (fixnum or bignum) | |
| ;; round? is a boolean | |
| ;; v is a flonum | |
| (let ((est | |
| (##flonum->fixnum | |
| (##flceiling (##fl- (base-10-log v) (epsilon)))))) | |
| (if (##fxnegative? est) | |
| (let ((factor (10^ (##fx- est)))) | |
| (fixup (##* r factor) | |
| s | |
| (##* m+ factor) | |
| (##* m- factor) | |
| est | |
| round?)) | |
| (let ((factor (10^ est))) | |
| (fixup r | |
| (##* s factor) | |
| m+ | |
| m- | |
| est | |
| round?))))) | |
| (define (fixup r s m+ m- k round?) | |
| (if (if round? | |
| (##not (##< (##+ r m+) s)) | |
| (##< s (##+ r m+))) | |
| (##cons (##fx+ k 1) | |
| (generate r | |
| s | |
| m+ | |
| m- | |
| round? | |
| 0)) | |
| (##cons k | |
| (generate (##* r 10) | |
| s | |
| (##* m+ 10) | |
| (##* m- 10) | |
| round? | |
| 0)))) | |
| (define (generate r s m+ m- round? n) | |
| (let* ((dr (##exact-int.div r s)) | |
| (d (##car dr)) | |
| (r (##cdr dr)) | |
| (tc (if round? | |
| (##not (##< (##+ r m+) s)) | |
| (##< s (##+ r m+))))) | |
| (if (if round? (##not (##< m- r)) (##< r m-)) | |
| (let* ((last-digit | |
| (if tc | |
| (let ((r*2 (##arithmetic-shift r 1))) | |
| (if (or (and (##fxeven? d) | |
| (##= r*2 s)) ;; tie, round d to even | |
| (##< r*2 s)) | |
| d | |
| (##fx+ d 1))) | |
| d)) | |
| (str | |
| (##make-string (##fx+ n 1)))) | |
| (##string-set! | |
| str | |
| n | |
| (##string-ref ##digit-to-char-table last-digit)) | |
| str) | |
| (if tc | |
| (let ((str | |
| (##make-string (##fx+ n 1)))) | |
| (##string-set! | |
| str | |
| n | |
| (##string-ref ##digit-to-char-table (##fx+ d 1))) | |
| str) | |
| (let ((str | |
| (generate (##* r 10) | |
| s | |
| (##* m+ 10) | |
| (##* m- 10) | |
| round? | |
| (##fx+ n 1)))) | |
| (##string-set! | |
| str | |
| n | |
| (##string-ref ##digit-to-char-table d)) | |
| str))))) | |
| (define (flonum->exponent-and-digits v) | |
| (let* ((x (##flonum->exact-exponential-format v)) | |
| (f (##vector-ref x 0)) | |
| (e (##vector-ref x 1)) | |
| (round? (##not (##odd? f)))) | |
| (if (##fxnegative? e) | |
| (if (and (##not (##fx= e (macro-flonum-e-min))) | |
| (##= f (macro-flonum-+m-min))) | |
| (scale (##arithmetic-shift f 2) | |
| (##arithmetic-shift 1 (##fx- 2 e)) | |
| 2 | |
| 1 | |
| round? | |
| v) | |
| (scale (##arithmetic-shift f 1) | |
| (##arithmetic-shift 1 (##fx- 1 e)) | |
| 1 | |
| 1 | |
| round? | |
| v)) | |
| (let ((2^e (##arithmetic-shift 1 e))) | |
| (if (##= f (macro-flonum-+m-min)) | |
| (scale (##arithmetic-shift f (##fx+ e 2)) | |
| 4 | |
| (##arithmetic-shift 1 (##fx+ e 1)) | |
| 2^e | |
| round? | |
| v) | |
| (scale (##arithmetic-shift f (##fx+ e 1)) | |
| 2 | |
| 2^e | |
| 2^e | |
| round? | |
| v)))))) | |
| (let* ((x (flonum->exponent-and-digits v)) | |
| (e (##car x)) | |
| (d (##cdr x)) ;; d = digits | |
| (n (##string-length d))) ;; n = number of digits | |
| (cond ((and (##not (##fx< e 0)) ;; 0<=e<=10 | |
| (##not (##fx< 10 e))) | |
| (cond ((##fx= e 0) ;; e=0 | |
| ;; Format 1: .DDD (0.DDD in chez-fp-syntax) | |
| (##string-append sign-prefix | |
| (if (macro-chez-fp-syntax) "0." ".") | |
| d)) | |
| ((##fx< e n) ;; e<n | |
| ;; Format 2: D.DDD up to DDD.D | |
| (##string-append sign-prefix | |
| (##substring d 0 e) | |
| "." | |
| (##substring d e n))) | |
| ((##fx= e n) ;; e=n | |
| ;; Format 3: DDD. (DDD.0 in chez-fp-syntax) | |
| (##string-append sign-prefix | |
| d | |
| (if (macro-chez-fp-syntax) ".0" "."))) | |
| (else ;; e>n | |
| ;; Format 4: DDD000000. (DDD000000.0 in chez-fp-syntax) | |
| (##string-append sign-prefix | |
| d | |
| (##make-string (##fx- e n) #\0) | |
| (if (macro-chez-fp-syntax) ".0" "."))))) | |
| ((and (##not (##fx< e -2)) ;; -2<=e<=-1 | |
| (##not (##fx< -1 e))) | |
| ;; Format 5: .0DDD or .00DDD (0.0DDD or 0.00DDD in chez-fp-syntax) | |
| (##string-append sign-prefix | |
| (if (macro-chez-fp-syntax) "0." ".") | |
| (##make-string (##fx- e) #\0) | |
| d)) | |
| (else | |
| ;; Format 6: D.DDDeEEE | |
| ;; | |
| ;; This is the most general format. We insert a period after | |
| ;; the first digit (unless there is only one digit) and add | |
| ;; an exponent. | |
| (##string-append sign-prefix | |
| (##substring d 0 1) | |
| (if (##fx= n 1) "" ".") | |
| (##substring d 1 n) | |
| "e" | |
| (##number->string (##fx- e 1) 10)))))) | |
| (define-prim (##flonum->string x rad force-sign?) | |
| (define (non-neg-num->str x rad sign-prefix) | |
| (if (##flzero? x) | |
| (##string-append sign-prefix (if (macro-chez-fp-syntax) "0.0" "0.")) | |
| (##flonum-printout x sign-prefix))) | |
| (cond ((##flnan? x) | |
| (##string-copy (if (or (macro-r6rs-fp-syntax) | |
| (macro-chez-fp-syntax)) | |
| "+nan.0" | |
| "+nan."))) | |
| ((##flnegative? (##flcopysign (macro-inexact-+1) x)) | |
| (let ((abs-x (##flcopysign x (macro-inexact-+1)))) | |
| (cond ((##fl= abs-x (macro-inexact-+inf)) | |
| (##string-copy (if (or (macro-r6rs-fp-syntax) | |
| (macro-chez-fp-syntax)) | |
| "-inf.0" | |
| "-inf."))) | |
| (else | |
| (non-neg-num->str abs-x rad "-"))))) | |
| (else | |
| (cond ((##fl= x (macro-inexact-+inf)) | |
| (##string-copy (if (or (macro-r6rs-fp-syntax) | |
| (macro-chez-fp-syntax)) | |
| "+inf.0" | |
| "+inf."))) | |
| (force-sign? | |
| (non-neg-num->str x rad "+")) | |
| (else | |
| (non-neg-num->str x rad "")))))) | |
| (define-prim (##cpxnum->string x rad force-sign?) | |
| (let* ((real | |
| (macro-cpxnum-real x)) | |
| (real-str | |
| (if (##eqv? real 0) "" (##number->string real rad force-sign?)))) | |
| (let ((imag (macro-cpxnum-imag x))) | |
| (cond ((##eqv? imag 1) | |
| (##string-append real-str "+i")) | |
| ((##eqv? imag -1) | |
| (##string-append real-str "-i")) | |
| (else | |
| (##string-append real-str | |
| (##number->string imag rad #t) | |
| "i")))))) | |
| (define-prim (##number->string x #!optional (rad 10) (force-sign? #f)) | |
| (macro-number-dispatch x '() | |
| (##exact-int->string x rad force-sign?) | |
| (##exact-int->string x rad force-sign?) | |
| (##ratnum->string x rad force-sign?) | |
| (##flonum->string x rad force-sign?) | |
| (##cpxnum->string x rad force-sign?))) | |
| (define-prim (number->string n #!optional (r (macro-absent-obj))) | |
| (macro-force-vars (n r) | |
| (let ((rad (if (##eq? r (macro-absent-obj)) 10 r))) | |
| (if (macro-exact-int? rad) | |
| (if (or (##eqv? rad 2) | |
| (##eqv? rad 8) | |
| (##eqv? rad 10) | |
| (##eqv? rad 16)) | |
| (let ((result (##number->string n rad #f))) | |
| (if (##null? result) | |
| (##fail-check-number 1 number->string n r) | |
| result)) | |
| (##raise-range-exception 2 number->string n r)) | |
| (##fail-check-exact-integer 2 number->string n r))))) | |
| (##define-macro (macro-make-char-to-digit-table) | |
| (let ((t (make-vector 128 99))) | |
| (vector-set! t (char->integer #\#) 0) ;; #\# counts as 0 | |
| (let loop1 ((i 9)) | |
| (if (not (< i 0)) | |
| (begin | |
| (vector-set! t (+ (char->integer #\0) i) i) | |
| (loop1 (- i 1))))) | |
| (let loop2 ((i 25)) | |
| (if (not (< i 0)) | |
| (begin | |
| (vector-set! t (+ (char->integer #\A) i) (+ i 10)) | |
| (vector-set! t (+ (char->integer #\a) i) (+ i 10)) | |
| (loop2 (- i 1))))) | |
| `',(list->u8vector (vector->list t)))) | |
| (define ##char-to-digit-table (macro-make-char-to-digit-table)) | |
| (define-prim (##string->number str #!optional (rad 10) (check-only? #f)) | |
| ;; The number grammar parsed by this procedure is: | |
| ;; | |
| ;; <num R E> : <prefix R E> <complex R E> | |
| ;; | |
| ;; <complex R E> : <real R E> | |
| ;; | <real R E> @ <real R E> | |
| ;; | <real R E> <sign> <ureal R> i | |
| ;; | <real R E> <sign-inf-nan R E> i | |
| ;; | <real R E> <sign> i | |
| ;; | <sign> <ureal R> i | |
| ;; | <sign-inf-nan R E> i | |
| ;; | <sign> i | |
| ;; | |
| ;; <real R E> : <ureal R> | |
| ;; | <sign> <ureal R> | |
| ;; | <sign-inf-nan R E> | |
| ;; | |
| ;; <sign-inf-nan R i> : +inf.0 | |
| ;; | -inf.0 | |
| ;; | +nan.0 | |
| ;; <sign-inf-nan R empty> : <sign-inf-nan R i> | |
| ;; | |
| ;; <ureal R> : <uinteger R> | |
| ;; | <uinteger R> / <uinteger R> | |
| ;; | <decimal R> | |
| ;; | |
| ;; <decimal 10> : <uinteger 10> <suffix> | |
| ;; | . <digit 10>+ #* <suffix> | |
| ;; | <digit 10>+ . <digit 10>* #* <suffix> | |
| ;; | <digit 10>+ #+ . #* <suffix> | |
| ;; | |
| ;; <uinteger R> : <digit R>+ #* | |
| ;; | |
| ;; <prefix R E> : <radix R E> <exactness E> | |
| ;; | <exactness E> <radix R E> | |
| ;; | |
| ;; <suffix> : <empty> | |
| ;; | <exponent marker> <digit 10>+ | |
| ;; | <exponent marker> <sign> <digit 10>+ | |
| ;; | |
| ;; <exponent marker> : e | s | f | d | l | |
| ;; <sign> : + | - | |
| ;; <exactness empty> : <empty> | |
| ;; <exactness i> : #i | |
| ;; <exactness e> : #e | |
| ;; <radix 2> : #b | |
| ;; <radix 8> : #o | |
| ;; <radix 10> : <empty> | #d | |
| ;; <radix 16> : #x | |
| ;; <digit 2> : 0 | 1 | |
| ;; <digit 8> : 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
| ;; <digit 10> : 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
| ;; <digit 16> : <digit 10> | a | b | c | d | e | f | |
| (##define-macro (macro-make-exact-10^n-table) | |
| (define max-exact-power-of-10 22) ;; (floor (inexact->exact (/ (log (expt 2 (macro-flonum-m-bits-plus-1))) (log 5)))) | |
| (let ((t (make-vector (+ max-exact-power-of-10 1)))) | |
| (let loop ((i max-exact-power-of-10)) | |
| (if (not (< i 0)) | |
| (begin | |
| (vector-set! t i (exact->inexact (expt 10 i))) | |
| (loop (- i 1))))) | |
| `',(list->f64vector (vector->list t)))) | |
| (define exact-10^n-table (macro-make-exact-10^n-table)) | |
| (##define-macro (macro-make-block-size) | |
| (let* ((max-rad 16) | |
| (t (make-vector (+ max-rad 1) 0))) | |
| (define max-fixnum 536870911) ;; OK to be conservative | |
| (define (block-size-for rad) | |
| (let loop ((i 0) (rad^i 1)) | |
| (let ((new-rad^i (* rad^i rad))) | |
| (if (<= new-rad^i max-fixnum) | |
| (loop (+ i 1) new-rad^i) | |
| i)))) | |
| (let loop ((i max-rad)) | |
| (if (< 1 i) | |
| (begin | |
| (vector-set! t i (block-size-for i)) | |
| (loop (- i 1))))) | |
| `',t)) | |
| (define block-size (macro-make-block-size)) | |
| (##define-macro (macro-make-rad^block-size) | |
| (let* ((max-rad 16) | |
| (t (make-vector (+ max-rad 1) 0))) | |
| (define max-fixnum 536870911) ;; OK to be conservative | |
| (define (rad^block-size-for rad) | |
| (let loop ((i 0) (rad^i 1)) | |
| (let ((new-rad^i (* rad^i rad))) | |
| (if (<= new-rad^i max-fixnum) | |
| (loop (+ i 1) new-rad^i) | |
| rad^i)))) | |
| (let loop ((i max-rad)) | |
| (if (< 1 i) | |
| (begin | |
| (vector-set! t i (rad^block-size-for i)) | |
| (loop (- i 1))))) | |
| `',t)) | |
| (define rad^block-size (macro-make-rad^block-size)) | |
| (define (substring->uinteger-fixnum str rad i j) | |
| ;; Simple case: result is known to fit in a fixnum. | |
| (let loop ((i i) (n 0)) | |
| (if (##fx< i j) | |
| (let* ((c (##string-ref str i)) | |
| (ic (##char->integer c))) | |
| (loop (##fx+ i 1) | |
| (##fx+ (##fx* n rad) | |
| (if (##fx< ic 128) | |
| (##u8vector-ref ##char-to-digit-table ic) | |
| 0)))) | |
| n))) | |
| (define (substring->uinteger-aux sqs width str rad i j) | |
| ;; Divide-and-conquer algorithm (fast for large bignums if bignum | |
| ;; multiplication is fast). | |
| (if (##null? sqs) | |
| (substring->uinteger-fixnum str rad i j) | |
| (let* ((new-sqs (##cdr sqs)) | |
| (new-width (##fxquotient width 2)) | |
| (mid (##fx- j new-width))) | |
| (if (##fx< i mid) | |
| (let* ((a (substring->uinteger-aux new-sqs new-width str rad i mid)) | |
| (b (substring->uinteger-aux new-sqs new-width str rad mid j))) | |
| (##+ (##* a (##car sqs)) b)) | |
| (substring->uinteger-aux new-sqs new-width str rad i j))))) | |
| (define (squares rad n) | |
| (let loop ((rad rad) (n n) (lst '())) | |
| (if (##fx= n 1) | |
| (##cons rad lst) | |
| (loop (##exact-int.square rad) | |
| (##fx- n 1) | |
| (##cons rad lst))))) | |
| (define (substring->uinteger str rad i j) | |
| ;; Converts a substring into an unsigned integer. Selects a fast | |
| ;; conversion algorithm when result fits in a fixnum. | |
| (let ((len (##fx- j i)) | |
| (size (##vector-ref block-size rad))) | |
| (if (##fx< size len) | |
| (let ((levels | |
| (##integer-length (##fxquotient (##fx- len 1) size)))) | |
| (substring->uinteger-aux | |
| (squares (##vector-ref rad^block-size rad) levels) | |
| (##fxarithmetic-shift-left size levels) | |
| str | |
| rad | |
| i | |
| j)) | |
| (substring->uinteger-fixnum str rad i j)))) | |
| (define (float-substring->uinteger str i j) | |
| ;; Converts a substring containing the decimals of a floating-point | |
| ;; number into an unsigned integer (any period is simply skipped). | |
| (let loop1 ((i i) (n 0)) | |
| (if (##not (##fx< i j)) | |
| n | |
| (let ((c (##string-ref str i))) | |
| (if (##char=? c #\.) | |
| (loop1 (##fx+ i 1) n) | |
| (let* ((ic | |
| (##char->integer c)) | |
| (new-n | |
| (##fx+ (##fx* n 10) | |
| (if (##fx< ic 128) | |
| (##u8vector-ref ##char-to-digit-table ic) | |
| 0)))) | |
| (if (##fx< new-n (macro-max-fixnum32-div-10)) | |
| (loop1 (##fx+ i 1) new-n) | |
| (let loop2 ((i i) (n n)) | |
| (if (##not (##fx< i j)) | |
| n | |
| (let ((c (##string-ref str i))) | |
| (if (##char=? c #\.) | |
| (loop2 (##fx+ i 1) n) | |
| (let* ((ic | |
| (##char->integer c)) | |
| (new-n | |
| (##+ (##* n 10) | |
| (if (##fx< ic 128) | |
| (##u8vector-ref ##char-to-digit-table ic) | |
| 0)))) | |
| (loop2 (##fx+ i 1) new-n))))))))))))) | |
| (define (uinteger str rad i) | |
| (and (##fx< i (##string-length str)) | |
| (let* ((c (##string-ref str i)) | |
| (ic (##char->integer c))) | |
| (and (##fx< ic 128) | |
| (##not (##char=? c #\#)) | |
| (##fx< (##u8vector-ref ##char-to-digit-table ic) rad) | |
| (digits-and-sharps str rad (##fx+ i 1)))))) | |
| (define (digits-and-sharps str rad i) | |
| (let loop ((i i)) | |
| (if (##fx< i (##string-length str)) | |
| (let* ((c (##string-ref str i)) | |
| (ic (##char->integer c))) | |
| (if (##fx< ic 128) | |
| (if (##char=? c #\#) | |
| (sharps str (##fx+ i 1)) | |
| (if (##fx< (##u8vector-ref ##char-to-digit-table ic) rad) | |
| (loop (##fx+ i 1)) | |
| i)) | |
| i)) | |
| i))) | |
| (define (sharps str i) | |
| (let loop ((i i)) | |
| (if (##fx< i (##string-length str)) | |
| (if (##char=? (##string-ref str i) #\#) | |
| (loop (##fx+ i 1)) | |
| i) | |
| i))) | |
| (define (suffix str i1) | |
| (if (##fx< (##fx+ i1 1) (##string-length str)) | |
| (let ((c1 (##string-ref str i1))) | |
| (if (or (##char=? c1 #\e) (##char=? c1 #\E) | |
| (##char=? c1 #\s) (##char=? c1 #\S) | |
| (##char=? c1 #\f) (##char=? c1 #\F) | |
| (##char=? c1 #\d) (##char=? c1 #\D) | |
| (##char=? c1 #\l) (##char=? c1 #\L)) | |
| (let ((c2 (##string-ref str (##fx+ i1 1)))) | |
| (let ((i2 | |
| (if (or (##char=? c2 #\+) (##char=? c2 #\-)) | |
| (uinteger str 10 (##fx+ i1 2)) | |
| (uinteger str 10 (##fx+ i1 1))))) | |
| (if (and i2 | |
| (##not (##char=? (##string-ref str (##fx- i2 1)) | |
| #\#))) | |
| i2 | |
| i1))) | |
| i1)) | |
| i1)) | |
| (define (ureal str rad e i1) | |
| (let ((i2 (uinteger str rad i1))) | |
| (if i2 | |
| (if (##fx< i2 (##string-length str)) | |
| (let ((c (##string-ref str i2))) | |
| (cond ((##char=? c #\/) | |
| (let ((i3 (uinteger str rad (##fx+ i2 1)))) | |
| (and i3 | |
| (let ((inexact-num? | |
| (or (##eq? e 'i) | |
| (and (##not e) | |
| (or (##char=? (##string-ref | |
| str | |
| (##fx- i2 1)) | |
| #\#) | |
| (##char=? (##string-ref | |
| str | |
| (##fx- i3 1)) | |
| #\#)))))) | |
| (if (and (##not inexact-num?) | |
| (##eqv? (substring->uinteger | |
| str | |
| rad | |
| (##fx+ i2 1) | |
| i3) | |
| 0)) | |
| #f | |
| (##vector i3 i2)))))) | |
| ((##fx= rad 10) | |
| (if (##char=? c #\.) | |
| (let ((i3 | |
| (if (##char=? (##string-ref str (##fx- i2 1)) | |
| #\#) | |
| (sharps str (##fx+ i2 1)) | |
| (digits-and-sharps str 10 (##fx+ i2 1))))) | |
| (and i3 | |
| (let ((i4 (suffix str i3))) | |
| (##vector i4 i3 i2)))) | |
| (let ((i3 (suffix str i2))) | |
| (if (##fx= i2 i3) | |
| i2 | |
| (##vector i3 i2 i2))))) | |
| (else | |
| i2))) | |
| i2) | |
| (and (##fx= rad 10) | |
| (##fx< i1 (##string-length str)) | |
| (##char=? (##string-ref str i1) #\.) | |
| (let ((i3 (uinteger str rad (##fx+ i1 1)))) | |
| (and i3 | |
| (let ((i4 (suffix str i3))) | |
| (##vector i4 i3 i1)))))))) | |
| (define (inf-nan str sign i e) | |
| (and (##not (##eq? e 'e)) | |
| (if (##fx< (##fx+ i (if (or (macro-r6rs-fp-syntax) | |
| (macro-chez-fp-syntax)) | |
| 4 | |
| 3)) | |
| (##string-length str)) | |
| (and (##char=? (##string-ref str (##fx+ i 3)) #\.) | |
| (if (or (macro-r6rs-fp-syntax) | |
| (macro-chez-fp-syntax)) | |
| (##char=? (##string-ref str (##fx+ i 4)) #\0) | |
| #t) | |
| (or (and (let ((c (##string-ref str i))) | |
| (or (##char=? c #\i) (##char=? c #\I))) | |
| (let ((c (##string-ref str (##fx+ i 1)))) | |
| (or (##char=? c #\n) (##char=? c #\N))) | |
| (let ((c (##string-ref str (##fx+ i 2)))) | |
| (or (##char=? c #\f) (##char=? c #\F)))) | |
| (and (##not (##char=? sign #\-)) | |
| (let ((c (##string-ref str i))) | |
| (or (##char=? c #\n) (##char=? c #\N))) | |
| (let ((c (##string-ref str (##fx+ i 1)))) | |
| (or (##char=? c #\a) (##char=? c #\A))) | |
| (let ((c (##string-ref str (##fx+ i 2)))) | |
| (or (##char=? c #\n) (##char=? c #\N))))) | |
| (##vector (##fx+ i (if (or (macro-r6rs-fp-syntax) | |
| (macro-chez-fp-syntax)) | |
| 5 | |
| 4)))) | |
| #f))) | |
| (define (make-rec x y) | |
| (##make-rectangular x y)) | |
| (define (make-pol x y e) | |
| (let ((n (##make-polar x y))) | |
| (if (##eq? e 'e) | |
| (##inexact->exact n) | |
| n))) | |
| (define (make-inexact-real sign uinteger exponent) | |
| (let ((n | |
| (if (and (##fixnum? uinteger) | |
| (##fixnum->flonum-exact? uinteger) | |
| (##fixnum? exponent) | |
| (##fx< (##fx- exponent) | |
| (##f64vector-length exact-10^n-table)) | |
| (##fx< exponent | |
| (##f64vector-length exact-10^n-table))) | |
| (if (##fx< exponent 0) | |
| (##fl/ (##fixnum->flonum uinteger) | |
| (##f64vector-ref exact-10^n-table | |
| (##fx- exponent))) | |
| (##fl* (##fixnum->flonum uinteger) | |
| (##f64vector-ref exact-10^n-table | |
| exponent))) | |
| (##exact->inexact | |
| (##* uinteger (##expt 10 exponent)))))) | |
| (if (##char=? sign #\-) | |
| (##flcopysign n (macro-inexact--1)) | |
| n))) | |
| (define (get-zero e) | |
| (if (##eq? e 'i) | |
| (macro-inexact-+0) | |
| 0)) | |
| (define (get-one sign e) | |
| (if (##eq? e 'i) | |
| (if (##char=? sign #\-) (macro-inexact--1) (macro-inexact-+1)) | |
| (if (##char=? sign #\-) -1 1))) | |
| (define (get-real start sign str rad e i) | |
| (if (##fixnum? i) | |
| (let* ((abs-n | |
| (substring->uinteger str rad start i)) | |
| (n | |
| (if (##char=? sign #\-) | |
| (##negate abs-n) | |
| abs-n))) | |
| (if (or (##eq? e 'i) | |
| (and (##not e) | |
| (##char=? (##string-ref str (##fx- i 1)) #\#))) | |
| (##exact->inexact n) | |
| n)) | |
| (let ((j (##vector-ref i 0)) | |
| (len (##vector-length i))) | |
| (cond ((##fx= len 3) ;; xxx.yyyEzzz | |
| (let* ((after-frac-part | |
| (##vector-ref i 1)) | |
| (unadjusted-exponent | |
| (if (##fx= after-frac-part j) ;; no exponent part? | |
| 0 | |
| (let* ((c | |
| (##string-ref | |
| str | |
| (##fx+ after-frac-part 1))) | |
| (n | |
| (substring->uinteger | |
| str | |
| 10 | |
| (if (or (##char=? c #\+) (##char=? c #\-)) | |
| (##fx+ after-frac-part 2) | |
| (##fx+ after-frac-part 1)) | |
| j))) | |
| (if (##char=? c #\-) | |
| (##negate n) | |
| n)))) | |
| (c | |
| (##string-ref str start)) | |
| (uinteger | |
| (float-substring->uinteger str start after-frac-part)) | |
| (decimals-after-point | |
| (##fx- | |
| (##fx- after-frac-part (##vector-ref i 2)) | |
| 1)) | |
| (exponent | |
| (if (##fx< 0 decimals-after-point) | |
| (if (and (##fixnum? unadjusted-exponent) | |
| (##fx< (##fx- unadjusted-exponent | |
| decimals-after-point) | |
| unadjusted-exponent)) | |
| (##fx- unadjusted-exponent | |
| decimals-after-point) | |
| (##- unadjusted-exponent | |
| decimals-after-point)) | |
| unadjusted-exponent))) | |
| (if (##eq? e 'e) | |
| (##* | |
| (if (##char=? sign #\-) | |
| (##negate uinteger) | |
| uinteger) | |
| (##expt 10 exponent)) | |
| (make-inexact-real sign uinteger exponent)))) | |
| ((##fx= len 2) ;; xxx/yyy | |
| (let* ((after-num | |
| (##vector-ref i 1)) | |
| (inexact-num? | |
| (or (##eq? e 'i) | |
| (and (##not e) | |
| (or (##char=? (##string-ref | |
| str | |
| (##fx- after-num 1)) | |
| #\#) | |
| (##char=? (##string-ref | |
| str | |
| (##fx- j 1)) | |
| #\#))))) | |
| (abs-num | |
| (substring->uinteger str rad start after-num)) | |
| (den | |
| (substring->uinteger str | |
| rad | |
| (##fx+ after-num 1) | |
| j))) | |
| (define (num-div-den) | |
| (##/ (if (##char=? sign #\-) | |
| (##negate abs-num) | |
| abs-num) | |
| den)) | |
| (if inexact-num? | |
| (if (##eqv? den 0) | |
| (let ((n | |
| (if (##eqv? abs-num 0) | |
| (macro-inexact-+nan) | |
| (macro-inexact-+inf)))) | |
| (if (##char=? sign #\-) | |
| (##flcopysign n (macro-inexact--1)) | |
| n)) | |
| (##exact->inexact (num-div-den))) | |
| (num-div-den)))) | |
| (else ;; (##fx= len 1) ;; inf or nan | |
| (let* ((c | |
| (##string-ref str start)) | |
| (n | |
| (if (or (##char=? c #\i) (##char=? c #\I)) | |
| (macro-inexact-+inf) | |
| (macro-inexact-+nan)))) | |
| (if (##char=? sign #\-) | |
| (##flcopysign n (macro-inexact--1)) | |
| n))))))) | |
| (define (i-end str i) | |
| (and (##fx= (##fx+ i 1) (##string-length str)) | |
| (let ((c (##string-ref str i))) | |
| (or (##char=? c #\i) (##char=? c #\I))))) | |
| (define (complex start sign str rad e i) | |
| (let ((j (if (##fixnum? i) i (##vector-ref i 0)))) | |
| (let ((c (##string-ref str j))) | |
| (cond ((##char=? c #\@) | |
| (let ((j+1 (##fx+ j 1))) | |
| (if (##fx< j+1 (##string-length str)) | |
| (let* ((sign2 | |
| (##string-ref str j+1)) | |
| (start2 | |
| (if (or (##char=? sign2 #\+) (##char=? sign2 #\-)) | |
| (##fx+ j+1 1) | |
| j+1)) | |
| (k | |
| (or (ureal str rad e start2) | |
| (and (##fx< j+1 start2) | |
| (inf-nan str sign2 start2 e))))) | |
| (and k | |
| (let ((l (if (##fixnum? k) k (##vector-ref k 0)))) | |
| (and (##fx= l (##string-length str)) | |
| (or check-only? | |
| (make-pol | |
| (get-real start sign str rad e i) | |
| (get-real start2 sign2 str rad e k) | |
| e)))))) | |
| #f))) | |
| ((or (##char=? c #\+) (##char=? c #\-)) | |
| (let* ((start2 | |
| (##fx+ j 1)) | |
| (k | |
| (or (ureal str rad e start2) | |
| (inf-nan str c start2 e)))) | |
| (if (##not k) | |
| (if (i-end str start2) | |
| (or check-only? | |
| (make-rec | |
| (get-real start sign str rad e i) | |
| (get-one c e))) | |
| #f) | |
| (let ((l (if (##fixnum? k) k (##vector-ref k 0)))) | |
| (and (i-end str l) | |
| (or check-only? | |
| (make-rec | |
| (get-real start sign str rad e i) | |
| (get-real start2 c str rad e k)))))))) | |
| (else | |
| #f))))) | |
| (define (after-prefix start str rad e) | |
| ;; invariant: start = 0, 2 or 4, (string-length str) > start | |
| (let ((c (##string-ref str start))) | |
| (if (or (##char=? c #\+) (##char=? c #\-)) | |
| (let ((i (or (ureal str rad e (##fx+ start 1)) | |
| (inf-nan str c (##fx+ start 1) e)))) | |
| (if (##not i) | |
| (if (i-end str (##fx+ start 1)) | |
| (or check-only? | |
| (make-rec | |
| (get-zero e) | |
| (get-one c e))) | |
| #f) | |
| (let ((j (if (##fixnum? i) i (##vector-ref i 0)))) | |
| (cond ((##fx= j (##string-length str)) | |
| (or check-only? | |
| (get-real (##fx+ start 1) c str rad e i))) | |
| ((i-end str j) | |
| (or check-only? | |
| (make-rec | |
| (get-zero e) | |
| (get-real (##fx+ start 1) c str rad e i)))) | |
| (else | |
| (complex (##fx+ start 1) c str rad e i)))))) | |
| (let ((i (ureal str rad e start))) | |
| (if (##not i) | |
| #f | |
| (let ((j (if (##fixnum? i) i (##vector-ref i 0)))) | |
| (cond ((##fx= j (##string-length str)) | |
| (or check-only? | |
| (get-real start #\+ str rad e i))) | |
| (else | |
| (complex start #\+ str rad e i))))))))) | |
| (define (radix-prefix c) | |
| (cond ((or (##char=? c #\b) (##char=? c #\B)) 2) | |
| ((or (##char=? c #\o) (##char=? c #\O)) 8) | |
| ((or (##char=? c #\d) (##char=? c #\D)) 10) | |
| ((or (##char=? c #\x) (##char=? c #\X)) 16) | |
| (else #f))) | |
| (define (exactness-prefix c) | |
| (cond ((or (##char=? c #\i) (##char=? c #\I)) 'i) | |
| ((or (##char=? c #\e) (##char=? c #\E)) 'e) | |
| (else #f))) | |
| (cond ((##fx< 2 (##string-length str)) ;; >= 3 chars | |
| (if (##char=? (##string-ref str 0) #\#) | |
| (let ((rad1 (radix-prefix (##string-ref str 1)))) | |
| (if rad1 | |
| (if (and (##fx< 4 (##string-length str)) ;; >= 5 chars | |
| (##char=? (##string-ref str 2) #\#)) | |
| (let ((e1 (exactness-prefix (##string-ref str 3)))) | |
| (if e1 | |
| (after-prefix 4 str rad1 e1) | |
| #f)) | |
| (after-prefix 2 str rad1 #f)) | |
| (let ((e2 (exactness-prefix (##string-ref str 1)))) | |
| (if e2 | |
| (if (and (##fx< 4 (##string-length str)) ;; >= 5 chars | |
| (##char=? (##string-ref str 2) #\#)) | |
| (let ((rad2 (radix-prefix (##string-ref str 3)))) | |
| (if rad2 | |
| (after-prefix 4 str rad2 e2) | |
| #f)) | |
| (after-prefix 2 str rad e2)) | |
| #f)))) | |
| (after-prefix 0 str rad #f))) | |
| ((##fx< 0 (##string-length str)) ;; >= 1 char | |
| (after-prefix 0 str rad #f)) | |
| (else | |
| #f))) | |
| (define-prim (string->number str #!optional (r (macro-absent-obj))) | |
| (macro-force-vars (str r) | |
| (macro-check-string str 1 (string->number str r) | |
| (let ((rad (if (##eq? r (macro-absent-obj)) 10 r))) | |
| (if (macro-exact-int? rad) | |
| (if (or (##eqv? rad 2) | |
| (##eqv? rad 8) | |
| (##eqv? rad 10) | |
| (##eqv? rad 16)) | |
| (##string->number str rad #f) | |
| (##raise-range-exception 2 string->number str r)) | |
| (##fail-check-exact-integer 2 string->number str r)))))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Bitwise operations. | |
| (define-prim (##bitwise-ior x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (define (bignum-bitwise-ior-loop x result n) | |
| (##declare (not interrupts-enabled)) | |
| (let loop ((i (fx- n 1))) | |
| (if (##fx< i 0) | |
| (##bignum.normalize! result) | |
| (begin | |
| (##bignum.adigit-bitwise-ior! result i x i) | |
| (loop (##fx- i 1)))))) | |
| (define (bignum-bitwise-ior x x-length y y-length) | |
| ;; x-length <= y-length | |
| (if (##bignum.negative? x) | |
| (bignum-bitwise-ior-loop y (##bignum.copy x) x-length) | |
| (bignum-bitwise-ior-loop x (##bignum.copy y) x-length))) | |
| (cond ((##fixnum? x) | |
| (cond ((##fixnum? y) | |
| (##fxior x y)) | |
| ((##bignum? y) | |
| (let* ((x-bignum (##fixnum->bignum x)) | |
| (x-length (##bignum.adigit-length x-bignum)) | |
| (y-length (##bignum.adigit-length y))) | |
| (bignum-bitwise-ior x-bignum x-length y y-length))) | |
| (else | |
| (type-error-on-y)))) | |
| ((##bignum? x) | |
| (let ((x-length (##bignum.adigit-length x))) | |
| (cond ((##fixnum? y) | |
| (let* ((y-bignum (##fixnum->bignum y)) | |
| (y-length (##bignum.adigit-length y-bignum))) | |
| (bignum-bitwise-ior y-bignum y-length x x-length))) | |
| ((##bignum? y) | |
| (let ((y-length (##bignum.adigit-length y))) | |
| (if (##fx< x-length y-length) | |
| (bignum-bitwise-ior x x-length y y-length) | |
| (bignum-bitwise-ior y y-length x x-length)))) | |
| (else | |
| (type-error-on-y))))) | |
| (else | |
| (type-error-on-x)))) | |
| (define-prim-nary (bitwise-ior x y) | |
| 0 | |
| (if (macro-exact-int? x) x '(1)) | |
| (##bitwise-ior x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-exact-integer)) | |
| (define-prim (##bitwise-xor x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (define (bignum-bitwise-xor x x-length y y-length) | |
| (let ((result (##bignum.copy y))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop1 ((i 0)) | |
| (if (##fx< i x-length) | |
| (begin | |
| (##bignum.adigit-bitwise-xor! result i x i) | |
| (loop1 (##fx+ i 1))) | |
| (if (##bignum.negative? x) | |
| (let loop2 ((i i)) | |
| (if (##fx< i y-length) | |
| (begin | |
| (##bignum.adigit-bitwise-not! result i) | |
| (loop2 (##fx+ i 1))) | |
| (##bignum.normalize! result))) | |
| (##bignum.normalize! result)))))) | |
| (cond ((##fixnum? x) | |
| (cond ((##fixnum? y) | |
| (##fxxor x y)) | |
| ((##bignum? y) | |
| (let* ((x-bignum (##fixnum->bignum x)) | |
| (x-length (##bignum.adigit-length x-bignum)) | |
| (y-length (##bignum.adigit-length y))) | |
| (bignum-bitwise-xor x-bignum x-length y y-length))) | |
| (else | |
| (type-error-on-y)))) | |
| ((##bignum? x) | |
| (let ((x-length (##bignum.adigit-length x))) | |
| (cond ((##fixnum? y) | |
| (let* ((y-bignum (##fixnum->bignum y)) | |
| (y-length (##bignum.adigit-length y-bignum))) | |
| (bignum-bitwise-xor y-bignum y-length x x-length))) | |
| ((##bignum? y) | |
| (let ((y-length (##bignum.adigit-length y))) | |
| (if (##fx< x-length y-length) | |
| (bignum-bitwise-xor x x-length y y-length) | |
| (bignum-bitwise-xor y y-length x x-length)))) | |
| (else | |
| (type-error-on-y))))) | |
| (else | |
| (type-error-on-x)))) | |
| (define-prim-nary (bitwise-xor x y) | |
| 0 | |
| (if (macro-exact-int? x) x '(1)) | |
| (##bitwise-xor x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-exact-integer)) | |
| (define-prim (##bitwise-and x y) | |
| (##define-macro (type-error-on-x) `'(1)) | |
| (##define-macro (type-error-on-y) `'(2)) | |
| (define (bignum-bitwise-and-loop x result n) | |
| (##declare (not interrupts-enabled)) | |
| (let loop ((i (##fx- n 1))) | |
| (if (##fx< i 0) | |
| (##bignum.normalize! result) | |
| (begin | |
| (##bignum.adigit-bitwise-and! result i x i) | |
| (loop (##fx- i 1)))))) | |
| (define (bignum-bitwise-and x x-length y y-length) | |
| ;; x-length <= y-length | |
| (if (##bignum.negative? x) | |
| (bignum-bitwise-and-loop x (##bignum.copy y) x-length) | |
| (bignum-bitwise-and-loop y (##bignum.copy x) x-length))) | |
| (cond ((##fixnum? x) | |
| (cond ((##fixnum? y) | |
| (##fxand x y)) | |
| ((##bignum? y) | |
| (let* ((x-bignum (##fixnum->bignum x)) | |
| (x-length (##bignum.adigit-length x-bignum)) | |
| (y-length (##bignum.adigit-length y))) | |
| (bignum-bitwise-and x-bignum x-length y y-length))) | |
| (else | |
| (type-error-on-y)))) | |
| ((##bignum? x) | |
| (let ((x-length (##bignum.adigit-length x))) | |
| (cond ((##fixnum? y) | |
| (let* ((y-bignum (##fixnum->bignum y)) | |
| (y-length (##bignum.adigit-length y-bignum))) | |
| (bignum-bitwise-and y-bignum y-length x x-length))) | |
| ((##bignum? y) | |
| (let ((y-length (##bignum.adigit-length y))) | |
| (if (##fx< x-length y-length) | |
| (bignum-bitwise-and x x-length y y-length) | |
| (bignum-bitwise-and y y-length x x-length)))) | |
| (else | |
| (type-error-on-y))))) | |
| (else | |
| (type-error-on-x)))) | |
| (define-prim-nary (bitwise-and x y) | |
| -1 | |
| (if (macro-exact-int? x) x '(1)) | |
| (##bitwise-and x y) | |
| macro-force-vars | |
| macro-no-check | |
| (##pair? ##fail-check-exact-integer)) | |
| (define-prim (##bitwise-not x) | |
| (define (type-error) | |
| (##fail-check-exact-integer 1 bitwise-not x)) | |
| (cond ((##fixnum? x) | |
| (##fxnot x)) | |
| ((##bignum? x) | |
| (##bignum.make (##bignum.adigit-length x) x #t)) ;; don't copy, bitwise invert | |
| (else | |
| (type-error)))) | |
| (define-prim (bitwise-not x) | |
| (macro-force-vars (x) | |
| (##bitwise-not x))) | |
| (define-prim (##arithmetic-shift x y) | |
| (define (type-error-on-x) | |
| (##fail-check-exact-integer 1 arithmetic-shift x y)) | |
| (define (type-error-on-y) | |
| (##fail-check-exact-integer 2 arithmetic-shift x y)) | |
| (define (overflow) | |
| (##raise-heap-overflow-exception) | |
| (##arithmetic-shift x y)) | |
| (define (general-fixnum-fixnum-case) | |
| (##bignum.arithmetic-shift (##fixnum->bignum x) y)) | |
| (cond ((##fixnum? x) | |
| (cond ((##fixnum? y) | |
| (cond ((##fxzero? y) | |
| x) | |
| ((##fxnegative? y) ;; right shift | |
| (if (##fx< (##fx- ##fixnum-width) y) | |
| (##fxarithmetic-shift-right x (##fx- y)) | |
| (if (##fxnegative? x) | |
| -1 | |
| 0))) | |
| (else ;; left shift | |
| (or (and (##fx< y ##fixnum-width) | |
| (##fxarithmetic-shift-left? x y)) | |
| (general-fixnum-fixnum-case))))) | |
| ((##bignum? y) | |
| (cond ((##fxzero? x) | |
| 0) | |
| ((##bignum.negative? y) | |
| (if (##fxnegative? x) | |
| -1 | |
| 0)) | |
| (else | |
| (overflow)))) | |
| (else | |
| (type-error-on-y)))) | |
| ((##bignum? x) | |
| (cond ((##eqv? y 0) | |
| x) | |
| ((##fixnum? y) | |
| (##bignum.arithmetic-shift x y)) | |
| ((##bignum? y) | |
| (cond ((##bignum.negative? y) | |
| (if (##bignum.negative? x) | |
| -1 | |
| 0)) | |
| (else | |
| (overflow)))) | |
| (else | |
| (type-error-on-y)))) | |
| (else | |
| (type-error-on-x)))) | |
| (define-prim (arithmetic-shift x y) | |
| (macro-force-vars (x y) | |
| (##arithmetic-shift x y))) | |
| (define-prim (##bit-count x) | |
| (define (type-error) | |
| (##fail-check-exact-integer 1 bit-count x)) | |
| (cond ((##fixnum? x) | |
| (##fxbit-count x)) | |
| ((##bignum? x) | |
| (let ((x-length (##bignum.mdigit-length x))) | |
| (let loop ((i (##fx- x-length 1)) | |
| (n 0)) | |
| (if (##fx< i 0) | |
| (if (##bignum.negative? x) | |
| (##fx- (##fx* x-length ##bignum.mdigit-width) n) | |
| n) | |
| (loop (##fx- i 1) | |
| (##fx+ n (##fxbit-count (##bignum.mdigit-ref x i)))))))) | |
| (else | |
| (type-error)))) | |
| (define-prim (bit-count x) | |
| (macro-force-vars (x) | |
| (##bit-count x))) | |
| (define-prim (##integer-length x) | |
| (define (type-error) | |
| (##fail-check-exact-integer 1 integer-length x)) | |
| (cond ((##fixnum? x) | |
| (##fxlength x)) | |
| ((##bignum? x) | |
| (let ((x-length (##bignum.mdigit-length x))) | |
| (if (##bignum.negative? x) | |
| (let loop1 ((i (##fx- x-length 1))) | |
| (let ((mdigit (##bignum.mdigit-ref x i))) | |
| (if (##fx= mdigit ##bignum.mdigit-base-minus-1) | |
| (loop1 (##fx- i 1)) | |
| (##fx+ | |
| (##fxlength (##fx- ##bignum.mdigit-base-minus-1 mdigit)) | |
| (##fx* i ##bignum.mdigit-width))))) | |
| (let loop2 ((i (##fx- x-length 1))) | |
| (let ((mdigit (##bignum.mdigit-ref x i))) | |
| (if (##fx= mdigit 0) | |
| (loop2 (##fx- i 1)) | |
| (##fx+ | |
| (##fxlength mdigit) | |
| (##fx* i ##bignum.mdigit-width)))))))) | |
| (else | |
| (type-error)))) | |
| (define-prim (integer-length x) | |
| (macro-force-vars (x) | |
| (##integer-length x))) | |
| (define-prim (##bitwise-merge x y z) | |
| (##bitwise-ior (##bitwise-and (##bitwise-not x) y) | |
| (##bitwise-and x z))) | |
| (define-prim (bitwise-merge x y z) | |
| (macro-force-vars (x y z) | |
| (cond ((##not (macro-exact-int? x)) | |
| (##fail-check-exact-integer 1 bitwise-merge x y z)) | |
| ((##not (macro-exact-int? y)) | |
| (##fail-check-exact-integer 2 bitwise-merge x y z)) | |
| ((##not (macro-exact-int? z)) | |
| (##fail-check-exact-integer 3 bitwise-merge x y z)) | |
| (else | |
| (##bitwise-merge x y z))))) | |
| (define-prim (##bit-set? x y) | |
| (define (type-error-on-x) | |
| (##fail-check-exact-integer 1 bit-set? x y)) | |
| (define (type-error-on-y) | |
| (##fail-check-exact-integer 2 bit-set? x y)) | |
| (define (range-error) | |
| (##raise-range-exception 1 bit-set? x y)) | |
| (cond ((##fixnum? x) | |
| (cond ((##fixnum? y) | |
| (if (##fxnegative? x) | |
| (range-error) | |
| (if (##fx< x ##fixnum-width) | |
| (##fxodd? (##fxarithmetic-shift-right y x)) | |
| (##fxnegative? y)))) | |
| ((##bignum? y) | |
| (if (##fxnegative? x) | |
| (range-error) | |
| (let ((i (##fxquotient x ##bignum.mdigit-width))) | |
| (if (##fx< i (##bignum.mdigit-length y)) | |
| (##fxodd? | |
| (##fxarithmetic-shift-right | |
| (##bignum.mdigit-ref y i) | |
| (##fxmodulo x ##bignum.mdigit-width))) | |
| (##bignum.negative? y))))) | |
| (else | |
| (type-error-on-y)))) | |
| ((##bignum? x) | |
| (cond ((##fixnum? y) | |
| (if (##bignum.negative? x) | |
| (range-error) | |
| (##fxnegative? y))) | |
| ((##bignum? y) | |
| (if (##bignum.negative? x) | |
| (range-error) | |
| (##bignum.negative? y))) | |
| (else | |
| (type-error-on-y)))) | |
| (else | |
| (type-error-on-x)))) | |
| (define-prim (bit-set? x y) | |
| (macro-force-vars (x y) | |
| (##bit-set? x y))) | |
| (define-prim (##any-bits-set? x y) | |
| (##not (##eqv? (##bitwise-and x y) 0))) | |
| (define-prim (any-bits-set? x y) | |
| (macro-force-vars (x y) | |
| (cond ((##not (macro-exact-int? x)) | |
| (##fail-check-exact-integer 1 any-bits-set? x y)) | |
| ((##not (macro-exact-int? y)) | |
| (##fail-check-exact-integer 2 any-bits-set? x y)) | |
| (else | |
| (##any-bits-set? x y))))) | |
| (define-prim (##all-bits-set? x y) | |
| (##= x (##bitwise-and x y))) | |
| (define-prim (all-bits-set? x y) | |
| (macro-force-vars (x y) | |
| (cond ((##not (macro-exact-int? x)) | |
| (##fail-check-exact-integer 1 all-bits-set? x y)) | |
| ((##not (macro-exact-int? y)) | |
| (##fail-check-exact-integer 2 all-bits-set? x y)) | |
| (else | |
| (##all-bits-set? x y))))) | |
| (define-prim (##first-bit-set x) | |
| (define (type-error) | |
| (##fail-check-exact-integer 1 first-bit-set x)) | |
| (cond ((##fixnum? x) | |
| (##fxfirst-bit-set x)) | |
| ((##bignum? x) | |
| (let ((x-length (##bignum.mdigit-length x))) | |
| (let loop ((i 0)) | |
| (let ((mdigit (##bignum.mdigit-ref x i))) | |
| (if (##fx= mdigit 0) | |
| (loop (##fx+ i 1)) | |
| (##fx+ | |
| (##fxfirst-bit-set mdigit) | |
| (##fx* i ##bignum.mdigit-width))))))) | |
| (else | |
| (type-error)))) | |
| (define-prim (first-bit-set x) | |
| (macro-force-vars (x) | |
| (##first-bit-set x))) | |
| (define-prim (##extract-bit-field size position n) | |
| ;; I've decided to be brutally simple and not optimize | |
| ;; for special cases, fixnums, etc. | |
| (let* ((result-length | |
| (##fxceiling-ratio (##fx+ 1 size) ##bignum.adigit-width)) ;; top bit is always 0 | |
| (bignum-n | |
| (if (##bignum? n) n (##fixnum->bignum n))) | |
| (result | |
| (##bignum.arithmetic-shift-into! | |
| bignum-n (##fx- position) (##bignum.make result-length #f #f)))) | |
| ;; zero top bits of result and normalize | |
| (let ((size-words (##fxquotient size ##bignum.mdigit-width)) | |
| (size-bits (##fxremainder size ##bignum.mdigit-width))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop ((i (##fx- (##bignum.mdigit-length result) 1))) | |
| (if (##fx< size-words i) | |
| (begin | |
| (##bignum.mdigit-set! result i 0) | |
| (loop (##fx- i 1))) | |
| (##bignum.mdigit-set! | |
| result i | |
| (##fxand | |
| (##bignum.mdigit-ref result i) | |
| (##fxnot (##fxarithmetic-shift-left -1 size-bits))))) | |
| (##bignum.normalize! result))))) | |
| (define-prim (extract-bit-field size position n) | |
| (macro-force-vars (size position n) | |
| (macro-check-index | |
| size | |
| 1 | |
| (extract-bit-field size position n) | |
| (macro-check-index | |
| position | |
| 2 | |
| (extract-bit-field size position n) | |
| (if (##not (macro-exact-int? n)) | |
| (##fail-check-exact-integer 3 extract-bit-field size position n) | |
| (##extract-bit-field size position n)))))) | |
| (define-prim (##test-bit-field? size position n) | |
| (##not (##eqv? (##extract-bit-field size position n) | |
| 0))) | |
| (define-prim (test-bit-field? size position n) | |
| (macro-force-vars (size position n) | |
| (macro-check-index | |
| size | |
| 1 | |
| (test-bit-field? size position n) | |
| (macro-check-index | |
| position | |
| 2 | |
| (test-bit-field? size position n) | |
| (if (##not (macro-exact-int? n)) | |
| (##fail-check-exact-integer 3 test-bit-field? size position n) | |
| (##test-bit-field? size position n)))))) | |
| (define-prim (##clear-bit-field size position n) | |
| (##replace-bit-field size position 0 n)) | |
| (define-prim (clear-bit-field size position n) | |
| (macro-force-vars (size position n) | |
| (macro-check-index | |
| size | |
| 1 | |
| (clear-bit-field size position n) | |
| (macro-check-index | |
| position | |
| 2 | |
| (clear-bit-field size position n) | |
| (if (##not (macro-exact-int? n)) | |
| (##fail-check-exact-integer 3 clear-bit-field size position n) | |
| (##clear-bit-field size position n)))))) | |
| (define-prim (##replace-bit-field size position newfield n) | |
| (let ((m (##bit-mask size))) | |
| (##bitwise-ior | |
| (##bitwise-and n (##bitwise-not (##arithmetic-shift m position))) | |
| (##arithmetic-shift (##bitwise-and newfield m) position)))) | |
| (define-prim (replace-bit-field size position newfield n) | |
| (macro-force-vars (size position newfield n) | |
| (macro-check-index | |
| size | |
| 1 | |
| (replace-bit-field size position newfield n) | |
| (macro-check-index | |
| position | |
| 2 | |
| (replace-bit-field size position newfield n) | |
| (cond ((##not (macro-exact-int? newfield)) | |
| (##fail-check-exact-integer 3 replace-bit-field size position newfield n)) | |
| ((##not (macro-exact-int? n)) | |
| (##fail-check-exact-integer 4 replace-bit-field size position newfield n)) | |
| (else | |
| (##replace-bit-field size position newfield n))))))) | |
| (define-prim (##copy-bit-field size position from to) | |
| (##bitwise-merge | |
| (##arithmetic-shift (##bit-mask size) position) | |
| to | |
| from)) | |
| (define-prim (copy-bit-field size position from to) | |
| (macro-force-vars (size position from to) | |
| (macro-check-index | |
| size | |
| 1 | |
| (copy-bit-field size position from to) | |
| (macro-check-index | |
| position | |
| 2 | |
| (copy-bit-field size position from to) | |
| (cond ((##not (macro-exact-int? from)) | |
| (##fail-check-exact-integer 3 copy-bit-field size position from to)) | |
| ((##not (macro-exact-int? to)) | |
| (##fail-check-exact-integer 4 copy-bit-field size position from to)) | |
| (else | |
| (##copy-bit-field size position from to))))))) | |
| (define-prim (##bit-mask size) | |
| (##bitwise-not (##arithmetic-shift -1 size))) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Fixnum operations | |
| ;;; ----------------- | |
| (##define-macro (define-prim-fixnum form . special-body) | |
| (let ((body (if (null? special-body) form `(begin ,@special-body)))) | |
| (cond ((= 1 (length (cdr form))) | |
| (let* ((name-fn (car form)) | |
| (name-param1 (cadr form))) | |
| `(define-prim ,form | |
| (macro-force-vars (,name-param1) | |
| (macro-check-fixnum | |
| ,name-param1 | |
| 1 | |
| ,form | |
| ,body))))) | |
| ((= 2 (length (cdr form))) | |
| (let* ((name-fn (car form)) | |
| (name-param1 (cadr form)) | |
| (name-param2 (caddr form))) | |
| `(define-prim ,form | |
| (macro-force-vars (,name-param1 ,name-param2) | |
| (macro-check-fixnum | |
| ,name-param1 | |
| 1 | |
| ,form | |
| (macro-check-fixnum | |
| ,name-param2 | |
| 2 | |
| ,form | |
| ,body)))))) | |
| (else | |
| (error "define-prim-fixnum supports only 1 or 2 parameter procedures"))))) | |
| (define-prim (fixnum? obj) | |
| (macro-force-vars (obj) | |
| (##fixnum? obj))) | |
| (define-prim-nary-bool (##fx= x y) | |
| #t | |
| #t | |
| (##fx= x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fx= x y) | |
| #t | |
| #t | |
| (##fx= x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary-bool (##fx< x y) | |
| #t | |
| #t | |
| (##fx< x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fx< x y) | |
| #t | |
| #t | |
| (##fx< x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary-bool (##fx> x y) | |
| #t | |
| #t | |
| (##fx> x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fx> x y) | |
| #t | |
| #t | |
| (##fx> x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary-bool (##fx<= x y) | |
| #t | |
| #t | |
| (##fx<= x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fx<= x y) | |
| #t | |
| #t | |
| (##fx<= x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary-bool (##fx>= x y) | |
| #t | |
| #t | |
| (##fx>= x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fx>= x y) | |
| #t | |
| #t | |
| (##fx>= x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim (##fxzero? x)) | |
| (define-prim-fixnum (fxzero? x) | |
| (##fxzero? x)) | |
| (define-prim (##fxpositive? x)) | |
| (define-prim-fixnum (fxpositive? x) | |
| (##fxpositive? x)) | |
| (define-prim (##fxnegative? x)) | |
| (define-prim-fixnum (fxnegative? x) | |
| (##fxnegative? x)) | |
| (define-prim (##fxodd? x)) | |
| (define-prim-fixnum (fxodd? x) | |
| (##fxodd? x)) | |
| (define-prim (##fxeven? x)) | |
| (define-prim-fixnum (fxeven? x) | |
| (##fxeven? x)) | |
| (define-prim-nary (##fxmax x y) | |
| () | |
| x | |
| (##fxmax x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxmax x y) | |
| () | |
| x | |
| (##fxmax x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fxmin x y) | |
| () | |
| x | |
| (##fxmin x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxmin x y) | |
| () | |
| x | |
| (##fxmin x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fxwrap+ x y) | |
| 0 | |
| x | |
| (##fxwrap+ x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxwrap+ x y) | |
| 0 | |
| x | |
| (##fxwrap+ x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fx+ x y) | |
| 0 | |
| x | |
| (##fx+ x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fx+ x y) | |
| 0 | |
| x | |
| (##fx+? x y) | |
| macro-force-vars | |
| macro-check-fixnum | |
| (##not ##raise-fixnum-overflow-exception)) | |
| (define-prim (##fx+? x y)) | |
| (define-prim-nary (##fxwrap* x y) | |
| 1 | |
| x | |
| (##fxwrap* x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxwrap* x y) | |
| 1 | |
| x | |
| (##fxwrap* x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fx* x y) | |
| 1 | |
| x | |
| (##fx* x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fx* x y) | |
| 1 | |
| x | |
| ((lambda (x y) | |
| (cond ((##fx= y 0) | |
| 0) | |
| ((##fx= y -1) | |
| (##fx-? x)) | |
| (else | |
| (##fx*? x y)))) | |
| x | |
| y) | |
| macro-force-vars | |
| macro-check-fixnum | |
| (##not ##raise-fixnum-overflow-exception)) | |
| (define-prim (##fx*? x y)) | |
| (define-prim-nary (##fxwrap- x y) | |
| () | |
| (##fxwrap- x) | |
| (##fxwrap- x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxwrap- x y) | |
| () | |
| (##fxwrap- x) | |
| (##fxwrap- x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fx- x y) | |
| () | |
| (##fx- x) | |
| (##fx- x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fx- x y) | |
| () | |
| (##fx-? x) | |
| (##fx-? x y) | |
| macro-force-vars | |
| macro-check-fixnum | |
| (##not ##raise-fixnum-overflow-exception)) | |
| (define-prim (##fx-? x #!optional (y (macro-absent-obj))) | |
| (if (##eq? y (macro-absent-obj)) | |
| (##fx-? x) | |
| (##fx-? x y))) | |
| (define-prim (##fxwrapquotient x y)) | |
| (define-prim-fixnum (fxwrapquotient x y) | |
| (if (##fx= y 0) | |
| (##raise-divide-by-zero-exception fxwrapquotient x y) | |
| (##fxwrapquotient x y))) | |
| (define-prim (##fxquotient x y)) | |
| (define-prim-fixnum (fxquotient x y) | |
| (if (##fx= y 0) | |
| (##raise-divide-by-zero-exception fxquotient x y) | |
| (if (##fx= y -1) | |
| (or (##fx-? x) | |
| (##raise-fixnum-overflow-exception fxquotient x y)) | |
| (##fxquotient x y)))) | |
| (define-prim (##fxremainder x y)) | |
| (define-prim-fixnum (fxremainder x y) | |
| (if (##fx= y 0) | |
| (##raise-divide-by-zero-exception fxremainder x y) | |
| (##fxremainder x y))) | |
| (define-prim (##fxmodulo x y)) | |
| (define-prim-fixnum (fxmodulo x y) | |
| (if (##fx= y 0) | |
| (##raise-divide-by-zero-exception fxmodulo x y) | |
| (##fxmodulo x y))) | |
| (define-prim (##fxnot x) | |
| (##fx- -1 x)) | |
| (define-prim-fixnum (fxnot x) | |
| (##fxnot x)) | |
| (define-prim-nary (##fxand x y) | |
| -1 | |
| x | |
| (##fxand x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxand x y) | |
| -1 | |
| x | |
| (##fxand x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fxior x y) | |
| 0 | |
| x | |
| (##fxior x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxior x y) | |
| 0 | |
| x | |
| (##fxior x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim-nary (##fxxor x y) | |
| 0 | |
| x | |
| (##fxxor x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fxxor x y) | |
| 0 | |
| x | |
| (##fxxor x y) | |
| macro-force-vars | |
| macro-check-fixnum) | |
| (define-prim (##fxif x y z)) | |
| (define-prim (fxif x y z) | |
| (macro-force-vars (x y z) | |
| (macro-check-fixnum | |
| x | |
| 1 | |
| (fxif x y z) | |
| (macro-check-fixnum | |
| y | |
| 2 | |
| (fxif x y z) | |
| (macro-check-fixnum | |
| z | |
| 3 | |
| (fxif x y z) | |
| (##fxif x y z)))))) | |
| (define-prim (##fxbit-count x)) | |
| (define-prim (fxbit-count x) | |
| (macro-force-vars (x) | |
| (macro-check-fixnum | |
| x | |
| 1 | |
| (fxbit-count x) | |
| (##fxbit-count x)))) | |
| (define-prim (##fxlength x)) | |
| (define-prim (fxlength x) | |
| (macro-force-vars (x) | |
| (macro-check-fixnum | |
| x | |
| 1 | |
| (fxlength x) | |
| (##fxlength x)))) | |
| (define-prim (##fxfirst-bit-set x)) | |
| (define-prim (fxfirst-bit-set x) | |
| (macro-force-vars (x) | |
| (macro-check-fixnum | |
| x | |
| 1 | |
| (fxfirst-bit-set x) | |
| (##fxfirst-bit-set x)))) | |
| (define-prim (##fxbit-set? x y)) | |
| (define-prim (fxbit-set? x y) | |
| (macro-force-vars (x y) | |
| (macro-check-fixnum-range-incl | |
| x | |
| 1 | |
| 0 | |
| ##fixnum-width | |
| (fxbit-set? x y) | |
| (macro-check-fixnum | |
| y | |
| 2 | |
| (fxbit-set? x y) | |
| (##fxbit-set? x y))))) | |
| (define-prim (##fxwraparithmetic-shift x y)) | |
| (define-prim (fxwraparithmetic-shift x y) | |
| (macro-force-vars (x y) | |
| (macro-check-fixnum | |
| x | |
| 1 | |
| (fxwraparithmetic-shift x y) | |
| (macro-check-fixnum-range-incl | |
| y | |
| 2 | |
| ##fixnum-width-neg | |
| ##fixnum-width | |
| (fxwraparithmetic-shift x y) | |
| (##fxwraparithmetic-shift x y))))) | |
| (define-prim (##fxarithmetic-shift x y)) | |
| (define-prim-fixnum (fxarithmetic-shift x y) | |
| (or (##fxarithmetic-shift? x y) | |
| (##raise-fixnum-overflow-exception fxarithmetic-shift x y))) | |
| (define-prim (##fxarithmetic-shift? x y)) | |
| (define-prim (##fxwraparithmetic-shift-left x y)) | |
| (define-prim (fxwraparithmetic-shift-left x y) | |
| (macro-force-vars (x y) | |
| (macro-check-fixnum | |
| x | |
| 1 | |
| (fxwraparithmetic-shift-left x y) | |
| (macro-check-fixnum-range-incl | |
| y | |
| 2 | |
| 0 | |
| ##fixnum-width | |
| (fxwraparithmetic-shift-left x y) | |
| (##fxwraparithmetic-shift-left x y))))) | |
| (define-prim (##fxarithmetic-shift-left x y)) | |
| (define-prim-fixnum (fxarithmetic-shift-left x y) | |
| (or (##fxarithmetic-shift-left? x y) | |
| (if (##fx< y 0) | |
| (##raise-range-exception 2 fxarithmetic-shift-left x y) | |
| (##raise-fixnum-overflow-exception fxarithmetic-shift-left x y)))) | |
| (define-prim (##fxarithmetic-shift-left? x y)) | |
| (define-prim (##fxarithmetic-shift-right x y)) | |
| (define-prim-fixnum (fxarithmetic-shift-right x y) | |
| (or (##fxarithmetic-shift-right? x y) | |
| (##raise-range-exception 2 fxarithmetic-shift-right x y))) | |
| (define-prim (##fxarithmetic-shift-right? x y)) | |
| (define-prim (##fxwraplogical-shift-right x y)) | |
| (define-prim-fixnum (fxwraplogical-shift-right x y) | |
| (or (##fxwraplogical-shift-right? x y) | |
| (##raise-range-exception 2 fxwraplogical-shift-right x y))) | |
| (define-prim (##fxwraplogical-shift-right? x y)) | |
| (define-prim (##fxwrapabs x)) | |
| (define-prim-fixnum (fxwrapabs x) | |
| (##fxwrapabs x)) | |
| (define-prim (##fxabs x)) | |
| (define-prim-fixnum (fxabs x) | |
| (or (##fxabs? x) | |
| (##raise-fixnum-overflow-exception fxabs x))) | |
| (define-prim (##fxabs? x)) | |
| (define-prim (##fxwrapsquare x)) | |
| (define-prim-fixnum (fxwrapsquare x) | |
| (##fxwrapsquare x)) | |
| (define-prim (##fxsquare x)) | |
| (define-prim-fixnum (fxsquare x) | |
| (or (##fxsquare? x) | |
| (##raise-fixnum-overflow-exception fxsquare x))) | |
| (define-prim (##fxsquare? x)) | |
| (define-prim (##integer->char x)) | |
| (define-prim (##char->integer x)) | |
| ;;; ------------------------------------------------------------------------------ | |
| ;;; Bignum Operations | |
| ;;; ------------------------------------------------------------------------------ | |
| ;;; | |
| ;;; The bignum operations were implemented mostly by Brad Lucier | |
| ;;; (http://www.math.purdue.edu/~lucier) with some coding guidance from | |
| ;;; Marc Feeley. | |
| ;;; | |
| ;;; The low-level representation of bignums and the low-level operations on | |
| ;;; bignums are inspired by the paper | |
| ;;; | |
| ;;; Reconfigurable, retargetable bignums: | |
| ;;; a case study in efficient, portable Lisp system building | |
| ;;; Jon L White | |
| ;;; Conference on LISP and Functional Programming | |
| ;;; Proceedings of the 1986 ACM conference on LISP and functional programming | |
| ;;; Cambridge, Massachusetts, United States | |
| ;;; Pages: 174 - 191 | |
| ;;; Year of Publication: 1986 | |
| ;;; ISBN:0-89791-200-4 | |
| ;;; | |
| ;;; We describe here the representation for the C back end. See _univlib.scm for | |
| ;;; other back ends. | |
| ;;; | |
| ;;; Bignums are represented as vectors of "adigit"s. Each element is an unsigned | |
| ;;; integer containing ##bignum.adigit-width bits, which is 64 bits if a 64-bit | |
| ;;; type is available (either as long or as long long). Logically, the 0th adigit | |
| ;;; of a bignum contains its least-significant bits; bignums are little-endian, | |
| ;;; and the top bit of the last adigit is interpreted as the sign bit of the bignum. | |
| ;;; Before being returned to the user, bignums must be normalized so that they have | |
| ;;; no redundant all-zero or all-one high-order adigits. Adigits are so called | |
| ;;; because they're used in addition (among other operations). For the purpose of | |
| ;;; documentation we'll use "adigit-base" to represent (expt 2 ##bignum.adigit-width). | |
| ;;; | |
| ;;; The bits of a bignum can be accessed as a vector of "mdigit"s, which are | |
| ;;; unsigned integers containing ##bignum.mdigit-width bits, which is 16 bits | |
| ;;; on a 32-bit Gambit or 32 bits on a 64-bit Gambit (so an mdigit always fits | |
| ;;; in a fixnum). Mdigits are so called because they're used in multiplciation | |
| ;;; (among other operations). For the purpose of documentation we'll use "mdigit-base" | |
| ;;; to represent (expt 2 ##bignum.mdigit-width). | |
| ;;; | |
| ;;; Finally, the bits of a bignum can be accessed as a vector of "fdigit"s, | |
| ;;; which are unsigned integers containing ##bignum.fdigit-width bits, which | |
| ;;; is currently 8 on all architectures. Fdigits are so called because a | |
| ;;; bignum is represented as fdigits before the Fast Fourier Transforms used | |
| ;;; in large bignum multiplications are performed. Some comments indicate that for | |
| ;;; bignums of larger than half a billion bits, four-bit fdigits may be useful, but that | |
| ;;; isn't implemented. | |
| ;;; | |
| ;;; The global variables ##bignum.adigit-width, ##bignum.mdigit-width, and | |
| ;;; ##bignum.fdigit-width are defined in _kernel.scm. | |
| ;;; | |
| ;;; All issues of big-endian or little-endian accesses are taken care of in the | |
| ;;; C macros implementing the low-level operations, so we can program as if we're | |
| ;;; on a little-endian machine. | |
| ;;; | |
| ;;; ------------------------------------------------------------------------------- | |
| ;;; These are the low-level operations on adigits, mdigits, and fdigits. | |
| ;;; Two-argument functions are generally destructive, and overwrite part of | |
| ;;; their first argument. These operations are supported in the Gambit Virtual | |
| ;;; Machine (GVM) and the Gambit Scheme Compiler (gsc). | |
| ;;; Returns #t if x is negative, #f otherwise | |
| (define-prim (##bignum.negative? x)) | |
| ;;; Returns the number of adigits in x (always a fixnum) | |
| (define-prim (##bignum.adigit-length x)) | |
| ;;; Increments the i'th adigit of x by 1 and returns 1 if the result | |
| ;;; overflowed, and 0 otherwise. | |
| (define-prim (##bignum.adigit-inc! x i)) | |
| ;;; Decrements the i'th digit of x by 1 and returns 1 if the result | |
| ;;; underflowed and 0 otherwise. | |
| (define-prim (##bignum.adigit-dec! x i)) | |
| ;;; Calculate | |
| ;;; sum = x[i] + y[j] + carry (accessing x and y as adigits) | |
| ;;; Sets x[i] = sum modulo adigit-base; returns 1 if overflow occured, | |
| ;;; 0 otherwise. | |
| (define-prim (##bignum.adigit-add! x i y j carry)) | |
| ;;; Calculate | |
| ;;; difference = x[i] - y[j] - borrow (accessing x and y as adigits) | |
| ;;; Sets x[i] = difference modulo adigit-base; returns 1 if underflow occured, | |
| ;;; 0 otherwise. | |
| (define-prim (##bignum.adigit-sub! x i y j borrow)) | |
| ;;; Returns the number of mdigits in x (always a fixnum) | |
| (define-prim (##bignum.mdigit-length x)) | |
| ;;; Returns the i'th mdigit of x | |
| (define-prim (##bignum.mdigit-ref x i)) | |
| ;;; Sets the i'th mdigit of x to mdigit | |
| (define-prim (##bignum.mdigit-set! x i mdigit)) | |
| ;;; Calculate | |
| ;;; z = x[i] + y[j] * multiplier + carry (accessing x and y as mdigits) | |
| ;;; Sets x[i] = z modulo mdigit-base; returns (quotient z mdigit-base) | |
| (define-prim (##bignum.mdigit-mul! x i y j multiplier carry)) | |
| ;;; Calculate | |
| ;;; z = x[i] - y[j] * quotient + borrow | |
| ;;; Sets x[i] to z modulo mdigit-base; returns | |
| ;;; (quotient (z - x[i]) mdigit-base) | |
| (define-prim (##bignum.mdigit-div! x i y j quotient borrow)) | |
| ;;; Returns | |
| ;;; (u[j] * mdigit-base + u[j-1]) / v | |
| ;;; (accessing u as mdigits) | |
| (define-prim (##bignum.mdigit-quotient u j v_n-1)) | |
| ;;; Returns | |
| ;;; (u[j] * mdigit-base + u[j-1] - v_n-1 * q-hat) | |
| ;;; (accessing u as mdigits) | |
| (define-prim (##bignum.mdigit-remainder u j v_n-1 q-hat)) | |
| ;;; Returns #t if | |
| ;;; q-hat * v_n-2 > (r-hat * mdigit-base + u_j-2) | |
| ;;; and #f otherwise | |
| (define-prim (##bignum.mdigit-test? q-hat v_n-2 r-hat u_j-2)) | |
| ;;; Returns #t if x[i] (accessed as adigits) is all ones, and | |
| ;;; #f otherwise | |
| (define-prim (##bignum.adigit-ones? x i)) | |
| ;;; Returns #t if x[i] (accessed as adigits) is all zeros, and | |
| ;;; #f otherwise | |
| (define-prim (##bignum.adigit-zero? x i)) | |
| ;;; Returns #t if the high-order bit of x[i] (accessing x as | |
| ;;; adigits) is 1, and #f otherwise | |
| (define-prim (##bignum.adigit-negative? x i)) | |
| ;;; Returns #t if x[i]=y[i] (accessing x and y as adigits) and | |
| ;;; #f otherwise | |
| (define-prim (##bignum.adigit-= x y i)) | |
| ;;; Returns #t if x[i]<y[i] (accessing x and y as adigits) and | |
| ;;; #f otherwise | |
| (define-prim (##bignum.adigit-< x y i)) | |
| ;;; Convert the fixnum x to an (unnormalized) bignum with one adigit | |
| (define-prim (##fixnum->bignum x)) | |
| ;;; Sets the number of adigits in the bignum x to n; must not increase | |
| ;;; the number of adigits in x | |
| (define-prim (##bignum.adigit-shrink! x n)) | |
| ;;; Sets x[i] to y[j] (accessing x and y as adigits) | |
| (define-prim (##bignum.adigit-copy! x i y j)) | |
| ;;; Calculate | |
| ;;; z = hi[j] << divider | lo[k] >> (##bignum.adigit-width - divider) | |
| ;;; (accessing hi and lo as adigits) | |
| ;;; Sets x[i] to z modulo adigit-base | |
| (define-prim (##bignum.adigit-cat! x i hi j lo k divider)) | |
| ;;; Sets x[i] to x[i] & y[j] (accessing x and y as adigits) | |
| (define-prim (##bignum.adigit-bitwise-and! x i y j)) | |
| ;;; Sets x[i] to x[i] | y[j] (accessing x and y as adigits) | |
| (define-prim (##bignum.adigit-bitwise-ior! x i y j)) | |
| ;;; Sets x[i] to x[i] ^ y[j] (accessing x and y as adigits) | |
| (define-prim (##bignum.adigit-bitwise-xor! x i y j)) | |
| ;;; Sets x[i] to !x[i] (accessing x as adigits) | |
| (define-prim (##bignum.adigit-bitwise-not! x i)) | |
| (macro-case-target | |
| ((C) | |
| ;; Returns the number of fdigits in x | |
| (define-prim (##bignum.fdigit-length x)) | |
| ;; Returns x[i] (accessing x as fdigits) | |
| (define-prim (##bignum.fdigit-ref x i)) | |
| ;; Sets x[i] to fdigit (accessing x as fdigits) | |
| (define-prim (##bignum.fdigit-set! x i fdigit)))) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Bignum related constants. | |
| (define ##bignum.adigit-ones (##fixnum->bignum -1)) ;; the 0th adigit is all ones | |
| (define ##bignum.adigit-zeros (##fixnum->bignum 0)) ;; the 0th adigit is all zeros | |
| (macro-case-target | |
| ((C) | |
| (define ##bignum.fdigit-base | |
| (##fxarithmetic-shift-left 1 ##bignum.fdigit-width)))) | |
| (define ##bignum.mdigit-base | |
| (##fxarithmetic-shift-left 1 ##bignum.mdigit-width)) | |
| (define ##bignum.inexact-mdigit-base | |
| (##fixnum->flonum ##bignum.mdigit-base)) | |
| (define ##bignum.mdigit-base-minus-1 | |
| (##fx- ##bignum.mdigit-base 1)) | |
| (define ##bignum.minus-mdigit-base | |
| (##fx- ##bignum.mdigit-base)) | |
| (define ##bignum.max-fixnum-div-mdigit-base | |
| (##fxquotient ##max-fixnum ##bignum.mdigit-base)) | |
| (define ##bignum.min-fixnum-div-mdigit-base | |
| (##fxquotient ##min-fixnum ##bignum.mdigit-base)) | |
| (define ##bignum.2*min-fixnum | |
| (if (##fixnum? -1073741824) | |
| -4611686018427387904 ;; (- (expt 2 62)) | |
| -1073741824)) ;; (- (expt 2 30)) | |
| ;;; The following global variables control when each of the three | |
| ;;; multiplication algorithms are used. | |
| ;;; | |
| ;;; Naive (grade-school) multiplication is used as long as one of | |
| ;;; the arguments has fewer than ##bignum.naive-mul-max-width | |
| ;;; bits. | |
| ;;; | |
| ;;; Karatsuba multiplication is used if the smaller of the two | |
| ;;; multiplication arguments has fewer than ##bignum.fft-mul-min-width | |
| ;;; or the larger of the two arguments has more than | |
| ;;; ##bignum.fft-mul-max-width bits | |
| ;;; | |
| ;;; For other sizes of the arguments use FFT multiplication. | |
| ;;; | |
| ;;; A "fast", reciprocal-based division is used if the divisor has | |
| ;;; more than ##bignum.fft-mul-min-width bits and the difference in | |
| ;;; size of the divident and divisor is more than | |
| ;;; ##bignum.fft-mul-min-width bits. | |
| ;;; | |
| ;;; Note that these global variables are not constants that are | |
| ;;; inlined, so one can change them if you like. | |
| (define ##bignum.naive-mul-max-width 1400) | |
| (set! ##bignum.naive-mul-max-width ##bignum.naive-mul-max-width) | |
| (define ##bignum.fft-mul-min-width 20000) | |
| (set! ##bignum.fft-mul-min-width ##bignum.fft-mul-min-width) | |
| (define ##bignum.fft-mul-max-width | |
| (if (##fixnum? -1073741824) ;; #t iff using 64-bit fixnums | |
| 536870912 | |
| ;; to avoid creating f64vectors that are too long | |
| 4194304)) | |
| (set! ##bignum.fft-mul-max-width ##bignum.fft-mul-max-width) | |
| ;;; An O(N(\log N)^2) algorithm for GCD is used if both arguments have more | |
| ;;; than ##bignum.fast-gcd-size bits | |
| (define ##bignum.fast-gcd-size ##bignum.naive-mul-max-width) ;; must be >= 64 | |
| (set! ##bignum.fast-gcd-size ##bignum.fast-gcd-size) | |
| ;;; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
| ;;; Operations where arguments are in bignum format | |
| (define-prim (##bignum.make k x complement?) | |
| (##declare (not interrupts-enabled)) | |
| (let ((v (##c-code " | |
| ___SIZE_TS i; | |
| ___SIZE_TS n = ___INT(___ARG1); | |
| ___SCMOBJ result; | |
| if (n > ___CAST(___WORD, ___LMASK>>___LF)/(___BIG_ABASE_WIDTH/8)) | |
| result = ___FIX(___HEAP_OVERFLOW_ERR); /* requested object is too big! */ | |
| else | |
| { | |
| #if ___BIG_ABASE_WIDTH == 32 | |
| ___SIZE_TS words = ___WORDS((n*(___BIG_ABASE_WIDTH/8))) + 1; | |
| #else | |
| #if ___WS == 4 | |
| ___SIZE_TS words = ___WORDS((n*(___BIG_ABASE_WIDTH/8))) + 2; | |
| #else | |
| ___SIZE_TS words = ___WORDS((n*(___BIG_ABASE_WIDTH/8))) + 1; | |
| #endif | |
| #endif | |
| if (words > ___MSECTION_BIGGEST) | |
| { | |
| ___FRAME_STORE_RA(___R0) | |
| ___W_ALL | |
| #if ___BIG_ABASE_WIDTH == 32 | |
| result = ___EXT(___alloc_scmobj) (___ps, ___sBIGNUM, n<<2); | |
| #else | |
| result = ___EXT(___alloc_scmobj) (___ps, ___sBIGNUM, n<<3); | |
| #endif | |
| ___R_ALL | |
| ___SET_R0(___FRAME_FETCH_RA) | |
| if (!___FIXNUMP(result)) | |
| ___still_obj_refcount_dec (result); | |
| } | |
| else | |
| { | |
| ___BOOL overflow = 0; | |
| ___hp += words; | |
| if (___hp > ___ps->heap_limit) | |
| { | |
| ___FRAME_STORE_RA(___R0) | |
| ___W_ALL | |
| overflow = ___heap_limit (___PSPNC) && ___garbage_collect (___PSP 0); | |
| ___R_ALL | |
| ___SET_R0(___FRAME_FETCH_RA) | |
| } | |
| else | |
| ___hp -= words; | |
| if (overflow) | |
| result = ___FIX(___HEAP_OVERFLOW_ERR); | |
| else | |
| { | |
| #if ___BIG_ABASE_WIDTH == 32 | |
| result = ___TAG(___hp, ___tSUBTYPED); | |
| #else | |
| #if ___WS == 4 | |
| result = ___TAG(___CAST(___SCMOBJ*,___CAST(___SCMOBJ,___hp+2)&~7)-1, | |
| ___tSUBTYPED); | |
| #else | |
| result = ___TAG(___hp, ___tSUBTYPED); | |
| #endif | |
| #endif | |
| #if ___BIG_ABASE_WIDTH == 32 | |
| ___HEADER(result) = ___MAKE_HD_BYTES((n<<2), ___sBIGNUM); | |
| #else | |
| ___HEADER(result) = ___MAKE_HD_BYTES((n<<3), ___sBIGNUM); | |
| #endif | |
| ___hp += words; | |
| } | |
| } | |
| } | |
| if (!___FIXNUMP(result)) | |
| { | |
| ___SCMOBJ x = ___ARG2; | |
| ___SCMOBJ len; | |
| if (x == ___FAL) | |
| len = 0; | |
| else | |
| { | |
| len = ___INT(___BIGALENGTH(x)); | |
| if (len > n) | |
| len = n; | |
| } | |
| #if ___BIG_ABASE_WIDTH == 32 | |
| if (___ARG3 == ___FAL) | |
| { | |
| for (i=0; i<len; i++) | |
| ___STORE_U32(___BODY_AS(result,___tSUBTYPED),i, | |
| ___FETCH_U32(___BODY_AS(x,___tSUBTYPED),i)); | |
| if (x != ___FAL && | |
| ___FETCH_S32(___BODY_AS(x,___tSUBTYPED),(i-1)) < 0) | |
| for (; i<n; i++) | |
| ___STORE_U32(___BODY_AS(result,___tSUBTYPED),i,___BIG_ABASE_MIN_1); | |
| else | |
| for (; i<n; i++) | |
| ___STORE_U32(___BODY_AS(result,___tSUBTYPED),i,0); | |
| } | |
| else | |
| { | |
| for (i=0; i<len; i++) | |
| ___STORE_U32(___BODY_AS(result,___tSUBTYPED),i, | |
| ~___FETCH_U32(___BODY_AS(x,___tSUBTYPED),i)); | |
| if (x != ___FAL && | |
| ___FETCH_S32(___BODY_AS(x,___tSUBTYPED),(i-1)) < 0) | |
| for (; i<n; i++) | |
| ___STORE_U32(___BODY_AS(result,___tSUBTYPED),i,0); | |
| else | |
| for (; i<n; i++) | |
| ___STORE_U32(___BODY_AS(result,___tSUBTYPED),i,___BIG_ABASE_MIN_1); | |
| } | |
| #else | |
| if (___ARG3 == ___FAL) | |
| { | |
| for (i=0; i<len; i++) | |
| ___STORE_U64(___BODY_AS(result,___tSUBTYPED),i, | |
| ___FETCH_U64(___BODY_AS(x,___tSUBTYPED),i)); | |
| if (x != ___FAL && | |
| ___FETCH_S64(___BODY_AS(x,___tSUBTYPED),(i-1)) < 0) | |
| for (; i<n; i++) | |
| ___STORE_U64(___BODY_AS(result,___tSUBTYPED),i,___BIG_ABASE_MIN_1); | |
| else | |
| for (; i<n; i++) | |
| ___STORE_U64(___BODY_AS(result,___tSUBTYPED),i,0); | |
| } | |
| else | |
| { | |
| for (i=0; i<len; i++) | |
| ___STORE_U64(___BODY_AS(result,___tSUBTYPED),i, | |
| ~___FETCH_U64(___BODY_AS(x,___tSUBTYPED),i)); | |
| if (x != ___FAL && | |
| ___FETCH_S64(___BODY_AS(x,___tSUBTYPED),(i-1)) < 0) | |
| for (; i<n; i++) | |
| ___STORE_U64(___BODY_AS(result,___tSUBTYPED),i,0); | |
| else | |
| for (; i<n; i++) | |
| ___STORE_U64(___BODY_AS(result,___tSUBTYPED),i,___BIG_ABASE_MIN_1); | |
| } | |
| #endif | |
| } | |
| ___RESULT = result; | |
| " k x complement?))) | |
| (if (##fixnum? v) | |
| (begin | |
| (##raise-heap-overflow-exception) | |
| (##bignum.make k x complement?)) | |
| v))) | |
| (define-prim (##bignum.copy x) | |
| (##bignum.make (##bignum.adigit-length x) x #f)) | |
| ;;; Bignum addition and subtraction. | |
| (define-prim (##bignum.+ x y) | |
| ;; x is an unnormalized bignum, y is an unnormalized bignum | |
| (define (add x x-length y y-length) | |
| (let* ((result-length | |
| (##fx+ y-length | |
| (if (##eq? (##bignum.negative? x) | |
| (##bignum.negative? y)) | |
| 1 | |
| 0))) | |
| (result | |
| (##bignum.make result-length y #f))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop ((i 0) | |
| (carry 0)) | |
| (if (##fx< i x-length) | |
| (loop (##fx+ i 1) | |
| (##bignum.adigit-add! result i x i carry)) | |
| (##bignum.propagate-carry-and-normalize! | |
| result | |
| result-length | |
| x-length | |
| (##bignum.negative? x) | |
| (##fxzero? carry)))))) | |
| (let ((x-length (##bignum.adigit-length x)) | |
| (y-length (##bignum.adigit-length y))) | |
| (if (##fx< x-length y-length) | |
| (add x x-length y y-length) | |
| (add y y-length x x-length)))) | |
| (define-prim (##bignum.- x y) | |
| ;; x is an unnormalized bignum, y is an unnormalized bignum | |
| (let ((x-length (##bignum.adigit-length x)) | |
| (y-length (##bignum.adigit-length y))) | |
| (if (##fx< x-length y-length) | |
| (let* ((result-length | |
| (##fx+ y-length | |
| (if (##eq? (##bignum.negative? x) | |
| (##bignum.negative? y)) | |
| 0 | |
| 1))) | |
| (result | |
| (##bignum.make result-length y #t))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop1 ((i 0) | |
| (carry 1)) | |
| (if (##fx< i x-length) | |
| (loop1 (##fx+ i 1) | |
| (##bignum.adigit-add! result i x i carry)) | |
| (##bignum.propagate-carry-and-normalize! | |
| result | |
| result-length | |
| x-length | |
| (##bignum.negative? x) | |
| (##fxzero? carry))))) | |
| (let* ((result-length | |
| (##fx+ x-length | |
| (if (##eq? (##bignum.negative? x) | |
| (##bignum.negative? y)) | |
| 0 | |
| 1))) | |
| (result | |
| (##bignum.make result-length x #f))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop2 ((i 0) | |
| (borrow 0)) | |
| (if (##fx< i y-length) | |
| (loop2 (##fx+ i 1) | |
| (##bignum.adigit-sub! result i y i borrow)) | |
| (##bignum.propagate-carry-and-normalize! | |
| result | |
| result-length | |
| y-length | |
| (##not (##bignum.negative? y)) | |
| (##not (##fxzero? borrow))))))))) | |
| (define-prim (##bignum.propagate-carry-and-normalize! | |
| result | |
| result-length | |
| i | |
| borrow? | |
| propagate?) | |
| (##declare (not interrupts-enabled)) | |
| (if (##eq? borrow? propagate?) | |
| (if borrow? | |
| (let loop1 ((i i) | |
| (borrow 1)) | |
| (if (and (##not (##fxzero? borrow)) | |
| (##fx< i result-length)) | |
| (loop1 (##fx+ i 1) | |
| (##bignum.adigit-dec! result i)) | |
| (##bignum.normalize! result))) | |
| (let loop2 ((i i) | |
| (carry 1)) | |
| (if (and (##not (##fxzero? carry)) | |
| (##fx< i result-length)) | |
| (loop2 (##fx+ i 1) | |
| (##bignum.adigit-inc! result i)) | |
| (##bignum.normalize! result)))) | |
| (##bignum.normalize! result))) | |
| (define-prim (##bignum->fixnum? bn) | |
| (let* ((i | |
| (##fx- (##bignum.mdigit-length bn) 1)) | |
| (n | |
| (##bignum.mdigit-ref bn i)) | |
| (bias | |
| (if (##fx< (##fx* 2 n) ##bignum.mdigit-base) | |
| 0 | |
| ##bignum.mdigit-base-minus-1))) | |
| (let loop ((n (##fx- n bias)) | |
| (i (##fx- i 1))) | |
| (if (##fx< i 0) | |
| (if (##fx= 0 bias) | |
| n | |
| (##fx+? n -1)) | |
| (let ((n1 (##fx*? n ##bignum.mdigit-base))) | |
| (and n1 | |
| (let ((n2 (##fx+? n1 (##fx- (##bignum.mdigit-ref bn i) bias)))) | |
| (and n2 | |
| (loop n2 | |
| (##fx- i 1)))))))))) | |
| (define-prim (##bignum.normalize! result) | |
| (##declare (not interrupts-enabled)) | |
| (or (##bignum->fixnum? result) | |
| (let ((n (##fx- (##bignum.adigit-length result) 1))) | |
| (cond ((##bignum.adigit-zero? result n) | |
| (let loop1 ((i (##fx- n 1))) | |
| (cond ((##fx< i 0) | |
| 0) | |
| ((##bignum.adigit-zero? result i) | |
| (loop1 (##fx- i 1))) | |
| ((##bignum.adigit-negative? result i) | |
| (##bignum.adigit-shrink! result (##fx+ i 2))) | |
| (else | |
| (##bignum.adigit-shrink! result (##fx+ i 1)))))) | |
| ((##bignum.adigit-ones? result n) | |
| (let loop2 ((i (##fx- n 1))) | |
| (cond ((##fx< i 0) | |
| -1) | |
| ((##bignum.adigit-ones? result i) | |
| (loop2 (##fx- i 1))) | |
| ((##not (##bignum.adigit-negative? result i)) | |
| (##bignum.adigit-shrink! result (##fx+ i 2))) | |
| (else | |
| (##bignum.adigit-shrink! result (##fx+ i 1)))))) | |
| (else | |
| result))))) | |
| ;;; Bignum multiplication. | |
| (define-prim (##bignum.* x y) | |
| (define (fft-mul x y) | |
| ;; Marc, the results of make-w should be cached, since bigger | |
| ;; tables can be used for any smaller size FFT. | |
| ;; This code works for x and y up to 536,870,912 bits, with | |
| ;; results up to 1Gb; numbers of this size require 8Gb, or 1GB, of | |
| ;; intermediate storage. It is always faster than the old code, | |
| ;; and it is mathematically correct. (Whether it is | |
| ;; programmatically correct is, of course, another matter, but I | |
| ;; have tested it extensively.) | |
| ;; This is an experiment. | |
| ;; This code implements bignum multiplication based on | |
| ;; double-precision FFT computations rather than on | |
| ;; number-theoretic FFTs and the Chinese remainder theorem. | |
| ;; The theory is in the article | |
| ;; Rapid multiplication modulo the sum and difference of highly | |
| ;; composite numbers, by Colin Percival | |
| ;; The complex roots of unity ("twiddle factors") need to be | |
| ;; computed in such a way that there is a known bound on the | |
| ;; error. I did this with a "computable reals" package I wrote. | |
| ;; I did not know a bound for the roots of unity in Ooura's FFT, | |
| ;; which is what we previously used.. | |
| ;; If you use a different complex FFT, then you need to ensure | |
| ;; that the same operations are done as in this FFT (perhaps in a | |
| ;; somewhat different order), or that you prove the corresponding | |
| ;; theorem for your FFT that Percival proved in his paper. On a | |
| ;; 2GHz PPC 970, my complex FFT seems to be about half as fast as | |
| ;; FFTW's complex FFT, so that doesn't seem too bad for one | |
| ;; written by hand in Scheme. | |
| ;; After years of fiddling around, I finally understook the | |
| ;; weighted FT transform and the so-called right-angle | |
| ;; convolution. See section 8.3.2 the book "Algorithms for | |
| ;; Programmers" by Jo"rg Arndt, currently available at | |
| ;; www.jjj.de/fxt/fxtbook.pdf for a description of the right-angle | |
| ;; transform. It's also covered in "Prime Numbers" by Crandall | |
| ;; and Pomerance, and was originally introduced in 1994 by | |
| ;; Crandall and Fagin. | |
| ;; The basic reference for the fft codes is | |
| ;; {\it Inside the FFT Black Box,} by Eleanor Chu and Alan George, | |
| ;; CRC Press, New York, 2000. In the end, I should say that these | |
| ;; codes are just motivated by this book. | |
| ;; One of the biggest problem in translating their notation is | |
| ;; that they work with complex numbers, and we're working with | |
| ;; pairs of reals. Let us assume that all complex numbers are | |
| ;; stored with adjacent real and imaginary parts, real first. | |
| #| | |
| The strategy in the next function is to calculate a 2^n'th | |
| root of unity by multiplying entries from up to three look-up | |
| tables, each of which has lut-table-size complex entries, stored | |
| as pairs of f64s. Each of the tables contains correctly-rounded | |
| complex roots of unity, as computed by my computable-reals code. | |
| The j'th entry of the first table is | |
| exp(\pi/2 * i * (bit-reverse j log-lut-table-size)/lut-table-size), j = 0,...,lut-table-size - 1. | |
| where (bit-reverse j k) reverses the bits of j when | |
| considered as a bit string of length k. | |
| The j'th entry of the second table is | |
| exp(\pi/2 * i * j/lut-table-size^2), j = 0,...,lut-table-size-1 | |
| and the j'th entry in the third table is | |
| exp(\pi/2 * i * j/lut-table-size^3), j = 0,...,lut-table-size-1 | |
| From these three tables we construct a lut w in bit-reverse | |
| order of size 2^log-n. | |
| Any table we construct is also usable for ffts of a smaller size. | |
| The errors in the tables are as follows. | |
| When log-lut-table-size=10, we have the error in the first | |
| table is bounded by | |
| 7.241394152931137e-17 | |
| Theoretically, it should be bounded by | |
| > (* (sqrt 1/2) (expt 2. -53)) | |
| 7.850462293418875e-17 | |
| The maximum error in the product of the first two tables is bounded by | |
| 2.5438950740364204e-16 | |
| The error in the general product of two correctly-rounded | |
| complex floating-point numbers of magnitude one is bounded by | |
| > (* (+ (sqrt 5) (sqrt 1/2) (sqrt 1/2)) (expt 2. -53)) | |
| 4.052626611931048e-16 | |
| but what we're seeing here is that the entries of the second | |
| table have real part close to 1 and imaginary part < | |
| pi/2*2^{-10}, so (a) the error in the entries of the second table | |
| is much closer to 1/2 epsilon rather than (sqrt 1/2) epsilon, | |
| and (2) we might expect an error of about sqrt(2)epsilon in the | |
| complex product instead of the general result of sqrt(5)epsilon, | |
| or | |
| > (* (+ (sqrt 2) (sqrt 1/2) 1/2) (expt 2. -53)) | |
| 2.910250200338241e-16 | |
| The maximum error in the product of entries from all three tables is | |
| 4.158491068379826e-16 | |
| which we can plug into the error bounds. Using the above | |
| heuristics, we would expect it to be < | |
| > (* (+ (sqrt 2) (sqrt 2) (sqrt 1/2) 1/2 1/2) (expt 2. -53)) | |
| 5.035454171334594e-16 | |
| and we have the general bound of | |
| > (* (+ (* 2 (sqrt 5)) (* 3 (sqrt 1/2))) (expt 2. -53)) | |
| 7.320206994520208e-16 | |
| so I'm glad I measured it. | |
| And, yes, I waited six days to compute the difference between | |
| the computed roots of unity and the exact roots of unity for all | |
| 2^{30} products from the three tables. | |
| When log-lut-table-size=9, the corresponding maximum errors are | |
| 7.113686303921851e-17 | |
| for entries in the first table, | |
| 2.4506454051660923e-16 | |
| for products of entries in the first two tables, and | |
| 4.164343159519809e-16 | |
| for products from all three tables. | |
| Added later: | |
| We could try a different strategy here. | |
| If it's necessary to multiply entries of all three tables to populate | |
| the result, we multiply the entries from the last two tables first to | |
| get a multiplier. Because the real parts of the second and third table | |
| entries are nearly one and the imaginary parts are < 2^{-9} or so, the | |
| rounding error in each entry is about 1/2 epsilon instead of (sqrt 1/2) | |
| epsilon, and the biggest error in the product is 1/2 epsilon in the | |
| product of the real parts and then another 1/2 epsilon when subtracting | |
| the product of the imaginary parts. So the total error is about | |
| (* (+ 1/2 1/2 1/2 1/2) (expt 2 -53)) | |
| or 2.220446049250313e-16. | |
| The final product adds further error of (sqrt 1/2) epsilon in the | |
| entries in the first table and then (sqrt 2) epsilon in the product. | |
| So my guess is that the total error in the product of three entries | |
| from the table will be bounded by | |
| (* (+ 1/2 1/2 1/2 1/2 (sqrt 1/2) (sqrt 2)) (expt 2 -53)) | |
| or 4.575584737275976e-16. | |
| |# | |
| (define lut-table-size 512) | |
| (define lut-table-size^2 262144) | |
| (define lut-table-size^3 134217728) | |
| (define log-lut-table-size 9) | |
| (define low-lut | |
| '#f64(1. 0. | |
| .7071067811865476 .7071067811865476 | |
| .9238795325112867 .3826834323650898 | |
| .3826834323650898 .9238795325112867 | |
| .9807852804032304 .19509032201612828 | |
| .5555702330196022 .8314696123025452 | |
| .8314696123025452 .5555702330196022 | |
| .19509032201612828 .9807852804032304 | |
| .9951847266721969 .0980171403295606 | |
| .6343932841636455 .773010453362737 | |
| .881921264348355 .47139673682599764 | |
| .2902846772544624 .9569403357322088 | |
| .9569403357322088 .2902846772544624 | |
| .47139673682599764 .881921264348355 | |
| .773010453362737 .6343932841636455 | |
| .0980171403295606 .9951847266721969 | |
| .9987954562051724 .049067674327418015 | |
| .6715589548470184 .7409511253549591 | |
| .9039892931234433 .4275550934302821 | |
| .33688985339222005 .9415440651830208 | |
| .970031253194544 .2429801799032639 | |
| .5141027441932218 .8577286100002721 | |
| .8032075314806449 .5956993044924334 | |
| .14673047445536175 .989176509964781 | |
| .989176509964781 .14673047445536175 | |
| .5956993044924334 .8032075314806449 | |
| .8577286100002721 .5141027441932218 | |
| .2429801799032639 .970031253194544 | |
| .9415440651830208 .33688985339222005 | |
| .4275550934302821 .9039892931234433 | |
| .7409511253549591 .6715589548470184 | |
| .049067674327418015 .9987954562051724 | |
| .9996988186962042 .024541228522912288 | |
| .6895405447370669 .7242470829514669 | |
| .9142097557035307 .40524131400498986 | |
| .35989503653498817 .9329927988347388 | |
| .9757021300385286 .2191012401568698 | |
| .5349976198870973 .8448535652497071 | |
| .8175848131515837 .5758081914178453 | |
| .17096188876030122 .9852776423889412 | |
| .99247953459871 .1224106751992162 | |
| .6152315905806268 .7883464276266062 | |
| .8700869911087115 .49289819222978404 | |
| .26671275747489837 .9637760657954398 | |
| .9495281805930367 .31368174039889146 | |
| .4496113296546066 .8932243011955153 | |
| .7572088465064846 .6531728429537768 | |
| .07356456359966743 .9972904566786902 | |
| .9972904566786902 .07356456359966743 | |
| .6531728429537768 .7572088465064846 | |
| .8932243011955153 .4496113296546066 | |
| .31368174039889146 .9495281805930367 | |
| .9637760657954398 .26671275747489837 | |
| .49289819222978404 .8700869911087115 | |
| .7883464276266062 .6152315905806268 | |
| .1224106751992162 .99247953459871 | |
| .9852776423889412 .17096188876030122 | |
| .5758081914178453 .8175848131515837 | |
| .8448535652497071 .5349976198870973 | |
| .2191012401568698 .9757021300385286 | |
| .9329927988347388 .35989503653498817 | |
| .40524131400498986 .9142097557035307 | |
| .7242470829514669 .6895405447370669 | |
| .024541228522912288 .9996988186962042 | |
| .9999247018391445 .012271538285719925 | |
| .6983762494089728 .7157308252838187 | |
| .9191138516900578 .3939920400610481 | |
| .37131719395183754 .9285060804732156 | |
| .9783173707196277 .20711137619221856 | |
| .5453249884220465 .8382247055548381 | |
| .8245893027850253 .5657318107836132 | |
| .18303988795514095 .9831054874312163 | |
| .9939069700023561 .11022220729388306 | |
| .6248594881423863 .7807372285720945 | |
| .8760700941954066 .4821837720791228 | |
| .2785196893850531 .9604305194155658 | |
| .9533060403541939 .3020059493192281 | |
| .46053871095824 .8876396204028539 | |
| .765167265622459 .6438315428897915 | |
| .0857973123444399 .996312612182778 | |
| .9981181129001492 .06132073630220858 | |
| .6624157775901718 .7491363945234594 | |
| .8986744656939538 .43861623853852766 | |
| .3253102921622629 .9456073253805213 | |
| .9669764710448521 .25486565960451457 | |
| .5035383837257176 .8639728561215867 | |
| .7958369046088836 .6055110414043255 | |
| .1345807085071262 .99090263542778 | |
| .9873014181578584 .15885814333386145 | |
| .5857978574564389 .8104571982525948 | |
| .8513551931052652 .524589682678469 | |
| .2310581082806711 .9729399522055602 | |
| .937339011912575 .34841868024943456 | |
| .4164295600976372 .9091679830905224 | |
| .7326542716724128 .680600997795453 | |
| .03680722294135883 .9993223845883495 | |
| .9993223845883495 .03680722294135883 | |
| .680600997795453 .7326542716724128 | |
| .9091679830905224 .4164295600976372 | |
| .34841868024943456 .937339011912575 | |
| .9729399522055602 .2310581082806711 | |
| .524589682678469 .8513551931052652 | |
| .8104571982525948 .5857978574564389 | |
| .15885814333386145 .9873014181578584 | |
| .99090263542778 .1345807085071262 | |
| .6055110414043255 .7958369046088836 | |
| .8639728561215867 .5035383837257176 | |
| .25486565960451457 .9669764710448521 | |
| .9456073253805213 .3253102921622629 | |
| .43861623853852766 .8986744656939538 | |
| .7491363945234594 .6624157775901718 | |
| .06132073630220858 .9981181129001492 | |
| .996312612182778 .0857973123444399 | |
| .6438315428897915 .765167265622459 | |
| .8876396204028539 .46053871095824 | |
| .3020059493192281 .9533060403541939 | |
| .9604305194155658 .2785196893850531 | |
| .4821837720791228 .8760700941954066 | |
| .7807372285720945 .6248594881423863 | |
| .11022220729388306 .9939069700023561 | |
| .9831054874312163 .18303988795514095 | |
| .5657318107836132 .8245893027850253 | |
| .8382247055548381 .5453249884220465 | |
| .20711137619221856 .9783173707196277 | |
| .9285060804732156 .37131719395183754 | |
| .3939920400610481 .9191138516900578 | |
| .7157308252838187 .6983762494089728 | |
| .012271538285719925 .9999247018391445 | |
| .9999811752826011 .006135884649154475 | |
| .7027547444572253 .7114321957452164 | |
| .9215140393420419 .3883450466988263 | |
| .37700741021641826 .9262102421383114 | |
| .9795697656854405 .2011046348420919 | |
| .5504579729366048 .83486287498638 | |
| .8280450452577558 .560661576197336 | |
| .18906866414980622 .9819638691095552 | |
| .9945645707342554 .10412163387205457 | |
| .629638238914927 .7768884656732324 | |
| .8790122264286335 .47679923006332214 | |
| .2844075372112718 .9587034748958716 | |
| .9551411683057707 .29615088824362384 | |
| .4659764957679662 .8847970984309378 | |
| .7691033376455796 .6391244448637757 | |
| .09190895649713272 .9957674144676598 | |
| .9984755805732948 .05519524434968994 | |
| .6669999223036375 .745057785441466 | |
| .901348847046022 .43309381885315196 | |
| .33110630575987643 .9435934581619604 | |
| .9685220942744173 .24892760574572018 | |
| .508830142543107 .8608669386377673 | |
| .799537269107905 .600616479383869 | |
| .14065823933284924 .9900582102622971 | |
| .9882575677307495 .15279718525844344 | |
| .5907597018588743 .8068475535437992 | |
| .8545579883654005 .5193559901655896 | |
| .2370236059943672 .9715038909862518 | |
| .9394592236021899 .3426607173119944 | |
| .4220002707997997 .9065957045149153 | |
| .7368165688773699 .6760927035753159 | |
| .04293825693494082 .9990777277526454 | |
| .9995294175010931 .030674803176636626 | |
| .6850836677727004 .7284643904482252 | |
| .9117060320054299 .41084317105790397 | |
| .3541635254204904 .9351835099389476 | |
| .9743393827855759 .22508391135979283 | |
| .5298036246862947 .8481203448032972 | |
| .8140363297059484 .5808139580957645 | |
| .16491312048996992 .9863080972445987 | |
| .9917097536690995 .12849811079379317 | |
| .6103828062763095 .7921065773002124 | |
| .8670462455156926 .49822766697278187 | |
| .2607941179152755 .9653944416976894 | |
| .9475855910177411 .3195020308160157 | |
| .44412214457042926 .8959662497561851 | |
| .7531867990436125 .6578066932970786 | |
| .06744391956366406 .9977230666441916 | |
| .9968202992911657 .07968243797143013 | |
| .6485144010221124 .7612023854842618 | |
| .8904487232447579 .45508358712634384 | |
| .30784964004153487 .9514350209690083 | |
| .9621214042690416 .272621355449949 | |
| .48755016014843594 .8730949784182901 | |
| .7845565971555752 .6200572117632892 | |
| .11631863091190477 .9932119492347945 | |
| .984210092386929 .17700422041214875 | |
| .5707807458869673 .8211025149911046 | |
| .8415549774368984 .5401714727298929 | |
| .21311031991609136 .9770281426577544 | |
| .9307669610789837 .36561299780477385 | |
| .39962419984564684 .9166790599210427 | |
| .7200025079613817 .693971460889654 | |
| .01840672990580482 .9998305817958234 | |
| .9998305817958234 .01840672990580482 | |
| .693971460889654 .7200025079613817 | |
| .9166790599210427 .39962419984564684 | |
| .36561299780477385 .9307669610789837 | |
| .9770281426577544 .21311031991609136 | |
| .5401714727298929 .8415549774368984 | |
| .8211025149911046 .5707807458869673 | |
| .17700422041214875 .984210092386929 | |
| .9932119492347945 .11631863091190477 | |
| .6200572117632892 .7845565971555752 | |
| .8730949784182901 .48755016014843594 | |
| .272621355449949 .9621214042690416 | |
| .9514350209690083 .30784964004153487 | |
| .45508358712634384 .8904487232447579 | |
| .7612023854842618 .6485144010221124 | |
| .07968243797143013 .9968202992911657 | |
| .9977230666441916 .06744391956366406 | |
| .6578066932970786 .7531867990436125 | |
| .8959662497561851 .44412214457042926 | |
| .3195020308160157 .9475855910177411 | |
| .9653944416976894 .2607941179152755 | |
| .49822766697278187 .8670462455156926 | |
| .7921065773002124 .6103828062763095 | |
| .12849811079379317 .9917097536690995 | |
| .9863080972445987 .16491312048996992 | |
| .5808139580957645 .8140363297059484 | |
| .8481203448032972 .5298036246862947 | |
| .22508391135979283 .9743393827855759 | |
| .9351835099389476 .3541635254204904 | |
| .41084317105790397 .9117060320054299 | |
| .7284643904482252 .6850836677727004 | |
| .030674803176636626 .9995294175010931 | |
| .9990777277526454 .04293825693494082 | |
| .6760927035753159 .7368165688773699 | |
| .9065957045149153 .4220002707997997 | |
| .3426607173119944 .9394592236021899 | |
| .9715038909862518 .2370236059943672 | |
| .5193559901655896 .8545579883654005 | |
| .8068475535437992 .5907597018588743 | |
| .15279718525844344 .9882575677307495 | |
| .9900582102622971 .14065823933284924 | |
| .600616479383869 .799537269107905 | |
| .8608669386377673 .508830142543107 | |
| .24892760574572018 .9685220942744173 | |
| .9435934581619604 .33110630575987643 | |
| .43309381885315196 .901348847046022 | |
| .745057785441466 .6669999223036375 | |
| .05519524434968994 .9984755805732948 | |
| .9957674144676598 .09190895649713272 | |
| .6391244448637757 .7691033376455796 | |
| .8847970984309378 .4659764957679662 | |
| .29615088824362384 .9551411683057707 | |
| .9587034748958716 .2844075372112718 | |
| .47679923006332214 .8790122264286335 | |
| .7768884656732324 .629638238914927 | |
| .10412163387205457 .9945645707342554 | |
| .9819638691095552 .18906866414980622 | |
| .560661576197336 .8280450452577558 | |
| .83486287498638 .5504579729366048 | |
| .2011046348420919 .9795697656854405 | |
| .9262102421383114 .37700741021641826 | |
| .3883450466988263 .9215140393420419 | |
| .7114321957452164 .7027547444572253 | |
| .006135884649154475 .9999811752826011 | |
| .9999952938095762 .003067956762965976 | |
| .7049340803759049 .7092728264388657 | |
| .9227011283338785 .38551605384391885 | |
| .37984720892405116 .9250492407826776 | |
| .9801821359681174 .1980984107179536 | |
| .5530167055800276 .8331701647019132 | |
| .829761233794523 .5581185312205561 | |
| .19208039704989244 .9813791933137546 | |
| .9948793307948056 .10106986275482782 | |
| .6320187359398091 .7749531065948739 | |
| .8804708890521608 .47410021465055 | |
| .2873474595447295 .9578264130275329 | |
| .9560452513499964 .29321916269425863 | |
| .46868882203582796 .8833633386657316 | |
| .7710605242618138 .6367618612362842 | |
| .094963495329639 .9954807554919269 | |
| .9986402181802653 .052131704680283324 | |
| .6692825883466361 .7430079521351217 | |
| .9026733182372588 .4303264813400826 | |
| .3339996514420094 .9425731976014469 | |
| .9692812353565485 .24595505033579462 | |
| .5114688504379704 .8593018183570084 | |
| .8013761717231402 .5981607069963423 | |
| .14369503315029444 .9896220174632009 | |
| .9887216919603238 .1497645346773215 | |
| .5932322950397998 .8050313311429635 | |
| .8561473283751945 .5167317990176499 | |
| .2400030224487415 .9707721407289504 | |
| .9405060705932683 .33977688440682685 | |
| .4247796812091088 .9052967593181188 | |
| .7388873244606151 .673829000378756 | |
| .04600318213091463 .9989412931868569 | |
| .9996188224951786 .027608145778965743 | |
| .6873153408917592 .726359155084346 | |
| .9129621904283982 .4080441628649787 | |
| .35703096123343003 .9340925504042589 | |
| .9750253450669941 .22209362097320354 | |
| .532403127877198 .8464909387740521 | |
| .8158144108067338 .5783137964116556 | |
| .16793829497473117 .9857975091675675 | |
| .9920993131421918 .12545498341154623 | |
| .6128100824294097 .79023022143731 | |
| .8685707059713409 .49556526182577254 | |
| .2637546789748314 .9645897932898128 | |
| .9485613499157303 .31659337555616585 | |
| .4468688401623742 .8945994856313827 | |
| .7552013768965365 .6554928529996153 | |
| .07050457338961387 .9975114561403035 | |
| .997060070339483 .07662386139203149 | |
| .6508466849963809 .7592091889783881 | |
| .8918407093923427 .4523495872337709 | |
| .3107671527496115 .9504860739494817 | |
| .9629532668736839 .2696683255729151 | |
| .49022648328829116 .8715950866559511 | |
| .7864552135990858 .617647307937804 | |
| .11936521481099137 .9928504144598651 | |
| .9847485018019042 .17398387338746382 | |
| .5732971666980422 .819347520076797 | |
| .8432082396418454 .5375870762956455 | |
| .21610679707621952 .9763697313300211 | |
| .9318842655816681 .3627557243673972 | |
| .40243465085941843 .9154487160882678 | |
| .7221281939292153 .6917592583641577 | |
| .021474080275469508 .9997694053512153 | |
| .9998823474542126 .015339206284988102 | |
| .696177131491463 .7178700450557317 | |
| .9179007756213905 .3968099874167103 | |
| .3684668299533723 .9296408958431812 | |
| .9776773578245099 .2101118368804696 | |
| .5427507848645159 .8398937941959995 | |
| .8228497813758263 .5682589526701316 | |
| .18002290140569951 .9836624192117303 | |
| .9935641355205953 .11327095217756435 | |
| .62246127937415 .7826505961665757 | |
| .8745866522781761 .4848692480007911 | |
| .27557181931095814 .9612804858113206 | |
| .9523750127197659 .30492922973540243 | |
| .45781330359887723 .8890483558546646 | |
| .7631884172633813 .6461760129833164 | |
| .08274026454937569 .9965711457905548 | |
| .997925286198596 .06438263092985747 | |
| .6601143420674205 .7511651319096864 | |
| .8973245807054183 .44137126873171667 | |
| .32240767880106985 .9466009130832835 | |
| .9661900034454125 .257831102162159 | |
| .5008853826112408 .8655136240905691 | |
| .7939754775543372 .6079497849677736 | |
| .13154002870288312 .9913108598461154 | |
| .9868094018141855 .16188639378011183 | |
| .5833086529376983 .8122505865852039 | |
| .8497417680008524 .5271991347819014 | |
| .22807208317088573 .973644249650812 | |
| .9362656671702783 .35129275608556715 | |
| .41363831223843456 .9104412922580672 | |
| .7305627692278276 .6828455463852481 | |
| .03374117185137759 .9994306045554617 | |
| .9992047586183639 .03987292758773981 | |
| .6783500431298615 .7347388780959635 | |
| .9078861164876663 .41921688836322396 | |
| .34554132496398904 .9384035340631081 | |
| .9722264970789363 .23404195858354343 | |
| .5219752929371544 .8529606049303636 | |
| .808656181588175 .5882815482226453 | |
| .15582839765426523 .9877841416445722 | |
| .9904850842564571 .13762012158648604 | |
| .6030665985403482 .7976908409433912 | |
| .8624239561110405 .5061866453451553 | |
| .25189781815421697 .9677538370934755 | |
| .9446048372614803 .32820984357909255 | |
| .4358570799222555 .9000158920161603 | |
| .7471006059801801 .6647109782033449 | |
| .05825826450043576 .9983015449338929 | |
| .996044700901252 .0888535525825246 | |
| .6414810128085832 .7671389119358204 | |
| .8862225301488806 .4632597835518602 | |
| .2990798263080405 .9542280951091057 | |
| .9595715130819845 .281464937925758 | |
| .479493757660153 .8775452902072612 | |
| .778816512381476 .6272518154951441 | |
| .10717242495680884 .9942404494531879 | |
| .9825393022874412 .18605515166344666 | |
| .5631993440138341 .8263210628456635 | |
| .836547727223512 .5478940591731002 | |
| .20410896609281687 .9789481753190622 | |
| .9273625256504011 .374164062971458 | |
| .39117038430225387 .9203182767091106 | |
| .7135848687807936 .7005687939432483 | |
| .00920375478205982 .9999576445519639 | |
| .9999576445519639 .00920375478205982 | |
| .7005687939432483 .7135848687807936 | |
| .9203182767091106 .39117038430225387 | |
| .374164062971458 .9273625256504011 | |
| .9789481753190622 .20410896609281687 | |
| .5478940591731002 .836547727223512 | |
| .8263210628456635 .5631993440138341 | |
| .18605515166344666 .9825393022874412 | |
| .9942404494531879 .10717242495680884 | |
| .6272518154951441 .778816512381476 | |
| .8775452902072612 .479493757660153 | |
| .281464937925758 .9595715130819845 | |
| .9542280951091057 .2990798263080405 | |
| .4632597835518602 .8862225301488806 | |
| .7671389119358204 .6414810128085832 | |
| .0888535525825246 .996044700901252 | |
| .9983015449338929 .05825826450043576 | |
| .6647109782033449 .7471006059801801 | |
| .9000158920161603 .4358570799222555 | |
| .32820984357909255 .9446048372614803 | |
| .9677538370934755 .25189781815421697 | |
| .5061866453451553 .8624239561110405 | |
| .7976908409433912 .6030665985403482 | |
| .13762012158648604 .9904850842564571 | |
| .9877841416445722 .15582839765426523 | |
| .5882815482226453 .808656181588175 | |
| .8529606049303636 .5219752929371544 | |
| .23404195858354343 .9722264970789363 | |
| .9384035340631081 .34554132496398904 | |
| .41921688836322396 .9078861164876663 | |
| .7347388780959635 .6783500431298615 | |
| .03987292758773981 .9992047586183639 | |
| .9994306045554617 .03374117185137759 | |
| .6828455463852481 .7305627692278276 | |
| .9104412922580672 .41363831223843456 | |
| .35129275608556715 .9362656671702783 | |
| .973644249650812 .22807208317088573 | |
| .5271991347819014 .8497417680008524 | |
| .8122505865852039 .5833086529376983 | |
| .16188639378011183 .9868094018141855 | |
| .9913108598461154 .13154002870288312 | |
| .6079497849677736 .7939754775543372 | |
| .8655136240905691 .5008853826112408 | |
| .257831102162159 .9661900034454125 | |
| .9466009130832835 .32240767880106985 | |
| .44137126873171667 .8973245807054183 | |
| .7511651319096864 .6601143420674205 | |
| .06438263092985747 .997925286198596 | |
| .9965711457905548 .08274026454937569 | |
| .6461760129833164 .7631884172633813 | |
| .8890483558546646 .45781330359887723 | |
| .30492922973540243 .9523750127197659 | |
| .9612804858113206 .27557181931095814 | |
| .4848692480007911 .8745866522781761 | |
| .7826505961665757 .62246127937415 | |
| .11327095217756435 .9935641355205953 | |
| .9836624192117303 .18002290140569951 | |
| .5682589526701316 .8228497813758263 | |
| .8398937941959995 .5427507848645159 | |
| .2101118368804696 .9776773578245099 | |
| .9296408958431812 .3684668299533723 | |
| .3968099874167103 .9179007756213905 | |
| .7178700450557317 .696177131491463 | |
| .015339206284988102 .9998823474542126 | |
| .9997694053512153 .021474080275469508 | |
| .6917592583641577 .7221281939292153 | |
| .9154487160882678 .40243465085941843 | |
| .3627557243673972 .9318842655816681 | |
| .9763697313300211 .21610679707621952 | |
| .5375870762956455 .8432082396418454 | |
| .819347520076797 .5732971666980422 | |
| .17398387338746382 .9847485018019042 | |
| .9928504144598651 .11936521481099137 | |
| .617647307937804 .7864552135990858 | |
| .8715950866559511 .49022648328829116 | |
| .2696683255729151 .9629532668736839 | |
| .9504860739494817 .3107671527496115 | |
| .4523495872337709 .8918407093923427 | |
| .7592091889783881 .6508466849963809 | |
| .07662386139203149 .997060070339483 | |
| .9975114561403035 .07050457338961387 | |
| .6554928529996153 .7552013768965365 | |
| .8945994856313827 .4468688401623742 | |
| .31659337555616585 .9485613499157303 | |
| .9645897932898128 .2637546789748314 | |
| .49556526182577254 .8685707059713409 | |
| .79023022143731 .6128100824294097 | |
| .12545498341154623 .9920993131421918 | |
| .9857975091675675 .16793829497473117 | |
| .5783137964116556 .8158144108067338 | |
| .8464909387740521 .532403127877198 | |
| .22209362097320354 .9750253450669941 | |
| .9340925504042589 .35703096123343003 | |
| .4080441628649787 .9129621904283982 | |
| .726359155084346 .6873153408917592 | |
| .027608145778965743 .9996188224951786 | |
| .9989412931868569 .04600318213091463 | |
| .673829000378756 .7388873244606151 | |
| .9052967593181188 .4247796812091088 | |
| .33977688440682685 .9405060705932683 | |
| .9707721407289504 .2400030224487415 | |
| .5167317990176499 .8561473283751945 | |
| .8050313311429635 .5932322950397998 | |
| .1497645346773215 .9887216919603238 | |
| .9896220174632009 .14369503315029444 | |
| .5981607069963423 .8013761717231402 | |
| .8593018183570084 .5114688504379704 | |
| .24595505033579462 .9692812353565485 | |
| .9425731976014469 .3339996514420094 | |
| .4303264813400826 .9026733182372588 | |
| .7430079521351217 .6692825883466361 | |
| .052131704680283324 .9986402181802653 | |
| .9954807554919269 .094963495329639 | |
| .6367618612362842 .7710605242618138 | |
| .8833633386657316 .46868882203582796 | |
| .29321916269425863 .9560452513499964 | |
| .9578264130275329 .2873474595447295 | |
| .47410021465055 .8804708890521608 | |
| .7749531065948739 .6320187359398091 | |
| .10106986275482782 .9948793307948056 | |
| .9813791933137546 .19208039704989244 | |
| .5581185312205561 .829761233794523 | |
| .8331701647019132 .5530167055800276 | |
| .1980984107179536 .9801821359681174 | |
| .9250492407826776 .37984720892405116 | |
| .38551605384391885 .9227011283338785 | |
| .7092728264388657 .7049340803759049 | |
| .003067956762965976 .9999952938095762 | |
| )) | |
| (define med-lut | |
| '#f64(1. 0. | |
| .9999999999820472 5.9921124526424275e-6 | |
| .9999999999281892 1.1984224905069707e-5 | |
| .9999999998384257 1.7976337357066685e-5 | |
| .9999999997127567 2.396844980841822e-5 | |
| .9999999995511824 2.9960562258909154e-5 | |
| .9999999993537025 3.5952674708324344e-5 | |
| .9999999991203175 4.1944787156448635e-5 | |
| .9999999988510269 4.793689960306688e-5 | |
| .9999999985458309 5.3929012047963936e-5 | |
| .9999999982047294 5.992112449092465e-5 | |
| .9999999978277226 6.591323693173387e-5 | |
| .9999999974148104 7.190534937017645e-5 | |
| .9999999969659927 7.789746180603723e-5 | |
| .9999999964812697 8.388957423910108e-5 | |
| .9999999959606412 8.988168666915283e-5 | |
| .9999999954041073 9.587379909597734e-5 | |
| .999999994811668 1.0186591151935948e-4 | |
| .9999999941833233 1.0785802393908407e-4 | |
| .9999999935190732 1.1385013635493597e-4 | |
| .9999999928189177 1.1984224876670004e-4 | |
| .9999999920828567 1.2583436117416112e-4 | |
| .9999999913108903 1.3182647357710405e-4 | |
| .9999999905030187 1.3781858597531374e-4 | |
| .9999999896592414 1.4381069836857496e-4 | |
| .9999999887795589 1.498028107566726e-4 | |
| .9999999878639709 1.5579492313939151e-4 | |
| .9999999869124775 1.6178703551651655e-4 | |
| .9999999859250787 1.6777914788783258e-4 | |
| .9999999849017744 1.737712602531244e-4 | |
| .9999999838425648 1.797633726121769e-4 | |
| .9999999827474497 1.8575548496477492e-4 | |
| .9999999816164293 1.9174759731070332e-4 | |
| .9999999804495034 1.9773970964974692e-4 | |
| .9999999792466722 2.037318219816906e-4 | |
| .9999999780079355 2.0972393430631923e-4 | |
| .9999999767332933 2.1571604662341763e-4 | |
| .9999999754227459 2.2170815893277063e-4 | |
| .9999999740762929 2.2770027123416315e-4 | |
| .9999999726939346 2.3369238352737996e-4 | |
| .9999999712756709 2.3968449581220595e-4 | |
| .9999999698215016 2.45676608088426e-4 | |
| .9999999683314271 2.5166872035582493e-4 | |
| .9999999668054471 2.5766083261418755e-4 | |
| .9999999652435617 2.636529448632988e-4 | |
| .9999999636457709 2.696450571029434e-4 | |
| .9999999620120748 2.756371693329064e-4 | |
| .9999999603424731 2.8162928155297243e-4 | |
| .9999999586369661 2.876213937629265e-4 | |
| .9999999568955537 2.936135059625534e-4 | |
| .9999999551182358 2.99605618151638e-4 | |
| .9999999533050126 3.055977303299651e-4 | |
| .9999999514558838 3.115898424973196e-4 | |
| .9999999495708498 3.1758195465348636e-4 | |
| .9999999476499103 3.235740667982502e-4 | |
| .9999999456930654 3.2956617893139595e-4 | |
| .9999999437003151 3.3555829105270853e-4 | |
| .9999999416716594 3.4155040316197275e-4 | |
| .9999999396070982 3.475425152589734e-4 | |
| .9999999375066316 3.535346273434955e-4 | |
| .9999999353702598 3.595267394153237e-4 | |
| .9999999331979824 3.6551885147424295e-4 | |
| .9999999309897996 3.7151096352003814e-4 | |
| .9999999287457114 3.7750307555249406e-4 | |
| .9999999264657179 3.8349518757139556e-4 | |
| .9999999241498189 3.8948729957652753e-4 | |
| .9999999217980144 3.954794115676748e-4 | |
| .9999999194103046 4.0147152354462224e-4 | |
| .9999999169866894 4.0746363550715466e-4 | |
| .9999999145271687 4.134557474550569e-4 | |
| .9999999120317428 4.194478593881139e-4 | |
| .9999999095004113 4.2543997130611036e-4 | |
| .9999999069331744 4.314320832088313e-4 | |
| .9999999043300322 4.3742419509606144e-4 | |
| .9999999016909845 4.4341630696758576e-4 | |
| .9999998990160315 4.4940841882318896e-4 | |
| .9999998963051729 4.55400530662656e-4 | |
| .999999893558409 4.613926424857717e-4 | |
| .9999998907757398 4.673847542923209e-4 | |
| .9999998879571651 4.7337686608208844e-4 | |
| .9999998851026849 4.793689778548592e-4 | |
| .9999998822122994 4.8536108961041806e-4 | |
| .9999998792860085 4.913532013485497e-4 | |
| .9999998763238122 4.973453130690393e-4 | |
| .9999998733257104 5.033374247716714e-4 | |
| .9999998702917032 5.09329536456231e-4 | |
| .9999998672217907 5.153216481225028e-4 | |
| .9999998641159727 5.213137597702719e-4 | |
| .9999998609742493 5.27305871399323e-4 | |
| .9999998577966206 5.332979830094408e-4 | |
| .9999998545830864 5.392900946004105e-4 | |
| .9999998513336468 5.452822061720168e-4 | |
| .9999998480483018 5.512743177240444e-4 | |
| .9999998447270514 5.572664292562783e-4 | |
| .9999998413698955 5.632585407685033e-4 | |
| .9999998379768343 5.692506522605043e-4 | |
| .9999998345478677 5.752427637320661e-4 | |
| .9999998310829956 5.812348751829735e-4 | |
| .9999998275822183 5.872269866130116e-4 | |
| .9999998240455354 5.93219098021965e-4 | |
| .9999998204729471 5.992112094096185e-4 | |
| .9999998168644535 6.052033207757572e-4 | |
| .9999998132200545 6.111954321201659e-4 | |
| .99999980953975 6.171875434426292e-4 | |
| .9999998058235401 6.231796547429323e-4 | |
| .9999998020714248 6.291717660208597e-4 | |
| .9999997982834041 6.351638772761965e-4 | |
| .9999997944594781 6.411559885087275e-4 | |
| .9999997905996466 6.471480997182375e-4 | |
| .9999997867039097 6.531402109045114e-4 | |
| .9999997827722674 6.591323220673341e-4 | |
| .9999997788047197 6.651244332064902e-4 | |
| .9999997748012666 6.711165443217649e-4 | |
| .9999997707619082 6.771086554129428e-4 | |
| .9999997666866443 6.83100766479809e-4 | |
| .9999997625754748 6.89092877522148e-4 | |
| .9999997584284002 6.950849885397449e-4 | |
| .9999997542454201 7.010770995323844e-4 | |
| .9999997500265345 7.070692104998515e-4 | |
| .9999997457717437 7.130613214419311e-4 | |
| .9999997414810473 7.190534323584079e-4 | |
| .9999997371544456 7.250455432490666e-4 | |
| .9999997327919384 7.310376541136925e-4 | |
| .9999997283935259 7.3702976495207e-4 | |
| .999999723959208 7.430218757639842e-4 | |
| .9999997194889846 7.490139865492199e-4 | |
| .9999997149828559 7.55006097307562e-4 | |
| .9999997104408218 7.609982080387952e-4 | |
| .9999997058628822 7.669903187427045e-4 | |
| .9999997012490373 7.729824294190747e-4 | |
| .9999996965992869 7.789745400676906e-4 | |
| .9999996919136313 7.849666506883372e-4 | |
| .99999968719207 7.909587612807992e-4 | |
| .9999996824346035 7.969508718448614e-4 | |
| .9999996776412315 8.029429823803089e-4 | |
| .9999996728119542 8.089350928869263e-4 | |
| .9999996679467715 8.149272033644986e-4 | |
| .9999996630456833 8.209193138128106e-4 | |
| .9999996581086897 8.269114242316472e-4 | |
| .9999996531357909 8.329035346207931e-4 | |
| .9999996481269865 8.388956449800333e-4 | |
| .9999996430822767 8.448877553091527e-4 | |
| .9999996380016616 8.508798656079359e-4 | |
| .999999632885141 8.56871975876168e-4 | |
| .9999996277327151 8.628640861136338e-4 | |
| .9999996225443838 8.68856196320118e-4 | |
| .9999996173201471 8.748483064954056e-4 | |
| .999999612060005 8.808404166392814e-4 | |
| .9999996067639574 8.868325267515304e-4 | |
| .9999996014320045 8.928246368319371e-4 | |
| .9999995960641462 8.988167468802867e-4 | |
| .9999995906603825 9.048088568963639e-4 | |
| .9999995852207133 9.108009668799535e-4 | |
| .9999995797451389 9.167930768308405e-4 | |
| .9999995742336589 9.227851867488095e-4 | |
| .9999995686862736 9.287772966336457e-4 | |
| .9999995631029829 9.347694064851338e-4 | |
| .9999995574837868 9.407615163030585e-4 | |
| .9999995518286853 9.467536260872047e-4 | |
| .9999995461376784 9.527457358373575e-4 | |
| .9999995404107661 9.587378455533015e-4 | |
| .9999995346479484 9.647299552348216e-4 | |
| .9999995288492254 9.707220648817027e-4 | |
| .9999995230145969 9.767141744937296e-4 | |
| .9999995171440631 9.827062840706872e-4 | |
| .9999995112376238 9.886983936123602e-4 | |
| .9999995052952791 9.946905031185337e-4 | |
| .9999994993170291 .0010006826125889925 | |
| .9999994933028736 .0010066747220235214 | |
| .9999994872528128 .001012666831421905 | |
| .9999994811668466 .0010186589407839286 | |
| .999999475044975 .0010246510501093766 | |
| .9999994688871979 .0010306431593980344 | |
| .9999994626935156 .0010366352686496862 | |
| .9999994564639277 .0010426273778641173 | |
| .9999994501984345 .0010486194870411127 | |
| .999999443897036 .0010546115961804568 | |
| .999999437559732 .0010606037052819344 | |
| .9999994311865227 .0010665958143453308 | |
| .9999994247774079 .0010725879233704307 | |
| .9999994183323877 .0010785800323570187 | |
| .9999994118514622 .0010845721413048801 | |
| .9999994053346313 .0010905642502137994 | |
| .9999993987818949 .0010965563590835613 | |
| .9999993921932533 .0011025484679139511 | |
| .9999993855687062 .0011085405767047535 | |
| .9999993789082536 .0011145326854557532 | |
| .9999993722118957 .001120524794166735 | |
| .9999993654796325 .0011265169028374842 | |
| .9999993587114638 .0011325090114677853 | |
| .9999993519073898 .001138501120057423 | |
| .9999993450674104 .0011444932286061825 | |
| .9999993381915255 .0011504853371138485 | |
| .9999993312797354 .0011564774455802057 | |
| .9999993243320398 .0011624695540050393 | |
| .9999993173484387 .001168461662388134 | |
| .9999993103289324 .0011744537707292742 | |
| .9999993032735206 .0011804458790282454 | |
| .9999992961822035 .0011864379872848323 | |
| .9999992890549809 .0011924300954988195 | |
| .999999281891853 .001198422203669992 | |
| .9999992746928197 .0012044143117981348 | |
| .999999267457881 .0012104064198830327 | |
| .999999260187037 .0012163985279244702 | |
| .9999992528802875 .0012223906359222325 | |
| .9999992455376326 .0012283827438761045 | |
| .9999992381590724 .0012343748517858707 | |
| .9999992307446068 .0012403669596513162 | |
| .9999992232942359 .001246359067472226 | |
| .9999992158079595 .0012523511752483847 | |
| .9999992082857777 .001258343282979577 | |
| .9999992007276906 .001264335390665588 | |
| .999999193133698 .0012703274983062026 | |
| .9999991855038001 .0012763196059012057 | |
| .9999991778379967 .001282311713450382 | |
| .9999991701362881 .0012883038209535163 | |
| .999999162398674 .0012942959284103935 | |
| .9999991546251547 .0013002880358207985 | |
| .9999991468157298 .001306280143184516 | |
| .9999991389703996 .001312272250501331 | |
| .999999131089164 .0013182643577710285 | |
| .999999123172023 .0013242564649933932 | |
| .9999991152189767 .0013302485721682098 | |
| .9999991072300249 .001336240679295263 | |
| .9999990992051678 .0013422327863743383 | |
| .9999990911444054 .0013482248934052201 | |
| .9999990830477375 .0013542170003876934 | |
| .9999990749151643 .001360209107321543 | |
| .9999990667466857 .0013662012142065536 | |
| .9999990585423016 .0013721933210425101 | |
| .9999990503020123 .0013781854278291975 | |
| .9999990420258176 .0013841775345664006 | |
| .9999990337137175 .0013901696412539043 | |
| .999999025365712 .0013961617478914935 | |
| .999999016981801 .0014021538544789526 | |
| .9999990085619848 .001408145961016067 | |
| .9999990001062631 .0014141380675026214 | |
| .9999989916146361 .0014201301739384005 | |
| .9999989830871038 .0014261222803231893 | |
| .9999989745236659 .0014321143866567725 | |
| .9999989659243228 .001438106492938935 | |
| .9999989572890743 .0014440985991694619 | |
| .9999989486179204 .0014500907053481378 | |
| .9999989399108612 .0014560828114747475 | |
| .9999989311678965 .0014620749175490758 | |
| .9999989223890265 .001468067023570908 | |
| .9999989135742512 .0014740591295400284 | |
| .9999989047235704 .0014800512354562223 | |
| .9999988958369843 .0014860433413192743 | |
| .9999988869144928 .0014920354471289693 | |
| .9999988779560959 .0014980275528850922 | |
| .9999988689617937 .0015040196585874275 | |
| .9999988599315861 .0015100117642357607 | |
| .999998850865473 .0015160038698298762 | |
| .9999988417634548 .001521995975369559 | |
| .999998832625531 .0015279880808545937 | |
| .9999988234517019 .0015339801862847657 | |
| .9999988142419675 .0015399722916598592 | |
| .9999988049963277 .0015459643969796596 | |
| .9999987957147825 .0015519565022439512 | |
| .9999987863973319 .0015579486074525195 | |
| .9999987770439759 .001563940712605149 | |
| .9999987676547146 .0015699328177016243 | |
| .999998758229548 .0015759249227417307 | |
| .9999987487684759 .0015819170277252528 | |
| .9999987392714985 .0015879091326519755 | |
| .9999987297386157 .0015939012375216837 | |
| .9999987201698276 .0015998933423341623 | |
| .9999987105651341 .001605885447089196 | |
| .9999987009245352 .0016118775517865696 | |
| .999998691248031 .0016178696564260683 | |
| .9999986815356214 .0016238617610074765 | |
| .9999986717873064 .0016298538655305794 | |
| .9999986620030861 .0016358459699951618 | |
| .9999986521829605 .0016418380744010084 | |
| .9999986423269294 .0016478301787479041 | |
| .999998632434993 .0016538222830356339 | |
| .9999986225071512 .0016598143872639823 | |
| .999998612543404 .0016658064914327345 | |
| .9999986025437515 .0016717985955416754 | |
| .9999985925081937 .0016777906995905894 | |
| .9999985824367305 .0016837828035792617 | |
| .9999985723293618 .0016897749075074774 | |
| .999998562186088 .0016957670113750207 | |
| .9999985520069086 .0017017591151816769 | |
| .9999985417918239 .0017077512189272307 | |
| .999998531540834 .001713743322611467 | |
| .9999985212539385 .0017197354262341706 | |
| .9999985109311378 .0017257275297951264 | |
| .9999985005724317 .0017317196332941192 | |
| .9999984901778203 .0017377117367309341 | |
| .9999984797473034 .0017437038401053556 | |
| .9999984692808812 .0017496959434171687 | |
| .9999984587785538 .0017556880466661582 | |
| .9999984482403208 .001761680149852109 | |
| .9999984376661826 .0017676722529748061 | |
| .999998427056139 .0017736643560340342 | |
| .99999841641019 .001779656459029578 | |
| .9999984057283358 .0017856485619612225 | |
| .9999983950105761 .0017916406648287528 | |
| .999998384256911 .0017976327676319532 | |
| .9999983734673407 .001803624870370609 | |
| .9999983626418649 .0018096169730445048 | |
| .9999983517804839 .0018156090756534257 | |
| .9999983408831975 .0018216011781971562 | |
| .9999983299500057 .0018275932806754815 | |
| .9999983189809085 .0018335853830881864 | |
| .999998307975906 .0018395774854350557 | |
| .9999982969349982 .001845569587715874 | |
| .9999982858581851 .0018515616899304264 | |
| .9999982747454665 .001857553792078498 | |
| .9999982635968426 .001863545894159873 | |
| .9999982524123134 .0018695379961743367 | |
| .9999982411918789 .001875530098121674 | |
| .9999982299355389 .0018815222000016696 | |
| .9999982186432936 .0018875143018141083 | |
| .999998207315143 .0018935064035587748 | |
| .999998195951087 .0018994985052354545 | |
| .9999981845511257 .0019054906068439318 | |
| .9999981731152591 .0019114827083839918 | |
| .999998161643487 .001917474809855419 | |
| .9999981501358096 .0019234669112579987 | |
| .999998138592227 .0019294590125915154 | |
| .9999981270127389 .0019354511138557542 | |
| .9999981153973455 .0019414432150504997 | |
| .9999981037460468 .0019474353161755369 | |
| .9999980920588427 .001953427417230651 | |
| .9999980803357332 .001959419518215626 | |
| .9999980685767185 .0019654116191302473 | |
| .9999980567817984 .0019714037199743 | |
| .9999980449509729 .0019773958207475683 | |
| .9999980330842422 .0019833879214498375 | |
| .999998021181606 .001989380022080892 | |
| .9999980092430646 .0019953721226405176 | |
| .9999979972686177 .002001364223128498 | |
| .9999979852582656 .002007356323544619 | |
| .9999979732120081 .002013348423888665 | |
| .9999979611298453 .002019340524160421 | |
| .9999979490117771 .0020253326243596715 | |
| .9999979368578036 .0020313247244862017 | |
| .9999979246679247 .002037316824539796 | |
| .9999979124421405 .00204330892452024 | |
| .999997900180451 .002049301024427318 | |
| .9999978878828562 .0020552931242608153 | |
| .9999978755493559 .002061285224020516 | |
| .9999978631799504 .0020672773237062057 | |
| .9999978507746395 .002073269423317669 | |
| .9999978383334234 .0020792615228546903 | |
| .9999978258563018 .002085253622317055 | |
| .999997813343275 .0020912457217045484 | |
| .9999978007943428 .002097237821016954 | |
| .9999977882095052 .0021032299202540577 | |
| .9999977755887623 .0021092220194156444 | |
| .9999977629321142 .0021152141185014984 | |
| .9999977502395607 .0021212062175114043 | |
| .9999977375111019 .002127198316445148 | |
| .9999977247467376 .0021331904153025134 | |
| .9999977119464681 .002139182514083286 | |
| .9999976991102932 .0021451746127872503 | |
| .9999976862382131 .002151166711414191 | |
| .9999976733302276 .0021571588099638934 | |
| .9999976603863368 .0021631509084361423 | |
| .9999976474065406 .002169143006830722 | |
| .9999976343908391 .002175135105147418 | |
| .9999976213392323 .0021811272033860148 | |
| .9999976082517201 .002187119301546297 | |
| .9999975951283027 .00219311139962805 | |
| .9999975819689799 .0021991034976310588 | |
| .9999975687737518 .0022050955955551076 | |
| .9999975555426184 .0022110876933999816 | |
| .9999975422755796 .0022170797911654654 | |
| .9999975289726355 .002223071888851344 | |
| .9999975156337861 .0022290639864574026 | |
| .9999975022590314 .0022350560839834253 | |
| .9999974888483714 .002241048181429198 | |
| .999997475401806 .0022470402787945045 | |
| .9999974619193353 .00225303237607913 | |
| .9999974484009593 .0022590244732828596 | |
| .9999974348466779 .0022650165704054784 | |
| .9999974212564913 .0022710086674467703 | |
| .9999974076303992 .002277000764406521 | |
| .9999973939684019 .002282992861284515 | |
| .9999973802704993 .0022889849580805368 | |
| .9999973665366915 .0022949770547943723 | |
| .9999973527669782 .0023009691514258054 | |
| .9999973389613596 .002306961247974621 | |
| .9999973251198357 .0023129533444406045 | |
| .9999973112424065 .0023189454408235406 | |
| .999997297329072 .0023249375371232135 | |
| .9999972833798322 .002330929633339409 | |
| .999997269394687 .0023369217294719113 | |
| .9999972553736366 .0023429138255205055 | |
| .9999972413166809 .0023489059214849765 | |
| .9999972272238198 .002354898017365109 | |
| .9999972130950534 .0023608901131606883 | |
| .9999971989303816 .0023668822088714985 | |
| .9999971847298047 .0023728743044973246 | |
| .9999971704933224 .0023788664000379523 | |
| .9999971562209347 .0023848584954931653 | |
| .9999971419126418 .0023908505908627493 | |
| .9999971275684435 .0023968426861464883 | |
| .99999711318834 .002402834781344168 | |
| .9999970987723311 .0024088268764555732 | |
| .9999970843204169 .002414818971480488 | |
| .9999970698325974 .002420811066418698 | |
| .9999970553088726 .0024268031612699878 | |
| .9999970407492426 .002432795256034142 | |
| .9999970261537071 .002438787350710946 | |
| .9999970115222664 .002444779445300184 | |
| .9999969968549204 .0024507715398016418 | |
| .9999969821516691 .002456763634215103 | |
| .9999969674125124 .002462755728540353 | |
| .9999969526374506 .0024687478227771774 | |
| .9999969378264834 .00247473991692536 | |
| .9999969229796108 .002480732010984686 | |
| .999996908096833 .0024867241049549406 | |
| .9999968931781499 .002492716198835908 | |
| .9999968782235614 .0024987082926273734 | |
| .9999968632330677 .002504700386329122 | |
| .9999968482066687 .002510692479940938 | |
| .9999968331443644 .0025166845734626068 | |
| .9999968180461547 .0025226766668939127 | |
| .9999968029120399 .002528668760234641 | |
| .9999967877420196 .002534660853484576 | |
| .9999967725360941 .0025406529466435036 | |
| .9999967572942633 .002546645039711208 | |
| .9999967420165272 .002552637132687474 | |
| .9999967267028858 .002558629225572086 | |
| .9999967113533391 .0025646213183648297 | |
| .9999966959678871 .0025706134110654896 | |
| .9999966805465298 .002576605503673851 | |
| .9999966650892672 .0025825975961896977 | |
| .9999966495960994 .0025885896886128153 | |
| .9999966340670262 .0025945817809429885 | |
| .9999966185020478 .0026005738731800024 | |
| .9999966029011641 .0026065659653236417 | |
| .999996587264375 .002612558057373691 | |
| .9999965715916808 .002618550149329935 | |
| .9999965558830811 .0026245422411921592 | |
| .9999965401385762 .002630534332960148 | |
| .9999965243581661 .002636526424633687 | |
| .9999965085418506 .0026425185162125596 | |
| .9999964926896299 .0026485106076965517 | |
| .9999964768015038 .0026545026990854484 | |
| .9999964608774725 .0026604947903790337 | |
| .9999964449175359 .0026664868815770926 | |
| .999996428921694 .0026724789726794104 | |
| .9999964128899468 .002678471063685772 | |
| .9999963968222944 .0026844631545959617 | |
| .9999963807187366 .002690455245409765 | |
| .9999963645792737 .002696447336126966 | |
| .9999963484039053 .00270243942674735 | |
| .9999963321926317 .002708431517270702 | |
| .9999963159454529 .0027144236076968066 | |
| .9999962996623687 .0027204156980254485 | |
| .9999962833433793 .002726407788256413 | |
| .9999962669884847 .002732399878389485 | |
| .9999962505976846 .0027383919684244484 | |
| .9999962341709794 .002744384058361089 | |
| .9999962177083689 .0027503761481991913 | |
| .999996201209853 .0027563682379385403 | |
| .9999961846754319 .0027623603275789207 | |
| .9999961681051056 .0027683524171201175 | |
| .999996151498874 .002774344506561915 | |
| .9999961348567371 .002780336595904099 | |
| .9999961181786949 .0027863286851464537 | |
| .9999961014647475 .0027923207742887642 | |
| .9999960847148948 .0027983128633308155 | |
| .9999960679291368 .002804304952272392 | |
| .9999960511074735 .002810297041113279 | |
| .9999960342499049 .0028162891298532606 | |
| .9999960173564312 .0028222812184921227 | |
| .9999960004270521 .002828273307029649 | |
| .9999959834617678 .002834265395465626 | |
| .9999959664605781 .0028402574837998367 | |
| .9999959494234832 .002846249572032067 | |
| .9999959323504831 .0028522416601621014 | |
| .9999959152415777 .002858233748189725 | |
| .999995898096767 .002864225836114723 | |
| .9999958809160512 .0028702179239368793 | |
| .9999958636994299 .0028762100116559793 | |
| .9999958464469034 .0028822020992718077 | |
| .9999958291584717 .0028881941867841495 | |
| .9999958118341348 .0028941862741927895 | |
| .9999957944738925 .0029001783614975127 | |
| .999995777077745 .002906170448698104 | |
| .9999957596456922 .0029121625357943475 | |
| .9999957421777342 .002918154622786029 | |
| .999995724673871 .0029241467096729327 | |
| .9999957071341024 .002930138796454844 | |
| .9999956895584287 .0029361308831315474 | |
| .9999956719468496 .0029421229697028273 | |
| .9999956542993652 .0029481150561684695 | |
| .9999956366159757 .0029541071425282584 | |
| .9999956188966809 .002960099228781979 | |
| .9999956011414808 .002966091314929416 | |
| .9999955833503754 .002972083400970354 | |
| .9999955655233649 .0029780754869045785 | |
| .9999955476604491 .0029840675727318736 | |
| .999995529761628 .002990059658452025 | |
| .9999955118269016 .0029960517440648163 | |
| .99999549385627 .0030020438295700336 | |
| .9999954758497331 .0030080359149674612 | |
| .999995457807291 .003014028000256884 | |
| .9999954397289438 .003020020085438087 | |
| .9999954216146911 .0030260121705108552 | |
| .9999954034645333 .003032004255474973 | |
| .9999953852784702 .003037996340330225 | |
| .9999953670565019 .003043988425076397 | |
| .9999953487986284 .003049980509713273 | |
| .9999953305048496 .0030559725942406386 | |
| .9999953121751655 .003061964678658278 | |
| )) | |
| (define high-lut | |
| '#f64(1. 0. | |
| .9999999999999999 1.1703344634137277e-8 | |
| .9999999999999998 2.3406689268274554e-8 | |
| .9999999999999993 3.5110033902411824e-8 | |
| .9999999999999989 4.6813378536549095e-8 | |
| .9999999999999983 5.851672317068635e-8 | |
| .9999999999999976 7.022006780482361e-8 | |
| .9999999999999967 8.192341243896085e-8 | |
| .9999999999999957 9.362675707309808e-8 | |
| .9999999999999944 1.0533010170723531e-7 | |
| .9999999999999931 1.170334463413725e-7 | |
| .9999999999999917 1.287367909755097e-7 | |
| .9999999999999901 1.4044013560964687e-7 | |
| .9999999999999885 1.5214348024378403e-7 | |
| .9999999999999866 1.6384682487792116e-7 | |
| .9999999999999846 1.7555016951205827e-7 | |
| .9999999999999825 1.8725351414619535e-7 | |
| .9999999999999802 1.989568587803324e-7 | |
| .9999999999999778 2.1066020341446942e-7 | |
| .9999999999999752 2.2236354804860645e-7 | |
| .9999999999999726 2.3406689268274342e-7 | |
| .9999999999999698 2.4577023731688034e-7 | |
| .9999999999999668 2.5747358195101726e-7 | |
| .9999999999999638 2.6917692658515413e-7 | |
| .9999999999999606 2.8088027121929094e-7 | |
| .9999999999999571 2.9258361585342776e-7 | |
| .9999999999999537 3.042869604875645e-7 | |
| .99999999999995 3.159903051217012e-7 | |
| .9999999999999463 3.276936497558379e-7 | |
| .9999999999999424 3.3939699438997453e-7 | |
| .9999999999999384 3.5110033902411114e-7 | |
| .9999999999999342 3.6280368365824763e-7 | |
| .9999999999999298 3.7450702829238413e-7 | |
| .9999999999999254 3.8621037292652057e-7 | |
| .9999999999999208 3.979137175606569e-7 | |
| .9999999999999161 4.0961706219479325e-7 | |
| .9999999999999113 4.2132040682892953e-7 | |
| .9999999999999063 4.330237514630657e-7 | |
| .9999999999999011 4.447270960972019e-7 | |
| .9999999999998959 4.5643044073133796e-7 | |
| .9999999999998904 4.68133785365474e-7 | |
| .9999999999998849 4.7983712999961e-7 | |
| .9999999999998792 4.915404746337459e-7 | |
| .9999999999998733 5.032438192678817e-7 | |
| .9999999999998674 5.149471639020175e-7 | |
| .9999999999998613 5.266505085361531e-7 | |
| .9999999999998551 5.383538531702888e-7 | |
| .9999999999998487 5.500571978044243e-7 | |
| .9999999999998422 5.617605424385598e-7 | |
| .9999999999998356 5.734638870726952e-7 | |
| .9999999999998288 5.851672317068305e-7 | |
| .9999999999998219 5.968705763409657e-7 | |
| .9999999999998148 6.085739209751009e-7 | |
| .9999999999998076 6.202772656092359e-7 | |
| .9999999999998003 6.319806102433709e-7 | |
| .9999999999997928 6.436839548775058e-7 | |
| .9999999999997853 6.553872995116406e-7 | |
| .9999999999997775 6.670906441457753e-7 | |
| .9999999999997696 6.7879398877991e-7 | |
| .9999999999997616 6.904973334140445e-7 | |
| .9999999999997534 7.02200678048179e-7 | |
| .9999999999997452 7.139040226823132e-7 | |
| .9999999999997368 7.256073673164475e-7 | |
| .9999999999997282 7.373107119505817e-7 | |
| .9999999999997194 7.490140565847157e-7 | |
| .9999999999997107 7.607174012188497e-7 | |
| .9999999999997017 7.724207458529835e-7 | |
| .9999999999996926 7.841240904871172e-7 | |
| .9999999999996834 7.958274351212508e-7 | |
| .9999999999996739 8.075307797553844e-7 | |
| .9999999999996644 8.192341243895178e-7 | |
| .9999999999996547 8.309374690236511e-7 | |
| .999999999999645 8.426408136577842e-7 | |
| .9999999999996351 8.543441582919173e-7 | |
| .999999999999625 8.660475029260503e-7 | |
| .9999999999996148 8.777508475601831e-7 | |
| .9999999999996044 8.894541921943158e-7 | |
| .999999999999594 9.011575368284484e-7 | |
| .9999999999995833 9.128608814625808e-7 | |
| .9999999999995726 9.245642260967132e-7 | |
| .9999999999995617 9.362675707308454e-7 | |
| .9999999999995507 9.479709153649775e-7 | |
| .9999999999995395 9.596742599991095e-7 | |
| .9999999999995283 9.713776046332412e-7 | |
| .9999999999995168 9.83080949267373e-7 | |
| .9999999999995052 9.947842939015044e-7 | |
| .9999999999994935 1.006487638535636e-6 | |
| .9999999999994816 1.0181909831697673e-6 | |
| .9999999999994696 1.0298943278038984e-6 | |
| .9999999999994575 1.0415976724380293e-6 | |
| .9999999999994453 1.0533010170721601e-6 | |
| .9999999999994329 1.065004361706291e-6 | |
| .9999999999994204 1.0767077063404215e-6 | |
| .9999999999994077 1.088411050974552e-6 | |
| .9999999999993949 1.1001143956086822e-6 | |
| .9999999999993819 1.1118177402428122e-6 | |
| .9999999999993688 1.1235210848769423e-6 | |
| .9999999999993556 1.135224429511072e-6 | |
| .9999999999993423 1.1469277741452017e-6 | |
| .9999999999993288 1.1586311187793313e-6 | |
| .9999999999993151 1.1703344634134605e-6 | |
| .9999999999993014 1.1820378080475897e-6 | |
| .9999999999992875 1.1937411526817187e-6 | |
| .9999999999992735 1.2054444973158477e-6 | |
| .9999999999992593 1.2171478419499764e-6 | |
| .9999999999992449 1.2288511865841048e-6 | |
| .9999999999992305 1.2405545312182331e-6 | |
| .999999999999216 1.2522578758523615e-6 | |
| .9999999999992012 1.2639612204864894e-6 | |
| .9999999999991863 1.2756645651206173e-6 | |
| .9999999999991713 1.287367909754745e-6 | |
| .9999999999991562 1.2990712543888725e-6 | |
| .9999999999991409 1.3107745990229998e-6 | |
| .9999999999991255 1.3224779436571269e-6 | |
| .9999999999991099 1.3341812882912537e-6 | |
| .9999999999990943 1.3458846329253806e-6 | |
| .9999999999990785 1.3575879775595072e-6 | |
| .9999999999990625 1.3692913221936337e-6 | |
| .9999999999990464 1.3809946668277597e-6 | |
| .9999999999990302 1.3926980114618857e-6 | |
| .9999999999990138 1.4044013560960117e-6 | |
| .9999999999989974 1.4161047007301373e-6 | |
| .9999999999989807 1.4278080453642627e-6 | |
| .9999999999989639 1.439511389998388e-6 | |
| .999999999998947 1.451214734632513e-6 | |
| .99999999999893 1.462918079266638e-6 | |
| .9999999999989128 1.4746214239007625e-6 | |
| .9999999999988954 1.486324768534887e-6 | |
| .999999999998878 1.4980281131690111e-6 | |
| .9999999999988604 1.5097314578031353e-6 | |
| .9999999999988426 1.5214348024372591e-6 | |
| .9999999999988247 1.5331381470713828e-6 | |
| .9999999999988067 1.544841491705506e-6 | |
| .9999999999987886 1.5565448363396294e-6 | |
| .9999999999987703 1.5682481809737524e-6 | |
| .9999999999987519 1.579951525607875e-6 | |
| .9999999999987333 1.5916548702419977e-6 | |
| .9999999999987146 1.60335821487612e-6 | |
| .9999999999986958 1.615061559510242e-6 | |
| .9999999999986768 1.626764904144364e-6 | |
| .9999999999986577 1.6384682487784858e-6 | |
| .9999999999986384 1.6501715934126072e-6 | |
| .9999999999986191 1.6618749380467283e-6 | |
| .9999999999985996 1.6735782826808495e-6 | |
| .9999999999985799 1.6852816273149702e-6 | |
| .9999999999985602 1.6969849719490907e-6 | |
| .9999999999985402 1.708688316583211e-6 | |
| .9999999999985201 1.720391661217331e-6 | |
| .9999999999985 1.732095005851451e-6 | |
| .9999999999984795 1.7437983504855706e-6 | |
| .9999999999984591 1.7555016951196899e-6 | |
| .9999999999984385 1.767205039753809e-6 | |
| .9999999999984177 1.778908384387928e-6 | |
| .9999999999983968 1.7906117290220465e-6 | |
| .9999999999983759 1.802315073656165e-6 | |
| .9999999999983546 1.814018418290283e-6 | |
| .9999999999983333 1.825721762924401e-6 | |
| .9999999999983119 1.8374251075585186e-6 | |
| .9999999999982904 1.8491284521926361e-6 | |
| .9999999999982686 1.8608317968267533e-6 | |
| .9999999999982468 1.8725351414608702e-6 | |
| .9999999999982249 1.8842384860949866e-6 | |
| .9999999999982027 1.8959418307291031e-6 | |
| .9999999999981805 1.9076451753632194e-6 | |
| .999999999998158 1.919348519997335e-6 | |
| .9999999999981355 1.9310518646314507e-6 | |
| .9999999999981128 1.942755209265566e-6 | |
| .9999999999980901 1.954458553899681e-6 | |
| .9999999999980671 1.966161898533796e-6 | |
| .999999999998044 1.9778652431679103e-6 | |
| .9999999999980208 1.9895685878020246e-6 | |
| .9999999999979975 2.0012719324361386e-6 | |
| .999999999997974 2.012975277070252e-6 | |
| .9999999999979503 2.0246786217043656e-6 | |
| .9999999999979265 2.0363819663384787e-6 | |
| .9999999999979027 2.048085310972592e-6 | |
| .9999999999978786 2.0597886556067045e-6 | |
| .9999999999978545 2.0714920002408167e-6 | |
| .9999999999978302 2.0831953448749286e-6 | |
| .9999999999978058 2.0948986895090404e-6 | |
| .9999999999977811 2.106602034143152e-6 | |
| .9999999999977564 2.118305378777263e-6 | |
| .9999999999977315 2.1300087234113738e-6 | |
| .9999999999977065 2.1417120680454843e-6 | |
| .9999999999976814 2.153415412679595e-6 | |
| .9999999999976561 2.1651187573137046e-6 | |
| .9999999999976307 2.1768221019478143e-6 | |
| .9999999999976051 2.188525446581924e-6 | |
| .9999999999975795 2.200228791216033e-6 | |
| .9999999999975536 2.2119321358501417e-6 | |
| .9999999999975278 2.22363548048425e-6 | |
| .9999999999975017 2.2353388251183586e-6 | |
| .9999999999974754 2.247042169752466e-6 | |
| .999999999997449 2.2587455143865738e-6 | |
| .9999999999974225 2.2704488590206814e-6 | |
| .9999999999973959 2.282152203654788e-6 | |
| .9999999999973691 2.293855548288895e-6 | |
| .9999999999973422 2.305558892923001e-6 | |
| .9999999999973151 2.317262237557107e-6 | |
| .999999999997288 2.328965582191213e-6 | |
| .9999999999972606 2.340668926825318e-6 | |
| .9999999999972332 2.352372271459423e-6 | |
| .9999999999972056 2.364075616093528e-6 | |
| .9999999999971778 2.3757789607276323e-6 | |
| .99999999999715 2.3874823053617365e-6 | |
| .999999999997122 2.3991856499958403e-6 | |
| .9999999999970938 2.4108889946299437e-6 | |
| .9999999999970656 2.4225923392640466e-6 | |
| .9999999999970371 2.4342956838981495e-6 | |
| .9999999999970085 2.445999028532252e-6 | |
| .9999999999969799 2.457702373166354e-6 | |
| .999999999996951 2.4694057178004558e-6 | |
| .999999999996922 2.4811090624345574e-6 | |
| .9999999999968929 2.4928124070686583e-6 | |
| .9999999999968637 2.504515751702759e-6 | |
| .9999999999968343 2.5162190963368595e-6 | |
| .9999999999968048 2.5279224409709594e-6 | |
| .9999999999967751 2.5396257856050594e-6 | |
| .9999999999967454 2.5513291302391585e-6 | |
| .9999999999967154 2.5630324748732576e-6 | |
| .9999999999966853 2.5747358195073563e-6 | |
| .9999999999966551 2.5864391641414546e-6 | |
| .9999999999966248 2.5981425087755525e-6 | |
| .9999999999965944 2.6098458534096503e-6 | |
| .9999999999965637 2.6215491980437473e-6 | |
| .999999999996533 2.6332525426778443e-6 | |
| .9999999999965021 2.644955887311941e-6 | |
| .999999999996471 2.656659231946037e-6 | |
| .99999999999644 2.6683625765801328e-6 | |
| .9999999999964087 2.680065921214228e-6 | |
| .9999999999963772 2.6917692658483234e-6 | |
| .9999999999963456 2.703472610482418e-6 | |
| .999999999996314 2.7151759551165123e-6 | |
| .9999999999962821 2.7268792997506064e-6 | |
| .9999999999962501 2.7385826443846996e-6 | |
| .9999999999962179 2.750285989018793e-6 | |
| .9999999999961857 2.761989333652886e-6 | |
| .9999999999961533 2.7736926782869783e-6 | |
| .9999999999961208 2.78539602292107e-6 | |
| .9999999999960881 2.797099367555162e-6 | |
| .9999999999960553 2.808802712189253e-6 | |
| .9999999999960224 2.8205060568233443e-6 | |
| .9999999999959893 2.832209401457435e-6 | |
| .9999999999959561 2.8439127460915247e-6 | |
| .9999999999959227 2.8556160907256145e-6 | |
| .9999999999958893 2.867319435359704e-6 | |
| .9999999999958556 2.879022779993793e-6 | |
| .9999999999958219 2.8907261246278814e-6 | |
| .9999999999957879 2.90242946926197e-6 | |
| .999999999995754 2.9141328138960576e-6 | |
| .9999999999957198 2.925836158530145e-6 | |
| .9999999999956855 2.9375395031642317e-6 | |
| .999999999995651 2.9492428477983186e-6 | |
| .9999999999956164 2.9609461924324046e-6 | |
| .9999999999955816 2.9726495370664905e-6 | |
| .9999999999955468 2.9843528817005757e-6 | |
| .9999999999955118 2.996056226334661e-6 | |
| .9999999999954767 3.007759570968745e-6 | |
| .9999999999954414 3.0194629156028294e-6 | |
| .999999999995406 3.0311662602369133e-6 | |
| .9999999999953705 3.0428696048709963e-6 | |
| .9999999999953348 3.0545729495050794e-6 | |
| .999999999995299 3.066276294139162e-6 | |
| .999999999995263 3.0779796387732437e-6 | |
| .9999999999952269 3.0896829834073255e-6 | |
| .9999999999951907 3.101386328041407e-6 | |
| .9999999999951543 3.1130896726754873e-6 | |
| .9999999999951178 3.1247930173095678e-6 | |
| .9999999999950812 3.136496361943648e-6 | |
| .9999999999950444 3.148199706577727e-6 | |
| .9999999999950075 3.1599030512118063e-6 | |
| .9999999999949705 3.171606395845885e-6 | |
| .9999999999949333 3.183309740479963e-6 | |
| .999999999994896 3.195013085114041e-6 | |
| .9999999999948584 3.206716429748118e-6 | |
| .9999999999948209 3.218419774382195e-6 | |
| .9999999999947832 3.2301231190162714e-6 | |
| .9999999999947453 3.2418264636503477e-6 | |
| .9999999999947072 3.253529808284423e-6 | |
| .9999999999946692 3.265233152918498e-6 | |
| .9999999999946309 3.276936497552573e-6 | |
| .9999999999945924 3.288639842186647e-6 | |
| .9999999999945539 3.300343186820721e-6 | |
| .9999999999945152 3.312046531454794e-6 | |
| .9999999999944763 3.323749876088867e-6 | |
| .9999999999944373 3.3354532207229395e-6 | |
| .9999999999943983 3.3471565653570115e-6 | |
| .9999999999943591 3.358859909991083e-6 | |
| .9999999999943197 3.370563254625154e-6 | |
| .9999999999942801 3.3822665992592245e-6 | |
| .9999999999942405 3.3939699438932944e-6 | |
| .9999999999942008 3.4056732885273643e-6 | |
| .9999999999941608 3.4173766331614334e-6 | |
| .9999999999941207 3.429079977795502e-6 | |
| .9999999999940805 3.4407833224295702e-6 | |
| .9999999999940402 3.452486667063638e-6 | |
| .9999999999939997 3.4641900116977054e-6 | |
| .999999999993959 3.4758933563317723e-6 | |
| .9999999999939183 3.4875967009658384e-6 | |
| .9999999999938775 3.4993000455999045e-6 | |
| .9999999999938364 3.5110033902339697e-6 | |
| .9999999999937953 3.5227067348680345e-6 | |
| .999999999993754 3.534410079502099e-6 | |
| .9999999999937126 3.546113424136163e-6 | |
| .999999999993671 3.5578167687702264e-6 | |
| .9999999999936293 3.5695201134042896e-6 | |
| .9999999999935875 3.581223458038352e-6 | |
| .9999999999935454 3.592926802672414e-6 | |
| .9999999999935033 3.6046301473064755e-6 | |
| .9999999999934611 3.6163334919405365e-6 | |
| .9999999999934187 3.628036836574597e-6 | |
| .9999999999933762 3.639740181208657e-6 | |
| .9999999999933334 3.6514435258427166e-6 | |
| .9999999999932907 3.6631468704767755e-6 | |
| .9999999999932477 3.674850215110834e-6 | |
| .9999999999932047 3.686553559744892e-6 | |
| .9999999999931615 3.6982569043789496e-6 | |
| .9999999999931181 3.7099602490130064e-6 | |
| .9999999999930747 3.7216635936470627e-6 | |
| .999999999993031 3.733366938281119e-6 | |
| .9999999999929873 3.745070282915174e-6 | |
| .9999999999929433 3.756773627549229e-6 | |
| .9999999999928992 3.768476972183284e-6 | |
| .9999999999928552 3.7801803168173377e-6 | |
| .9999999999928109 3.791883661451391e-6 | |
| .9999999999927663 3.803587006085444e-6 | |
| .9999999999927218 3.8152903507194965e-6 | |
| .9999999999926771 3.826993695353548e-6 | |
| .9999999999926322 3.838697039987599e-6 | |
| .9999999999925873 3.85040038462165e-6 | |
| .9999999999925421 3.862103729255701e-6 | |
| .9999999999924968 3.87380707388975e-6 | |
| .9999999999924514 3.885510418523799e-6 | |
| .9999999999924059 3.897213763157848e-6 | |
| .9999999999923602 3.9089171077918965e-6 | |
| .9999999999923144 3.9206204524259435e-6 | |
| .9999999999922684 3.9323237970599905e-6 | |
| .9999999999922223 3.9440271416940376e-6 | |
| .9999999999921761 3.955730486328084e-6 | |
| .9999999999921297 3.967433830962129e-6 | |
| .9999999999920832 3.9791371755961736e-6 | |
| .9999999999920366 3.990840520230218e-6 | |
| .9999999999919899 4.002543864864262e-6 | |
| .9999999999919429 4.014247209498305e-6 | |
| .9999999999918958 4.025950554132348e-6 | |
| .9999999999918486 4.03765389876639e-6 | |
| .9999999999918013 4.049357243400431e-6 | |
| .9999999999917539 4.061060588034472e-6 | |
| .9999999999917063 4.072763932668513e-6 | |
| .9999999999916586 4.084467277302553e-6 | |
| .9999999999916107 4.096170621936592e-6 | |
| .9999999999915626 4.107873966570632e-6 | |
| .9999999999915146 4.119577311204669e-6 | |
| .9999999999914663 4.131280655838707e-6 | |
| .9999999999914179 4.142984000472745e-6 | |
| .9999999999913692 4.154687345106781e-6 | |
| .9999999999913206 4.166390689740817e-6 | |
| .9999999999912718 4.178094034374852e-6 | |
| .9999999999912228 4.189797379008887e-6 | |
| .9999999999911737 4.201500723642921e-6 | |
| .9999999999911244 4.213204068276955e-6 | |
| .999999999991075 4.224907412910988e-6 | |
| .9999999999910255 4.236610757545021e-6 | |
| .9999999999909759 4.248314102179053e-6 | |
| .9999999999909261 4.260017446813084e-6 | |
| .9999999999908762 4.271720791447115e-6 | |
| .9999999999908261 4.283424136081145e-6 | |
| .9999999999907759 4.295127480715175e-6 | |
| .9999999999907256 4.306830825349204e-6 | |
| .9999999999906751 4.3185341699832325e-6 | |
| .9999999999906245 4.33023751461726e-6 | |
| .9999999999905738 4.3419408592512875e-6 | |
| .9999999999905229 4.353644203885314e-6 | |
| .9999999999904718 4.36534754851934e-6 | |
| .9999999999904207 4.377050893153365e-6 | |
| .9999999999903694 4.38875423778739e-6 | |
| .999999999990318 4.400457582421414e-6 | |
| .9999999999902665 4.4121609270554384e-6 | |
| .9999999999902147 4.423864271689461e-6 | |
| .9999999999901629 4.435567616323483e-6 | |
| .9999999999901109 4.447270960957506e-6 | |
| .9999999999900587 4.458974305591527e-6 | |
| .9999999999900065 4.470677650225547e-6 | |
| .9999999999899541 4.482380994859567e-6 | |
| .9999999999899016 4.494084339493587e-6 | |
| .9999999999898489 4.5057876841276054e-6 | |
| .9999999999897962 4.517491028761624e-6 | |
| .9999999999897432 4.529194373395641e-6 | |
| .9999999999896901 4.5408977180296584e-6 | |
| .999999999989637 4.552601062663675e-6 | |
| .9999999999895836 4.564304407297691e-6 | |
| .99999999998953 4.5760077519317055e-6 | |
| .9999999999894764 4.5877110965657195e-6 | |
| .9999999999894227 4.5994144411997335e-6 | |
| .9999999999893688 4.611117785833747e-6 | |
| .9999999999893148 4.622821130467759e-6 | |
| .9999999999892606 4.634524475101771e-6 | |
| .9999999999892063 4.646227819735783e-6 | |
| .9999999999891518 4.657931164369793e-6 | |
| .9999999999890973 4.669634509003803e-6 | |
| .9999999999890425 4.681337853637813e-6 | |
| .9999999999889877 4.693041198271821e-6 | |
| .9999999999889327 4.704744542905829e-6 | |
| .9999999999888776 4.716447887539837e-6 | |
| .9999999999888223 4.728151232173843e-6 | |
| .9999999999887669 4.73985457680785e-6 | |
| .9999999999887114 4.751557921441855e-6 | |
| .9999999999886556 4.76326126607586e-6 | |
| .9999999999885999 4.774964610709864e-6 | |
| .9999999999885439 4.786667955343868e-6 | |
| .9999999999884878 4.798371299977871e-6 | |
| .9999999999884316 4.810074644611873e-6 | |
| .9999999999883752 4.821777989245874e-6 | |
| .9999999999883187 4.833481333879875e-6 | |
| .9999999999882621 4.845184678513876e-6 | |
| .9999999999882053 4.856888023147875e-6 | |
| .9999999999881484 4.868591367781874e-6 | |
| .9999999999880914 4.880294712415872e-6 | |
| .9999999999880341 4.89199805704987e-6 | |
| .9999999999879768 4.903701401683867e-6 | |
| .9999999999879194 4.915404746317863e-6 | |
| .9999999999878618 4.9271080909518585e-6 | |
| .9999999999878041 4.938811435585853e-6 | |
| .9999999999877462 4.9505147802198475e-6 | |
| .9999999999876882 4.962218124853841e-6 | |
| .99999999998763 4.973921469487834e-6 | |
| .9999999999875717 4.985624814121826e-6 | |
| .9999999999875133 4.997328158755817e-6 | |
| .9999999999874548 5.009031503389808e-6 | |
| .9999999999873961 5.0207348480237985e-6 | |
| .9999999999873372 5.032438192657788e-6 | |
| .9999999999872783 5.0441415372917765e-6 | |
| .9999999999872192 5.055844881925764e-6 | |
| .9999999999871599 5.067548226559752e-6 | |
| .9999999999871007 5.079251571193739e-6 | |
| .9999999999870411 5.090954915827725e-6 | |
| .9999999999869814 5.10265826046171e-6 | |
| .9999999999869217 5.1143616050956945e-6 | |
| .9999999999868617 5.126064949729678e-6 | |
| .9999999999868017 5.1377682943636615e-6 | |
| .9999999999867415 5.149471638997644e-6 | |
| .9999999999866811 5.161174983631626e-6 | |
| .9999999999866207 5.172878328265607e-6 | |
| .9999999999865601 5.184581672899587e-6 | |
| .9999999999864994 5.196285017533567e-6 | |
| .9999999999864384 5.2079883621675455e-6 | |
| .9999999999863775 5.219691706801524e-6 | |
| .9999999999863163 5.2313950514355015e-6 | |
| .999999999986255 5.243098396069478e-6 | |
| .9999999999861935 5.254801740703454e-6 | |
| .999999999986132 5.266505085337429e-6 | |
| .9999999999860703 5.278208429971404e-6 | |
| .9999999999860084 5.289911774605378e-6 | |
| .9999999999859465 5.301615119239351e-6 | |
| .9999999999858843 5.313318463873323e-6 | |
| .9999999999858221 5.325021808507295e-6 | |
| .9999999999857597 5.336725153141267e-6 | |
| .9999999999856971 5.3484284977752366e-6 | |
| .9999999999856345 5.360131842409206e-6 | |
| .9999999999855717 5.371835187043175e-6 | |
| .9999999999855087 5.383538531677143e-6 | |
| .9999999999854456 5.3952418763111104e-6 | |
| .9999999999853825 5.406945220945077e-6 | |
| .9999999999853191 5.418648565579043e-6 | |
| .9999999999852557 5.4303519102130076e-6 | |
| .9999999999851921 5.4420552548469724e-6 | |
| .9999999999851282 5.453758599480936e-6 | |
| .9999999999850644 5.465461944114899e-6 | |
| .9999999999850003 5.47716528874886e-6 | |
| .9999999999849362 5.488868633382822e-6 | |
| .9999999999848719 5.500571978016782e-6 | |
| .9999999999848074 5.512275322650742e-6 | |
| .9999999999847429 5.523978667284702e-6 | |
| .9999999999846781 5.53568201191866e-6 | |
| .9999999999846133 5.547385356552617e-6 | |
| .9999999999845482 5.5590887011865745e-6 | |
| .9999999999844832 5.57079204582053e-6 | |
| .9999999999844179 5.582495390454486e-6 | |
| .9999999999843525 5.59419873508844e-6 | |
| .9999999999842869 5.605902079722394e-6 | |
| .9999999999842213 5.617605424356347e-6 | |
| .9999999999841555 5.629308768990299e-6 | |
| .9999999999840895 5.641012113624251e-6 | |
| .9999999999840234 5.652715458258201e-6 | |
| .9999999999839572 5.664418802892152e-6 | |
| .9999999999838908 5.6761221475261e-6 | |
| .9999999999838243 5.687825492160048e-6 | |
| .9999999999837577 5.699528836793996e-6 | |
| .9999999999836909 5.711232181427943e-6 | |
| .999999999983624 5.722935526061889e-6 | |
| .9999999999835569 5.734638870695834e-6 | |
| .9999999999834898 5.746342215329779e-6 | |
| .9999999999834225 5.758045559963722e-6 | |
| .999999999983355 5.769748904597665e-6 | |
| .9999999999832874 5.781452249231607e-6 | |
| .9999999999832196 5.793155593865548e-6 | |
| .9999999999831518 5.804858938499489e-6 | |
| .9999999999830838 5.816562283133429e-6 | |
| .9999999999830157 5.8282656277673675e-6 | |
| .9999999999829474 5.839968972401306e-6 | |
| .9999999999828789 5.851672317035243e-6 | |
| .9999999999828104 5.86337566166918e-6 | |
| .9999999999827417 5.875079006303115e-6 | |
| .9999999999826729 5.88678235093705e-6 | |
| .9999999999826039 5.898485695570985e-6 | |
| .9999999999825349 5.910189040204917e-6 | |
| .9999999999824656 5.92189238483885e-6 | |
| .9999999999823962 5.933595729472782e-6 | |
| .9999999999823267 5.945299074106713e-6 | |
| .9999999999822571 5.957002418740643e-6 | |
| .9999999999821872 5.9687057633745715e-6 | |
| .9999999999821173 5.9804091080085e-6 | |
| )) | |
| (define low-lut-rac | |
| '#f64(1. 0. | |
| .9999952938095762 .003067956762965976 | |
| .9999811752826011 .006135884649154475 | |
| .9999576445519639 .00920375478205982 | |
| .9999247018391445 .012271538285719925 | |
| .9998823474542126 .015339206284988102 | |
| .9998305817958234 .01840672990580482 | |
| .9997694053512153 .021474080275469508 | |
| .9996988186962042 .024541228522912288 | |
| .9996188224951786 .027608145778965743 | |
| .9995294175010931 .030674803176636626 | |
| .9994306045554617 .03374117185137759 | |
| .9993223845883495 .03680722294135883 | |
| .9992047586183639 .03987292758773981 | |
| .9990777277526454 .04293825693494082 | |
| .9989412931868569 .04600318213091463 | |
| .9987954562051724 .049067674327418015 | |
| .9986402181802653 .052131704680283324 | |
| .9984755805732948 .05519524434968994 | |
| .9983015449338929 .05825826450043576 | |
| .9981181129001492 .06132073630220858 | |
| .997925286198596 .06438263092985747 | |
| .9977230666441916 .06744391956366406 | |
| .9975114561403035 .07050457338961387 | |
| .9972904566786902 .07356456359966743 | |
| .997060070339483 .07662386139203149 | |
| .9968202992911657 .07968243797143013 | |
| .9965711457905548 .08274026454937569 | |
| .996312612182778 .0857973123444399 | |
| .996044700901252 .0888535525825246 | |
| .9957674144676598 .09190895649713272 | |
| .9954807554919269 .094963495329639 | |
| .9951847266721969 .0980171403295606 | |
| .9948793307948056 .10106986275482782 | |
| .9945645707342554 .10412163387205457 | |
| .9942404494531879 .10717242495680884 | |
| .9939069700023561 .11022220729388306 | |
| .9935641355205953 .11327095217756435 | |
| .9932119492347945 .11631863091190477 | |
| .9928504144598651 .11936521481099137 | |
| .99247953459871 .1224106751992162 | |
| .9920993131421918 .12545498341154623 | |
| .9917097536690995 .12849811079379317 | |
| .9913108598461154 .13154002870288312 | |
| .99090263542778 .1345807085071262 | |
| .9904850842564571 .13762012158648604 | |
| .9900582102622971 .14065823933284924 | |
| .9896220174632009 .14369503315029444 | |
| .989176509964781 .14673047445536175 | |
| .9887216919603238 .1497645346773215 | |
| .9882575677307495 .15279718525844344 | |
| .9877841416445722 .15582839765426523 | |
| .9873014181578584 .15885814333386145 | |
| .9868094018141855 .16188639378011183 | |
| .9863080972445987 .16491312048996992 | |
| .9857975091675675 .16793829497473117 | |
| .9852776423889412 .17096188876030122 | |
| .9847485018019042 .17398387338746382 | |
| .984210092386929 .17700422041214875 | |
| .9836624192117303 .18002290140569951 | |
| .9831054874312163 .18303988795514095 | |
| .9825393022874412 .18605515166344666 | |
| .9819638691095552 .18906866414980622 | |
| .9813791933137546 .19208039704989244 | |
| .9807852804032304 .19509032201612828 | |
| .9801821359681174 .1980984107179536 | |
| .9795697656854405 .2011046348420919 | |
| .9789481753190622 .20410896609281687 | |
| .9783173707196277 .20711137619221856 | |
| .9776773578245099 .2101118368804696 | |
| .9770281426577544 .21311031991609136 | |
| .9763697313300211 .21610679707621952 | |
| .9757021300385286 .2191012401568698 | |
| .9750253450669941 .22209362097320354 | |
| .9743393827855759 .22508391135979283 | |
| .973644249650812 .22807208317088573 | |
| .9729399522055602 .2310581082806711 | |
| .9722264970789363 .23404195858354343 | |
| .9715038909862518 .2370236059943672 | |
| .9707721407289504 .2400030224487415 | |
| .970031253194544 .2429801799032639 | |
| .9692812353565485 .24595505033579462 | |
| .9685220942744173 .24892760574572018 | |
| .9677538370934755 .25189781815421697 | |
| .9669764710448521 .25486565960451457 | |
| .9661900034454125 .257831102162159 | |
| .9653944416976894 .2607941179152755 | |
| .9645897932898128 .2637546789748314 | |
| .9637760657954398 .26671275747489837 | |
| .9629532668736839 .2696683255729151 | |
| .9621214042690416 .272621355449949 | |
| .9612804858113206 .27557181931095814 | |
| .9604305194155658 .2785196893850531 | |
| .9595715130819845 .281464937925758 | |
| .9587034748958716 .2844075372112718 | |
| .9578264130275329 .2873474595447295 | |
| .9569403357322088 .2902846772544624 | |
| .9560452513499964 .29321916269425863 | |
| .9551411683057707 .29615088824362384 | |
| .9542280951091057 .2990798263080405 | |
| .9533060403541939 .3020059493192281 | |
| .9523750127197659 .30492922973540243 | |
| .9514350209690083 .30784964004153487 | |
| .9504860739494817 .3107671527496115 | |
| .9495281805930367 .31368174039889146 | |
| .9485613499157303 .31659337555616585 | |
| .9475855910177411 .3195020308160157 | |
| .9466009130832835 .32240767880106985 | |
| .9456073253805213 .3253102921622629 | |
| .9446048372614803 .32820984357909255 | |
| .9435934581619604 .33110630575987643 | |
| .9425731976014469 .3339996514420094 | |
| .9415440651830208 .33688985339222005 | |
| .9405060705932683 .33977688440682685 | |
| .9394592236021899 .3426607173119944 | |
| .9384035340631081 .34554132496398904 | |
| .937339011912575 .34841868024943456 | |
| .9362656671702783 .35129275608556715 | |
| .9351835099389476 .3541635254204904 | |
| .9340925504042589 .35703096123343003 | |
| .9329927988347388 .35989503653498817 | |
| .9318842655816681 .3627557243673972 | |
| .9307669610789837 .36561299780477385 | |
| .9296408958431812 .3684668299533723 | |
| .9285060804732156 .37131719395183754 | |
| .9273625256504011 .374164062971458 | |
| .9262102421383114 .37700741021641826 | |
| .9250492407826776 .37984720892405116 | |
| .9238795325112867 .3826834323650898 | |
| .9227011283338785 .38551605384391885 | |
| .9215140393420419 .3883450466988263 | |
| .9203182767091106 .39117038430225387 | |
| .9191138516900578 .3939920400610481 | |
| .9179007756213905 .3968099874167103 | |
| .9166790599210427 .39962419984564684 | |
| .9154487160882678 .40243465085941843 | |
| .9142097557035307 .40524131400498986 | |
| .9129621904283982 .4080441628649787 | |
| .9117060320054299 .41084317105790397 | |
| .9104412922580672 .41363831223843456 | |
| .9091679830905224 .4164295600976372 | |
| .9078861164876663 .41921688836322396 | |
| .9065957045149153 .4220002707997997 | |
| .9052967593181188 .4247796812091088 | |
| .9039892931234433 .4275550934302821 | |
| .9026733182372588 .4303264813400826 | |
| .901348847046022 .43309381885315196 | |
| .9000158920161603 .4358570799222555 | |
| .8986744656939538 .43861623853852766 | |
| .8973245807054183 .44137126873171667 | |
| .8959662497561851 .44412214457042926 | |
| .8945994856313827 .4468688401623742 | |
| .8932243011955153 .4496113296546066 | |
| .8918407093923427 .4523495872337709 | |
| .8904487232447579 .45508358712634384 | |
| .8890483558546646 .45781330359887723 | |
| .8876396204028539 .46053871095824 | |
| .8862225301488806 .4632597835518602 | |
| .8847970984309378 .4659764957679662 | |
| .8833633386657316 .46868882203582796 | |
| .881921264348355 .47139673682599764 | |
| .8804708890521608 .47410021465055 | |
| .8790122264286335 .47679923006332214 | |
| .8775452902072612 .479493757660153 | |
| .8760700941954066 .4821837720791228 | |
| .8745866522781761 .4848692480007911 | |
| .8730949784182901 .48755016014843594 | |
| .8715950866559511 .49022648328829116 | |
| .8700869911087115 .49289819222978404 | |
| .8685707059713409 .49556526182577254 | |
| .8670462455156926 .49822766697278187 | |
| .8655136240905691 .5008853826112408 | |
| .8639728561215867 .5035383837257176 | |
| .8624239561110405 .5061866453451553 | |
| .8608669386377673 .508830142543107 | |
| .8593018183570084 .5114688504379704 | |
| .8577286100002721 .5141027441932218 | |
| .8561473283751945 .5167317990176499 | |
| .8545579883654005 .5193559901655896 | |
| .8529606049303636 .5219752929371544 | |
| .8513551931052652 .524589682678469 | |
| .8497417680008524 .5271991347819014 | |
| .8481203448032972 .5298036246862947 | |
| .8464909387740521 .532403127877198 | |
| .8448535652497071 .5349976198870973 | |
| .8432082396418454 .5375870762956455 | |
| .8415549774368984 .5401714727298929 | |
| .8398937941959995 .5427507848645159 | |
| .8382247055548381 .5453249884220465 | |
| .836547727223512 .5478940591731002 | |
| .83486287498638 .5504579729366048 | |
| .8331701647019132 .5530167055800276 | |
| .8314696123025452 .5555702330196022 | |
| .829761233794523 .5581185312205561 | |
| .8280450452577558 .560661576197336 | |
| .8263210628456635 .5631993440138341 | |
| .8245893027850253 .5657318107836132 | |
| .8228497813758263 .5682589526701316 | |
| .8211025149911046 .5707807458869673 | |
| .819347520076797 .5732971666980422 | |
| .8175848131515837 .5758081914178453 | |
| .8158144108067338 .5783137964116556 | |
| .8140363297059484 .5808139580957645 | |
| .8122505865852039 .5833086529376983 | |
| .8104571982525948 .5857978574564389 | |
| .808656181588175 .5882815482226453 | |
| .8068475535437992 .5907597018588743 | |
| .8050313311429635 .5932322950397998 | |
| .8032075314806449 .5956993044924334 | |
| .8013761717231402 .5981607069963423 | |
| .799537269107905 .600616479383869 | |
| .7976908409433912 .6030665985403482 | |
| .7958369046088836 .6055110414043255 | |
| .7939754775543372 .6079497849677736 | |
| .7921065773002124 .6103828062763095 | |
| .79023022143731 .6128100824294097 | |
| .7883464276266062 .6152315905806268 | |
| .7864552135990858 .617647307937804 | |
| .7845565971555752 .6200572117632892 | |
| .7826505961665757 .62246127937415 | |
| .7807372285720945 .6248594881423863 | |
| .778816512381476 .6272518154951441 | |
| .7768884656732324 .629638238914927 | |
| .7749531065948739 .6320187359398091 | |
| .773010453362737 .6343932841636455 | |
| .7710605242618138 .6367618612362842 | |
| .7691033376455796 .6391244448637757 | |
| .7671389119358204 .6414810128085832 | |
| .765167265622459 .6438315428897915 | |
| .7631884172633813 .6461760129833164 | |
| .7612023854842618 .6485144010221124 | |
| .7592091889783881 .6508466849963809 | |
| .7572088465064846 .6531728429537768 | |
| .7552013768965365 .6554928529996153 | |
| .7531867990436125 .6578066932970786 | |
| .7511651319096864 .6601143420674205 | |
| .7491363945234594 .6624157775901718 | |
| .7471006059801801 .6647109782033449 | |
| .745057785441466 .6669999223036375 | |
| .7430079521351217 .6692825883466361 | |
| .7409511253549591 .6715589548470184 | |
| .7388873244606151 .673829000378756 | |
| .7368165688773699 .6760927035753159 | |
| .7347388780959635 .6783500431298615 | |
| .7326542716724128 .680600997795453 | |
| .7305627692278276 .6828455463852481 | |
| .7284643904482252 .6850836677727004 | |
| .726359155084346 .6873153408917592 | |
| .7242470829514669 .6895405447370669 | |
| .7221281939292153 .6917592583641577 | |
| .7200025079613817 .693971460889654 | |
| .7178700450557317 .696177131491463 | |
| .7157308252838187 .6983762494089728 | |
| .7135848687807936 .7005687939432483 | |
| .7114321957452164 .7027547444572253 | |
| .7092728264388657 .7049340803759049 | |
| )) | |
| (define (make-w log-n) | |
| (let* ((n (##expt 2 log-n)) ;; number of complexes | |
| (result (##make-f64vector (##fx* 2 n)))) | |
| (define (copy-low-lut) | |
| (##declare (not interrupts-enabled)) | |
| (do ((i 0 (##fx+ i 1))) | |
| ((##fx= i lut-table-size)) | |
| (let ((index (##fx* i 2))) | |
| (##f64vector-set! | |
| result | |
| index | |
| (##f64vector-ref low-lut index)) | |
| (##f64vector-set! | |
| result | |
| (##fx+ index 1) | |
| (##f64vector-ref low-lut (##fx+ index 1)))))) | |
| (define (extend-lut multiplier-lut bit-reverse-size bit-reverse-multiplier start end) | |
| (define (bit-reverse x n) | |
| (declare (not interrupts-enabled)) | |
| (do ((i 0 (##fx+ i 1)) | |
| (x x (##fxarithmetic-shift-right x 1)) | |
| (result 0 (##fx+ (##fx* result 2) | |
| (##fxand x 1)))) | |
| ((##fx= i n) result))) | |
| (let loop ((i start) | |
| (j 1)) | |
| (if (##fx< i end) | |
| (let* ((multiplier-index | |
| (##fx* 2 | |
| (bit-reverse j bit-reverse-size) | |
| bit-reverse-multiplier)) | |
| (multiplier-real | |
| (##f64vector-ref multiplier-lut multiplier-index)) | |
| (multiplier-imag | |
| (##f64vector-ref multiplier-lut (##fx+ multiplier-index 1)))) | |
| (let inner ((i i) | |
| (k 0)) | |
| (declare (not interrupts-enabled)) | |
| ;; we copy complex multiples of all entries below | |
| ;; start to entries starting at start | |
| (if (##fx< k start) | |
| (let* ((index | |
| (##fx* k 2)) | |
| (real | |
| (##f64vector-ref result index)) | |
| (imag | |
| (##f64vector-ref result (##fx+ index 1))) | |
| (result-real | |
| (##fl- (##fl* multiplier-real real) | |
| (##fl* multiplier-imag imag))) | |
| (result-imag | |
| (##fl+ (##fl* multiplier-real imag) | |
| (##fl* multiplier-imag real))) | |
| (result-index (##fx* i 2))) | |
| (##f64vector-set! result result-index result-real) | |
| (##f64vector-set! result (##fx+ result-index 1) result-imag) | |
| (inner (##fx+ i 1) | |
| (##fx+ k 1))) | |
| (loop i | |
| (##fx+ j 1))))) | |
| result))) | |
| (cond ((##fx<= n lut-table-size) | |
| low-lut) | |
| ((##fx<= n lut-table-size^2) | |
| (copy-low-lut) | |
| (extend-lut med-lut | |
| (##fx- log-n log-lut-table-size) | |
| (##fxarithmetic-shift-left 1 (##fx- (##fx* 2 log-lut-table-size) log-n)) | |
| lut-table-size | |
| n)) | |
| (else ;; (##fx<= n lut-table-size^3) | |
| (copy-low-lut) | |
| (extend-lut med-lut | |
| log-lut-table-size | |
| 1 | |
| lut-table-size | |
| lut-table-size^2) | |
| (extend-lut high-lut | |
| (##fx- log-n (##fx* 2 log-lut-table-size)) | |
| (##fxarithmetic-shift-left 1 (##fx- (##fx* 3 log-lut-table-size) log-n)) | |
| lut-table-size^2 | |
| n))))) | |
| (define (two^p>=m m) | |
| ;; returns smallest p, assumes fixnum m >= 0 | |
| (##fxlength (##fx- m))) | |
| ;; The next two routines are so-called radix-4 ffts, which seems | |
| ;; to mean that they combine two passes, each of which works on | |
| ;; pairs of complex numbers (hence radix-2?), so if you combine | |
| ;; two passes in one, you work on two pairs of complex numbers at | |
| ;; a time and make half as many passes through the f64vector a. | |
| (define (direct-fft-recursive-4 a W-table) | |
| ;; This is a direcct complex fft, using a decimation-in-time | |
| ;; algorithm with inputs in natural order and outputs in | |
| ;; bit-reversed order. The table of "twiddle" factors is in | |
| ;; bit-reversed order. | |
| ;; this is from page 66 of Chu and George, except that we have | |
| ;; combined passes in pairs to cut the number of passes through | |
| ;; the vector a | |
| (let ((W (##f64vector (macro-inexact-+0) | |
| (macro-inexact-+0) | |
| (macro-inexact-+0) | |
| (macro-inexact-+0)))) | |
| (define (main-loop M N K SizeOfGroup) | |
| (##declare (not interrupts-enabled)) | |
| (let inner-loop ((K K) | |
| (JFirst M)) | |
| (if (##fx< JFirst N) | |
| (let* ((JLast (##fx+ JFirst SizeOfGroup))) | |
| (if (##fxeven? K) | |
| (begin | |
| (##f64vector-set! W 0 (##f64vector-ref W-table K)) | |
| (##f64vector-set! W 1 (##f64vector-ref W-table (##fx+ K 1)))) | |
| (begin | |
| (##f64vector-set! W 0 (##fl- (##f64vector-ref W-table K))) | |
| (##f64vector-set! W 1 (##f64vector-ref W-table (##fx- K 1))))) | |
| ;; we know the that the next two complex roots of | |
| ;; unity have index 2K and 2K+1 so that the 2K+1 | |
| ;; index root can be gotten from the 2K index root | |
| ;; in the same way that we get W_0 and W_1 from the | |
| ;; table depending on whether K is even or not | |
| (##f64vector-set! W 2 (##f64vector-ref W-table (##fx* K 2))) | |
| (##f64vector-set! W 3 (##f64vector-ref W-table (##fx+ (##fx* K 2) 1))) | |
| (let J-loop ((J0 JFirst)) | |
| (if (##fx< J0 JLast) | |
| (let* ((J0 J0) | |
| (J1 (##fx+ J0 1)) | |
| (J2 (##fx+ J0 SizeOfGroup)) | |
| (J3 (##fx+ J2 1)) | |
| (J4 (##fx+ J2 SizeOfGroup)) | |
| (J5 (##fx+ J4 1)) | |
| (J6 (##fx+ J4 SizeOfGroup)) | |
| (J7 (##fx+ J6 1))) | |
| (let ((W_0 (##f64vector-ref W 0)) | |
| (W_1 (##f64vector-ref W 1)) | |
| (W_2 (##f64vector-ref W 2)) | |
| (W_3 (##f64vector-ref W 3)) | |
| (a_J0 (##f64vector-ref a J0)) | |
| (a_J1 (##f64vector-ref a J1)) | |
| (a_J2 (##f64vector-ref a J2)) | |
| (a_J3 (##f64vector-ref a J3)) | |
| (a_J4 (##f64vector-ref a J4)) | |
| (a_J5 (##f64vector-ref a J5)) | |
| (a_J6 (##f64vector-ref a J6)) | |
| (a_J7 (##f64vector-ref a J7))) | |
| ;; first we do the (overlapping) pairs of | |
| ;; butterflies with entries 2*SizeOfGroup | |
| ;; apart. | |
| (let ((Temp_0 (##fl- (##fl* W_0 a_J4) | |
| (##fl* W_1 a_J5))) | |
| (Temp_1 (##fl+ (##fl* W_0 a_J5) | |
| (##fl* W_1 a_J4))) | |
| (Temp_2 (##fl- (##fl* W_0 a_J6) | |
| (##fl* W_1 a_J7))) | |
| (Temp_3 (##fl+ (##fl* W_0 a_J7) | |
| (##fl* W_1 a_J6)))) | |
| (let ((a_J0 (##fl+ a_J0 Temp_0)) | |
| (a_J1 (##fl+ a_J1 Temp_1)) | |
| (a_J2 (##fl+ a_J2 Temp_2)) | |
| (a_J3 (##fl+ a_J3 Temp_3)) | |
| (a_J4 (##fl- a_J0 Temp_0)) | |
| (a_J5 (##fl- a_J1 Temp_1)) | |
| (a_J6 (##fl- a_J2 Temp_2)) | |
| (a_J7 (##fl- a_J3 Temp_3))) | |
| ;; now we do the two (disjoint) pairs | |
| ;; of butterflies distance SizeOfGroup | |
| ;; apart, the first pair with W2+W3i, | |
| ;; the second with -W3+W2i | |
| ;; we rewrite the multipliers so I | |
| ;; don't hurt my head too much when | |
| ;; thinking about them. | |
| (let ((W_0 W_2) | |
| (W_1 W_3) | |
| (W_2 (##fl- W_3)) | |
| (W_3 W_2)) | |
| (let ((Temp_0 | |
| (##fl- (##fl* W_0 a_J2) | |
| (##fl* W_1 a_J3))) | |
| (Temp_1 | |
| (##fl+ (##fl* W_0 a_J3) | |
| (##fl* W_1 a_J2))) | |
| (Temp_2 | |
| (##fl- (##fl* W_2 a_J6) | |
| (##fl* W_3 a_J7))) | |
| (Temp_3 | |
| (##fl+ (##fl* W_2 a_J7) | |
| (##fl* W_3 a_J6)))) | |
| (let ((a_J0 (##fl+ a_J0 Temp_0)) | |
| (a_J1 (##fl+ a_J1 Temp_1)) | |
| (a_J2 (##fl- a_J0 Temp_0)) | |
| (a_J3 (##fl- a_J1 Temp_1)) | |
| (a_J4 (##fl+ a_J4 Temp_2)) | |
| (a_J5 (##fl+ a_J5 Temp_3)) | |
| (a_J6 (##fl- a_J4 Temp_2)) | |
| (a_J7 (##fl- a_J5 Temp_3))) | |
| (##f64vector-set! a J0 a_J0) | |
| (##f64vector-set! a J1 a_J1) | |
| (##f64vector-set! a J2 a_J2) | |
| (##f64vector-set! a J3 a_J3) | |
| (##f64vector-set! a J4 a_J4) | |
| (##f64vector-set! a J5 a_J5) | |
| (##f64vector-set! a J6 a_J6) | |
| (##f64vector-set! a J7 a_J7) | |
| (J-loop (##fx+ J0 2))))))))) | |
| (inner-loop (##fx+ K 1) | |
| (##fx+ JFirst (##fx* SizeOfGroup 4))))))))) | |
| (define (recursive-bit M N K SizeOfGroup) | |
| (if (##fx<= 2 SizeOfGroup) | |
| (begin | |
| (main-loop M N K SizeOfGroup) | |
| (if (##fx< 2048 (##fx- N M)) | |
| (let ((new-size (##fxarithmetic-shift-right (##fx- N M) 2))) | |
| (recursive-bit M | |
| (##fx+ M new-size) | |
| (##fx* K 4) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)) | |
| (recursive-bit (##fx+ M new-size) | |
| (##fx+ M (##fx* new-size 2)) | |
| (##fx+ (##fx* K 4) 1) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)) | |
| (recursive-bit (##fx+ M (##fx* new-size 2)) | |
| (##fx+ M (##fx* new-size 3)) | |
| (##fx+ (##fx* K 4) 2) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)) | |
| (recursive-bit (##fx+ M (##fx* new-size 3)) | |
| N | |
| (##fx+ (##fx* K 4) 3) | |
| (##fxarithmetic-shift-right SizeOfGroup 2))) | |
| (recursive-bit M | |
| N | |
| (##fx* K 4) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)))))) | |
| (define (radix-2-pass a) | |
| ;; If we're here, the size of our (conceptually complex) | |
| ;; array is not a power of 4, so we need to do a basic radix | |
| ;; two pass with w=1 (so W[0]=1.0 and W[1] = 0.) and then | |
| ;; call recursive-bit appropriately on the two half arrays. | |
| (declare (not interrupts-enabled)) | |
| (let ((SizeOfGroup | |
| (##fxarithmetic-shift-right (##f64vector-length a) 1))) | |
| (let loop ((J0 0)) | |
| (if (##fx< J0 SizeOfGroup) | |
| (let ((J0 J0) | |
| (J2 (##fx+ J0 SizeOfGroup))) | |
| (let ((J1 (##fx+ J0 1)) | |
| (J3 (##fx+ J2 1))) | |
| (let ((a_J0 (##f64vector-ref a J0)) | |
| (a_J1 (##f64vector-ref a J1)) | |
| (a_J2 (##f64vector-ref a J2)) | |
| (a_J3 (##f64vector-ref a J3))) | |
| (let ((a_J0 (##fl+ a_J0 a_J2)) | |
| (a_J1 (##fl+ a_J1 a_J3)) | |
| (a_J2 (##fl- a_J0 a_J2)) | |
| (a_J3 (##fl- a_J1 a_J3))) | |
| (##f64vector-set! a J0 a_J0) | |
| (##f64vector-set! a J1 a_J1) | |
| (##f64vector-set! a J2 a_J2) | |
| (##f64vector-set! a J3 a_J3) | |
| (loop (##fx+ J0 2)))))))))) | |
| (let* ((n (##f64vector-length a)) | |
| (log_n (two^p>=m n))) | |
| ;; there are n/2 complex entries in a; if n/2 is not a power | |
| ;; of 4, then do a single radix-2 pass and do the rest of | |
| ;; the passes as radix-4 passes | |
| (if (##fxodd? log_n) | |
| (recursive-bit 0 n 0 (##fxarithmetic-shift-right n 2)) | |
| (let ((n/2 (##fxarithmetic-shift-right n 1)) | |
| (n/8 (##fxarithmetic-shift-right n 3))) | |
| (radix-2-pass a) | |
| (recursive-bit 0 n/2 0 n/8) | |
| (recursive-bit n/2 n 1 n/8)))))) | |
| ;; The following routine simply reverses the operations of the | |
| ;; previous routine. | |
| (define (inverse-fft-recursive-4 a W-table) | |
| ;; This is an complex fft, using a decimation-in-frequency algorithm | |
| ;; with inputs in bit-reversed order and outputs in natural order. | |
| ;; The organization of the algorithm has little to do with the the | |
| ;; associated algorithm on page 41 of Chu and George, | |
| ;; I just reversed the operations of the direct algorithm given | |
| ;; above (without dividing by 2 each time, so that this has to | |
| ;; be "normalized" by dividing by N/2 at the end. | |
| ;; The table of "twiddle" factors is in bit-reversed order. | |
| (let ((W (##f64vector (macro-inexact-+0) | |
| (macro-inexact-+0) | |
| (macro-inexact-+0) | |
| (macro-inexact-+0)))) | |
| (define (main-loop M N K SizeOfGroup) | |
| (##declare (not interrupts-enabled)) | |
| (let inner-loop ((K K) | |
| (JFirst M)) | |
| (if (##fx< JFirst N) | |
| (let* ((JLast (##fx+ JFirst SizeOfGroup))) | |
| (if (##fxeven? K) | |
| (begin | |
| (##f64vector-set! W 0 (##f64vector-ref W-table K)) | |
| (##f64vector-set! W 1 (##f64vector-ref W-table (##fx+ K 1)))) | |
| (begin | |
| (##f64vector-set! W 0 (##fl- (##f64vector-ref W-table K))) | |
| (##f64vector-set! W 1 (##f64vector-ref W-table (##fx- K 1))))) | |
| (##f64vector-set! W 2 (##f64vector-ref W-table (##fx* K 2))) | |
| (##f64vector-set! W 3 (##f64vector-ref W-table (##fx+ (##fx* K 2) 1))) | |
| (let J-loop ((J0 JFirst)) | |
| (if (##fx< J0 JLast) | |
| (let* ((J0 J0) | |
| (J1 (##fx+ J0 1)) | |
| (J2 (##fx+ J0 SizeOfGroup)) | |
| (J3 (##fx+ J2 1)) | |
| (J4 (##fx+ J2 SizeOfGroup)) | |
| (J5 (##fx+ J4 1)) | |
| (J6 (##fx+ J4 SizeOfGroup)) | |
| (J7 (##fx+ J6 1))) | |
| (let ((W_0 (##f64vector-ref W 0)) | |
| (W_1 (##f64vector-ref W 1)) | |
| (W_2 (##f64vector-ref W 2)) | |
| (W_3 (##f64vector-ref W 3)) | |
| (a_J0 (##f64vector-ref a J0)) | |
| (a_J1 (##f64vector-ref a J1)) | |
| (a_J2 (##f64vector-ref a J2)) | |
| (a_J3 (##f64vector-ref a J3)) | |
| (a_J4 (##f64vector-ref a J4)) | |
| (a_J5 (##f64vector-ref a J5)) | |
| (a_J6 (##f64vector-ref a J6)) | |
| (a_J7 (##f64vector-ref a J7))) | |
| (let ((W_00 W_2) | |
| (W_01 W_3) | |
| (W_02 (##fl- W_3)) | |
| (W_03 W_2)) | |
| (let ((Temp_0 (##fl- a_J0 a_J2)) | |
| (Temp_1 (##fl- a_J1 a_J3)) | |
| (Temp_2 (##fl- a_J4 a_J6)) | |
| (Temp_3 (##fl- a_J5 a_J7))) | |
| (let ((a_J0 (##fl+ a_J0 a_J2)) | |
| (a_J1 (##fl+ a_J1 a_J3)) | |
| (a_J4 (##fl+ a_J4 a_J6)) | |
| (a_J5 (##fl+ a_J5 a_J7)) | |
| (a_J2 (##fl+ (##fl* W_00 Temp_0) | |
| (##fl* W_01 Temp_1))) | |
| (a_J3 (##fl- (##fl* W_00 Temp_1) | |
| (##fl* W_01 Temp_0))) | |
| (a_J6 (##fl+ (##fl* W_02 Temp_2) | |
| (##fl* W_03 Temp_3))) | |
| (a_J7 (##fl- (##fl* W_02 Temp_3) | |
| (##fl* W_03 Temp_2)))) | |
| (let ((Temp_0 (##fl- a_J0 a_J4)) | |
| (Temp_1 (##fl- a_J1 a_J5)) | |
| (Temp_2 (##fl- a_J2 a_J6)) | |
| (Temp_3 (##fl- a_J3 a_J7))) | |
| (let ((a_J0 (##fl+ a_J0 a_J4)) | |
| (a_J1 (##fl+ a_J1 a_J5)) | |
| (a_J2 (##fl+ a_J2 a_J6)) | |
| (a_J3 (##fl+ a_J3 a_J7)) | |
| (a_J4 (##fl+ (##fl* W_0 Temp_0) | |
| (##fl* W_1 Temp_1))) | |
| (a_J5 (##fl- (##fl* W_0 Temp_1) | |
| (##fl* W_1 Temp_0))) | |
| (a_J6 (##fl+ (##fl* W_0 Temp_2) | |
| (##fl* W_1 Temp_3))) | |
| (a_J7 (##fl- (##fl* W_0 Temp_3) | |
| (##fl* W_1 Temp_2)))) | |
| (##f64vector-set! a J0 a_J0) | |
| (##f64vector-set! a J1 a_J1) | |
| (##f64vector-set! a J2 a_J2) | |
| (##f64vector-set! a J3 a_J3) | |
| (##f64vector-set! a J4 a_J4) | |
| (##f64vector-set! a J5 a_J5) | |
| (##f64vector-set! a J6 a_J6) | |
| (##f64vector-set! a J7 a_J7) | |
| (J-loop (##fx+ J0 2))))))))) | |
| (inner-loop (##fx+ K 1) | |
| (##fx+ JFirst (##fx* SizeOfGroup 4))))))))) | |
| (define (recursive-bit M N K SizeOfGroup) | |
| (if (##fx<= 2 SizeOfGroup) | |
| (begin | |
| (if (##fx< 2048 (##fx- N M)) | |
| (let ((new-size (##fxarithmetic-shift-right (##fx- N M) 2))) | |
| (recursive-bit M | |
| (##fx+ M new-size) | |
| (##fx* K 4) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)) | |
| (recursive-bit (##fx+ M new-size) | |
| (##fx+ M (##fx* new-size 2)) | |
| (##fx+ (##fx* K 4) 1) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)) | |
| (recursive-bit (##fx+ M (##fx* new-size 2)) | |
| (##fx+ M (##fx* new-size 3)) | |
| (##fx+ (##fx* K 4) 2) | |
| (##fxarithmetic-shift-right SizeOfGroup 2)) | |
| (recursive-bit (##fx+ M (##fx* new-size 3)) | |
| N | |
| (##fx+ (##fx* K 4) 3) | |
| (##fxarithmetic-shift-right SizeOfGroup 2))) | |
| (recursive-bit M | |
| N | |
| (##fx* K 4) | |
| (##fxarithmetic-shift-right SizeOfGroup 2))) | |
| (main-loop M N K SizeOfGroup)))) | |
| (define (radix-2-pass a) | |
| (declare (not interrupts-enabled)) | |
| (let ((SizeOfGroup | |
| (##fxarithmetic-shift-right (##f64vector-length a) 1))) | |
| (let loop ((J0 0)) | |
| (if (##fx< J0 SizeOfGroup) | |
| (let ((J0 J0) | |
| (J2 (##fx+ J0 SizeOfGroup))) | |
| (let ((J1 (##fx+ J0 1)) | |
| (J3 (##fx+ J2 1))) | |
| (let ((a_J0 (##f64vector-ref a J0)) | |
| (a_J1 (##f64vector-ref a J1)) | |
| (a_J2 (##f64vector-ref a J2)) | |
| (a_J3 (##f64vector-ref a J3))) | |
| (let ((a_J0 (##fl+ a_J0 a_J2)) | |
| (a_J1 (##fl+ a_J1 a_J3)) | |
| (a_J2 (##fl- a_J0 a_J2)) | |
| (a_J3 (##fl- a_J1 a_J3))) | |
| (##f64vector-set! a J0 a_J0) | |
| (##f64vector-set! a J1 a_J1) | |
| (##f64vector-set! a J2 a_J2) | |
| (##f64vector-set! a J3 a_J3) | |
| (loop (##fx+ J0 2)))))))))) | |
| (let* ((n (##f64vector-length a)) | |
| (log_n (two^p>=m n))) | |
| (if (##fxodd? log_n) | |
| (recursive-bit 0 n 0 (##fxarithmetic-shift-right n 2)) | |
| (let ((n/2 (##fxarithmetic-shift-right n 1)) | |
| (n/8 (##fxarithmetic-shift-right n 3))) | |
| (recursive-bit 0 n/2 0 n/8) | |
| (recursive-bit n/2 n 1 n/8) | |
| (radix-2-pass a)))))) | |
| #| | |
| See the wonderful paper | |
| Rapid multiplication modulo the sum and difference of highly | |
| composite numbers, by Colin Percival, electronically published | |
| by Mathematics of Computation, number S 0025-5718(02)01419-9, URL | |
| http://www.ams.org/journal-getitem?pii=S0025-5718-02-01419-9 | |
| that gives these very nice error bounds. This should be published | |
| in the paper journal sometime after March 2002. | |
| What we're going to do is: | |
| Take x and y, each with <= 2^n 8-bit fdigits. | |
| Put the fdigits of x and y into the real parts of the | |
| first 2^n complex entries of a vector of length 2^{n+1}. | |
| Do ffts of length 2^{n+1}. | |
| Multiply the complex fft coefficients of x and y. | |
| do an inverse fft of length 2^{n+1}. | |
| Extract the digits of x*y from the real parts of the inverse fft. | |
| From theorem 5.1 we get the following error bound: | |
| (define epsilon (expt 2. -53)) | |
| (define bigepsilon (* epsilon (sqrt 5))) | |
| (define n 26) | |
| (define beta 4.158491068379826e-16) ;; accuracy of trigonometric inputs (check) error in product of three entries from the tables | |
| (define norm-x (sqrt (* (expt 2 n) (* 255 255)))) | |
| (define norm-y norm-x) | |
| (define error (* norm-x | |
| norm-y | |
| ;; the following three lines use the slight overestimate that | |
| ;; ln(1+epsilon) = epsilon, etc. | |
| ;; there are more accurate ways to calculate this, but we | |
| ;; don't really need them. | |
| (- (exp (+ (* 3 (+ n 1) epsilon) | |
| (* (+ (* 3 (+ n 1)) 1) bigepsilon) | |
| (* 3 (+ n 1) beta))) | |
| 1))) | |
| (pp error) | |
| Error bound is .27518123388290405 < 1/2 | |
| So if x and y have fewer than 2^{26}\times 8=536,870,912 bits, this computes the product exactly. | |
| It appears that we need tables only of size 2^9 complex entries rather than 2^10 if we do this. That would | |
| cut down on memory. | |
| Let's look at what happens when you have 4-bit fft words: | |
| (define epsilon (expt 2. -53)) | |
| (define bigepsilon (* epsilon (sqrt 5))) | |
| (define n 34) | |
| (define beta 4.158491068379826e-16) ;; accuracy of trigonometric inputs | |
| (define l 4) | |
| (define norm-x (sqrt (* (expt 2 n) (* 15 15)))) | |
| (define norm-y norm-x) | |
| (define error (* norm-x | |
| norm-y | |
| (- (exp (+ (* 3 (+ n 1) epsilon) | |
| (* (+ (* 3 (+ n 1)) 1) bigepsilon) | |
| (* 3 (+ n 1) beta))) | |
| 1))) | |
| (pp error) | |
| Error bound is .31585693359375 < 1/2 | |
| So if x and y have fewer than 2^{34}\times 4=68,719,476,736 bits, this | |
| computes the product exactly. | |
| But then I would have to increase the size of the tables to 2^{11} | |
| complex entries each, so we'd have tables of 4 times the size. | |
| I think I won't add a four-bit fft word option for now. | |
| Because the fft algorithm as written requires temporary storage at least | |
| sixteen times the size of the final result, people working with large | |
| integers but barely enough memory on 64-bit machines may wish to | |
| set! ##bignum.fft-mul-max-width to a slightly smaller value so that | |
| karatsuba will kick in earlier for the largest integers. | |
| COMMENTS FOR THE RAC (Right-Angle Convolution) VERSION | |
| What we're going to do is: | |
| Take x and y, which together have a total of <= 2^{n+1} 8-bit fdigits. | |
| We take the fdigits of f and put them into the real parts of a complex | |
| vector of length 2^n; if there are any left over, place the rest in the | |
| imaginary parts of the complex vector, starting over at the 0 entry. | |
| We do the same for y. | |
| We componentwise multiply x_j by e^{\pi/2 i j/2^n}; similarly for y_j. | |
| (This is the "right-angle" part of the right-angle transform.) | |
| The maximum possible product of |x|_2 and |y|_2 are when they both | |
| have 2^n eight-bit digits. | |
| Do ffts of length 2^n. | |
| Multiply the complex fft coefficients of x and y. | |
| do an inverse fft of length 2^n. | |
| We componentwise multiply the result by e^{-\pi/2 i j/2^n}, i.e., | |
| the inverse of the entries of the weights applied to x and y | |
| Extract the digits of x*y from the real parts and then the imaginary | |
| parts of the weighted inverse fft. | |
| From Theorem 6.1 and the following displayed equation we have | |
| (define epsilon (expt 2. -53)) | |
| (define bigepsilon (* epsilon (sqrt 5))) | |
| (define n 26) | |
| (define beta 4.164343159519809e-16) ;; accuracy of trigonometric inputs (check) error in product of three entries from the tables | |
| (define norm-x (sqrt (* (expt 2 n) (* 255 255)))) | |
| (define norm-y norm-x) | |
| (define error (* norm-x | |
| norm-y | |
| ;; the following three lines use the slight overestimate that | |
| ;; ln(1+epsilon) = epsilon, etc. | |
| ;; there are more accurate ways to calculate this, but we | |
| ;; don't really need them. | |
| (- (exp (+ (* 3 n epsilon) | |
| (* (+ (* 3 n) 4) bigepsilon) | |
| (* (+ (* 3 n) 3) beta))) | |
| 1))) | |
| (pp error) | |
| The error bound is .2742122858762741, so we're cool. | |
| |# | |
| #| | |
| Let n = 2^{\log n}; the following routine calculates | |
| e^{\pi/2 i (j/n)} j=0,\ldots, n/2-1 | |
| It uses the tables med-lut and high-lut (both described above) and | |
| low-lut-rac, which contains in fftluts-9.scm | |
| e^{\pi/2 i (j/2^9)}, j=0,\ldots, 2^8-1 | |
| It uses the same general strategy as make-w, except, because the | |
| final result is in normal order rather than bit-reversed order, we | |
| start with the highest table and work our way to the lowest. As | |
| noted above, this should result in slightly smaller error than from make-w. | |
| Instead of always building a new table, one could reuse a bigger one with | |
| a stride (do the math). I don't want to do this, however; I'd rather build | |
| a new, compact table and hope that this will result in fewer cache/TLB/page | |
| misses. | |
| |# | |
| (define (make-w-rac log-n) | |
| (let* ((n (##expt 2 log-n)) | |
| (result (##make-f64vector n))) ;; contains n/2 complexes | |
| (define (copy-lut lut stride) | |
| ;; copies the (conceptually complex) entries | |
| ;; lut[0], lut[(stride/2)], lut[2*(stride/2)], ... | |
| ;; to the first entries of result. We stop when we hit | |
| ;; the end of lut. | |
| (##declare (not interrupts-enabled)) | |
| (let ((lut-size (##f64vector-length lut))) | |
| (do ((i 0 (##fx+ i 2)) | |
| (j 0 (##fx+ j stride))) | |
| ((##fx= j lut-size) result) | |
| (##f64vector-set! result i (##f64vector-ref lut j )) | |
| (##f64vector-set! result (##fx+ i 1) (##f64vector-ref lut (##fx+ j 1)))))) | |
| (define (extend-lut multiplier-lut start) | |
| ;; we multiply the table from 0 to start-1 (in pairs of reals | |
| ;; as complexes) by all the multipliers in multiplier-lut | |
| ;; starting at 2 (again in pairs of reals) | |
| (let ((end (##f64vector-length multiplier-lut))) | |
| (let loop ((i start) | |
| (j 2)) | |
| (if (##fx< j end) | |
| (let* ((multiplier-real (##f64vector-ref multiplier-lut j)) | |
| (multiplier-imag (##f64vector-ref multiplier-lut (##fx+ j 1)))) | |
| (let inner ((i i) | |
| (k 0)) | |
| (declare (not interrupts-enabled)) | |
| (if (##fx< k start) | |
| (let* ((real (##f64vector-ref result k)) | |
| (imag (##f64vector-ref result (##fx+ k 1))) | |
| (result-real (##fl- (##fl* multiplier-real real) | |
| (##fl* multiplier-imag imag))) | |
| (result-imag (##fl+ (##fl* multiplier-real imag) | |
| (##fl* multiplier-imag real)))) | |
| (##f64vector-set! result i result-real) | |
| (##f64vector-set! result (##fx+ i 1) result-imag) | |
| (inner (##fx+ i 2) | |
| (##fx+ k 2))) | |
| (loop i | |
| (##fx+ j 2))))) | |
| result)))) | |
| (cond ((##fx= n lut-table-size) | |
| low-lut-rac) | |
| ((##fx< n lut-table-size) | |
| (let ((stride (##fxquotient (##fx* lut-table-size 2) n))) ;; = 2 when n = lut-table-size, etc. | |
| (copy-lut low-lut-rac stride))) | |
| ((##fx<= n lut-table-size^2) | |
| (let* ((stride (##fxquotient (##fx* lut-table-size^2 2) n)) | |
| (start (##fxquotient (##fx* lut-table-size 4) stride))) ;; = 2 lut-table-size when n=lut-table-size^2 | |
| (copy-lut med-lut stride) | |
| (extend-lut low-lut-rac (##fxarithmetic-shift-right n (##fx- log-lut-table-size 1))))) | |
| ((##fx<= n lut-table-size^3) | |
| (let* ((stride (##fxquotient (##fx* lut-table-size^3 2) n)) | |
| (start (##fxquotient (##fx* lut-table-size 4) stride))) | |
| (copy-lut high-lut stride) | |
| (extend-lut med-lut start) | |
| (extend-lut low-lut-rac (##fx* start lut-table-size)))) | |
| (else | |
| (error "asking for too large a table"))))) | |
| (define (bignum->f64vector-rac x a) | |
| ;; Copies the first (##f64vector-length a)/2 fdigits of x into the | |
| ;; even components of a, which represent the real parts of complex | |
| ;; elements, and then the rest of the fdigits of x into the odd | |
| ;; components of a, starting over at 1. | |
| (let ((two^n (##f64vector-length a)) | |
| (x-length (##bignum.fdigit-length x))) | |
| (if (##fx<= (##fx* x-length 2) | |
| two^n) | |
| ;; all imaginary parts are 0. | |
| (let loop1 ((i 0) | |
| (j 0)) | |
| (##declare (not interrupts-enabled)) | |
| (if (##fx< i x-length) | |
| (let ((digit-real (##fixnum->flonum (##bignum.fdigit-ref x i)))) | |
| (##f64vector-set! a j digit-real) | |
| (##f64vector-set! a (##fx+ j 1) (macro-inexact-+0)) | |
| (loop1 (##fx+ i 1) | |
| (##fx+ j 2))) | |
| ;; all parts are zero | |
| (let loop2 ((j j)) | |
| (if (##fx< j two^n) | |
| (begin | |
| (##f64vector-set! a j (macro-inexact-+0)) | |
| (##f64vector-set! a (##fx+ j 1) (macro-inexact-+0)) | |
| (loop2 (##fx+ j 2))))))) | |
| (let ((offset (##fxarithmetic-shift-right two^n 1))) | |
| (let loop1 ((i 0) | |
| (j 0)) | |
| (##declare (not interrupts-enabled)) | |
| (if (##fx< (##fx+ i offset) x-length) | |
| (let ((digit-real (##fixnum->flonum (##bignum.fdigit-ref x i ))) | |
| (digit-imag (##fixnum->flonum (##bignum.fdigit-ref x (##fx+ i offset))))) | |
| (##f64vector-set! a j digit-real) | |
| (##f64vector-set! a (##fx+ j 1) digit-imag) | |
| (loop1 (##fx+ i 1) | |
| (##fx+ j 2))) | |
| ;; all imaginary parts are 0. | |
| (let loop2 ((i i) | |
| (j j)) | |
| (if (##fx< j two^n) | |
| (let ((digit-real (##fixnum->flonum (##bignum.fdigit-ref x i)))) | |
| (##f64vector-set! a j digit-real) | |
| (##f64vector-set! a (##fx+ j 1) (macro-inexact-+0)) | |
| (loop2 (##fx+ i 1) | |
| (##fx+ j 2))))))))))) | |
| (define (componentwise-rac-multiply a table) | |
| ;; the (conceptually complex) entries of table are | |
| ;; e^{\pi/2 i (j/2^n)}, j=0,...,2^{n-1}-1. | |
| ;; We multiply a_i componentwise by table_i, using symmetry when i\geq 2^{n-1} | |
| (let ((table-size (##f64vector-length table)) | |
| (a-size (##f64vector-length a))) | |
| (declare (not interrupts-enabled)) ;; note that this means we have to be careful not to cons. | |
| (let loop ((i 2) | |
| (j 2)) | |
| (if (##fx< i table-size) | |
| (let ((multiplier-real (##f64vector-ref table i)) | |
| (multiplier-imag (##f64vector-ref table (##fx+ i 1)))) | |
| (let ((a_j-real (##f64vector-ref a j )) | |
| (a_j-imag (##f64vector-ref a (##fx+ j 1))) | |
| (a_N-j-real (##f64vector-ref a (##fx- a-size j ))) | |
| (a_N-j-imag (##f64vector-ref a (##fx- a-size j -1)))) | |
| (let ((result_j-real (##fl- (##fl* a_j-real multiplier-real) | |
| (##fl* a_j-imag multiplier-imag))) | |
| (result_j-imag (##fl+ (##fl* a_j-imag multiplier-real) | |
| (##fl* a_j-real multiplier-imag))) | |
| ;; if multipler_j=(make-rectangular r i) then multiplier_{N-j}=(make-rectangular i r) | |
| (result_N-j-real (##fl- (##fl* a_N-j-real multiplier-imag) | |
| (##fl* a_N-j-imag multiplier-real))) | |
| (result_N-j-imag (##fl+ (##fl* a_N-j-imag multiplier-imag) | |
| (##fl* a_N-j-real multiplier-real)))) | |
| (##f64vector-set! a j result_j-real) | |
| (##f64vector-set! a (##fx+ j 1) result_j-imag) | |
| (##f64vector-set! a (##fx- a-size j ) result_N-j-real) | |
| (##f64vector-set! a (##fx- a-size j -1) result_N-j-imag) | |
| (loop (##fx+ i 2) | |
| (##fx+ j 2))))) | |
| (let ((multiplier-real .7071067811865476) ;; here the multiplier is always (sqrt i) | |
| (multiplier-imag .7071067811865476) | |
| (a_j-real (##f64vector-ref a j)) | |
| (a_j-imag (##f64vector-ref a (##fx+ j 1)))) | |
| (let ((result_j-real (##fl- (##fl* a_j-real multiplier-real) | |
| (##fl* a_j-imag multiplier-imag))) | |
| (result_j-imag (##fl+ (##fl* a_j-imag multiplier-real) | |
| (##fl* a_j-real multiplier-imag)))) | |
| (##f64vector-set! a j result_j-real) | |
| (##f64vector-set! a (##fx+ j 1) result_j-imag))))))) | |
| (define (componentwise-rac-multiply-conjugate a table) | |
| ;; the (conceptually complex) entries of table are | |
| ;; e^{\pi/2 i (j/2^n)}, j=0,...,2^{n-1}-1. | |
| ;; We multiply a_i componentwise by the conjugate/inverse of table_i, using symmetry when i\geq 2^{n-1} | |
| (let ((table-size (##f64vector-length table)) | |
| (a-size (##f64vector-length a))) | |
| (declare (not interrupts-enabled)) ;; note that this means we have to be careful not to cons. | |
| (let loop ((i 2) | |
| (j 2)) | |
| (if (##fx< i table-size) | |
| (let ((multiplier-real (##f64vector-ref table i)) | |
| (multiplier-imag (##f64vector-ref table (##fx+ i 1)))) | |
| (let ((a_j-real (##f64vector-ref a j )) | |
| (a_j-imag (##f64vector-ref a (##fx+ j 1))) | |
| (a_N-j-real (##f64vector-ref a (##fx- a-size j ))) | |
| (a_N-j-imag (##f64vector-ref a (##fx- a-size j -1)))) | |
| (let ((result_j-real (##fl+ (##fl* a_j-real multiplier-real) | |
| (##fl* a_j-imag multiplier-imag))) | |
| (result_j-imag (##fl- (##fl* a_j-imag multiplier-real) | |
| (##fl* a_j-real multiplier-imag))) | |
| ;; if multipler_j=(make-rectangular r i) then multiplier_{N-j}=(make-rectangular i r) | |
| (result_N-j-real (##fl+ (##fl* a_N-j-real multiplier-imag) | |
| (##fl* a_N-j-imag multiplier-real))) | |
| (result_N-j-imag (##fl- (##fl* a_N-j-imag multiplier-imag) | |
| (##fl* a_N-j-real multiplier-real)))) | |
| (##f64vector-set! a j result_j-real) | |
| (##f64vector-set! a (##fx+ j 1) result_j-imag) | |
| (##f64vector-set! a (##fx- a-size j ) result_N-j-real) | |
| (##f64vector-set! a (##fx- a-size j -1) result_N-j-imag) | |
| (loop (##fx+ i 2) | |
| (##fx+ j 2))))) | |
| (let ((multiplier-real .7071067811865476) ;; here the multiplier is always (sqrt i) | |
| (multiplier-imag .7071067811865476) | |
| (a_j-real (##f64vector-ref a j)) | |
| (a_j-imag (##f64vector-ref a (##fx+ j 1)))) | |
| (let ((result_j-real (##fl+ (##fl* a_j-real multiplier-real) | |
| (##fl* a_j-imag multiplier-imag))) | |
| (result_j-imag (##fl- (##fl* a_j-imag multiplier-real) | |
| (##fl* a_j-real multiplier-imag)))) | |
| (##f64vector-set! a j result_j-real) | |
| (##f64vector-set! a (##fx+ j 1) result_j-imag))))))) | |
| (define (componentwise-complex-multiply a b) | |
| (let ((two^n (##f64vector-length a))) | |
| (let loop ((j 0)) | |
| (##declare (not interrupts-enabled)) | |
| (if (##fx< j two^n) | |
| (let ((aj (##f64vector-ref a j)) | |
| (aj+1 (##f64vector-ref a (##fx+ j 1))) | |
| (bj (##f64vector-ref b j)) | |
| (bj+1 (##f64vector-ref b (##fx+ j 1)))) | |
| (##f64vector-set! a j | |
| (##fl- (##fl* bj aj) (##fl* aj+1 bj+1))) | |
| (##f64vector-set! a (##fx+ j 1) | |
| (##fl+ (##fl* bj aj+1) (##fl* aj bj+1))) | |
| (loop (##fx+ j 2))))))) | |
| (define (f64vector-rac->bignum a result result-length) | |
| ;; result-length is > the number of complex entries in a, because | |
| ;; otherwise the length of a would be cut in half. | |
| (let* ((normalizer (##fl/ (##fixnum->flonum (##fxarithmetic-shift-right (##f64vector-length a) 1)))) | |
| (fbase (##fixnum->flonum ##bignum.fdigit-base)) | |
| (fbase-inverse (##fl/ fbase))) | |
| (let ((loop-carry (##f64vector (macro-inexact-+0)))) | |
| (let loop ((i 0) | |
| (j 0) | |
| (limit (##fxarithmetic-shift-right (##f64vector-length a) 1))) ;; here we assume that there are always at least this many fdigits | |
| (##declare (not interrupts-enabled)) | |
| (if (##fx< i limit) | |
| (let* ((t | |
| (##fl+ (##fl+ (##f64vector-ref loop-carry 0) | |
| (macro-inexact-+1/2)) | |
| (##fl* (##f64vector-ref a j) | |
| normalizer))) | |
| (carry | |
| (##flfloor (##fl* t fbase-inverse))) | |
| (digit | |
| (##fl- t (##fl* carry fbase)))) | |
| (##bignum.fdigit-set! result i (##flonum->fixnum digit)) | |
| (##f64vector-set! loop-carry 0 carry) | |
| (loop (##fx+ i 1) | |
| (##fx+ j 2) | |
| limit)) | |
| (if (##fxeven? j) | |
| (loop i | |
| 1 | |
| result-length))))))) | |
| ;; this is the right-angle convolution method of section 6 in Percival's paper | |
| (let* ((x-length (##bignum.fdigit-length x)) | |
| (y-length (##bignum.fdigit-length y)) | |
| (result-length (##fx+ x-length y-length)) | |
| (result (##bignum.make | |
| (##fxquotient | |
| result-length | |
| (##fxquotient ##bignum.adigit-width | |
| ##bignum.fdigit-width)) | |
| #f | |
| #f)) | |
| ;; minimum power of 2 >= x-length + y-length, half # of complex elements in fft vectors | |
| (log-two^n (##fx- (two^p>=m (##fx+ x-length y-length)) 1)) | |
| (two^n (##fxarithmetic-shift-left 1 log-two^n))) | |
| (let ((a (##make-f64vector (##fx* two^n 2))) | |
| (table (make-w (##fx- log-two^n 1))) | |
| (rac-table (make-w-rac log-two^n))) | |
| (bignum->f64vector-rac x a) | |
| (componentwise-rac-multiply a rac-table) | |
| (direct-fft-recursive-4 a table) | |
| (if (##eq? x y) | |
| (componentwise-complex-multiply a a) | |
| (let ((b (##make-f64vector (##fx* two^n 2)))) | |
| (bignum->f64vector-rac y b) | |
| (componentwise-rac-multiply b rac-table) | |
| (direct-fft-recursive-4 b table) | |
| (componentwise-complex-multiply a b))) | |
| (inverse-fft-recursive-4 a table) | |
| (componentwise-rac-multiply-conjugate a rac-table) | |
| (f64vector-rac->bignum a result result-length) | |
| (cleanup x y result)))) | |
| (define (naive-mul x x-length y y-length) ;; multiplies x by each digit of y | |
| (let ((result | |
| (##bignum.make | |
| (##fx+ (##bignum.adigit-length x) (##bignum.adigit-length y)) | |
| #f | |
| #f))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop1 ((k 0)) | |
| (if (##fx< k y-length) | |
| (let ((multiplier (##bignum.mdigit-ref y k))) | |
| (if (##fx= multiplier 0) | |
| (loop1 (##fx+ k 1)) | |
| (let loop2 ((i 0) | |
| (j k) | |
| (carry 0)) | |
| (if (##fx< i x-length) | |
| (loop2 (##fx+ i 1) | |
| (##fx+ j 1) | |
| (##bignum.mdigit-mul! result | |
| j | |
| x | |
| i | |
| multiplier | |
| carry)) | |
| (begin | |
| (##bignum.mdigit-set! result j carry) | |
| (loop1 (##fx+ k 1))))))) | |
| (cleanup x y result))))) | |
| (define (cleanup x y result) | |
| ;; Both naive-mul and fft-mul do unsigned multiplies, fix that here. | |
| (define (fix x y result) | |
| (##declare (not interrupts-enabled)) | |
| (if (##bignum.negative? y) | |
| (let ((x-length (##bignum.adigit-length x))) | |
| (let loop ((i 0) | |
| (j (##bignum.adigit-length y)) | |
| (borrow 0)) | |
| (if (##fx< i x-length) | |
| (loop (##fx+ i 1) | |
| (##fx+ j 1) | |
| (##bignum.adigit-sub! result j x i borrow))))))) | |
| (fix x y result) | |
| (fix y x result) | |
| (##bignum.normalize! result)) | |
| (define (karatsuba-mul x y) | |
| (let* ((x-length | |
| (##bignum.adigit-length x)) | |
| (y-length | |
| (##bignum.adigit-length y)) | |
| (shift-digits | |
| (##fxarithmetic-shift-right y-length 1)) | |
| (shift-bits | |
| (##fx* shift-digits ##bignum.adigit-width)) | |
| (y-high | |
| (##bignum.arithmetic-shift y (##fx- shift-bits))) | |
| (y-low | |
| (##extract-bit-field shift-bits 0 y))) | |
| (if (##eq? x y) | |
| (let ((high-term | |
| (##* y-high y-high)) | |
| (low-term | |
| (##* y-low y-low)) | |
| (mid-term | |
| (let ((arg (##- y-high y-low))) | |
| (##* arg arg)))) | |
| (##+ (##arithmetic-shift high-term (##fx* shift-bits 2)) | |
| (##+ (##arithmetic-shift | |
| (##+ high-term | |
| (##- low-term mid-term)) | |
| shift-bits) | |
| low-term))) | |
| (let ((x-high | |
| (##bignum.arithmetic-shift x (##fx- shift-bits))) | |
| (x-low | |
| (##extract-bit-field shift-bits 0 x))) | |
| (let ((high-term | |
| (##* x-high y-high)) | |
| (low-term | |
| (##* x-low y-low)) | |
| (mid-term | |
| (##* (##- x-high x-low) | |
| (##- y-high y-low)))) | |
| (##+ (##arithmetic-shift high-term (##fx* shift-bits 2)) | |
| (##+ (##arithmetic-shift | |
| (##+ high-term | |
| (##- low-term mid-term)) | |
| shift-bits) | |
| low-term))))))) | |
| (define (mul x x-length y y-length) ;; x-length <= y-length | |
| (let ((x-width (##fx* x-length ##bignum.mdigit-width))) | |
| (cond ((##fx< x-width ##bignum.naive-mul-max-width) | |
| (naive-mul y y-length x x-length)) | |
| ((or (##fx< x-width ##bignum.fft-mul-min-width) | |
| (##fx< ##bignum.fft-mul-max-width | |
| (##fx* y-length ##bignum.mdigit-width))) | |
| (karatsuba-mul x y)) | |
| (else | |
| (fft-mul x y))))) | |
| ;; Certain decisions must be made for multiplication. | |
| ;; First, if both bignums are small, just do naive mul to avoid | |
| ;; further overhead. | |
| ;; This is done in the main body of ##bignum.*. | |
| ;; Second, if it would help to shift out low-order zeros of an | |
| ;; argument, do so. That's done in the main body of ##bignum.*. | |
| ;; Finally, one must decide whether one is using naive mul, karatsuba, or fft. | |
| ;; This is done in mul. | |
| (define (low-bits-to-shift x) | |
| (let ((size (##integer-length x)) | |
| (low-bits (##first-bit-set x))) | |
| (if (##fx< size (##fx+ low-bits low-bits)) | |
| low-bits | |
| 0))) | |
| (define (possibly-unnormalized-bignum-arithmetic-shift x bits) | |
| (if (##fx= bits 0) | |
| (if (##fx= (##bignum.adigit-length x) 1) | |
| (##bignum.normalize! x) | |
| x) | |
| (##arithmetic-shift x bits))) | |
| (let ((x-length (##bignum.mdigit-length x)) | |
| (y-length (##bignum.mdigit-length y))) | |
| (cond ((or (##not (use-fast-bignum-algorithms)) | |
| (and (##fx< x-length 50) | |
| (##fx< y-length 50))) | |
| (if (##fx< x-length y-length) | |
| (naive-mul y y-length x x-length) | |
| (naive-mul x x-length y y-length))) | |
| ((##eq? x y) | |
| (let ((low-bits (low-bits-to-shift x))) | |
| (if (##fx= low-bits 0) | |
| (mul x x-length x x-length) | |
| (##arithmetic-shift | |
| (##exact-int.square (##arithmetic-shift x (##fx- low-bits))) | |
| (##fx+ low-bits low-bits))))) | |
| (else | |
| (let ((x-low-bits (low-bits-to-shift x)) | |
| (y-low-bits (low-bits-to-shift y))) | |
| (if (##fx= (##fx+ x-low-bits y-low-bits) 0) | |
| (if (##fx< x-length y-length) | |
| (mul x x-length y y-length) | |
| (mul y y-length x x-length)) | |
| (##arithmetic-shift | |
| (##* (possibly-unnormalized-bignum-arithmetic-shift x (##fx- x-low-bits)) | |
| (possibly-unnormalized-bignum-arithmetic-shift y (##fx- y-low-bits))) | |
| (##fx+ x-low-bits y-low-bits)))))))) | |
| (define-prim (##bignum.arithmetic-shift x shift) | |
| (let* ((bit-shift | |
| (##fxmodulo shift ##bignum.adigit-width)) | |
| (digit-shift | |
| (##fxquotient (##fx- shift bit-shift) ##bignum.adigit-width)) | |
| (x-length | |
| (##bignum.adigit-length x)) | |
| (result-length | |
| (##fx+ (##fx+ x-length digit-shift) | |
| (if (##fxzero? bit-shift) 0 1)))) | |
| (cond ((##fx< 0 result-length) | |
| (##bignum.normalize! | |
| (##bignum.arithmetic-shift-into! x shift (##bignum.make result-length #f #f)))) | |
| ((##bignum.negative? x) | |
| -1) | |
| (else | |
| 0)))) | |
| (define-prim (##bignum.arithmetic-shift-into! x shift result) | |
| #| | |
| Shifts x by shift bits into result. | |
| Left pads by sign bit as necessary, right pads by zeros as necessary. | |
| Makes *no* error checks. | |
| |# | |
| ;; allocates nothing | |
| (declare (not interrupts-enabled)) | |
| (let* ((bit-shift | |
| (##fxmodulo shift ##bignum.adigit-width)) | |
| (digit-shift | |
| (##fxquotient (##fx- shift bit-shift) | |
| ##bignum.adigit-width)) | |
| (x-length | |
| (##bignum.adigit-length x)) | |
| (result-length | |
| (##bignum.adigit-length result)) | |
| (zeros | |
| ##bignum.adigit-zeros) | |
| (left-fill | |
| (if (##bignum.negative? x) | |
| ##bignum.adigit-ones | |
| ##bignum.adigit-zeros))) | |
| (if (##fxzero? bit-shift) | |
| ;; Copy left-fill into leftmost digits of result as needed. | |
| (let loop1 ((i (##fx- result-length 1)) ;; index for adigit in result | |
| (j (##fx- result-length 1 digit-shift))) ;; index for adigit in x | |
| (if (and (##fx>= i 0) (##fx>= j x-length)) | |
| (begin (##bignum.adigit-copy! result i left-fill 0) | |
| (loop1 (##fx- i 1) (##fx- j 1))) | |
| ;; Copy the digits from x into result as needed. | |
| (let loop2 ((i i) | |
| (j j)) | |
| (if (and (##fx>= i 0) (##fx>= j 0)) | |
| (begin (##bignum.adigit-copy! result i x j) | |
| (loop2 (##fx- i 1) (##fx- j 1))) | |
| ;; copy zero into digits of result as needed. | |
| (let loop3 ((i i)) | |
| (if (##fx>= i 0) | |
| (begin (##bignum.adigit-copy! result i zeros 0) | |
| (loop3 (##fx- i 1))))))))) | |
| (let () | |
| ;; copy left-fill into leftmost digits of result as needed, | |
| ;; then concatenate left-fill with leftmost digit of x if needed. | |
| (define (loop4 i j) | |
| (if (and (##fx>= i 0) (##fx>= j x-length)) | |
| (begin (##bignum.adigit-copy! result i left-fill 0) | |
| (loop4 (##fx- i 1) (##fx- j 1))) | |
| (if (##fx>= i 0) | |
| (if (##fx= (##fx+ j 1) x-length) | |
| (begin (##bignum.adigit-cat! result i left-fill 0 x j bit-shift) | |
| (loop5 (##fx- i 1) (##fx- j 1))) | |
| (loop5 i j))))) | |
| ;; concatenate adjacent digits of x into result as needed, | |
| ;; then concatenate rightmost digit of x with 0 if needed. | |
| (define (loop5 i j) | |
| (if (and (##fx>= i 0) (##fx>= j 0)) | |
| (begin (##bignum.adigit-cat! result i x (##fx+ j 1) x j bit-shift) | |
| (loop5 (##fx- i 1) (##fx- j 1))) | |
| (if (##fx>= i 0) | |
| (if (##fx= (##fx+ j 1) 0) | |
| (begin (##bignum.adigit-cat! result i x 0 zeros 0 bit-shift) | |
| (loop6 (##fx- i 1))) | |
| (loop6 i))))) | |
| ;; copy 0 into rightmost digits of x as needed. | |
| (define (loop6 i) | |
| (if (##fx>= i 0) | |
| (begin (##bignum.adigit-copy! result i zeros 0) | |
| (loop6 (##fx- i 1))))) | |
| (loop4 (##fx- result-length 1) ;; index for adigit in result | |
| (##fx- result-length digit-shift 2)))) ;; index for adigit in x | |
| ;; return something useful | |
| result)) | |
| ;;; Bignum division. | |
| (define ##reciprocal-cache (##make-table 0 #f #t #f ##eq?)) | |
| (define ##bignum.mdigit-width/2 | |
| (##fxquotient ##bignum.mdigit-width 2)) | |
| (define ##bignum.mdigit-base*16 | |
| (##fx* ##bignum.mdigit-base 16)) | |
| (define (##fxceiling-ratio a b) | |
| ;; computes (ceiling (/ a b)) with a b fixnums | |
| (##fxquotient (##fx+ a b -1) b)) | |
| (define-prim (##bignum.div u v #!optional (need-quotient? #t) (keep-dividend? #t)) | |
| ;; u is an unnormalized bignum, v is a normalized exact-int | |
| ;; 0 < v <= u | |
| (define (##exact-int.reciprocal v bits) | |
| ;; returns an approximation to the reciprocal of | |
| ;; .v1 v2 v3 ... | |
| ;; where v1 is the highest set bit of v; result is of the form | |
| ;; xx . xxxxxxxxxxxxxxxxxxx where there are bits + 1 bits to the | |
| ;; right of the binary point. The result is always <= 2; see Knuth, volume 2. | |
| (let ((cached-value (##table-ref ##reciprocal-cache v #f))) | |
| (if (and cached-value | |
| (##not (##fx< (##cdr cached-value) bits))) | |
| cached-value | |
| (let ((v-length (##integer-length v))) | |
| (define (recip v bits) | |
| (cond ((and cached-value | |
| (##not (##fx< (##cdr cached-value) bits))) | |
| cached-value) | |
| ((##fx<= bits ##bignum.mdigit-width/2) | |
| (##cons (##fxquotient | |
| ##bignum.mdigit-base*16 | |
| (##arithmetic-shift | |
| v | |
| (##fx- ##bignum.mdigit-width/2 -3 v-length))) | |
| ##bignum.mdigit-width/2)) | |
| (else | |
| (let* ((high-bits | |
| (##fxarithmetic-shift-right | |
| (##fx+ bits 1) | |
| 1)) | |
| (z-bits ;; >= high-bits + 1 to right of point | |
| (recip v high-bits)) | |
| (z ;; high-bits + 1 to right of point | |
| (##arithmetic-shift | |
| (##car z-bits) | |
| (##fx- high-bits (##cdr z-bits)))) | |
| (v-bits ;; bits + 3 to right of point | |
| (##arithmetic-shift | |
| v | |
| (##fx- (##fx+ bits 3) | |
| v-length))) | |
| (v*z*z ;; 2 * high-bits + bits + 5 to right | |
| (##* v-bits (##exact-int.square z))) | |
| (two-z ;; 2 * high-bits + bits + 5 to right | |
| (##arithmetic-shift | |
| z | |
| (##fx+ high-bits (##fx+ bits 5)))) | |
| (temp | |
| (##- two-z v*z*z)) | |
| (bits-to-shift | |
| (##fx+ 4 (##fx+ high-bits high-bits))) | |
| (shifted-temp | |
| (##arithmetic-shift | |
| temp | |
| (##fx- bits-to-shift)))) | |
| (if (##fx< (##first-bit-set temp) bits-to-shift) | |
| (##cons (##+ shifted-temp 1) bits) | |
| (##cons shifted-temp bits)))))) | |
| (let ((result (recip v bits))) | |
| (##table-set! ##reciprocal-cache v result) | |
| result))))) | |
| (define (naive-div u v) | |
| ;; u is a normalized bignum, v is a possibly unnormalized bignum | |
| ;; u >= v >= ##bignum.mdigit-base | |
| (define (estimate-q-hat top-bits-of-u v_n-1 v_n-2) | |
| ;; from Knuth | |
| (let ((q-hat | |
| (##bignum.mdigit-quotient top-bits-of-u 2 v_n-1)) | |
| (u_n+j-2 | |
| (##bignum.mdigit-ref top-bits-of-u 0 ))) | |
| (let ((r-hat | |
| (##bignum.mdigit-remainder top-bits-of-u 2 v_n-1 q-hat))) | |
| (if (or (##fx= q-hat ##bignum.mdigit-base) | |
| (##bignum.mdigit-test? q-hat v_n-2 r-hat u_n+j-2)) | |
| (let ((q-hat | |
| (##fx- q-hat 1)) | |
| (r-hat | |
| (##fx+ r-hat v_n-1))) | |
| (if (and (##fx< r-hat ##bignum.mdigit-base) | |
| (or (##fx= q-hat ##bignum.mdigit-base) | |
| (##bignum.mdigit-test? q-hat v_n-2 r-hat u_n+j-2))) | |
| (##fx- q-hat 1) | |
| q-hat)) | |
| q-hat)))) | |
| (define (subtract-multiple-of-v u v q-hat n j) | |
| ;; subtracts q-hat * v from u, starting at mdigit j, returns final q-hat | |
| (##declare (not interrupts-enabled)) | |
| (if (##fx= q-hat 0) | |
| q-hat | |
| (let loop4 ((i j) | |
| (k 0) | |
| (borrow 0)) | |
| (if (##fx< k n) | |
| (loop4 (##fx+ i 1) | |
| (##fx+ k 1) | |
| (##bignum.mdigit-div! u i v k q-hat borrow)) | |
| (let* ((borrow (if (or (##fxzero? borrow) | |
| (##fx= i (##bignum.mdigit-length u)) | |
| (##fx= (##bignum.mdigit-ref u i) 0)) | |
| borrow | |
| (##bignum.mdigit-div! u i ##bignum.adigit-zeros 0 q-hat borrow)))) | |
| (if (##fx< borrow 0) | |
| (let loop5 ((i j) | |
| (l 0) | |
| (carry 0)) | |
| (if (##fx< l n) | |
| (loop5 (##fx+ i 1) | |
| (##fx+ l 1) | |
| (##bignum.mdigit-mul! u i v l 1 carry)) | |
| (begin | |
| (if (and (##fx= carry 1) | |
| (not (or (##fx= i (##bignum.mdigit-length u)) | |
| (##fx= (##bignum.mdigit-ref u i) 0)))) | |
| (##bignum.mdigit-mul! u i ##bignum.adigit-zeros 0 1 carry)) | |
| (##fx- q-hat 1)))) | |
| q-hat)))))) | |
| (let ((u-bits | |
| (##integer-length u)) | |
| (v-bits | |
| (##integer-length v))) | |
| (let* ((n | |
| (##fxceiling-ratio v-bits ##bignum.mdigit-width)) | |
| (temp | |
| ;; need three mdigits for top-bits-of-u | |
| (##bignum.make (##fxceiling-ratio (##fx* 3 ##bignum.mdigit-width) | |
| ##bignum.adigit-width) | |
| #f | |
| #f)) | |
| (top-2*mdigit-width-bits-of-v | |
| (##bignum.arithmetic-shift-into! v (##fx- (##fx* ##bignum.mdigit-width 2) v-bits) temp)) | |
| (v_n-1 | |
| (##bignum.mdigit-ref top-2*mdigit-width-bits-of-v 1)) | |
| (v_n-2 | |
| (##bignum.mdigit-ref top-2*mdigit-width-bits-of-v 0))) | |
| ;; Knuth says to simplify things by shifting u and v so that | |
| ;; the top nonzero mdigit of v is >= mdigit-base/2 | |
| ;; We're not going to do the shift, but we're going to use that idea. | |
| ;; This strategy does a bit more work, but generates less garbage. | |
| (let* ((q-bits ;; maximum number of possible bits in q | |
| (##fx+ (##fx- u-bits v-bits) 2)) ;; 1 is not always sufficient... | |
| (q-adigits | |
| (##fxceiling-ratio q-bits ##bignum.adigit-width)) | |
| (q-mdigits | |
| (##fxceiling-ratio q-bits ##bignum.mdigit-width)) | |
| (q | |
| (and need-quotient? | |
| (##fx> q-mdigits 1) ;; result might be bignum | |
| (##bignum.make q-adigits #f #f))) | |
| (u | |
| (if keep-dividend? | |
| ;; copy u | |
| (##bignum.copy u) | |
| ;; overwrite u with remainder | |
| u))) | |
| (if (##fx= q-mdigits 1) | |
| ;; final result can't be bignum | |
| (let* ((top-bits-of-u | |
| (##bignum.arithmetic-shift-into! u (##fx- (##fx* 2 ##bignum.mdigit-width) v-bits) temp)) | |
| (q-hat-estimate | |
| (estimate-q-hat top-bits-of-u v_n-1 v_n-2)) | |
| (q-hat | |
| (subtract-multiple-of-v u v q-hat-estimate n 0))) | |
| (##cons (and need-quotient? q-hat) | |
| (##bignum.normalize! u))) | |
| ;; final result may be bignum | |
| (let loop3 ((j (##fx- q-mdigits 1))) | |
| (if (##not (##fx< j 0)) | |
| (let* ((top-bits-of-u | |
| (##bignum.arithmetic-shift-into! u (##fx- (##fx* (##fx- 2 j) ##bignum.mdigit-width) v-bits) temp)) | |
| (q-hat-estimate | |
| (estimate-q-hat top-bits-of-u v_n-1 v_n-2)) | |
| (q-hat | |
| (subtract-multiple-of-v u v q-hat-estimate n j))) | |
| (and need-quotient? (##bignum.mdigit-set! q j q-hat)) | |
| (loop3 (##fx- j 1))) | |
| (##cons (and need-quotient? (##bignum.normalize! q)) | |
| (##bignum.normalize! u))))))))) | |
| (define (div-one u v) | |
| (let ((m | |
| (let loop6 ((i (##fx- (##bignum.mdigit-length u) 1))) | |
| (if (##fx< 0 (##bignum.mdigit-ref u i)) | |
| (##fx+ i 1) | |
| (loop6 (##fx- i 1)))))) | |
| (let ((work-u (##bignum.make | |
| (##fxceiling-ratio (##fx* 2 ##bignum.mdigit-width) | |
| ##bignum.adigit-width) | |
| #f | |
| #f)) | |
| (q (and need-quotient? | |
| (##bignum.make (##bignum.adigit-length u) #f #f)))) | |
| (##declare (not interrupts-enabled)) | |
| (let loop7 ((i m) | |
| (r-hat 0)) | |
| (##bignum.mdigit-set! | |
| work-u | |
| 1 | |
| r-hat) | |
| (##bignum.mdigit-set! | |
| work-u | |
| 0 | |
| (##bignum.mdigit-ref u (##fx- i 1))) | |
| (let ((q-hat (##bignum.mdigit-quotient work-u 1 v))) | |
| (let ((r-hat (##bignum.mdigit-remainder work-u 1 v q-hat))) | |
| (and need-quotient? (##bignum.mdigit-set! q (##fx- i 1) q-hat)) | |
| (if (##fx< 1 i) | |
| (loop7 (##fx- i 1) | |
| r-hat) | |
| (let () | |
| (##declare (interrupts-enabled)) | |
| (##cons (and need-quotient? (##bignum.normalize! q)) | |
| r-hat))))))))) | |
| (define (big-divide u v) | |
| ;; u and v are positive bignums | |
| (let ((v-length (##integer-length v)) | |
| (v-first-bit-set (##first-bit-set v))) | |
| ;; first we check whether it may be beneficial to shift out | |
| ;; low-order zero bits of v | |
| (if (##fx>= v-first-bit-set | |
| (##fxarithmetic-shift-right v-length 1)) | |
| (let ((reduced-quotient | |
| (##exact-int.div | |
| (##bignum.arithmetic-shift u (##fx- v-first-bit-set)) | |
| (##bignum.arithmetic-shift v (##fx- v-first-bit-set)) | |
| #t ;; need-quotient? | |
| #f ;; keep-dividend? | |
| )) | |
| (extra-remainder | |
| (##extract-bit-field v-first-bit-set 0 u))) | |
| (##cons (##car reduced-quotient) | |
| (##+ (##arithmetic-shift (##cdr reduced-quotient) | |
| v-first-bit-set) | |
| extra-remainder))) | |
| (if (##fx< v-length ##bignum.fft-mul-min-width) | |
| (naive-div u v) | |
| (let* ((u-length (##integer-length u)) | |
| (length-difference (##fx- u-length v-length))) | |
| (if (##fx< length-difference ##bignum.fft-mul-min-width) | |
| (naive-div u v) | |
| (let* ((z-bits (##exact-int.reciprocal v length-difference)) | |
| (z (##car z-bits)) | |
| (bits (##cdr z-bits))) | |
| (let ((test-quotient | |
| (##bignum.arithmetic-shift | |
| (##* (##bignum.arithmetic-shift | |
| u | |
| (##fx- length-difference | |
| (##fx- u-length 2))) | |
| (##bignum.arithmetic-shift | |
| z | |
| (##fx- length-difference bits))) | |
| (##fx- -3 length-difference)))) | |
| (let ((rem (##- u (##* test-quotient v)))) | |
| ;; I believe, and I haven't found any counterexamples in my tests | |
| ;; to disprove it, that test-quotient can be off by at most +-1. | |
| ;; I can't prove this, however, so we put in the following loops. | |
| ;; Especially note that our reciprocal does not satisfy the | |
| ;; error bounds in Knuth's volume 2 in perhaps a vain effort to | |
| ;; save some computations. perhaps this should be fixed. blah. | |
| (cond ((##negative? rem) | |
| (let loop ((test-quotient test-quotient) | |
| (rem rem)) | |
| (let ((test-quotient (##- test-quotient 1)) | |
| (rem (##+ rem v))) | |
| (if (##negative? rem) | |
| (loop test-quotient rem) | |
| (##cons test-quotient rem))))) | |
| ((##< rem v) | |
| (##cons test-quotient | |
| rem)) | |
| (else | |
| (let loop ((test-quotient test-quotient) | |
| (rem rem)) | |
| (let ((test-quotient (##+ test-quotient 1)) | |
| (rem (##- rem v))) | |
| (if (##< rem v) | |
| (##cons test-quotient rem) | |
| (loop test-quotient rem))))))))))))))) | |
| (if (##fixnum? v) | |
| (if (##fx< v ##bignum.mdigit-base) | |
| (div-one u v) | |
| (begin | |
| ;; here it's probably not worth the extra cycles to check whether | |
| ;; a subtraction would be sufficient, i.e., we don't call | |
| ;; short-divisor-or-quotient-divide | |
| (naive-div u (##fixnum->bignum v)))) | |
| (if (use-fast-bignum-algorithms) | |
| (big-divide u v) | |
| (naive-div u v)))) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Exact integer operations | |
| ;;; ------------------------ | |
| (define (##exact-int.= x y) | |
| (##fx= 0 (##exact-int.compare x y))) | |
| (define (##exact-int.< x y) | |
| (##fx= -1 (##exact-int.compare x y))) | |
| (define (##exact-int.compare x y) | |
| ;; returns -1 if x < y, 0 if x = y, or 1 if x > y | |
| (define (compare x y x-smaller) | |
| (##declare (not interrupts-enabled)) | |
| (let ((x-digits (##bignum.adigit-length x)) | |
| (y-digits (##bignum.adigit-length y))) | |
| (cond ((##fx< x-digits y-digits) x-smaller) | |
| ((##fx< y-digits x-digits) (##fx- x-smaller)) | |
| (else | |
| (let loop ((i (##fx- x-digits 1))) | |
| (cond ((##fx< i 0) 0) | |
| ((##bignum.adigit-< x y i) -1) | |
| ((##bignum.adigit-< y x i) 1) | |
| (else | |
| (loop (##fx- i 1))))))))) | |
| (if (##fixnum? x) | |
| (if (##fixnum? y) | |
| (cond ((##fx< x y) -1) | |
| ((##fx= x y) 0) | |
| (else 1)) | |
| (if (##bignum.negative? y) 1 -1)) | |
| (if (##fixnum? y) | |
| (if (##bignum.negative? x) -1 1) | |
| (if (##bignum.negative? x) | |
| (if (##bignum.negative? y) (compare x y 1) -1) | |
| (if (##bignum.negative? y) 1 (compare x y -1)))))) | |
| (define-prim (##exact-int.*-expt2 x y) | |
| (if (##fxnegative? y) | |
| (##ratnum.normalize x (##arithmetic-shift 1 (##fx- y))) | |
| (##arithmetic-shift x y))) | |
| (define-prim (##exact-int.div x y #!optional (need-quotient? #t) (keep-dividend? #t)) | |
| (define (big-quotient x y) | |
| (let* ((x-negative? (##negative? x)) | |
| (abs-x (if x-negative? | |
| (##negate x) | |
| x)) | |
| (y-negative? (##negative? y)) | |
| (abs-y (if y-negative? | |
| (begin | |
| (set! keep-dividend? #f) | |
| (##negate y)) | |
| y))) | |
| (if (##< abs-x abs-y) | |
| (##cons 0 x) | |
| ;; at least one of x and y is a bignum, so | |
| ;; here abs-x must be a bignum | |
| (let ((result (##bignum.div abs-x abs-y need-quotient? keep-dividend?))) | |
| (if (and need-quotient? | |
| (##not (##eq? x-negative? y-negative?))) | |
| (##set-car! result (##negate (##car result)))) | |
| (if x-negative? | |
| (##set-cdr! result (##negate (##cdr result)))) | |
| result)))) | |
| (cond ((##eqv? y 1) | |
| (##cons x 0)) | |
| ((##eqv? y -1) | |
| (##cons (##negate x) 0)) | |
| ((##eq? x y) ;; can come up in rational arithmetic | |
| (##cons 1 0)) | |
| ((##fixnum? x) | |
| (if (##fixnum? y) | |
| (##cons (##fxquotient x y) ;; note: y can't be -1 | |
| (##fxremainder x y)) | |
| ;; y is a bignum, x is a fixnum | |
| (if (##fx< 1 (##bignum.adigit-length y)) | |
| ;; y has at least two adigits, so | |
| ;; (abs y) > (abs x) | |
| (##cons 0 x) | |
| (big-quotient x y)))) | |
| ((and (##bignum? y) | |
| (##fx< 1 (##fx- (##bignum.adigit-length y) | |
| (##bignum.adigit-length x)))) | |
| ;; x and y are bignums, and y has at least two more adigits | |
| ;; than x, so (abs y) > (abs x) | |
| (##cons 0 x)) | |
| (else | |
| (big-quotient x y)))) | |
| (define-prim (##exact-int.nth-root x y) | |
| (cond ((##eqv? x 0) | |
| 0) | |
| ((##eqv? x 1) | |
| 1) | |
| ((##eqv? y 1) | |
| x) | |
| ((##eqv? y 2) | |
| (##car (##exact-int.sqrt x))) | |
| ((##not (##fixnum? y)) | |
| 1) | |
| (else | |
| (let ((length (##integer-length x))) | |
| ;; (expt 2 (- length l 1)) <= x < (expt 2 length) | |
| (cond ((##fx<= length y) | |
| 1) | |
| ;; result is >= 2 | |
| ((##fx<= length (##fx* 2 y)) | |
| ;; result is < 4 | |
| (if (##< x (##expt 3 y)) | |
| 2 | |
| 3)) | |
| ((##fxeven? y) | |
| (##exact-int.nth-root | |
| (##car (##exact-int.sqrt x)) | |
| (##fxarithmetic-shift-right y 1))) | |
| (else | |
| (let* ((length/y/2 ;; length/y/2 >= 1 because (< (* 2 y) length) | |
| (##fxarithmetic-shift-right | |
| (##fxquotient | |
| (##fx- length 1) | |
| y) | |
| 1))) | |
| (let ((init-g | |
| (let* ((top-bits | |
| (##arithmetic-shift | |
| x | |
| (##fx- (##fx* length/y/2 y)))) | |
| (nth-root-top-bits | |
| (##exact-int.nth-root top-bits y))) | |
| (##arithmetic-shift | |
| (##+ nth-root-top-bits 1) | |
| length/y/2)))) | |
| (let loop ((g init-g)) | |
| (let* ((a (##expt g (##fx- y 1))) | |
| (b (##* a y)) | |
| (c (##* a (##fx- y 1))) | |
| (d (##quotient (##+ x (##* g c)) b))) | |
| (let ((diff (##- d g))) | |
| (cond ((##not (##negative? diff)) | |
| g) | |
| ((##< diff -1) | |
| (loop d)) | |
| (else | |
| ;; once the difference is one, it's more | |
| ;; efficient to just decrement until g^y <= x | |
| (let loop ((g d)) | |
| (if (##not (##< x (##expt g y))) | |
| g | |
| (loop (##- g 1))))))))))))))))) | |
| (define-prim (##integer-nth-root x y) | |
| (define (type-error-on-x) | |
| (##fail-check-exact-integer 1 integer-nth-root x y)) | |
| (define (type-error-on-y) | |
| (##fail-check-exact-integer 2 integer-nth-root x y)) | |
| (define (range-error-on-x) | |
| (##raise-range-exception 1 integer-nth-root x y)) | |
| (define (range-error-on-y) | |
| (##raise-range-exception 2 integer-nth-root x y)) | |
| (if (macro-exact-int? x) | |
| (if (macro-exact-int? y) | |
| (cond ((##negative? x) | |
| (range-error-on-x)) | |
| ((##positive? y) | |
| (##exact-int.nth-root x y)) | |
| (else | |
| (range-error-on-y))) | |
| (type-error-on-y)) | |
| (type-error-on-x))) | |
| (define-prim (integer-nth-root x y) | |
| (macro-force-vars (x y) | |
| (##integer-nth-root x y))) | |
| (define-prim (##exact-int.sqrt x) | |
| ;; 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 | |
| ;; (##< (##flsqrt (- (* 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 | |
| (##fx<= x 4503599627370496))) ;; 2^52 | |
| (let* ((s (##flonum->fixnum (##flsqrt (##fixnum->flonum x)))) | |
| (r (##fx- x (##fx* s s)))) | |
| (##cons s r)) | |
| (let ((length/4 | |
| (##fxarithmetic-shift-right | |
| (##fx+ (##integer-length x) 1) | |
| 2))) | |
| (let* ((s-prime&r-prime | |
| (##exact-int.sqrt | |
| (##arithmetic-shift | |
| x | |
| (##fx- (##fxarithmetic-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) | |
| #t ;; need-quotient? | |
| #f)) ;; keep-dividend? | |
| (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)))))))) | |
| (define-prim (##integer-sqrt x) | |
| (define (type-error) | |
| (##fail-check-exact-integer 1 integer-sqrt x)) | |
| (define (range-error) | |
| (##raise-range-exception 1 integer-sqrt x)) | |
| (if (macro-exact-int? x) | |
| (if (##negative? x) | |
| (range-error) | |
| (##car (##exact-int.sqrt x))) | |
| (type-error))) | |
| (define-prim (integer-sqrt x) | |
| (macro-force-vars (x) | |
| (##integer-sqrt x))) | |
| (define-prim (##exact-int.square n) | |
| (##* n n)) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Ratnum operations | |
| ;;; ----------------- | |
| (define-prim (##ratnum-make num den) | |
| (macro-ratnum-make num den)) | |
| (define-prim (##ratnum-numerator x) | |
| (macro-ratnum-numerator x)) | |
| (define-prim (##ratnum-denominator x) | |
| (macro-ratnum-denominator x)) | |
| (define-prim (##ratnum.= x y) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (and (= (macro-ratnum-numerator x) | |
| (macro-ratnum-numerator y)) | |
| (= (macro-ratnum-denominator x) | |
| (macro-ratnum-denominator y)))) | |
| (define-prim (##ratnum.< x y) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (< (* (macro-ratnum-numerator x) | |
| (macro-ratnum-denominator y)) | |
| (* (macro-ratnum-denominator x) | |
| (macro-ratnum-numerator y)))) | |
| (define-prim (##ratnum.+ x y) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (let ((p (macro-ratnum-numerator x)) | |
| (q (macro-ratnum-denominator x)) | |
| (r (macro-ratnum-numerator y)) | |
| (s (macro-ratnum-denominator y))) | |
| (let ((d1 (##gcd q s))) | |
| (if (eqv? d1 1) | |
| (macro-ratnum-make (+ (* p s) | |
| (* r q)) | |
| (* q s)) | |
| (let* ((s-prime (quotient s d1)) | |
| (t (+ (* p s-prime) | |
| (* r (quotient q d1)))) | |
| (d2 (##gcd d1 t)) | |
| (num (quotient t d2)) | |
| (den (* (quotient q d2) | |
| s-prime))) | |
| (if (eqv? den 1) | |
| num | |
| (macro-ratnum-make num den))))))) | |
| (define-prim (##ratnum.- x y) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (let ((p (macro-ratnum-numerator x)) | |
| (q (macro-ratnum-denominator x)) | |
| (r (macro-ratnum-numerator y)) | |
| (s (macro-ratnum-denominator y))) | |
| (let ((d1 (##gcd q s))) | |
| (if (eqv? d1 1) | |
| (macro-ratnum-make (- (* p s) | |
| (* r q)) | |
| (* q s)) | |
| (let* ((s-prime (quotient s d1)) | |
| (t (- (* p s-prime) | |
| (* r (quotient q d1)))) | |
| (d2 (##gcd d1 t)) | |
| (num (quotient t d2)) | |
| (den (* (quotient q d2) | |
| s-prime))) | |
| (if (eqv? den 1) | |
| num | |
| (macro-ratnum-make num den))))))) | |
| (define-prim (##ratnum.* x y) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (let ((p (macro-ratnum-numerator x)) | |
| (q (macro-ratnum-denominator x)) | |
| (r (macro-ratnum-numerator y)) | |
| (s (macro-ratnum-denominator y))) | |
| (if (eq? x y) | |
| (macro-ratnum-make (square p) (square q)) ;; already in lowest form | |
| (let* ((gcd-ps (##gcd p s)) | |
| (gcd-rq (##gcd r q)) | |
| (num (* (quotient p gcd-ps) (quotient r gcd-rq))) | |
| (den (* (quotient q gcd-rq) (quotient s gcd-ps)))) | |
| (if (eqv? den 1) | |
| num | |
| (macro-ratnum-make num den)))))) | |
| (define-prim (##ratnum./ x y) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (let ((p (macro-ratnum-numerator x)) | |
| (q (macro-ratnum-denominator x)) | |
| (r (macro-ratnum-denominator y)) | |
| (s (macro-ratnum-numerator y))) | |
| (if (eq? x y) | |
| 1 | |
| (let* ((gcd-ps (##gcd p s)) | |
| (gcd-rq (##gcd r q)) | |
| (num (* (quotient p gcd-ps) (quotient r gcd-rq))) | |
| (den (* (quotient q gcd-rq) (quotient s gcd-ps)))) | |
| (if (negative? den) | |
| (if (eqv? den -1) | |
| (- num) | |
| (macro-ratnum-make (- num) (- den))) | |
| (if (eqv? den 1) | |
| num | |
| (macro-ratnum-make num den))))))) | |
| (define-prim (##ratnum.normalize num den) | |
| (##declare (mostly-fixnum) | |
| (not safe) | |
| (standard-bindings)) | |
| (let* ((x (##gcd num den)) | |
| (y (if (negative? den) (- x) x)) | |
| (num (quotient num y)) | |
| (den (quotient den y))) | |
| (if (eqv? den 1) | |
| num | |
| (macro-ratnum-make num den)))) | |
| (define-prim (##exact-int->ratnum x) | |
| (macro-ratnum-make x 1)) | |
| (define-prim (##ratnum.round x #!optional (round-half-away-from-zero? #f)) | |
| (let ((num (macro-ratnum-numerator x)) | |
| (den (macro-ratnum-denominator x))) | |
| (if (##eqv? den 2) | |
| (if round-half-away-from-zero? | |
| (##arithmetic-shift (##+ num (if (##positive? num) 1 -1)) -1) | |
| (##arithmetic-shift (##arithmetic-shift (##+ num 1) -2) 1)) | |
| ;; here the ratnum cannot have fractional part = 1/2 | |
| (##floor | |
| (##ratnum.normalize | |
| (##+ (##arithmetic-shift num 1) den) | |
| (##arithmetic-shift den 1)))))) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Flonum operations | |
| ;;; ----------------- | |
| (##define-macro (define-prim-flonum form . special-body) | |
| (let ((body (if (null? special-body) form `(begin ,@special-body)))) | |
| (cond ((= 1 (length (cdr form))) | |
| (let* ((name-fn (car form)) | |
| (name-param1 (cadr form))) | |
| `(define-prim ,form | |
| (macro-force-vars (,name-param1) | |
| (macro-check-flonum | |
| ,name-param1 | |
| 1 | |
| ,form | |
| ,body))))) | |
| ((= 2 (length (cdr form))) | |
| (let* ((name-fn (car form)) | |
| (name-param1 (cadr form)) | |
| (name-param2 (caddr form))) | |
| `(define-prim ,form | |
| (macro-force-vars (,name-param1 ,name-param2) | |
| (macro-check-flonum | |
| ,name-param1 | |
| 1 | |
| ,form | |
| (macro-check-flonum | |
| ,name-param2 | |
| 2 | |
| ,form | |
| ,body)))))) | |
| (else | |
| (error "define-prim-flonum supports only 1 or 2 parameter procedures"))))) | |
| (define-prim (flonum? obj) | |
| (macro-force-vars (obj) | |
| (##flonum? obj))) | |
| (define-prim (##fleqv? x y)) | |
| (define-prim-nary-bool (##fl= x y) | |
| #t | |
| #t | |
| (##fl= x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fl= x y) | |
| #t | |
| #t | |
| (##fl= x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary-bool (##fl< x y) | |
| #t | |
| #t | |
| (##fl< x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fl< x y) | |
| #t | |
| #t | |
| (##fl< x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary-bool (##fl> x y) | |
| #t | |
| #t | |
| (##fl> x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fl> x y) | |
| #t | |
| #t | |
| (##fl> x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary-bool (##fl<= x y) | |
| #t | |
| #t | |
| (##fl<= x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fl<= x y) | |
| #t | |
| #t | |
| (##fl<= x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary-bool (##fl>= x y) | |
| #t | |
| #t | |
| (##fl>= x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary-bool (fl>= x y) | |
| #t | |
| #t | |
| (##fl>= x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim (##flinteger? x)) | |
| (define-prim-flonum (flinteger? x) | |
| (##flinteger? x)) | |
| (define-prim (##flzero? x)) | |
| (define-prim-flonum (flzero? x) | |
| (##flzero? x)) | |
| (define-prim (##flpositive? x)) | |
| (define-prim-flonum (flpositive? x) | |
| (##flpositive? x)) | |
| (define-prim (##flnegative? x)) | |
| (define-prim-flonum (flnegative? x) | |
| (##flnegative? x)) | |
| (define-prim (##flodd? x)) | |
| (define-prim-flonum (flodd? x) | |
| (##flodd? x)) | |
| (define-prim (##fleven? x)) | |
| (define-prim-flonum (fleven? x) | |
| (##fleven? x)) | |
| (define-prim (##flfinite? x)) | |
| (define-prim-flonum (flfinite? x) | |
| (##flfinite? x)) | |
| (define-prim (##flinfinite? x)) | |
| (define-prim-flonum (flinfinite? x) | |
| (##flinfinite? x)) | |
| (define-prim (##flnan? x)) | |
| (define-prim-flonum (flnan? x) | |
| (##flnan? x)) | |
| (define-prim-nary (##flmax x y) | |
| () | |
| x | |
| (##flmax x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (flmax x y) | |
| () | |
| x | |
| (##flmax x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary (##flmin x y) | |
| () | |
| x | |
| (##flmin x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (flmin x y) | |
| () | |
| x | |
| (##flmin x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary (##fl+ x y) | |
| (macro-inexact-+0) | |
| x | |
| (##fl+ x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fl+ x y) | |
| (macro-inexact-+0) | |
| x | |
| (##fl+ x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary (##fl* x y) | |
| (macro-inexact-+1) | |
| x | |
| (##fl* x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fl* x y) | |
| (macro-inexact-+1) | |
| x | |
| (##fl* x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary (##fl- x y) | |
| () | |
| (##fl- x) | |
| (##fl- x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fl- x y) | |
| () | |
| (##fl- x) | |
| (##fl- x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim-nary (##fl/ x y) | |
| () | |
| (##fl/ x) | |
| (##fl/ x y) | |
| macro-no-force | |
| macro-no-check) | |
| (define-prim-nary (fl/ x y) | |
| () | |
| (##fl/ x) | |
| (##fl/ x y) | |
| macro-force-vars | |
| macro-check-flonum) | |
| (define-prim (##flabs x)) | |
| (define-prim-flonum (flabs x) | |
| (##flabs x)) | |
| (define-prim-flonum (flnumerator x) | |
| (cond ((##flzero? x) | |
| x) | |
| ((macro-flonum-rational? x) | |
| (##exact->inexact (##numerator (##flonum->exact x)))) | |
| (else | |
| (##fail-check-rational 1 flnumerator x)))) | |
| (define-prim-flonum (fldenominator x) | |
| (if (macro-flonum-rational? x) | |
| (##exact->inexact (##denominator (##flonum->exact x))) | |
| (##fail-check-rational 1 fldenominator x))) | |
| (define-prim (##flfloor x)) | |
| (define-prim-flonum (flfloor x) | |
| (##flfloor x)) | |
| (define-prim (##flceiling x)) | |
| (define-prim-flonum (flceiling x) | |
| (##flceiling x)) | |
| (define-prim (##fltruncate x)) | |
| (define-prim-flonum (fltruncate x) | |
| (##fltruncate x)) | |
| (define-prim (##flround x)) | |
| (define-prim-flonum (flround x) | |
| (##flround x)) | |
| (define-prim (##flscalbn x n)) | |
| (define-prim (flscalbn x n) | |
| (macro-force-vars (x n) | |
| (macro-check-flonum x 1 (flscalbn x n) | |
| (macro-check-fixnum n 2 (flscalbn x n) | |
| (##flscalbn x n))))) | |
| (define-prim (##flilogb x)) | |
| (define-prim-flonum (flilogb x) | |
| (##flilogb x)) | |
| (define-prim (##flexp x)) | |
| (define-prim-flonum (flexp x) | |
| (##flexp x)) | |
| (define-prim (##flexpm1 x)) | |
| (define-prim-flonum (flexpm1 x) | |
| (##flexpm1 x)) | |
| (define-prim (##fllog x)) | |
| (define-prim-flonum (fllog x) | |
| (##fllog x)) | |
| (define-prim (##fllog1p x)) | |
| (define-prim-flonum (fllog1p x) | |
| (##fllog1p x)) | |
| (define-prim (##flsin x)) | |
| (define-prim-flonum (flsin x) | |
| (##flsin x)) | |
| (define-prim (##flcos x)) | |
| (define-prim-flonum (flcos x) | |
| (##flcos x)) | |
| (define-prim (##fltan x)) | |
| (define-prim-flonum (fltan x) | |
| (##fltan x)) | |
| (define-prim (##flasin x)) | |
| (define-prim-flonum (flasin x) | |
| (##flasin x)) | |
| (define-prim (##flacos x)) | |
| (define-prim-flonum (flacos x) | |
| (##flacos x)) | |
| (define-prim (##flatan x #!optional (y (macro-absent-obj))) | |
| (if (##eq? y (macro-absent-obj)) | |
| (##flatan x) | |
| (##flatan x y))) | |
| (define-prim (flatan x #!optional (y (macro-absent-obj))) | |
| (macro-force-vars (x y) | |
| (macro-check-flonum x 1 (flatan x y) | |
| (if (##eq? y (macro-absent-obj)) | |
| (##flatan x) | |
| (macro-check-flonum y 2 (flatan x y) | |
| (##flatan x y)))))) | |
| (define-prim (##flsinh x)) | |
| (define-prim-flonum (flsinh x) | |
| (##flsinh x)) | |
| (define-prim (##flcosh x)) | |
| (define-prim-flonum (flcosh x) | |
| (##flcosh x)) | |
| (define-prim (##fltanh x)) | |
| (define-prim-flonum (fltanh x) | |
| (##fltanh x)) | |
| (define-prim (##flasinh x)) | |
| (define-prim-flonum (flasinh x) | |
| (##flasinh x)) | |
| (define-prim (##flacosh x)) | |
| (define-prim-flonum (flacosh x) | |
| (##flacosh x)) | |
| (define-prim (##flatanh x)) | |
| (define-prim-flonum (flatanh x) | |
| (##flatanh x)) | |
| (define-prim (##flexpt x y)) | |
| (define-prim-flonum (flexpt x y) | |
| (##flexpt x y)) | |
| (define-prim (##flsqrt x)) | |
| (define-prim-flonum (flsqrt x) | |
| (##flsqrt x)) | |
| (define-prim (##flsquare x)) | |
| (define-prim-flonum (flsquare x) | |
| (##flsquare x)) | |
| (define-prim-fixnum (fixnum->flonum x) | |
| (##fixnum->flonum x)) | |
| (define-prim (##flcopysign x y)) | |
| (define-prim (##flonum->fixnum x)) | |
| (define-prim (##fixnum->flonum x)) | |
| (define-prim (##fixnum->flonum-exact? x)) | |
| (define-prim (##ratnum->flonum x #!optional (nonzero-fractional-part? #f)) | |
| (let* ((num (macro-ratnum-numerator x)) | |
| (n (##abs num)) | |
| (d (macro-ratnum-denominator x)) | |
| (wn (##integer-length n)) ;; 2^(wn-1) <= n < 2^wn | |
| (wd (##integer-length d)) ;; 2^(wd-1) <= d < 2^wd | |
| (p (##fx- wn wd))) | |
| (define (f1 sn sd) | |
| (if (##< sn sd) ;; n/(d*2^p) < 1 ? | |
| (f2 (##arithmetic-shift sn 1) sd (##fx- p 1)) | |
| (f2 sn sd p))) | |
| (define (f2 a b p) | |
| ;; 1 <= a/b < 2 and n/d = (2^p*a)/b and n/d < 2^(p+1) | |
| (let* ((shift | |
| (##fxmin (macro-flonum-m-bits) | |
| (##fx- p (macro-flonum-e-min)))) | |
| (normalized-result | |
| (##ratnum.normalize | |
| (##arithmetic-shift a shift) | |
| b)) | |
| (abs-result | |
| (##fl* | |
| (##exact-int->flonum | |
| (if (##ratnum? normalized-result) | |
| (##ratnum.round | |
| normalized-result | |
| nonzero-fractional-part?) | |
| normalized-result)) | |
| (##flonum-expt2 (##fx- p shift))))) | |
| (if (##negative? num) | |
| (##flcopysign abs-result (macro-inexact--1)) | |
| abs-result))) | |
| ;; 2^(p-1) <= n/d < 2^(p+1) | |
| ;; 1/2 <= n/(d*2^p) < 2 or equivalently 1/2 <= (n*2^-p)/d < 2 | |
| (if (##fxnegative? p) | |
| (f1 (##arithmetic-shift n (##fx- p)) d) | |
| (f1 n (##arithmetic-shift d p))))) | |
| (define-prim (##exact-int->flonum x #!optional (nonzero-fractional-part? #f)) | |
| (define (f1 x) | |
| (let* ((w ;; 2^(w-1) <= x < 2^w | |
| (##integer-length x)) | |
| (p ;; 2^52 <= x/2^p < 2^53 | |
| (##fx- w (macro-flonum-m-bits-plus-1)))) | |
| (if (##fx< p 1) | |
| ;; it really should be an error here if | |
| ;; positive-fractional-part? is true because we can't | |
| ;; determine the value of the first discarded bit | |
| (f2 x) | |
| (let* ((q (##arithmetic-shift x (##fx- p))) | |
| (next-bit-index (##fx- p 1))) | |
| (##fl* | |
| (##flonum-expt2 p) | |
| (f2 (if (and (##bit-set? next-bit-index x) | |
| (or nonzero-fractional-part? | |
| (##odd? q) | |
| (##fx< (##first-bit-set x) | |
| next-bit-index))) | |
| (##+ q 1) | |
| q))))))) | |
| (define (f2 x) ;; 0 <= x < 2^53 | |
| (if (##fixnum? x) | |
| (##fixnum->flonum x) | |
| (let* ((x (if (##fixnum? x) (##fixnum->bignum x) x)) | |
| (n (##bignum.mdigit-length x))) | |
| (let loop ((i (##fx- n 1)) | |
| (result (macro-inexact-+0))) | |
| (if (##fx< i 0) | |
| result | |
| (let ((mdigit (##bignum.mdigit-ref x i))) | |
| (loop (##fx- i 1) | |
| (##fl+ (##fl* result | |
| ##bignum.inexact-mdigit-base) | |
| (##fixnum->flonum mdigit))))))))) | |
| (if (##fixnum? x) | |
| (##fixnum->flonum x) | |
| (if (##negative? x) | |
| (##flcopysign (f1 (##negate x)) (macro-inexact--1)) | |
| (f1 x)))) | |
| (define-prim (##flonum-expt2 n) | |
| (cond ((##fxzero? n) | |
| (macro-inexact-+1)) | |
| ((##fxnegative? n) | |
| (##expt (macro-inexact-+1/2) (##fx- n))) | |
| (else | |
| (##expt (macro-inexact-+2) n)))) | |
| (define-prim (##flonum->exact-int x) | |
| (let loop1 ((z (##flabs x)) | |
| (n 1)) | |
| (if (##fl< ##bignum.inexact-mdigit-base z) | |
| (loop1 (##fl/ z ##bignum.inexact-mdigit-base) | |
| (##fx+ n 1)) | |
| (let loop2 ((result 0) | |
| (z z) | |
| (i n)) | |
| (if (##fx< 0 i) | |
| (let* ((inexact-floor-z | |
| (##flfloor z)) | |
| (floor-z | |
| (##flonum->fixnum inexact-floor-z)) | |
| (new-z | |
| (##fl* (##fl- z inexact-floor-z) | |
| ##bignum.inexact-mdigit-base))) | |
| (loop2 (##+ floor-z | |
| (##arithmetic-shift result ##bignum.mdigit-width)) | |
| new-z | |
| (##fx- i 1))) | |
| (if (##flnegative? x) | |
| (##negate result) | |
| result)))))) | |
| (define-prim (##flonum->inexact-exponential-format x) | |
| (define (exp-form-pos x y i) | |
| (let ((i*2 (##fx+ i i))) | |
| (let ((z (if (and (##not (##fx< (macro-flonum-e-bias) i*2)) | |
| (##not (##fl< x y))) | |
| (exp-form-pos x (##fl* y y) i*2) | |
| (##vector x 0 1)))) | |
| (let ((a (##vector-ref z 0)) (b (##vector-ref z 1))) | |
| (let ((i+b (##fx+ i b))) | |
| (if (and (##not (##fx< (macro-flonum-e-bias) i+b)) | |
| (##not (##fl< a y))) | |
| (begin | |
| (##vector-set! z 0 (##fl/ a y)) | |
| (##vector-set! z 1 i+b))) | |
| z))))) | |
| (define (exp-form-neg x y i) | |
| (let ((i*2 (##fx+ i i))) | |
| (let ((z (if (and (##fx< i*2 (macro-flonum-e-bias-minus-1)) | |
| (##fl< x y)) | |
| (exp-form-neg x (##fl* y y) i*2) | |
| (##vector x 0 1)))) | |
| (let ((a (##vector-ref z 0)) (b (##vector-ref z 1))) | |
| (let ((i+b (##fx+ i b))) | |
| (if (and (##fx< i+b (macro-flonum-e-bias-minus-1)) | |
| (##fl< a y)) | |
| (begin | |
| (##vector-set! z 0 (##fl/ a y)) | |
| (##vector-set! z 1 i+b))) | |
| z))))) | |
| (define (exp-form x) | |
| (if (##fl< x (macro-inexact-+1)) | |
| (let ((z (exp-form-neg x (macro-inexact-+1/2) 1))) | |
| (##vector-set! z 0 (##fl* (macro-inexact-+2) (##vector-ref z 0))) | |
| (##vector-set! z 1 (##fx- -1 (##vector-ref z 1))) | |
| z) | |
| (exp-form-pos x (macro-inexact-+2) 1))) | |
| (if (##flnegative? (##flcopysign (macro-inexact-+1) x)) | |
| (let ((z (exp-form (##flcopysign x (macro-inexact-+1))))) | |
| (##vector-set! z 2 -1) | |
| z) | |
| (exp-form x))) | |
| (define-prim (##flonum->exact-exponential-format x) | |
| (let ((z (##flonum->inexact-exponential-format x))) | |
| (let ((y (##vector-ref z 0))) | |
| (if (##not (##fl< y (macro-inexact-+2))) ;; +inf.0 or +nan.0? | |
| (begin | |
| (if (##fl< (macro-inexact-+0) y) | |
| (##vector-set! z 0 (macro-flonum-+m-min)) ;; +inf.0 | |
| (##vector-set! z 0 (macro-flonum-+m-max))) ;; +nan.0 | |
| (##vector-set! z 1 (macro-flonum-e-bias-plus-1))) | |
| (##vector-set! z 0 | |
| (##flonum->exact-int | |
| (##fl* (##vector-ref z 0) (macro-flonum-m-min))))) | |
| (##vector-set! z 1 (##fx- (##vector-ref z 1) (macro-flonum-m-bits))) | |
| z))) | |
| (define-prim (##flonum->exact x) | |
| (let ((y (##flonum->exact-exponential-format x))) | |
| (##exact-int.*-expt2 | |
| (if (##fxnegative? (##vector-ref y 2)) | |
| (##negate (##vector-ref y 0)) | |
| (##vector-ref y 0)) | |
| (##vector-ref y 1)))) | |
| (define-prim (##flonum->ratnum x) | |
| (let ((y (##flonum->exact x))) | |
| (if (macro-exact-int? y) | |
| (##exact-int->ratnum y) | |
| y))) | |
| (define-prim (##flonum->ieee754-32 x) | |
| (##u32vector-ref (##f32vector x) 0)) | |
| (define-prim (##ieee754-32->flonum n) | |
| (let ((x (##u32vector n))) | |
| (##f32vector-ref x 0))) | |
| (define-prim (##flonum->ieee754-64 x) | |
| (##u64vector-ref x 0)) | |
| (define-prim (##ieee754-64->flonum n) | |
| (let ((x (##u64vector n))) | |
| (##subtype-set! x (macro-subtype-flonum)) | |
| x)) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Cpxnum operations | |
| ;;; ----------------- | |
| (define-prim (##cpxnum-make real imag) | |
| (macro-cpxnum-make real imag)) | |
| (define-prim (##cpxnum-real x) | |
| (macro-cpxnum-real x)) | |
| (define-prim (##cpxnum-imag x) | |
| (macro-cpxnum-imag x)) | |
| (define-prim (##cpxnum.= x y) | |
| (and (##= (macro-cpxnum-real x) (macro-cpxnum-real y)) | |
| (##= (macro-cpxnum-imag x) (macro-cpxnum-imag y)))) | |
| (define-prim (##cpxnum.+ x y) | |
| (let ((a (macro-cpxnum-real x)) (b (macro-cpxnum-imag x)) | |
| (c (macro-cpxnum-real y)) (d (macro-cpxnum-imag y))) | |
| (if (and (##flonum? a) (##flonum? b) | |
| (##flonum? c) (##flonum? d)) | |
| (##make-rectangular (##fl+ a c) (##fl+ b d)) | |
| (let () | |
| (declare (standard-bindings) | |
| (mostly-fixnum)) | |
| (##make-rectangular (+ a c) (+ b d)))))) | |
| (define-prim (##cpxnum.* x y) | |
| (let ((a (macro-cpxnum-real x)) (b (macro-cpxnum-imag x)) | |
| (c (macro-cpxnum-real y)) (d (macro-cpxnum-imag y))) | |
| (if (and (##flonum? a) (##flonum? b) | |
| (##flonum? c) (##flonum? d)) | |
| (##make-rectangular (##fl- (##fl* a c) (##fl* b d)) | |
| (##fl+ (##fl* a d) (##fl* b c))) | |
| (let () | |
| (declare (standard-bindings) | |
| (mostly-fixnum)) | |
| (##make-rectangular (- (* a c) (* b d)) | |
| (+ (* a d) (* b c))))))) | |
| (define-prim (##cpxnum.- x y) | |
| (let ((a (macro-cpxnum-real x)) (b (macro-cpxnum-imag x)) | |
| (c (macro-cpxnum-real y)) (d (macro-cpxnum-imag y))) | |
| (if (and (##flonum? a) (##flonum? b) | |
| (##flonum? c) (##flonum? d)) | |
| (##make-rectangular (##fl- a c) (##fl- b d)) | |
| (let () | |
| (declare (standard-bindings) | |
| (mostly-fixnum)) | |
| (##make-rectangular (- a c) (- b d)))))) | |
| (define-prim (##cpxnum./ x y) | |
| (define (basic/ a b c d q) | |
| (##make-rectangular (##/ (##+ (##* a c) (##* b d)) q) | |
| (##/ (##- (##* b c) (##* a d)) q))) | |
| (let ((a (macro-cpxnum-real x)) (b (macro-cpxnum-imag x)) | |
| (c (macro-cpxnum-real y)) (d (macro-cpxnum-imag y))) | |
| (cond ((##eqv? d 0) | |
| ;; A normalized cpxnum can't have an imaginary part that is | |
| ;; exact 0 but it is possible that ##cpxnum./ receives a | |
| ;; nonnormalized cpxnum as x or y when it is called from ##/. | |
| (##make-rectangular (##/ a c) | |
| (##/ b c))) | |
| ((##eqv? c 0) | |
| (##make-rectangular (##/ b d) | |
| (##negate (##/ a d)))) | |
| ((and (##exact? c) (##exact? d)) | |
| (basic/ a b c d (##+ (##* c c) (##* d d)))) | |
| (else | |
| ;; just coerce everything to inexact and move on | |
| (let ((inexact-c (##exact->inexact c)) | |
| (inexact-d (##exact->inexact d))) | |
| (if (and (##flfinite? inexact-c) | |
| (##flfinite? inexact-d)) | |
| (let ((q | |
| (##fl+ (##fl* inexact-c inexact-c) | |
| (##fl* inexact-d inexact-d)))) | |
| (cond ((##not (##flfinite? q)) | |
| (let ((a | |
| (if (##flonum? a) | |
| (##fl* a (macro-inexact-scale-down)) | |
| (##* a (macro-scale-down)))) | |
| (b | |
| (if (##flonum? b) | |
| (##fl* b (macro-inexact-scale-down)) | |
| (##* b (macro-scale-down)))) | |
| (inexact-c | |
| (##fl* inexact-c | |
| (macro-inexact-scale-down))) | |
| (inexact-d | |
| (##fl* inexact-d | |
| (macro-inexact-scale-down)))) | |
| (basic/ a | |
| b | |
| inexact-c | |
| inexact-d | |
| (##fl+ | |
| (##fl* inexact-c inexact-c) | |
| (##fl* inexact-d inexact-d))))) | |
| ((##fl< q (macro-flonum-min-normal)) | |
| (let ((a | |
| (if (##flonum? a) | |
| (##fl* a (macro-inexact-scale-up)) | |
| (##* a (macro-scale-up)))) | |
| (b | |
| (if (##flonum? b) | |
| (##fl* b (macro-inexact-scale-up)) | |
| (##* b (macro-scale-up)))) | |
| (inexact-c | |
| (##fl* inexact-c | |
| (macro-inexact-scale-up))) | |
| (inexact-d | |
| (##fl* inexact-d | |
| (macro-inexact-scale-up)))) | |
| (basic/ a | |
| b | |
| inexact-c | |
| inexact-d | |
| (##fl+ | |
| (##fl* inexact-c inexact-c) | |
| (##fl* inexact-d inexact-d))))) | |
| (else | |
| (basic/ a b inexact-c inexact-d q)))) | |
| (cond ((##fl= inexact-c (macro-inexact-+inf)) | |
| (basic/ a | |
| b | |
| (macro-inexact-+0) | |
| (if (##flnan? inexact-d) | |
| inexact-d | |
| (##flcopysign (macro-inexact-+0) | |
| inexact-d)) | |
| (macro-inexact-+1))) | |
| ((##fl= inexact-c (macro-inexact--inf)) | |
| (basic/ a | |
| b | |
| (macro-inexact--0) | |
| (if (##flnan? inexact-d) | |
| inexact-d | |
| (##flcopysign (macro-inexact-+0) | |
| inexact-d)) | |
| (macro-inexact-+1))) | |
| ((##flnan? inexact-c) | |
| (cond ((##fl= inexact-d (macro-inexact-+inf)) | |
| (basic/ a | |
| b | |
| inexact-c | |
| (macro-inexact-+0) | |
| (macro-inexact-+1))) | |
| ((##fl= inexact-d (macro-inexact--inf)) | |
| (basic/ a | |
| b | |
| inexact-c | |
| (macro-inexact--0) | |
| (macro-inexact-+1))) | |
| ((##flnan? inexact-d) | |
| (basic/ a | |
| b | |
| inexact-c | |
| inexact-d | |
| (macro-inexact-+1))) | |
| (else | |
| (basic/ a | |
| b | |
| inexact-c | |
| (macro-inexact-+nan) | |
| (macro-inexact-+1))))) | |
| (else | |
| ;; finite inexact-c | |
| (cond ((##flnan? inexact-d) | |
| (basic/ a | |
| b | |
| (macro-inexact-+nan) | |
| inexact-d | |
| (macro-inexact-+1))) | |
| (else | |
| ;; inexact-d is +inf.0 or -inf.0 | |
| (basic/ a | |
| b | |
| (##flcopysign (macro-inexact-+0) | |
| inexact-c) | |
| (##flcopysign (macro-inexact-+0) | |
| inexact-d) | |
| (macro-inexact-+1)))))))))))) | |
| (define-prim (##noncpxnum->cpxnum x) | |
| (macro-cpxnum-make x 0)) | |
| ;;;---------------------------------------------------------------------------- | |
| ;;; Pseudo-random number generation, compatible with srfi-27. | |
| ;;; This code is based on Pierre Lecuyer's MRG32K3A generator. | |
| (define-type random-source | |
| id: 1b002758-f900-4e96-be5e-fa407e331fc0 | |
| implementer: implement-type-random-source | |
| constructor: macro-make-random-source | |
| type-exhibitor: macro-type-random-source | |
| macros: | |
| prefix: macro- | |
| opaque: | |
| (state-ref unprintable: read-only:) | |
| (state-set! unprintable: read-only:) | |
| (randomize! unprintable: read-only:) | |
| (pseudo-randomize! unprintable: read-only:) | |
| (make-integers unprintable: read-only:) | |
| (make-reals unprintable: read-only:) | |
| (make-u8vectors unprintable: read-only:) | |
| (make-f64vectors unprintable: read-only:) | |
| ) | |
| (define-check-type random-source | |
| (macro-type-random-source) | |
| macro-random-source?) | |
| (implement-type-random-source) | |
| (implement-check-type-random-source) | |
| (define-prim (##make-random-source-mrg32k3a) | |
| (##define-macro (macro-w) | |
| 65536) | |
| (##define-macro (macro-w^2-mod-m1) | |
| 209) | |
| (##define-macro (macro-w^2-mod-m2) | |
| 22853) | |
| (##define-macro (macro-m1) | |
| 4294967087) ;; (- (expt (macro-w) 2) (macro-w^2-mod-m1)) | |
| (##define-macro (macro-m1-inexact) | |
| 4294967087.0) ;; (exact->inexact (macro-m1)) | |
| (##define-macro (macro-m1-plus-1-inexact) | |
| 4294967088.0) ;; (exact->inexact (+ (macro-m1) 1)) | |
| (##define-macro (macro-inv-m1-plus-1-inexact) | |
| 2.328306549295728e-10) ;; (exact->inexact (/ (+ (macro-m1) 1))) | |
| (##define-macro (macro-m1-minus-1) | |
| 4294967086) ;; (- (macro-m1) 1) | |
| (##define-macro (macro-k) | |
| 28) | |
| (##define-macro (macro-2^k) | |
| 268435456) ;; (expt 2 (macro-k)) | |
| (##define-macro (macro-2^k-inexact) | |
| 268435456.0) ;; (exact->inexact (expt 2 (macro-k))) | |
| (##define-macro (macro-inv-2^k-inexact) | |
| 3.725290298461914e-9) ;; (exact->inexact (/ (expt 2 (macro-k)))) | |
| (##define-macro (macro-2^53-k-inexact) | |
| 33554432.0) ;; (exact->inexact (expt 2 (- 53 (macro-k)))) | |
| (##define-macro (macro-m1-div-2^k-inexact) | |
| 15.0) ;; (exact->inexact (quotient (macro-m1) (expt 2 (macro-k)))) | |
| (##define-macro (macro-m1-div-2^k-times-2^k-inexact) | |
| 4026531840.0) ;; (exact->inexact (* (quotient (macro-m1) (expt 2 (macro-k))) (expt 2 (macro-k)))) | |
| (##define-macro (macro-m2) | |
| 4294944443) ;; (- (expt (macro-w) 2) (macro-w^2-mod-m2)) | |
| (##define-macro (macro-m2-inexact) | |
| 4294944443.0) ;; (exact->inexact (macro-m2)) | |
| (##define-macro (macro-m2-minus-1) | |
| 4294944442) ;; (- (macro-m2) 1) | |
| (define (pack-state a b c d e f) | |
| (f64vector | |
| (##exact-int->flonum a) | |
| (##exact-int->flonum b) | |
| (##exact-int->flonum c) | |
| (##exact-int->flonum d) | |
| (##exact-int->flonum e) | |
| (##exact-int->flonum f) | |
| (macro-inexact-+0) ;; where the result of advance-state! is put | |
| (macro-inexact-+0) ;; q in rand-fixnum32 | |
| (macro-inexact-+0) ;; qn in rand-fixnum32 | |
| )) | |
| (define (unpack-state state) | |
| (vector | |
| (##flonum->exact-int (f64vector-ref state 0)) | |
| (##flonum->exact-int (f64vector-ref state 1)) | |
| (##flonum->exact-int (f64vector-ref state 2)) | |
| (##flonum->exact-int (f64vector-ref state 3)) | |
| (##flonum->exact-int (f64vector-ref state 4)) | |
| (##flonum->exact-int (f64vector-ref state 5)))) | |
| (let ((state ;; initial state is 0 3 6 9 12 15 of A^(2^4), see below | |
| (pack-state | |
| 1062452522 | |
| 2961816100 | |
| 342112271 | |
| 2854655037 | |
| 3321940838 | |
| 3542344109))) | |
| (define (state-ref) | |
| (unpack-state state)) | |
| (define (state-set! rs new-state) | |
| (define (integer-in-range? x m) | |
| (and (macro-exact-int? x) | |
| (not (negative? x)) | |
| (< x m))) | |
| (or (and (vector? new-state) | |
| (fx= (vector-length new-state) 6) | |
| (let ((a (vector-ref new-state 0)) | |
| (b (vector-ref new-state 1)) | |
| (c (vector-ref new-state 2)) | |
| (d (vector-ref new-state 3)) | |
| (e (vector-ref new-state 4)) | |
| (f (vector-ref new-state 5))) | |
| (and (integer-in-range? a (macro-m1)) | |
| (integer-in-range? b (macro-m1)) | |
| (integer-in-range? c (macro-m1)) | |
| (integer-in-range? d (macro-m2)) | |
| (integer-in-range? e (macro-m2)) | |
| (integer-in-range? f (macro-m2)) | |
| (not (and (eqv? a 0) (eqv? b 0) (eqv? c 0))) | |
| (not (and (eqv? d 0) (eqv? e 0) (eqv? f 0))) | |
| (begin | |
| (set! state | |
| (pack-state a b c d e f)) | |
| (void))))) | |
| (##raise-type-exception | |
| 2 | |
| 'random-source-state | |
| random-source-state-set! | |
| (list rs new-state)))) | |
| (define (randomize!) | |
| (define (random-fixnum-from-time) | |
| (let ((v (f64vector (macro-inexact-+0)))) | |
| (##get-current-time! v 0) | |
| (let ((x (f64vector-ref v 0))) | |
| (##flonum->fixnum | |
| (fl* 536870912.0 ;; (expt 2.0 29) | |
| (fl- x (flfloor x))))))) | |
| (define seed16 | |
| (random-fixnum-from-time)) | |
| (define (simple-random16) | |
| (let ((r (bitwise-and seed16 65535))) | |
| (set! seed16 | |
| (+ (* 30903 r) | |
| (arithmetic-shift seed16 -16))) | |
| r)) | |
| (define (simple-random32) | |
| (+ (arithmetic-shift (simple-random16) 16) | |
| (simple-random16))) | |
| ;; perturb the state randomly | |
| (let ((s (unpack-state state))) | |
| (set! state | |
| (pack-state | |
| (+ 1 | |
| (modulo (+ (vector-ref s 0) | |
| (simple-random32)) | |
| (macro-m1-minus-1))) | |
| (modulo (+ (vector-ref s 1) | |
| (simple-random32)) | |
| (macro-m1)) | |
| (modulo (+ (vector-ref s 2) | |
| (simple-random32)) | |
| (macro-m1)) | |
| (+ 1 | |
| (modulo (+ (vector-ref s 3) | |
| (simple-random32)) | |
| (macro-m2-minus-1))) | |
| (modulo (+ (vector-ref s 4) | |
| (simple-random32)) | |
| (macro-m2)) | |
| (modulo (+ (vector-ref s 5) | |
| (simple-random32)) | |
| (macro-m2)))) | |
| (void))) | |
| (define (pseudo-randomize! i j) | |
| (define (mult A B) ;; A*B | |
| (define (lc i0 i1 i2 j0 j1 j2 m) | |
| (modulo (+ (* (vector-ref A i0) | |
| (vector-ref B j0)) | |
| (+ (* (vector-ref A i1) | |
| (vector-ref B j1)) | |
| (* (vector-ref A i2) | |
| (vector-ref B j2)))) | |
| m)) | |
| (vector | |
| (lc 0 1 2 0 3 6 (macro-m1)) | |
| (lc 0 1 2 1 4 7 (macro-m1)) | |
| (lc 0 1 2 2 5 8 (macro-m1)) | |
| (lc 3 4 5 0 3 6 (macro-m1)) | |
| (lc 3 4 5 1 4 7 (macro-m1)) | |
| (lc 3 4 5 2 5 8 (macro-m1)) | |
| (lc 6 7 8 0 3 6 (macro-m1)) | |
| (lc 6 7 8 1 4 7 (macro-m1)) | |
| (lc 6 7 8 2 5 8 (macro-m1)) | |
| (lc 9 10 11 9 12 15 (macro-m2)) | |
| (lc 9 10 11 10 13 16 (macro-m2)) | |
| (lc 9 10 11 11 14 17 (macro-m2)) | |
| (lc 12 13 14 9 12 15 (macro-m2)) | |
| (lc 12 13 14 10 13 16 (macro-m2)) | |
| (lc 12 13 14 11 14 17 (macro-m2)) | |
| (lc 15 16 17 9 12 15 (macro-m2)) | |
| (lc 15 16 17 10 13 16 (macro-m2)) | |
| (lc 15 16 17 11 14 17 (macro-m2)))) | |
| (define (power A e) ;; A^e | |
| (cond ((eq? e 0) | |
| identity) | |
| ((eq? e 1) | |
| A) | |
| ((even? e) | |
| (power (mult A A) (arithmetic-shift e -1))) | |
| (else | |
| (mult (power A (- e 1)) A)))) | |
| (define identity | |
| '#( 1 0 0 | |
| 0 1 0 | |
| 0 0 1 | |
| 1 0 0 | |
| 0 1 0 | |
| 0 0 1)) | |
| (define A ;; primary MRG32k3a equations | |
| '#( 0 1403580 4294156359 | |
| 1 0 0 | |
| 0 1 0 | |
| 527612 0 4293573854 | |
| 1 0 0 | |
| 0 1 0)) | |
| (define A^2^127 ;; A^(2^127) | |
| '#(1230515664 986791581 1988835001 | |
| 3580155704 1230515664 226153695 | |
| 949770784 3580155704 2427906178 | |
| 2093834863 32183930 2824425944 | |
| 1022607788 1464411153 32183930 | |
| 1610723613 277697599 1464411153)) | |
| (define A^2^76 ;; A^(2^76) | |
| '#( 69195019 3528743235 3672091415 | |
| 1871391091 69195019 3672831523 | |
| 4127413238 1871391091 82758667 | |
| 3708466080 4292754251 3859662829 | |
| 3889917532 1511326704 4292754251 | |
| 1610795712 3759209742 1511326704)) | |
| (define A^2^4 ;; A^(2^4) | |
| '#(1062452522 340793741 2955879160 | |
| 2961816100 1062452522 387300998 | |
| 342112271 2961816100 736416029 | |
| 2854655037 1817134745 3493477402 | |
| 3321940838 818368950 1817134745 | |
| 3542344109 3790774567 818368950)) | |
| (let ((M ;; M = A^(2^4 + i*2^127 + j*2^76) | |
| (mult A^2^4 | |
| (mult (power A^2^127 i) | |
| (power A^2^76 j))))) | |
| (set! state | |
| (pack-state | |
| (vector-ref M 0) | |
| (vector-ref M 3) | |
| (vector-ref M 6) | |
| (vector-ref M 9) | |
| (vector-ref M 12) | |
| (vector-ref M 15))) | |
| (void))) | |
| (define (advance-state!) | |
| (##declare (not interrupts-enabled)) | |
| (let* ((state state) | |
| (x10 | |
| (fl- (fl* 1403580.0 (f64vector-ref state 1)) | |
| (fl* 810728.0 (f64vector-ref state 2)))) | |
| (y10 | |
| (fl- x10 | |
| (fl* (flfloor (fl/ x10 (macro-m1-inexact))) | |
| (macro-m1-inexact)))) | |
| (x20 | |
| (fl- (fl* 527612.0 (f64vector-ref state 3)) | |
| (fl* 1370589.0 (f64vector-ref state 5)))) | |
| (y20 | |
| (fl- x20 | |
| (fl* (flfloor (fl/ x20 (macro-m2-inexact))) | |
| (macro-m2-inexact))))) | |
| (f64vector-set! state 5 (f64vector-ref state 4)) | |
| (f64vector-set! state 4 (f64vector-ref state 3)) | |
| (f64vector-set! state 3 y20) | |
| (f64vector-set! state 2 (f64vector-ref state 1)) | |
| (f64vector-set! state 1 (f64vector-ref state 0)) | |
| (f64vector-set! state 0 y10) | |
| (if (fl< y10 y20) | |
| (f64vector-set! state 6 (fl+ (macro-m1-inexact) | |
| (fl- (f64vector-ref state 0) | |
| (f64vector-ref state 3)))) | |
| (f64vector-set! state 6 (fl- (f64vector-ref state 0) | |
| (f64vector-ref state 3)))))) | |
| (define (make-integers) | |
| (define (random-integer range) | |
| (define (type-error) | |
| (##fail-check-exact-integer 1 random-integer range)) | |
| (define (range-error) | |
| (##raise-range-exception 1 random-integer range)) | |
| (macro-force-vars (range) | |
| (cond ((fixnum? range) | |
| (if (fxpositive? range) | |
| (if (fx< (macro-max-fixnum32) range) | |
| (rand-integer range) | |
| (rand-fixnum32 range)) | |
| (range-error))) | |
| ((##bignum? range) | |
| (if (##bignum.negative? range) | |
| (range-error) | |
| (rand-integer range))) | |
| (else | |
| (type-error))))) | |
| random-integer) | |
| (define (rand-integer range) | |
| ;; constants for computing fixnum approximation of inverse of range | |
| (define size 14) | |
| (define 2^2*size 268435456) | |
| (let ((len (integer-length range))) | |
| (if (fx= (fx- len 1) ;; check if range is a power of 2 | |
| (first-bit-set range)) | |
| (rand-integer-2^ (fx- len 1)) | |
| (let* ((inv | |
| (fxquotient | |
| 2^2*size | |
| (fx+ 1 | |
| (extract-bit-field size (fx- len size) range)))) | |
| (range2 | |
| (* range inv))) | |
| (let loop () | |
| (let ((r (rand-integer-2^ (fx+ len size)))) | |
| (if (< r range2) | |
| (quotient r inv) | |
| (loop)))))))) | |
| (define (rand-integer-2^ w) | |
| (define (rand w s) | |
| (cond ((fx< w (macro-k)) | |
| (fxand (rand-fixnum32-2^k) | |
| (fx- (fxarithmetic-shift-left 1 w) 1))) | |
| ((fx= w (macro-k)) | |
| (rand-fixnum32-2^k)) | |
| (else | |
| (let ((s/2 (fxarithmetic-shift-right s 1))) | |
| (if (fx< s w) | |
| (+ (rand s s/2) | |
| (arithmetic-shift (rand (fx- w s) s/2) s)) | |
| (rand w s/2)))))) | |
| (define (split w s) | |
| (let ((s*2 (fx* 2 s))) | |
| (if (fx< s*2 w) | |
| (split w s*2) | |
| s))) | |
| (rand w (split w (macro-k)))) | |
| (define (rand-fixnum32-2^k) | |
| (##declare (not interrupts-enabled)) | |
| (let loop () | |
| (advance-state!) | |
| (if (fl< (f64vector-ref state 6) | |
| (macro-m1-div-2^k-times-2^k-inexact)) | |
| (##flonum->fixnum | |
| (fl/ (f64vector-ref state 6) | |
| (macro-m1-div-2^k-inexact))) | |
| (loop)))) | |
| (define (rand-fixnum32 range) ;; range is a fixnum32 | |
| (##declare (not interrupts-enabled)) | |
| (let* ((a (fixnum->flonum range)) | |
| (b (flfloor (fl/ (macro-m1-inexact) a)))) | |
| (f64vector-set! state 7 b) | |
| (f64vector-set! state 8 (fl* a b))) | |
| (let loop () | |
| (advance-state!) | |
| (if (fl< (f64vector-ref state 6) | |
| (f64vector-ref state 8)) | |
| (##flonum->fixnum | |
| (fl/ (f64vector-ref state 6) | |
| (f64vector-ref state 7))) | |
| (loop)))) | |
| (define (make-reals precision) | |
| (if (fl< precision (macro-inv-m1-plus-1-inexact)) | |
| (lambda () | |
| (let loop ((r (fixnum->flonum (rand-fixnum32-2^k))) | |
| (d (macro-inv-2^k-inexact))) | |
| (if (fl< r (macro-flonum-+m-max-plus-1-inexact)) | |
| (loop (fl+ (fl* r (macro-2^k-inexact)) | |
| (fixnum->flonum (rand-fixnum32-2^k))) | |
| (fl* d (macro-inv-2^k-inexact))) | |
| (fl* r d)))) | |
| (lambda () | |
| (##declare (not interrupts-enabled)) | |
| (advance-state!) | |
| (fl* (fl+ (macro-inexact-+1) (f64vector-ref state 6)) | |
| (macro-inv-m1-plus-1-inexact))))) | |
| (define (make-u8vectors) | |
| (define (random-u8vector len) | |
| (macro-force-vars (len) | |
| (macro-check-index len 1 (random-u8vector len) | |
| (let ((u8vect (##make-u8vector len 0))) | |
| (let loop ((i (fx- len 1))) | |
| (if (fx< i 0) | |
| u8vect | |
| (begin | |
| (##u8vector-set! u8vect i (rand-fixnum32 256)) | |
| (loop (fx- i 1))))))))) | |
| random-u8vector) | |
| (define (make-f64vectors precision) | |
| (if (fl< precision (macro-inv-m1-plus-1-inexact)) | |
| (let ((make-real (make-reals precision))) | |
| (lambda (len) | |
| (macro-force-vars (len) | |
| (macro-check-index len 1 (random-f64vector len) | |
| (let ((f64vect (##make-f64vector len 0.))) | |
| (let loop ((i (fx- len 1))) | |
| (if (fx< i 0) | |
| f64vect | |
| (begin | |
| (##f64vector-set! f64vect i (make-real)) | |
| (loop (fx- i 1)))))))))) | |
| (lambda (len) | |
| (macro-force-vars (len) | |
| (macro-check-index len 1 (random-f64vector len) | |
| (let ((f64vect (##make-f64vector len 0.))) | |
| (let loop ((i (fx- len 1))) | |
| (if (fx< i 0) | |
| f64vect | |
| (let () | |
| (##declare (not interrupts-enabled)) | |
| (advance-state!) | |
| (##f64vector-set! f64vect i (fl* (fl+ (macro-inexact-+1) | |
| (f64vector-ref state 6)) | |
| (macro-inv-m1-plus-1-inexact))) | |
| (loop (fx- i 1))))))))))) | |
| (macro-make-random-source | |
| state-ref | |
| state-set! | |
| randomize! | |
| pseudo-randomize! | |
| make-integers | |
| make-reals | |
| make-u8vectors | |
| make-f64vectors))) | |
| (define-prim (make-random-source) | |
| (##make-random-source-mrg32k3a)) | |
| (define-prim (random-source? obj) | |
| (macro-force-vars (obj) | |
| (macro-random-source? obj))) | |
| (define-prim (##random-source-state-ref rs) | |
| ((macro-random-source-state-ref rs))) | |
| (define-prim (random-source-state-ref rs) | |
| (macro-force-vars (rs) | |
| (macro-check-random-source rs 1 (random-source-state-ref rs) | |
| (##random-source-state-ref rs)))) | |
| (define-prim (##random-source-state-set! rs new-state) | |
| ((macro-random-source-state-set! rs) rs new-state)) | |
| (define-prim (random-source-state-set! rs new-state) | |
| (macro-force-vars (rs new-state) | |
| (macro-check-random-source rs 1 (random-source-state-set! rs new-state) | |
| (##random-source-state-set! rs new-state)))) | |
| (define-prim (##random-source-randomize! rs) | |
| ((macro-random-source-randomize! rs))) | |
| (define-prim (random-source-randomize! rs) | |
| (macro-force-vars (rs) | |
| (macro-check-random-source rs 1 (random-source-randomize! rs) | |
| (##random-source-randomize! rs)))) | |
| (define-prim (##random-source-pseudo-randomize! rs i j) | |
| ((macro-random-source-pseudo-randomize! rs) i j)) | |
| (define-prim (random-source-pseudo-randomize! rs i j) | |
| (macro-force-vars (rs i j) | |
| (macro-check-random-source rs 1 (random-source-pseudo-randomize! rs i j) | |
| (if (not (macro-exact-int? i)) | |
| (##fail-check-exact-integer 2 random-source-pseudo-randomize! rs i j) | |
| (if (not (macro-exact-int? j)) | |
| (##fail-check-exact-integer 3 random-source-pseudo-randomize! rs i j) | |
| (if (negative? i) | |
| (##raise-range-exception 2 random-source-pseudo-randomize! rs i j) | |
| (if (negative? j) | |
| (##raise-range-exception 3 random-source-pseudo-randomize! rs i j) | |
| (##random-source-pseudo-randomize! rs i j)))))))) | |
| (define-prim (##random-source-make-integers rs) | |
| ((macro-random-source-make-integers rs))) | |
| (define-prim (random-source-make-integers rs) | |
| (macro-force-vars (rs) | |
| (macro-check-random-source rs 1 (random-source-make-integers rs) | |
| (##random-source-make-integers rs)))) | |
| (define-prim (##random-source-make-reals rs #!optional (p (macro-absent-obj))) | |
| ((macro-random-source-make-reals rs) | |
| (if (eq? p (macro-absent-obj)) | |
| (macro-inexact-+1) | |
| p))) | |
| (define-prim (random-source-make-reals rs #!optional (p (macro-absent-obj))) | |
| (macro-force-vars (rs p) | |
| (macro-check-random-source rs 1 (random-source-make-reals rs p) | |
| (if (eq? p (macro-absent-obj)) | |
| (##random-source-make-reals rs) | |
| (if (rational? p) | |
| (let ((precision (macro-real->inexact p))) | |
| (if (and (fl< (macro-inexact-+0) precision) | |
| (fl< precision (macro-inexact-+1))) | |
| (##random-source-make-reals rs precision) | |
| (##raise-range-exception 2 random-source-make-reals rs p))) | |
| (##fail-check-finite-real 2 random-source-make-reals rs p)))))) | |
| (define-prim (##random-source-make-f64vectors rs #!optional (p (macro-absent-obj))) | |
| ((macro-random-source-make-f64vectors rs) | |
| (if (eq? p (macro-absent-obj)) | |
| (macro-inexact-+1) | |
| p))) | |
| (define-prim (random-source-make-f64vectors rs #!optional (p (macro-absent-obj))) | |
| (macro-force-vars (rs p) | |
| (macro-check-random-source rs 1 (random-source-make-f64vectors rs p) | |
| (if (eq? p (macro-absent-obj)) | |
| (##random-source-make-f64vectors rs) | |
| (if (rational? p) | |
| (let ((precision (macro-real->inexact p))) | |
| (if (and (fl< (macro-inexact-+0) precision) | |
| (fl< precision (macro-inexact-+1))) | |
| (##random-source-make-f64vectors rs precision) | |
| (##raise-range-exception 2 random-source-make-f64vectors rs p))) | |
| (##fail-check-finite-real 2 random-source-make-f64vectors rs p)))))) | |
| (define-prim (##random-source-make-u8vectors rs) | |
| ((macro-random-source-make-u8vectors rs))) | |
| (define-prim (random-source-make-u8vectors rs) | |
| (macro-force-vars (rs) | |
| (macro-check-random-source rs 1 (random-source-make-u8vectors rs) | |
| (##random-source-make-u8vectors rs)))) | |
| (define default-random-source #f) | |
| (set! default-random-source (##make-random-source-mrg32k3a)) | |
| (define random-integer | |
| (##random-source-make-integers default-random-source)) | |
| (define random-real | |
| (##random-source-make-reals default-random-source)) | |
| (define random-u8vector | |
| (##random-source-make-u8vectors default-random-source)) | |
| (define random-f64vector | |
| (##random-source-make-f64vectors default-random-source)) | |
| ;;;============================================================================ |