;;; Ikarus Scheme -- A compiler for R6RS Scheme. ;;; Copyright (C) 2006,2007,2008 Abdulaziz Ghuloum ;;; ;;; This program is free software: you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License version 3 as ;;; published by the Free Software Foundation. ;;; ;;; This program is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . (library (ikarus flonums) (export $flonum->exact $flonum->integer flonum-parts inexact->exact exact $flonum-rational? $flonum-integer? $flzero? $flnegative? flpositive? flabs fixnum->flonum flsin flcos fltan flasin flacos flatan fleven? flodd? flfloor flceiling flnumerator fldenominator flexp fllog flinteger? flonum-bytes flnan? flfinite? flinfinite? flexpt $flround flround) (import (ikarus system $bytevectors) (ikarus system $fx) (only (ikarus system $flonums) $fl>= $flonum-sbe) (ikarus system $bignums) (except (ikarus system $flonums) $flonum-rational? $flonum-integer? $flround) (except (ikarus) inexact->exact exact flpositive? flabs fixnum->flonum flsin flcos fltan flasin flacos flatan fleven? flodd? flfloor flceiling flnumerator fldenominator flexp fllog flexpt flinteger? flonum-parts flonum-bytes flnan? flfinite? flinfinite? flround)) (define (flonum-bytes f) (unless (flonum? f) (die 'flonum-bytes "not a flonum" f)) (values ($flonum-u8-ref f 0) ($flonum-u8-ref f 1) ($flonum-u8-ref f 2) ($flonum-u8-ref f 3) ($flonum-u8-ref f 4) ($flonum-u8-ref f 5) ($flonum-u8-ref f 6) ($flonum-u8-ref f 7))) (define (flonum-parts x) (unless (flonum? x) (die 'flonum-parts "not a flonum" x)) (let-values ([(b0 b1 b2 b3 b4 b5 b6 b7) (flonum-bytes x)]) (values (zero? (fxlogand b0 128)) (+ (fxsll (fxlogand b0 127) 4) (fxsra b1 4)) (+ (+ b7 (fxsll b6 8) (fxsll b5 16)) (* (+ b4 (fxsll b3 8) (fxsll b2 16) (fxsll (fxlogand b1 #b1111) 24)) (expt 2 24)))))) (define ($zero-m? f) (and ($fxzero? ($flonum-u8-ref f 7)) ($fxzero? ($flonum-u8-ref f 6)) ($fxzero? ($flonum-u8-ref f 5)) ($fxzero? ($flonum-u8-ref f 4)) ($fxzero? ($flonum-u8-ref f 3)) ($fxzero? ($flonum-u8-ref f 2)) ($fxzero? ($fxlogand ($flonum-u8-ref f 1) #b1111)))) (define ($flonum-rational? x) (let ([be ($fxlogand ($flonum-sbe x) ($fxsub1 ($fxsll 1 11)))]) ($fx< be 2047))) (define ($flonum-integer? x) (let ([be ($fxlogand ($flonum-sbe x) ($fxsub1 ($fxsll 1 11)))]) (cond [($fx= be 2047) ;;; nans and infs #f] [($fx>= be 1075) ;;; magnitue large enough #t] [($fx= be 0) ;;; denormalized double, only +/-0.0 is integer (and ($fx= ($flonum-u8-ref x 7) 0) ($fx= ($flonum-u8-ref x 6) 0) ($fx= ($flonum-u8-ref x 5) 0) ($fx= ($flonum-u8-ref x 4) 0) ($fx= ($flonum-u8-ref x 3) 0) ($fx= ($flonum-u8-ref x 2) 0) ($fx= ($flonum-u8-ref x 1) 0))] [($fx< be ($fx+ 1075 -52)) ;;; too small to be an integer #f] [else ($fl= x ($flround x))]))) (define ($flround x) (foreign-call "ikrt_fl_round" x ($make-flonum))) (define (flround x) (if (flonum? x) ($flround x) (die 'flround "not a flonum" x))) (module ($flonum->integer $flonum->exact) (define ($flonum-signed-mantissa x) (let ([b0 ($flonum-u8-ref x 0)]) (let ([m0 ($fx+ ($flonum-u8-ref x 7) ($fx+ ($fxsll ($flonum-u8-ref x 6) 8) ($fxsll ($flonum-u8-ref x 5) 16)))] [m1 ($fx+ ($flonum-u8-ref x 4) ($fx+ ($fxsll ($flonum-u8-ref x 3) 8) ($fxsll ($flonum-u8-ref x 2) 16)))] [m2 (let ([b1 ($flonum-u8-ref x 1)]) (if (and ($fx= ($fxlogand b0 #x7F) 0) ($fx= ($fxsra b1 4) 0)) ($fxlogand b1 #xF) ($fxlogor ($fxlogand b1 #xF) #x10)))]) (if ($fx= 0 ($fxlogand #x80 b0)) (+ (bitwise-arithmetic-shift-left ($fxlogor m1 ($fxsll m2 24)) 24) m0) (+ (bitwise-arithmetic-shift-left ($fx- 0 ($fxlogor m1 ($fxsll m2 24))) 24) ($fx- 0 m0)))))) (define ($flonum->integer x) (let ([sbe ($flonum-sbe x)]) (let ([be ($fxlogand sbe #x7FF)]) (cond [($fx= be 2047) #f] ;;; nans/infs [($fx>= be 1075) ;;; magnitude large enough to be an integer (bitwise-arithmetic-shift-left ($flonum-signed-mantissa x) (- be 1075))] [else (let-values ([(pos? be m) (flonum-parts x)]) (cond [(<= 1 be 2046) ; normalized flonum (let ([n (+ m (expt 2 52))] [d (expt 2 (- be 1075))]) (let-values ([(q r) (quotient+remainder n d)]) (if (= r 0) (if pos? q (- q)) #f)))] [(= be 0) (if (= m 0) 0 #f)] [else #f]))])))) (define-syntax ctexpt (lambda (x) (import (ikarus)) (syntax-case x () [(_ n m) (expt (syntax->datum #'n) (syntax->datum #'m))]))) (define ($flonum->exact x) (import (ikarus)) (let ([sbe ($flonum-sbe x)]) (let ([be ($fxlogand sbe #x7FF)]) (cond [($fx= be 2047) #f] ;;; nans/infs [($fx>= be 1075) ;;; magnitude large enough to be an integer (bitwise-arithmetic-shift-left ($flonum-signed-mantissa x) (- be 1075))] [else ;;; this really needs to get optimized. (let-values ([(pos? be m) (flonum-parts x)]) (cond [(= be 0) ;;; denormalized (if (= m 0) 0 (* (if pos? 1 -1) (/ m (ctexpt 2 1074))))] [else ; normalized flonum (/ (+ m (ctexpt 2 52)) (bitwise-arithmetic-shift-left (if pos? 1 -1) (- 1075 be)))]))]))))) (define (flnumerator x) (unless (flonum? x) (die 'flnumerator "not a flonum" x)) (cond [($flonum-integer? x) x] [($flonum-rational? x) (exact->inexact (numerator ($flonum->exact x)))] [else x])) (define (fldenominator x) (unless (flonum? x) (die 'fldenominator "not a flonum" x)) (cond [($flonum-integer? x) 1.0] [($flonum-rational? x) (exact->inexact (denominator ($flonum->exact x)))] [(flnan? x) x] [else 1.0])) (define (fleven? x) ;;; FIXME: optimize (unless (flonum? x) (die 'fleven? "not a flonum" x)) (let ([v ($flonum->exact x)]) (cond [(fixnum? v) ($fx= ($fxlogand v 1) 0)] [(bignum? v) (foreign-call "ikrt_even_bn" v)] [else (die 'fleven? "not an integer flonum" x)]))) (define (flodd? x) (unless (flonum? x) (die 'flodd? "not a flonum" x)) ;;; FIXME: optimize (let ([v ($flonum->exact x)]) (cond [(fixnum? v) ($fx= ($fxlogand v 1) 1)] [(bignum? v) (not (foreign-call "ikrt_even_bn" v))] [else (die 'flodd? "not an integer flonum" x)]))) (define (flinteger? x) (if (flonum? x) ($flonum-integer? x) (die 'flinteger? "not a flonum" x))) (define (flinfinite? x) (if (flonum? x) (let ([be (fxlogand ($flonum-sbe x) (sub1 (fxsll 1 11)))]) (and (fx= be 2047) ;;; nans and infs ($zero-m? x))) (die 'flinfinite? "not a flonum" x))) (define (flnan? x) (if (flonum? x) (let ([be (fxlogand ($flonum-sbe x) (sub1 (fxsll 1 11)))]) (and (fx= be 2047) ;;; nans and infs (not ($zero-m? x)))) (die 'flnan? "not a flonum" x))) (define (flfinite? x) (if (flonum? x) (let ([be (fxlogand ($flonum-sbe x) (sub1 (fxsll 1 11)))]) (not (fx= be 2047))) (die 'flfinite? "not a flonum" x))) (define ($flzero? x) (let ([be (fxlogand ($flonum-sbe x) (sub1 (fxsll 1 11)))]) (and (fx= be 0) ;;; denormalized double, only +/-0.0 is integer (and (fx= ($flonum-u8-ref x 7) 0) (fx= ($flonum-u8-ref x 6) 0) (fx= ($flonum-u8-ref x 5) 0) (fx= ($flonum-u8-ref x 4) 0) (fx= ($flonum-u8-ref x 3) 0) (fx= ($flonum-u8-ref x 2) 0) (fx= ($flonum-u8-ref x 1) 0))))) (define ($flnegative? x) (let ([b0 ($flonum-u8-ref x 0)]) (fx> b0 127))) (define (inexact->exact x) (cond [(flonum? x) (or ($flonum->exact x) (die 'inexact->exact "no real value" x))] [(or (fixnum? x) (ratnum? x) (bignum? x)) x] [else (die 'inexact->exact "not an inexact number" x)])) (define (exact x) (cond [(flonum? x) (or ($flonum->exact x) (die 'exact "no real value" x))] [(or (fixnum? x) (ratnum? x) (bignum? x)) x] [else (die 'exact "not an inexact number" x)])) (define (flpositive? x) (if (flonum? x) ($fl> x 0.0) (die 'flpositive? "not a flonum" x))) (define (flabs x) (if (flonum? x) (if ($fx> ($flonum-u8-ref x 0) 127) ($fl* x -1.0) x) (die 'flabs "not a flonum" x))) (define (fixnum->flonum x) (if (fixnum? x) ($fixnum->flonum x) (die 'fixnum->flonum "not a fixnum"))) (define (flsin x) (if (flonum? x) (foreign-call "ikrt_fl_sin" x) (die 'flsin "not a flonum" x))) (define (flcos x) (if (flonum? x) (foreign-call "ikrt_fl_cos" x) (die 'flcos "not a flonum" x))) (define (fltan x) (if (flonum? x) (foreign-call "ikrt_fl_tan" x) (die 'fltan "not a flonum" x))) (define (flasin x) (if (flonum? x) (foreign-call "ikrt_fl_asin" x) (die 'flasin "not a flonum" x))) (define (flacos x) (if (flonum? x) (foreign-call "ikrt_fl_acos" x) (die 'flacos "not a flonum" x))) (define (flatan x) (if (flonum? x) (foreign-call "ikrt_fl_atan" x) (die 'flatan "not a flonum" x))) (define (flfloor x) (define (ratnum-floor x) (let ([n (numerator x)] [d (denominator x)]) (let ([q (quotient n d)]) (if (>= n 0) q (- q 1))))) (cond [(flonum? x) ;;; optimize for integer flonums case (let ([e ($flonum->exact x)]) (cond [(ratnum? e) (exact->inexact (ratnum-floor e))] [else x]))] [else (die 'flfloor "not a flonum" x)])) (define (flceiling x) (cond [(flonum? x) ;;; optimize for integer flonums case (let ([e ($flonum->exact x)]) (cond [(ratnum? e) (exact->inexact (ceiling e))] [else x]))] [else (die 'flceiling "not a flonum" x)])) (define (flexp x) (if (flonum? x) (foreign-call "ikrt_fl_exp" x ($make-flonum)) (die 'flexp "not a flonum" x))) (define (fllog x) (if (flonum? x) (if ($fl>= x 0.0) (foreign-call "ikrt_fl_log" x) (die 'fllog "argument should not be negative" x)) (die 'fllog "not a flonum" x))) (define (flexpt x y) (if (flonum? x) (if (flonum? y) (let ([y^ ($flonum->exact y)]) ;;; FIXME: performance bottleneck? (cond [(fixnum? y^) (inexact (expt x y^))] [(bignum? y^) (inexact (expt x y^))] [else (foreign-call "ikrt_flfl_expt" x y ($make-flonum))])) (die 'flexpt "not a flonum" y)) (die 'fllog "not a flonum" x))) ) (library (ikarus generic-arithmetic) (export + - * / zero? = < <= > >= add1 sub1 quotient remainder modulo even? odd? bitwise-and bitwise-not bitwise-ior bitwise-xor bitwise-arithmetic-shift-right bitwise-arithmetic-shift-left bitwise-arithmetic-shift bitwise-length bitwise-copy-bit bitwise-bit-field positive? negative? expt gcd lcm numerator denominator exact-integer-sqrt quotient+remainder number->string string->number min max abs truncate fltruncate sra sll real->flonum exact->inexact inexact floor ceiling round log fl=? fl? fl>=? fl+ fl- fl* fl/ flsqrt flmin flzero? flnegative? sin cos tan asin acos atan sqrt exp flmax random error@add1 error@sub1) (import (ikarus system $fx) (ikarus system $flonums) (ikarus system $ratnums) (ikarus system $bignums) (ikarus system $compnums) (ikarus system $chars) (ikarus system $strings) (only (ikarus flonums) $flonum->exact $flzero? $flnegative? $flonum->integer $flround) (except (ikarus) + - * / zero? = < <= > >= add1 sub1 quotient remainder modulo even? odd? quotient+remainder number->string bitwise-arithmetic-shift-right bitwise-arithmetic-shift-left bitwise-arithmetic-shift bitwise-length bitwise-copy-bit bitwise-bit-field positive? negative? bitwise-and bitwise-not bitwise-ior bitwise-xor string->number expt gcd lcm numerator denominator exact->inexact inexact floor ceiling round log exact-integer-sqrt min max abs real->flonum fl=? fl? fl>=? fl+ fl- fl* fl/ flsqrt flmin flzero? flnegative? sra sll exp sin cos tan asin acos atan sqrt truncate fltruncate flmax random)) (define (bignum->flonum x) (foreign-call "ikrt_bignum_to_flonum" x 0 ($make-flonum))) ;;; (define (ratnum->flonum x) ;;; (define (->flonum n d) ;;; (let-values ([(q r) (quotient+remainder n d)]) ;;; (if (= r 0) ;;; (inexact q) ;;; (if (= q 0) ;;; (/ (->flonum d n)) ;;; (+ q (->flonum r d)))))) ;;; (let ([n (numerator x)] [d (denominator x)]) ;;; (let ([b (bitwise-first-bit-set n)]) ;;; (if (eqv? b 0) ;;; (let ([b (bitwise-first-bit-set d)]) ;;; (if (eqv? b 0) ;;; (->flonum n d) ;;; (/ (->flonum n (bitwise-arithmetic-shift-right d b)) ;;; (expt 2.0 b)))) ;;; (* (->flonum (bitwise-arithmetic-shift-right n b) d) ;;; (expt 2.0 b)))))) ;;; (define (ratnum->flonum x) ;;; (let f ([n ($ratnum-n x)] [d ($ratnum-d x)]) ;;; (let-values ([(q r) (quotient+remainder n d)]) ;;; (if (= q 0) ;;; (/ 1.0 (f d n)) ;;; (if (= r 0) ;;; (inexact q) ;;; (+ q (f r d))))))) (define (ratnum->flonum num) (define (rat n m) (let-values ([(q r) (quotient+remainder n m)]) (if (= r 0) (inexact q) (fl+ (inexact q) (fl/ 1.0 (rat m r)))))) (define (pos n d) (cond [(> n d) (rat n d)] [(even? n) (* (pos (sra n 1) d) 2.0)] [(even? d) (/ (pos n (sra d 1)) 2.0)] [else (/ (rat d n))])) (let ([n ($ratnum-n num)] [d ($ratnum-d num)]) (if (> n 0) (pos n d) (- (pos (- n) d))))) (define (err who x) (die who (if (number? x) "invalid argument" "not a number") x)) (define binary+ (lambda (x y) (cond [(fixnum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxfxplus" x y)] [(bignum? y) (foreign-call "ikrt_fxbnplus" x y)] [(flonum? y) ($fl+ ($fixnum->flonum x) y)] [(ratnum? y) ($make-ratnum (+ (* x ($ratnum-d y)) ($ratnum-n y)) ($ratnum-d y))] [(compnum? y) ($make-compnum (binary+ x ($compnum-real y)) ($compnum-imag y))] [(cflonum? y) ($make-cflonum (binary+ x ($cflonum-real y)) ($cflonum-imag y))] [else (err '+ y)])] [(bignum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxbnplus" y x)] [(bignum? y) (foreign-call "ikrt_bnbnplus" x y)] [(flonum? y) ($fl+ (bignum->flonum x) y)] [(ratnum? y) ($make-ratnum (+ (* x ($ratnum-d y)) ($ratnum-n y)) ($ratnum-d y))] [(compnum? y) ($make-compnum (binary+ x ($compnum-real y)) ($compnum-imag y))] [(cflonum? y) ($make-cflonum (binary+ x ($cflonum-real y)) ($cflonum-imag y))] [else (err '+ y)])] [(flonum? x) (cond [(fixnum? y) ($fl+ x ($fixnum->flonum y))] [(bignum? y) ($fl+ x (bignum->flonum y))] [(flonum? y) ($fl+ x y)] [(ratnum? y) ($fl+ x (ratnum->flonum y))] [(cflonum? y) ($make-cflonum ($fl+ x ($cflonum-real y)) ($cflonum-imag y))] [(compnum? y) ($make-cflonum (binary+ x ($compnum-real y)) (inexact ($compnum-imag y)))] [else (err '+ y)])] [(ratnum? x) (cond [(or (fixnum? y) (bignum? y)) ($make-ratnum (+ (* y ($ratnum-d x)) ($ratnum-n x)) ($ratnum-d x))] [(flonum? y) ($fl+ y (ratnum->flonum x))] [(ratnum? y) (let ([n0 ($ratnum-n x)] [n1 ($ratnum-n y)] [d0 ($ratnum-d x)] [d1 ($ratnum-d y)]) ;;; FIXME: inefficient (/ (+ (* n0 d1) (* n1 d0)) (* d0 d1)))] [(compnum? y) ($make-compnum (binary+ x ($compnum-real y)) ($compnum-imag y))] [(cflonum? y) ($make-cflonum (binary+ x ($cflonum-real y)) ($cflonum-imag y))] [else (err '+ y)])] [(compnum? x) (cond [(or (fixnum? y) (bignum? y) (ratnum? y)) ($make-compnum (binary+ ($compnum-real x) y) ($compnum-imag x))] [(compnum? y) ($make-rectangular (binary+ ($compnum-real x) ($compnum-real y)) (binary+ ($compnum-imag x) ($compnum-imag y)))] [(flonum? y) ($make-cflonum (binary+ y ($compnum-real x)) (inexact ($compnum-imag x)))] [(cflonum? y) ($make-rectangular (binary+ ($compnum-real x) ($cflonum-real y)) (binary+ ($compnum-imag x) ($cflonum-imag y)))] [else (err '+ y)])] [(cflonum? x) (cond [(cflonum? y) ($make-rectangular (binary+ ($cflonum-real x) ($cflonum-real y)) (binary+ ($cflonum-imag x) ($cflonum-imag y)))] [(flonum? y) ($make-cflonum ($fl+ ($cflonum-real x) y) ($cflonum-imag x))] [(or (fixnum? y) (bignum? y) (ratnum? y)) ($make-compnum (binary+ ($compnum-real x) y) ($compnum-imag x))] [(compnum? y) ($make-rectangular (binary+ ($cflonum-real x) ($compnum-real y)) (binary+ ($cflonum-imag x) ($compnum-imag y)))] [else (err '+ y)])] [else (err '+ x)]))) (define binary-bitwise-and (lambda (x y) (cond [(fixnum? x) (cond [(fixnum? y) ($fxlogand x y)] [(bignum? y) (foreign-call "ikrt_fxbnlogand" x y)] [else (die 'bitwise-and "not an exact integer" y)])] [(bignum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxbnlogand" y x)] [(bignum? y) (foreign-call "ikrt_bnbnlogand" x y)] [else (die 'bitwise-and "not an exact integer" y)])] [else (die 'bitwise-and "not an exact integer" x)]))) (define binary-bitwise-ior (lambda (x y) (cond [(fixnum? x) (cond [(fixnum? y) ($fxlogor x y)] [(bignum? y) (foreign-call "ikrt_fxbnlogor" x y)] [else (die 'bitwise-ior "not an exact integer" y)])] [(bignum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxbnlogor" y x)] [(bignum? y) (foreign-call "ikrt_bnbnlogor" x y)] [else (die 'bitwise-ior "not an exact integer" y)])] [else (die 'bitwise-ior "not an exact integer" x)]))) (define binary-bitwise-xor (lambda (x y) (define (fxbn x y) (let ([y0 (bitwise-and y (greatest-fixnum))] [y1 (bitwise-arithmetic-shift-right y (- (fixnum-width) 1))]) (bitwise-ior ($fxlogand ($fxlogxor x y0) (greatest-fixnum)) (bitwise-arithmetic-shift-left (bitwise-arithmetic-shift-right (if ($fx>= x 0) y (bitwise-not y)) (- (fixnum-width) 1)) (- (fixnum-width) 1))))) (define (bnbn x y) (let ([x0 (bitwise-and x (greatest-fixnum))] [x1 (bitwise-arithmetic-shift-right x (- (fixnum-width) 1))] [y0 (bitwise-and y (greatest-fixnum))] [y1 (bitwise-arithmetic-shift-right y (- (fixnum-width) 1))]) (bitwise-ior ($fxlogand ($fxlogxor x0 y0) (greatest-fixnum)) (bitwise-arithmetic-shift-left (binary-bitwise-xor x1 y1) (- (fixnum-width) 1))))) (cond [(fixnum? x) (cond [(fixnum? y) ($fxlogxor x y)] [(bignum? y) (fxbn x y)] [else (die 'bitwise-xor "not an exact integer" y)])] [(bignum? x) (cond [(fixnum? y) (fxbn y x)] [(bignum? y) (bnbn x y)] [else (die 'bitwise-xor "not an exact integer" y)])] [else (die 'bitwise-xor "not an exact integer" x)]))) (define binary- (lambda (x y) (cond [(fixnum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxfxminus" x y)] [(bignum? y) (foreign-call "ikrt_fxbnminus" x y)] [(flonum? y) (if ($fx= x 0) ($fl* y -1.0) ($fl- ($fixnum->flonum x) y))] [(ratnum? y) (let ([n ($ratnum-n y)] [d ($ratnum-d y)]) (binary/ (binary- (binary* d x) n) d))] [(compnum? y) ($make-compnum (binary- x ($compnum-real y)) (binary- 0 ($compnum-imag y)))] [(cflonum? y) ($make-cflonum (binary- x ($cflonum-real y)) ($fl- 0.0 ($cflonum-imag y)))] [else (err '- y)])] [(bignum? x) (cond [(fixnum? y) (foreign-call "ikrt_bnfxminus" x y)] [(bignum? y) (foreign-call "ikrt_bnbnminus" x y)] [(flonum? y) ($fl- (bignum->flonum x) y)] [(ratnum? y) (let ([n ($ratnum-n y)] [d ($ratnum-d y)]) (binary/ (binary- (binary* d x) n) d))] [(compnum? y) ($make-compnum (binary- x ($compnum-real y)) (binary- 0 ($compnum-imag y)))] [(cflonum? y) ($make-cflonum (binary- x ($cflonum-real y)) ($fl- 0.0 ($cflonum-imag y)))] [else (err '- y)])] [(flonum? x) (cond [(flonum? y) ($fl- x y)] [(cflonum? y) ($make-cflonum ($fl- x ($cflonum-real y)) ($fl- 0.0 ($cflonum-imag y)))] [(fixnum? y) ($fl- x ($fixnum->flonum y))] [(bignum? y) ($fl- x (bignum->flonum y))] [(ratnum? y) (let ([n ($ratnum-n y)] [d ($ratnum-d y)]) (binary/ (binary- (binary* d x) n) d))] [(compnum? y) ($make-cflonum (binary- x ($compnum-real y)) (binary- 0.0 ($compnum-imag y)))] [else (err '- y)])] [(ratnum? x) (let ([nx ($ratnum-n x)] [dx ($ratnum-d x)]) (cond [(or (fixnum? y) (bignum? y) (flonum? y)) (binary/ (binary- nx (binary* dx y)) dx)] [(ratnum? y) (let ([ny ($ratnum-n y)] [dy ($ratnum-d y)]) (binary/ (binary- (binary* nx dy) (binary* ny dx)) (binary* dx dy)))] [(compnum? y) ($make-compnum (binary- x ($compnum-real y)) (binary- 0 ($compnum-imag y)))] [(cflonum? y) ($make-cflonum (binary- x ($cflonum-real y)) ($fl- 0.0 ($cflonum-imag y)))] [else (err '- y)]))] [(compnum? x) (cond [(or (fixnum? y) (bignum? y) (ratnum? y)) ($make-compnum (binary- ($compnum-real x) y) ($compnum-imag x))] [(compnum? y) ($make-rectangular (binary- ($compnum-real x) ($compnum-real y)) (binary- ($compnum-imag x) ($compnum-imag y)))] [(cflonum? y) ($make-rectangular (binary- ($compnum-real x) ($cflonum-real y)) (binary- ($compnum-imag x) ($cflonum-imag y)))] [else (err '- y)])] [(cflonum? x) (cond [(flonum? y) ($make-cflonum ($fl- ($cflonum-real x) y) ($cflonum-imag x))] [(cflonum? y) ($make-rectangular (binary- ($cflonum-real x) ($cflonum-real y)) (binary- ($cflonum-imag x) ($cflonum-imag y)))] [(or (fixnum? y) (bignum? y) (ratnum? y)) ($make-cflonum (binary- ($cflonum-real x) y) ($cflonum-imag x))] [(compnum? y) ($make-rectangular (binary- ($cflonum-real x) ($compnum-real y)) (binary- ($cflonum-imag x) ($compnum-imag y)))] [else (err '- y)])] [else (err '- x)]))) (define binary* (lambda (x y) (cond [(fixnum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxfxmult" x y)] [(bignum? y) (foreign-call "ikrt_fxbnmult" x y)] [(flonum? y) ($fl* ($fixnum->flonum x) y)] [(ratnum? y) (binary/ (binary* x ($ratnum-n y)) ($ratnum-d y))] [(compnum? y) ($make-rectangular (binary* x ($compnum-real y)) (binary* x ($compnum-imag y)))] [(cflonum? y) ($make-rectangular (binary* x ($cflonum-real y)) (binary* x ($cflonum-imag y)))] [else (err '* y)])] [(bignum? x) (cond [(fixnum? y) (foreign-call "ikrt_fxbnmult" y x)] [(bignum? y) (foreign-call "ikrt_bnbnmult" x y)] [(flonum? y) ($fl* (bignum->flonum x) y)] [(ratnum? y) (binary/ (binary* x ($ratnum-n y)) ($ratnum-d y))] [(compnum? y) ($make-rectangular (binary* x ($compnum-real y)) (binary* x ($compnum-imag y)))] [(cflonum? y) ($make-rectangular (binary* x ($cflonum-real y)) (binary* x ($cflonum-imag y)))] [else (err '* y)])] [(flonum? x) (cond [(flonum? y) ($fl* x y)] [(cflonum? y) ($make-rectangular ($fl* x ($cflonum-real y)) ($fl* x ($cflonum-imag y)))] [(fixnum? y) ($fl* x ($fixnum->flonum y))] [(bignum? y) ($fl* x (bignum->flonum y))] [(ratnum? y) (binary/ (binary* x ($ratnum-n y)) ($ratnum-d y))] [(compnum? y) ($make-rectangular (binary* x ($compnum-real y)) (binary* x ($compnum-imag y)))] [else (err '* y)])] [(ratnum? x) (cond [(ratnum? y) (binary/ (binary* ($ratnum-n x) ($ratnum-n y)) (binary* ($ratnum-d x) ($ratnum-d y)))] [(compnum? y) ($make-rectangular (binary* x ($compnum-real y)) (binary* x ($compnum-imag y)))] [(cflonum? y) ($make-rectangular (binary* x ($cflonum-real y)) (binary* x ($cflonum-imag y)))] [else (binary* y x)])] [(compnum? x) (cond [(or (fixnum? y) (bignum? y) (ratnum? y) (flonum? y)) ($make-rectangular (binary* ($compnum-real x) y) (binary* ($compnum-imag x) y))] [(compnum? y) (let ([r0 ($compnum-real x)] [r1 ($compnum-real y)] [i0 ($compnum-imag x)] [i1 ($compnum-imag y)]) ($make-rectangular (- (* r0 r1) (* i0 i1)) (+ (* r0 i1) (* i0 r1))))] [(cflonum? y) (let ([r0 ($compnum-real x)] [r1 ($cflonum-real y)] [i0 ($compnum-imag x)] [i1 ($cflonum-imag y)]) ($make-rectangular (- (* r0 r1) (* i0 i1)) (+ (* r0 i1) (* i0 r1))))] [else (err '* y)])] [(cflonum? x) (cond [(flonum? y) ($make-rectangular ($fl* ($cflonum-real x) y) ($fl* ($cflonum-imag x) y))] [(cflonum? y) (let ([r0 ($cflonum-real x)] [r1 ($cflonum-real y)] [i0 ($cflonum-imag x)] [i1 ($cflonum-imag y)]) ($make-rectangular ($fl- ($fl* r0 r1) ($fl* i0 i1)) ($fl+ ($fl* r0 i1) ($fl* i0 r1))))] [(or (fixnum? y) (bignum? y) (ratnum? y)) ($make-rectangular (binary* ($compnum-real x) y) (binary* ($compnum-imag x) y))] [(compnum? y) (let ([r0 ($compnum-real x)] [r1 ($compnum-real y)] [i0 ($compnum-imag x)] [i1 ($compnum-imag y)]) ($make-rectangular (- (* r0 r1) (* i0 i1)) (+ (* r0 i1) (* i0 r1))))] [else (err '* y)])] [else (err '* x)]))) (define + (case-lambda [(x y) (binary+ x y)] [(x y z) (binary+ (binary+ x y) z)] [(a) (cond [(fixnum? a) a] [(number? a) a] [else (die '+ "not a number" a)])] [() 0] [(a b c d . e*) (let f ([ac (binary+ (binary+ (binary+ a b) c) d)] [e* e*]) (cond [(null? e*) ac] [else (f (binary+ ac (car e*)) (cdr e*))]))])) (define bitwise-and (case-lambda [(x y) (binary-bitwise-and x y)] [(x y z) (binary-bitwise-and (binary-bitwise-and x y) z)] [(a) (cond [(fixnum? a) a] [(bignum? a) a] [else (die 'bitwise-and "not a number" a)])] [() -1] [(a b c d . e*) (let f ([ac (binary-bitwise-and a (binary-bitwise-and b (binary-bitwise-and c d)))] [e* e*]) (cond [(null? e*) ac] [else (f (binary-bitwise-and ac (car e*)) (cdr e*))]))])) (define bitwise-ior (case-lambda [(x y) (binary-bitwise-ior x y)] [(x y z) (binary-bitwise-ior (binary-bitwise-ior x y) z)] [(a) (cond [(fixnum? a) a] [(bignum? a) a] [else (die 'bitwise-ior "not a number" a)])] [() 0] [(a b c d . e*) (let f ([ac (binary-bitwise-ior a (binary-bitwise-ior b (binary-bitwise-ior c d)))] [e* e*]) (cond [(null? e*) ac] [else (f (binary-bitwise-ior ac (car e*)) (cdr e*))]))])) (define bitwise-xor (case-lambda [(x y) (binary-bitwise-xor x y)] [(x y z) (binary-bitwise-xor (binary-bitwise-xor x y) z)] [(a) (cond [(fixnum? a) a] [(bignum? a) a] [else (die 'bitwise-xor "not a number" a)])] [() 0] [(a b c d . e*) (let f ([ac (binary-bitwise-xor a (binary-bitwise-xor b (binary-bitwise-xor c d)))] [e* e*]) (cond [(null? e*) ac] [else (f (binary-bitwise-xor ac (car e*)) (cdr e*))]))])) (define (bitwise-not x) (cond [(fixnum? x) ($fxlognot x)] [(bignum? x) (foreign-call "ikrt_bnlognot" x)] [else (die 'bitwise-not "invalid argument" x)])) (define - (case-lambda [(x y) (binary- x y)] [(x y z) (binary- (binary- x y) z)] [(a) (binary- 0 a)] [(a b c d . e*) (let f ([ac (binary- (binary- (binary- a b) c) d)] [e* e*]) (cond [(null? e*) ac] [else (f (binary- ac (car e*)) (cdr e*))]))])) (define * (case-lambda [(x y) (binary* x y)] [(x y z) (binary* (binary* x y) z)] [(a) (cond [(fixnum? a) a] [(number? a) a] [else (die '* "not a number" a)])] [() 1] [(a b c d . e*) (let f ([ac (binary* (binary* (binary* a b) c) d)] [e* e*]) (cond [(null? e*) ac] [else (f (binary* ac (car e*)) (cdr e*))]))])) (define (binary-gcd x y) (define (gcd x y) (cond [($fx= y 0) x] [else (gcd y (remainder x y))])) (let ([x (if (< x 0) (- x) x)] [y (if (< y 0) (- y) y)]) (cond [(> x y) (gcd x y)] [(< x y) (gcd y x)] [else x]))) (define gcd (case-lambda [(x y) (cond [(or (fixnum? x) (bignum? x)) (cond [(or (fixnum? y) (bignum? y)) (binary-gcd x y)] [(number? y) (die 'gcd "not an exact integer" y)] [else (die 'gcd "not a number" y)])] [(number? x) (die 'gcd "not an exact integer" x)] [else (die 'gcd "not a number" x)])] [(x) (cond [(or (fixnum? x) (bignum? x)) x] [(number? x) (die 'gcd "not an exact integer" x)] [else (die 'gcd "not a number" x)])] [() 0] [(x y z . ls) (let f ([g (gcd (gcd x y) z)] [ls ls]) (cond [(null? ls) g] [else (f (gcd g (car ls)) (cdr ls))]))])) (define lcm (case-lambda [(x y) (cond [(or (fixnum? x) (bignum? x)) (cond [(or (fixnum? y) (bignum? y)) (let ([x (if (< x 0) (- x) x)] [y (if (< y 0) (- y) y)]) (let ([g (binary-gcd x y)]) (binary* y (quotient x g))))] [(number? y) (die 'lcm "not an exact integer" y)] [else (die 'lcm "not a number" y)])] [(number? x) (die 'lcm "not an exact integer" x)] [else (die 'lcm "not a number" x)])] [(x) (cond [(or (fixnum? x) (bignum? x)) x] [(number? x) (die 'lcm "not an exact integer" x)] [else (die 'lcm "not a number" x)])] [() 1] [(x y z . ls) (let f ([g (lcm (lcm x y) z)] [ls ls]) (cond [(null? ls) g] [else (f (lcm g (car ls)) (cdr ls))]))])) (define binary/ (lambda (x y) (define (x/compy x y) (let ([yr (real-part y)] [yi (imag-part y)]) (let ([denom (+ (* yr yr) (* yi yi))]) ($make-rectangular (binary/ (* x yr) denom) (binary/ (* (- x) yi) denom))))) (define (compx/y x y) (let ([xr (real-part x)] [xi (imag-part x)]) ($make-rectangular (binary/ xr y) (binary/ xi y)))) (define (compx/compy x y) (let ([xr (real-part x)] [xi (imag-part x)] [yr (real-part y)] [yi (imag-part y)]) (let ([denom (+ (* yr yr) (* yi yi))]) ($make-rectangular (binary/ (+ (* xr yr) (* xi yi)) denom) (binary/ (- (* xi yr) (* xr yi)) denom))))) (cond [(flonum? x) (cond [(flonum? y) ($fl/ x y)] [(fixnum? y) ($fl/ x ($fixnum->flonum y))] [(bignum? y) ($fl/ x (bignum->flonum y))] [(ratnum? y) ($fl/ x (ratnum->flonum y))] [else (err '/ y)])] [(fixnum? x) (cond [(flonum? y) ($fl/ ($fixnum->flonum x) y)] [(fixnum? y) (cond [($fx= y 0) (die '/ "division by 0")] [($fx> y 0) (if ($fx= y 1) x (let ([g (binary-gcd x y)]) (cond [($fx= g y) (fxquotient x g)] [($fx= g 1) ($make-ratnum x y)] [else ($make-ratnum (fxquotient x g) (fxquotient y g))])))] [else (if ($fx= y -1) (binary- 0 x) (let ([g (binary-gcd x y)]) (cond [($fx= ($fx- 0 g) y) (binary- 0 (fxquotient x g))] [($fx= g 1) ($make-ratnum (binary- 0 x) (binary- 0 y))] [else ($make-ratnum (binary- 0 (fxquotient x g)) (binary- 0 (fxquotient y g)))])))])] [(bignum? y) (let ([g (binary-gcd x y)]) (cond [(= g y) (quotient x g)] ;;; should not happen [($bignum-positive? y) (if ($fx= g 1) ($make-ratnum x y) ($make-ratnum (fxquotient x g) (quotient y g)))] [else (if ($fx= g 1) ($make-ratnum (binary- 0 x) (binary- 0 y)) ($make-ratnum (binary- 0 (fxquotient x g)) (binary- 0 (quotient y g))))]))] [(ratnum? y) (/ (* x ($ratnum-d y)) ($ratnum-n y))] [(or (compnum? y) (cflonum? y)) (x/compy x y)] [else (err '/ y)])] [(bignum? x) (cond [(fixnum? y) (cond [($fx= y 0) (die '/ "division by 0")] [($fx> y 0) (if ($fx= y 1) x (let ([g (binary-gcd x y)]) (cond [($fx= g 1) ($make-ratnum x y)] [($fx= g y) (quotient x g)] [else ($make-ratnum (quotient x g) (quotient y g))])))] [else (if ($fx= y -1) (- x) (let ([g (binary-gcd x y)]) (cond [(= (- g) y) (- (quotient x g))] [else ($make-ratnum (- (quotient x g)) (- (quotient y g)))])))])] [(bignum? y) (let ([g (binary-gcd x y)]) (cond [($fx= g 1) (if ($bignum-positive? y) ($make-ratnum x y) ($make-ratnum (binary- 0 x) (binary- 0 y)))] [($bignum-positive? y) (if (= g y) (quotient x g) ($make-ratnum (quotient x g) (quotient y g)))] [else (let ([y (binary- 0 y)]) (if (= g y) (binary- 0 (quotient x g)) ($make-ratnum (binary- 0 (quotient x g)) (quotient y g))))]))] [(flonum? y) ($fl/ (bignum->flonum x) y)] [(ratnum? y) (binary/ (binary* x ($ratnum-n y)) ($ratnum-d y))] [(or (compnum? y) (cflonum? y)) (x/compy x y)] [else (err '/ y)])] [(ratnum? x) (cond [(ratnum? y) (binary/ (binary* ($ratnum-n x) ($ratnum-d y)) (binary* ($ratnum-n y) ($ratnum-d x)))] [(or (compnum? y) (cflonum? y)) (x/compy x y)] [else (binary/ 1 (binary/ y x))])] [(or (compnum? x) (cflonum? x)) (cond [(or (compnum? y) (cflonum? y)) (compx/compy x y)] [(or (fixnum? y) (bignum? y) (ratnum? y) (flonum? y)) (compx/y x y)] [else (err '/ y)])] [else (err '/ x)]))) (define / (case-lambda [(x y) (binary/ x y)] [(x) (cond [(fixnum? x) (cond [($fxzero? x) (die '/ "division by 0")] [($fx> x 0) (if ($fx= x 1) 1 ($make-ratnum 1 x))] [else (if ($fx= x -1) -1 ($make-ratnum -1 (- x)))])] [(bignum? x) (if ($bignum-positive? x) ($make-ratnum 1 x) ($make-ratnum -1 (- x)))] [(flonum? x) (foreign-call "ikrt_fl_invert" x)] [(ratnum? x) (let ([n ($ratnum-n x)] [d ($ratnum-d x)]) (cond [($fx= n 1) d] [($fx= n -1) (- d)] [else ($make-ratnum d n)]))] [(compnum? x) (binary/ 1 x)] [else (die '/ "not a number" x)])] [(x y z . rest) (let f ([a (binary/ x y)] [b z] [ls rest]) (cond [(null? rest) (binary/ a b)] [else (f (binary/ a b) (car ls) (cdr ls))]))])) (define flmax (case-lambda [(x y) (if (flonum? x) (if (flonum? y) (if ($fl< x y) y x) (die 'flmax "not a flonum" y)) (die 'flmax "not a flonum" x))] [(x y z . rest) (let f ([a (flmax x y)] [b z] [ls rest]) (cond [(null? ls) (flmax a b)] [else (f (flmax a b) (car ls) (cdr ls))]))] [(x) (if (flonum? x) x (die 'flmax "not a number" x))])) (define max (case-lambda [(x y) (cond [(fixnum? x) (cond [(fixnum? y) (if ($fx> x y) x y)] [(bignum? y) (if (positive-bignum? y) y x)] [(flonum? y) (let ([x ($fixnum->flonum x)]) (if ($fl>= y x) y x))] [(ratnum? y) ;;; FIXME: optimize (if (>= x y) x y)] [else (die 'max "not a number" y)])] [(bignum? x) (cond [(fixnum? y) (if (positive-bignum? x) x y)] [(bignum? y) (if (bnbn> x y) x y)] [(flonum? y) (let ([x (bignum->flonum x)]) (if ($fl>= y x) y x))] [(ratnum? y) ;;; FIXME: optimize (if (>= x y) x y)] [else (die 'max "not a number" y)])] [(flonum? x) (cond [(flonum? y) (if ($fl>= x y) x y)] [(fixnum? y) (let ([y ($fixnum->flonum y)]) (if ($fl>= y x) y x))] [(bignum? y) (let ([y (bignum->flonum y)]) (if ($fl>= y x) y x))] [(ratnum? y) ;;; FIXME: may be incorrect (let ([y (ratnum->flonum y)]) (if ($fl>= y x) y x))] [else (die 'max "not a number" y)])] [(ratnum? x) (cond [(or (fixnum? y) (bignum? y) (ratnum? y)) (if (>= x y) x y)] [(flonum? y) (let ([x (ratnum->flonum x)]) (if ($fl>= x y) x y))] [else (die 'max "not a number" y)])] [else (die 'max "not a number" x)])] [(x y z . rest) (let f ([a (max x y)] [b z] [ls rest]) (cond [(null? ls) (max a b)] [else (f (max a b) (car ls) (cdr ls))]))] [(x) (if (number? x) x (die 'max "not a number" x))])) (define min (case-lambda [(x y) (cond [(fixnum? x) (cond [(fixnum? y) (if ($fx> x y) y x)] [(bignum? y) (if (positive-bignum? y) x y)] [(flonum? y) (let ([x ($fixnum->flonum x)]) (if ($fl>= y x) x y))] [(ratnum? y) ;;; FIXME: optimize (if (>= x y) y x)] [else (die 'min "not a number" y)])] [(bignum? x) (cond [(fixnum? y) (if (positive-bignum? x) y x)] [(bignum? y) (if (bnbn> x y) y x)] [(flonum? y) (let ([x (bignum->flonum x)]) (if ($fl>= y x) x y))] [(ratnum? y) ;;; FIXME: optimize (if (>= x y) y x)] [else (die 'min "not a number" y)])] [(flonum? x) (cond [(flonum? y) (if ($fl>= x y) y x)] [(fixnum? y) (let ([y ($fixnum->flonum y)]) (if ($fl>= y x) x y))] [(bignum? y) (let ([y (bignum->flonum y)]) (if ($fl>= y x) x y))] [(ratnum? y) ;;; FIXME: may be incorrect (let ([y (ratnum->flonum y)]) (if ($fl>= y x) x y))] [else (die 'min "not a number" y)])] [(ratnum? x) (cond [(or (fixnum? y) (bignum? y) (ratnum? y)) (if (>= x y) y x)] [(flonum? y) (let ([x (ratnum->flonum x)]) (if ($fl>= x y) y x))] [else (die 'min "not a number" y)])] [else (die 'min "not a number" x)])] [(x y z . rest) (let f ([a (min x y)] [b z] [ls rest]) (cond [(null? ls) (min a b)] [else (f (min a b) (car ls) (cdr ls))]))] [(x) (if (number? x) x (die 'min "not a number" x))])) (define (abs x) (cond [(fixnum? x) (if ($fx< x 0) (- x) x)] [(bignum? x) (if ($bignum-positive? x) x (- x))] [(flonum? x) (if ($fx> ($flonum-u8-ref x 0) 127) ($fl* x -1.0) x)] [(ratnum? x) (let ([n ($ratnum-n x)]) (if (< n 0) ($make-ratnum (- n) ($ratnum-d x)) x))] [else (die 'abs "not a number" x)])) (define flmin (case-lambda [(x y) (if (flonum? x) (if (flonum? y) (if ($fl< x y) x y) (die 'flmin "not a flonum" y)) (die 'flmin "not a flonum" x))] [(x y z . rest) (let f ([a (flmin x y)] [b z] [ls rest]) (cond [(null? ls) (flmin a b)] [else (f (flmin a b) (car ls) (cdr ls))]))] [(x) (if (flonum? x) x (die 'flmin "not a flonum" x))])) (define exact->inexact (lambda (x) (cond [(fixnum? x) ($fixnum->flonum x)] [(bignum? x) (bignum->flonum x)] [(ratnum? x) (ratnum->flonum x)] [else (die 'exact->inexact "not an exact number" x)]))) (define inexact (lambda (x) (cond [(fixnum? x) ($fixnum->flonum x)] [(bignum? x) (bignum->flonum x)] [(ratnum? x) (ratnum->flonum x)] [(flonum? x) x] [else (die 'inexact "not a number" x)]))) (define real->flonum (lambda (x) (cond [(fixnum? x) ($fixnum->flonum x)] [(bignum? x) (bignum->flonum x)] [(ratnum? x) (ratnum->flonum x)] [(flonum? x) x] [else (die 'real->flonum "not a real number" x)]))) (define positive-bignum? (lambda (x) (foreign-call "ikrt_positive_bn" x))) (define even-bignum? (lambda (x) (foreign-call "ikrt_even_bn" x))) (define ($fxeven? x) ($fxzero? ($fxlogand x 1))) (define (even? x) (cond [(fixnum? x) ($fxeven? x)] [(bignum? x) (even-bignum? x)] [(flonum? x) (die 'even? "BUG" x)] [else (die 'even? "not an integer" x)])) (define (odd? x) (not (cond [(fixnum? x) ($fxeven? x)] [(bignum? x) (even-bignum? x)] [(flonum? x) (die 'odd? "BUG" x)] [else (die 'odd? "not an integer" x)]))) (module (number->string) (module (bignum->string) (define (bignum->decimal-string x) (utf8->string (foreign-call "ikrt_bignum_to_bytevector" x))) (module (bignum->power-string) (define string-map "0123456789ABCDEF") (define (init-string x chars) (if ($bignum-positive? x) (make-string chars) (let ([s (make-string ($fxadd1 chars))]) (string-set! s 0 #\-) s))) (define (bignum-bits x) (define (add-bits b n) (cond [($fxzero? b) n] [else (add-bits ($fxsra b 1) ($fx+ n 1))])) (let f ([i ($fxsub1 ($bignum-size x))]) (let ([b ($bignum-byte-ref x i)]) (cond [($fxzero? b) (f ($fxsub1 i))] [else (add-bits b ($fxsll i 3))])))) (define (bignum->power-string x mask shift) (let ([bits (bignum-bits x)]) (let ([chars (fxquotient (fx+ bits (fx- shift 1)) shift)]) (let* ([s (init-string x chars)] [n ($fx- (string-length s) 1)]) (let f ([i 0] [j 0] [k 0] [b 0]) (cond [($fx= i chars) s] [($fx< k 8) (f i ($fxadd1 j) ($fx+ k 8) ($fxlogor b ($fxsll ($bignum-byte-ref x j) k)))] [else (string-set! s ($fx- n i) (string-ref string-map ($fxlogand mask b))) (f ($fxadd1 i) j ($fx- k shift) ($fxsra b shift))]))))))) (define (bignum->string x r) (case r [(10) (bignum->decimal-string x)] [(2) (bignum->power-string x 1 1)] [(8) (bignum->power-string x 7 3)] [(16) (bignum->power-string x 15 4)] [else (die 'number->string "BUG")]))) (define ratnum->string (lambda (x r) (string-append ($number->string ($ratnum-n x) r) "/" ($number->string ($ratnum-d x) r)))) (define (imag x r) (cond [(eqv? x 1) "+"] [(eqv? x -1) "-"] [(< x 0) ($number->string x r)] [else (string-append "+" ($number->string x r))])) (define $number->string (lambda (x r) (import (ikarus system $compnums)) (cond [(fixnum? x) (fixnum->string x r)] [(bignum? x) (bignum->string x r)] [(flonum? x) (unless (eqv? r 10) (die 'number->string "invalid radix for inexact number" r x)) (flonum->string x)] [(ratnum? x) (ratnum->string x r)] [(compnum? x) (string-append ($number->string ($compnum-real x) r) (imag ($compnum-imag x) r) "i")] [(cflonum? x) (string-append ($number->string ($cflonum-real x) r) (imag ($cflonum-imag x) r) "i")] [else (die 'number->string "not a number" x)]))) (define number->string (case-lambda [(x) ($number->string x 10)] [(x r) (unless (memv r '(2 8 10 16)) (die 'number->string "invalid radix" r)) ($number->string x r)] [(x r precision) (die 'number->string "BUG: precision is not supported yet")]))) (define modulo (lambda (n m) (cond [(fixnum? n) (cond [(fixnum? m) ($fxmodulo n m)] [(bignum? m) (if ($fx< n 0) (if ($bignum-positive? m) (foreign-call "ikrt_fxbnplus" n m) n) (if ($bignum-positive? m) n (foreign-call "ikrt_fxbnplus" n m)))] [(flonum? m) (let ([v ($flonum->integer m)]) (cond [v (inexact (modulo n v))] [else (die 'modulo "not an integer" m)]))] [(ratnum? m) (die 'modulo "not an integer" m)] [else (die 'modulo "not a number" m)])] [(bignum? n) (cond [(fixnum? m) (foreign-call "ikrt_bnfx_modulo" n m)] [(bignum? m) (if ($bignum-positive? n) (if ($bignum-positive? m) (remainder n m) (+ m (remainder n m))) (if ($bignum-positive? m) (+ m (remainder n m)) (remainder n m)))] [(flonum? m) (let ([v ($flonum->integer m)]) (cond [v (inexact (modulo n v))] [else (die 'modulo "not an integer" m)]))] [(ratnum? m) (die 'modulo "not an integer" m)] [else (die 'modulo "not a number" m)])] [(flonum? n) (let ([v ($flonum->integer n)]) (cond [v (inexact (modulo v m))] [else (die 'modulo "not an integer" n)]))] [(ratnum? n) (die 'modulo "not an integer" n)] [else (die 'modulo "not a number" n)]))) (define-syntax mk< (syntax-rules () [(_ name fxfx< fxbn< bnfx< bnbn< fxfl< flfx< bnfl< flbn< flfl< fxrt< rtfx< bnrt< rtbn< flrt< rtfl< rtrt<) (let () (define err (lambda (x) (die 'name "not a real number" x))) (define fxloopt (lambda (x y ls) (cond [(fixnum? y) (if (null? ls) (fxfx< x y) (if (fxfx< x y) (fxloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(bignum? y) (if (null? ls) (fxbn< x y) (if (fxbn< x y) (bnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(flonum? y) (if (null? ls) (fxfl< x y) (if (fxfl< x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(ratnum? y) (if (null? ls) (fxrt< x y) (if (fxrt< x y) (rtloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [else (err y)]))) (define bnloopt (lambda (x y ls) (cond [(fixnum? y) (if (null? ls) (bnfx< x y) (if (bnfx< x y) (fxloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(bignum? y) (if (null? ls) (bnbn< x y) (if (bnbn< x y) (bnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(flonum? y) (if (null? ls) (bnfl< x y) (if (bnfl< x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(ratnum? y) (if (null? ls) (bnrt< x y) (if (bnrt< x y) (rtloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [else (err y)]))) (define flloopt (lambda (x y ls) (cond [(fixnum? y) (if (null? ls) (flfx< x y) (if (flfx< x y) (fxloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(bignum? y) (if (null? ls) (flbn< x y) (if (flbn< x y) (bnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(flonum? y) (if (null? ls) (flfl< x y) (if (flfl< x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(ratnum? y) (if (null? ls) (flrt< x y) (if (flrt< x y) (rtloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [else (err y)]))) (define rtloopt (lambda (x y ls) (cond [(fixnum? y) (if (null? ls) (rtfx< x y) (if (rtfx< x y) (fxloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(bignum? y) (if (null? ls) (rtbn< x y) (if (rtbn< x y) (bnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(flonum? y) (if (null? ls) (rtfl< x y) (if (rtfl< x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(ratnum? y) (if (null? ls) (rtrt< x y) (if (rtrt< x y) (rtloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [else (err y)]))) (define loopf (lambda (x ls) (cond [(number? x) (if (null? ls) #f (loopf (car ls) (cdr ls)))] [else (err x)]))) (define name (case-lambda [(x y) (cond [(fixnum? x) (cond [(fixnum? y) (fxfx< x y)] [(bignum? y) (fxbn< x y)] [(flonum? y) (fxfl< x y)] [(ratnum? y) (fxrt< x y)] [else (err y)])] [(bignum? x) (cond [(fixnum? y) (bnfx< x y)] [(bignum? y) (bnbn< x y)] [(flonum? y) (bnfl< x y)] [(ratnum? y) (bnrt< x y)] [else (err y)])] [(flonum? x) (cond [(fixnum? y) (flfx< x y)] [(bignum? y) (flbn< x y)] [(flonum? y) (flfl< x y)] [(ratnum? y) (flrt< x y)] [else (err y)])] [(ratnum? x) (cond [(fixnum? y) (rtfx< x y)] [(bignum? y) (rtbn< x y)] [(flonum? y) (rtfl< x y)] [(ratnum? y) (rtrt< x y)] [else (err y)])] [else (err x)])] [(x y z) (and (name x y) (name y z))] [(x) (if (number? x) #t (err x))] [(x y . ls) (cond [(fixnum? x) (fxloopt x y ls)] [(bignum? x) (bnloopt x y ls)] [(flonum? x) (flloopt x y ls)] [(ratnum? x) (rtloopt x y ls)] [else (err x)])])) name)])) (define-syntax false (syntax-rules () [(_ x y) #f])) (define-syntax bnbncmp (syntax-rules () [(_ x y cmp) (cmp (foreign-call "ikrt_bnbncomp" x y) 0)])) (define-syntax bnbn= (syntax-rules () [(_ x y) (bnbncmp x y $fx=)])) (define-syntax bnbn< (syntax-rules () [(_ x y) (bnbncmp x y $fx<)])) (define-syntax bnbn> (syntax-rules () [(_ x y) (bnbncmp x y $fx>)])) (define-syntax bnbn<= (syntax-rules () [(_ x y) (bnbncmp x y $fx<=)])) (define-syntax bnbn>= (syntax-rules () [(_ x y) (bnbncmp x y $fx>=)])) (define-syntax fxbn< (syntax-rules () [(_ x y) (positive-bignum? y)])) (define-syntax bnfx< (syntax-rules () [(_ x y) (not (positive-bignum? x))])) (define-syntax fxbn> (syntax-rules () [(_ x y) (not (positive-bignum? y))])) (define-syntax bnfx> (syntax-rules () [(_ x y) (positive-bignum? x)])) (define-syntax flcmp (syntax-rules () [(_ flfl? flfx? fxfl? flbn? bnfl? fl?) (begin (define-syntax flfl? (syntax-rules () [(_ x y) (fl? x y)])) (define-syntax flfx? (syntax-rules () [(_ x y) (fl? x ($fixnum->flonum y))])) (define-syntax flbn? (syntax-rules () [(_ x y) (fl? x (bignum->flonum y))])) (define-syntax fxfl? (syntax-rules () [(_ x y) (fl? ($fixnum->flonum x) y)])) (define-syntax bnfl? (syntax-rules () [(_ x y) (fl? (bignum->flonum x) y)])))])) ;;; #; ;;; (begin ;;; (define-syntax $fl= ;;; (syntax-rules () [(_ x y) (foreign-call "ikrt_fl_equal" x y)])) ;;; (define-syntax $fl< ;;; (syntax-rules () [(_ x y) (foreign-call "ikrt_fl_less" x y)])) ;;; (define-syntax $fl<= ;;; (syntax-rules () [(_ x y) (foreign-call "ikrt_fl_less_or_equal" x y)])) ;;; (define-syntax $fl> ;;; (syntax-rules () [(_ x y) (foreign-call "ikrt_fl_less" y x)])) ;;; (define-syntax $fl>= ;;; (syntax-rules () [(_ x y) (foreign-call "ikrt_fl_less_or_equal" y x)]))) (define-syntax define-flcmp (syntax-rules () [(_ fl? $fl>) (define-flcmp fl>=? $fl>=) (define fl+ (case-lambda [(x y) (if (flonum? x) (if (flonum? y) ($fl+ x y) (die 'fl+ "not a flonum" y)) (die 'fl+ "not a flonum" x))] [(x y z) (fl+ (fl+ x y) z)] [(x y z q . rest) (let f ([ac (fl+ (fl+ (fl+ x y) z) q)] [rest rest]) (if (null? rest) ac (f (fl+ ac (car rest)) (cdr rest))))] [(x) (if (flonum? x) x (die 'fl+ "not a flonum" x))] [() (exact->inexact 0)])) (define fl- (case-lambda [(x y) (if (flonum? x) (if (flonum? y) ($fl- x y) (die 'fl- "not a flonum" y)) (die 'fl- "not a flonum" x))] [(x y z) (fl- (fl- x y) z)] [(x y z q . rest) (let f ([ac (fl- (fl- (fl- x y) z) q)] [rest rest]) (if (null? rest) ac (f (fl- ac (car rest)) (cdr rest))))] [(x) (if (flonum? x) ($fl* -1.0 x) (die 'fl+ "not a flonum" x))])) (define fl* (case-lambda [(x y) (if (flonum? x) (if (flonum? y) ($fl* x y) (die 'fl* "not a flonum" y)) (die 'fl* "not a flonum" x))] [(x y z) (fl* (fl* x y) z)] [(x y z q . rest) (let f ([ac (fl* (fl* (fl* x y) z) q)] [rest rest]) (if (null? rest) ac (f (fl* ac (car rest)) (cdr rest))))] [(x) (if (flonum? x) x (die 'fl* "not a flonum" x))] [() 1.0])) (define fl/ (case-lambda [(x y) (if (flonum? x) (if (flonum? y) ($fl/ x y) (die 'fl/ "not a flonum" y)) (die 'fl/ "not a flonum" x))] [(x y z) (fl/ (fl/ x y) z)] [(x y z q . rest) (let f ([ac (fl/ (fl/ (fl/ x y) z) q)] [rest rest]) (if (null? rest) ac (f (fl/ ac (car rest)) (cdr rest))))] [(x) (if (flonum? x) ($fl/ 1.0 x) (die 'fl/ "not a flonum" x))])) (flcmp flfl= flfx= fxfl= flbn= bnfl= $fl=) (flcmp flfl< flfx< fxfl< flbn< bnfl< $fl<) (flcmp flfl> flfx> fxfl> flbn> bnfl> $fl>) (flcmp flfl<= flfx<= fxfl<= flbn<= bnfl<= $fl<=) (flcmp flfl>= flfx>= fxfl>= flbn>= bnfl>= $fl>=) (define-syntax flrt= (syntax-rules () [(_ x y) (= (inexact->exact x) y)])) (define-syntax rtfl= (syntax-rules () [(_ x y) (= x (inexact->exact y))])) (define-syntax flrt< (syntax-rules () [(_ x y) (< (inexact->exact x) y)])) (define-syntax rtfl< (syntax-rules () [(_ x y) (< x (inexact->exact y))])) (define-syntax flrt<= (syntax-rules () [(_ x y) (<= (inexact->exact x) y)])) (define-syntax rtfl<= (syntax-rules () [(_ x y) (<= x (inexact->exact y))])) (define-syntax flrt> (syntax-rules () [(_ x y) (> (inexact->exact x) y)])) (define-syntax rtfl> (syntax-rules () [(_ x y) (> x (inexact->exact y))])) (define-syntax flrt>= (syntax-rules () [(_ x y) (>= (inexact->exact x) y)])) (define-syntax rtfl>= (syntax-rules () [(_ x y) (>= x (inexact->exact y))])) (define (exrt< x y) (< (* x ($ratnum-d y)) ($ratnum-n y))) (define (rtex< x y) (< ($ratnum-n x) (* y ($ratnum-d x)))) (define (rtrt< x y) (< (* ($ratnum-n x) ($ratnum-d y)) (* ($ratnum-n y) ($ratnum-d x)))) (define (rtrt<= x y) (<= (* ($ratnum-n x) ($ratnum-d y)) (* ($ratnum-n y) ($ratnum-d x)))) (define (exrt> x y) (> (* x ($ratnum-d y)) ($ratnum-n y))) (define (rtex> x y) (> ($ratnum-n x) (* y ($ratnum-d x)))) (define (rtrt> x y) (> (* ($ratnum-n x) ($ratnum-d y)) (* ($ratnum-n y) ($ratnum-d x)))) (define (rtrt>= x y) (>= (* ($ratnum-n x) ($ratnum-d y)) (* ($ratnum-n y) ($ratnum-d x)))) (define (rtrt= x y) (and (= ($ratnum-n x) ($ratnum-n y)) (= ($ratnum-d x) ($ratnum-d y)))) (define = (let () (define err (lambda (x) (die '= "not a number" x))) (define fxloopt (lambda (x y ls) (cond [(fixnum? y) (if (null? ls) ($fx= x y) (if ($fx= x y) (fxloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(bignum? y) (loopf (car ls) (cdr ls))] [(flonum? y) (if (null? ls) (fxfl= x y) (if (fxfl= x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(or (ratnum? y) (compnum? y) (cflonum? y)) (and (pair? ls) (loopf (car ls) (cdr ls)))] [else (err y)]))) (define bnloopt (lambda (x y ls) (cond [(fixnum? y) (loopf (car ls) (cdr ls))] [(bignum? y) (if (null? ls) (bnbn= x y) (if (bnbn= x y) (bnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(flonum? y) (if (null? ls) (bnfl= x y) (if (bnfl= x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(or (ratnum? y) (compnum? y) (cflonum? y)) (and (pair? ls) (loopf (car ls) (cdr ls)))] [else (err y)]))) (define flloopt (lambda (x y ls) (cond [(fixnum? y) (if (null? ls) (flfx= x y) (if (flfx= x y) (fxloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(bignum? y) (if (null? ls) (flbn= x y) (if (flbn= x y) (bnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(flonum? y) (if (null? ls) (flfl= x y) (if (flfl= x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(ratnum? y) (if (null? ls) (flrt= x y) (if (flrt= x y) (rtloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(or (compnum? y) (cflonum? y)) (and (pair? ls) (loopf (car ls) (cdr ls)))] [else (err y)]))) (define rtloopt (lambda (x y ls) (cond [(flonum? y) (if (null? ls) (rtfl= x y) (if (rtfl= x y) (flloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(ratnum? y) (if (null? ls) (rtrt= x y) (if (rtrt= x y) (rtloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(or (fixnum? y) (bignum? y) (compnum? y) (cflonum? y)) (and (pair? ls) (loopf (car ls) (cdr ls)))] [else (err y)]))) (define cnloopt (lambda (x y ls) (cond [(compnum? y) (if (null? ls) (cncn= x y) (if (cncn= x y) (cnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(cflonum? y) (if (null? ls) (cncf= x y) (if (cncf= x y) (cfloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(or (fixnum? y) (bignum? y) (flonum? y) (ratnum? y)) (and (pair? ls) (loopf (car ls) (cdr ls)))] [else (err y)]))) (define cfloopt (lambda (x y ls) (cond [(cflonum? y) (if (null? ls) (cfcf= x y) (if (cfcf= x y) (cfloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(compnum? y) (if (null? ls) (cncf= y x) (if (cncf= y x) (cnloopt y (car ls) (cdr ls)) (loopf (car ls) (cdr ls))))] [(or (fixnum? y) (bignum? y) (flonum? y) (ratnum? y)) (and (pair? ls) (loopf (car ls) (cdr ls)))] [else (err y)]))) (define loopf (lambda (x ls) (cond [(number? x) (if (null? ls) #f (loopf (car ls) (cdr ls)))] [else (err x)]))) (define (cncn= x y) (and (= ($compnum-real x) ($compnum-real y)) (= ($compnum-imag x) ($compnum-imag y)))) (define (cncf= x y) (and (= ($compnum-real x) ($cflonum-real y)) (= ($compnum-imag x) ($cflonum-imag y)))) (define (cfcf= x y) (and (= ($cflonum-real x) ($cflonum-real y)) (= ($cflonum-imag x) ($cflonum-imag y)))) (define = (case-lambda [(x y) (cond [(fixnum? x) (cond [(fixnum? y) ($fx= x y)] [(flonum? y) (fxfl= x y)] [(or (bignum? y) (ratnum? y) (compnum? y) (cflonum? y)) #f] [else (err y)])] [(bignum? x) (cond [(bignum? y) (bnbn= x y)] [(flonum? y) (bnfl= x y)] [(or (fixnum? y) (ratnum? y) (compnum? y) (cflonum? y)) #f] [else (err y)])] [(flonum? x) (cond [(fixnum? y) (flfx= x y)] [(bignum? y) (flbn= x y)] [(flonum? y) (flfl= x y)] [(ratnum? y) (flrt= x y)] [(or (compnum? y) (cflonum? y)) #f] [else (err y)])] [(ratnum? x) (cond [(flonum? y) (rtfl= x y)] [(ratnum? y) (rtrt= x y)] [(or (fixnum? y) (bignum? y) (compnum? y) (cflonum? y)) #f] [else (err y)])] [(compnum? x) (cond [(compnum? y) (cncn= x y)] [(cflonum? y) (cncf= x y)] [(or (fixnum? y) (bignum? y) (flonum? y) (ratnum? y)) #f] [else (err y)])] [(cflonum? x) (cond [(cflonum? y) (cfcf= x y)] [(compnum? y) (cncf= y x)] [(or (fixnum? y) (bignum? y) (flonum? y) (ratnum? y)) #f] [else (err y)])] [else (err x)])] [(x y z) (and (= x y) (= y z))] [(x) (if (number? x) #t (err x))] [(x y . ls) (cond [(fixnum? x) (fxloopt x y ls)] [(bignum? x) (bnloopt x y ls)] [(flonum? x) (flloopt x y ls)] [(ratnum? x) (rtloopt x y ls)] [(compnum? x) (cnloopt x y ls)] [(cflonum? x) (cfloopt x y ls)] [else (err x)])])) =)) ;(define = ; (mk< = $fx= false false bnbn= fxfl= flfx= bnfl= flbn= flfl= ; false false false false flrt= rtfl= rtrt=)) (define < (mk< < $fx< fxbn< bnfx< bnbn< fxfl< flfx< bnfl< flbn< flfl< exrt< rtex< exrt< rtex< flrt< rtfl< rtrt<)) (define > (mk< > $fx> fxbn> bnfx> bnbn> fxfl> flfx> bnfl> flbn> flfl> exrt> rtex> exrt> rtex> flrt> rtfl> rtrt>)) (define <= (mk< <= $fx<= fxbn< bnfx< bnbn<= fxfl<= flfx<= bnfl<= flbn<= flfl<= exrt< rtex< exrt< rtex< flrt<= rtfl<= rtrt<=)) (define >= (mk< >= $fx>= fxbn> bnfx> bnbn>= fxfl>= flfx>= bnfl>= flbn>= flfl>= exrt> rtex> exrt> rtex> flrt>= rtfl>= rtrt>=)) (define error@add1 (lambda (x) (import (ikarus)) (cond [(fixnum? x) (+ (greatest-fixnum) 1)] [(number? x) (+ x 1)] [else (die 'add1 "not a number" x)]))) (define add1 (lambda (x) (import (ikarus)) (add1 x))) (define error@sub1 (lambda (x) (import (ikarus)) (cond [(fixnum? x) (- (least-fixnum) 1)] [(number? x) (- x 1)] [else (die 'sub1 "not a number" x)]))) (define sub1 (lambda (x) (import (ikarus)) (sub1 x))) (define zero? (lambda (x) (cond [(fixnum? x) (eq? x 0)] [(bignum? x) #f] [(flonum? x) (or ($fl= x 0.0) ($fl= x -0.0))] [else (die 'zero? "not a number" x)]))) (define expt (lambda (n m) (define fxexpt (lambda (n m) (cond [($fxzero? m) 1] [($fxzero? ($fxlogand m 1)) (fxexpt (binary* n n) ($fxsra m 1))] [else (binary* n (fxexpt (binary* n n) ($fxsra m 1)))]))) (unless (number? n) (die 'expt "not a numebr" n)) (cond [(fixnum? m) (if ($fx>= m 0) (cond [(ratnum? n) ($make-ratnum (expt ($ratnum-n n) m) (expt ($ratnum-d n) m))] [else (fxexpt n m)]) (/ 1 (expt n (- m))))] [(bignum? m) (cond [(eq? n 0) 0] [(eq? n 1) 1] [(eq? n -1) (if (positive-bignum? m) (if (even-bignum? m) 1 -1) (/ 1 (expt n (- m))))] [else (die 'expt "result is too big to compute" n m)])] [(flonum? m) (flexpt (inexact n) m)] [(ratnum? m) (flexpt (inexact n) (inexact m))] [(or (compnum? m) (cflonum? m)) (let ([e 2.718281828459045]) (define (ln x) (/ (log x) (log e))) (exp (* m (ln n))))] [else (die 'expt "not a number" m)]))) (define quotient (lambda (x y) (let-values ([(q r) (quotient+remainder x y)]) q))) (define remainder (lambda (x y) (let-values ([(q r) (quotient+remainder x y)]) r))) (define quotient+remainder (lambda (x y) (cond [(eq? y 0) (die 'quotient+remainder "second argument must be non-zero")] [(fixnum? x) (cond [(fixnum? y) (values (fxquotient x y) (fxremainder x y))] [(bignum? y) (values 0 x)] [(flonum? y) (let ([v ($flonum->integer y)]) (cond [v (let-values ([(q r) (quotient+remainder x v)]) (values (inexact q) (inexact r)))] [else (die 'quotient+remainder "not an integer" y)]))] [else (die 'quotient+remainder "not a number" y)])] [(bignum? x) (cond [(fixnum? y) (let ([p (foreign-call "ikrt_bnfxdivrem" x y)]) (values (car p) (cdr p)))] [(bignum? y) (let ([p (foreign-call "ikrt_bnbndivrem" x y)]) (values (car p) (cdr p)))] [(flonum? y) (let ([v ($flonum->integer y)]) (cond [v (let-values ([(q r) (quotient+remainder x v)]) (values (inexact q) (inexact r)))] [else (die 'quotient+remainder "not an integer" y)]))] [else (die 'quotient+remainder "not a number" y)])] [(flonum? x) (let ([v ($flonum->integer x)]) (cond [v (let-values ([(q r) (quotient+remainder v y)]) (values (inexact q) (inexact r)))] [else (die 'quotient+remainder "not an integer" x)]))] [else (die 'quotient+remainder "not a number" x)]))) (define positive? (lambda (x) (cond [(fixnum? x) ($fx> x 0)] [(flonum? x) ($fl> x 0.0)] [(bignum? x) (positive-bignum? x)] [(ratnum? x) (positive? ($ratnum-n x))] [else (die 'positive? "not a number" x)]))) (define negative? (lambda (x) (cond [(fixnum? x) ($fx< x 0)] [(flonum? x) ($fl< x 0.0)] [(bignum? x) (not (positive-bignum? x))] [(ratnum? x) (negative? ($ratnum-n x))] [else (die 'negative? "not a number" x)]))) (define sin (lambda (x) (cond [(flonum? x) (foreign-call "ikrt_fl_sin" x)] [(fixnum? x) (foreign-call "ikrt_fx_sin" x)] [(number? x) (sin (inexact x))] [else (die 'sin "not a number" x)]))) (define cos (lambda (x) (cond [(flonum? x) (foreign-call "ikrt_fl_cos" x)] [(fixnum? x) (foreign-call "ikrt_fx_cos" x)] [(number? x) (cos (inexact x))] [else (die 'cos "not a number" x)]))) (define tan (lambda (x) (cond [(flonum? x) (foreign-call "ikrt_fl_tan" x)] [(fixnum? x) (foreign-call "ikrt_fx_tan" x)] [(number? x) (tan (inexact x))] [else (die 'tan "not a number" x)]))) (define asin (lambda (x) (cond [(flonum? x) (foreign-call "ikrt_fl_asin" x)] [(fixnum? x) (foreign-call "ikrt_fx_asin" x)] [(number? x) (asin (inexact x))] [else (die 'asin "not a number" x)]))) (define acos (lambda (x) (cond [(flonum? x) (foreign-call "ikrt_fl_acos" x)] [(fixnum? x) (foreign-call "ikrt_fx_acos" x)] [(number? x) (acos (inexact x))] [else (die 'acos "not a number" x)]))) (define atan (case-lambda [(x) (cond [(flonum? x) (foreign-call "ikrt_fl_atan" x)] [(fixnum? x) (foreign-call "ikrt_fx_atan" x)] [(or (ratnum? x) (bignum? x)) (atan (inexact x))] [else (die 'atan "not a number" x)])] [(y x) (unless (real? x) (die 'atan "not a real number" x)) (unless (real? y) (die 'atan "not a real number" y)) (foreign-call "ikrt_atan2" (inexact y) (inexact x))])) (define sqrt (lambda (x) (cond [(flonum? x) (foreign-call "ikrt_fl_sqrt" x)] [(fixnum? x) (cond [($fx< x 0) (let-values ([(s r) (exact-integer-sqrt (- x))]) (cond [(eq? r 0) ($make-rectangular 0 s)] [else (error 'sqrt "inexact complex numbers not supported yet")]))] [else (let-values ([(s r) (exact-integer-sqrt x)]) (cond [(eq? r 0) s] [else (foreign-call "ikrt_fx_sqrt" x)]))])] [(bignum? x) (cond [($bignum-positive? x) (let-values ([(s r) (exact-integer-sqrt x)]) (cond [(eq? r 0) s] [else (let ([v (sqrt (inexact x))]) ;;; could the [dropped] residual ever affect the answer? (cond [(infinite? v) (if (bignum? s) (foreign-call "ikrt_bignum_to_flonum" s 1 ;;; round up in case of a tie ($make-flonum)) (inexact s))] [else v]))]))] [else (let-values ([(s r) (exact-integer-sqrt (- x))]) (cond [(eq? r 0) (make-rectangular 0 s)] [else (error 'sqrt "inexact complex numbers not supported yet")]))])] [(ratnum? x) ;;; FIXME: incorrect as per bug 180170 (/ (sqrt ($ratnum-n x)) (sqrt ($ratnum-d x)))] [(or (compnum? x) (cflonum? x)) (let ([xr (real-part x)] [xi (imag-part x)]) (let ([m (sqrt (+ (* xr xr) (* xi xi)))] [s (if (> xi 0) 1 -1)]) (make-rectangular (sqrt (/ (+ m xr) 2)) (* s (sqrt (/ (- m xr) 2))))))] [else (die 'sqrt "not a number" x)]))) (define flsqrt (lambda (x) (if (flonum? x) (foreign-call "ikrt_fl_sqrt" x) (die 'flsqrt "not a flonum" x)))) (define flzero? (lambda (x) (if (flonum? x) ($flzero? x) (die 'flzero? "not a flonum" x)))) (define flnegative? (lambda (x) (if (flonum? x) ($fl< x 0.0) (die 'flnegative? "not a flonum" x)))) (define exact-integer-sqrt (lambda (x) (define who 'exact-integer-sqrt) (define (fxsqrt x i k) (let ([j ($fxsra ($fx+ i k) 1)]) (let ([j^2 ($fx* j j)]) (if ($fx> j^2 x) (fxsqrt x i j) (if ($fx= i j) (values j ($fx- x j^2)) (fxsqrt x j k)))))) (cond [(fixnum? x) (cond [($fx< x 0) (die who "invalid argument" x)] [($fx= x 0) (values 0 0)] [($fx< x 4) (values 1 ($fx- x 1))] [($fx< x 9) (values 2 ($fx- x 4))] [($fx< x 46340) (fxsqrt x 3 ($fxsra x 1))] [else (fxsqrt x 215 23171)])] [(bignum? x) (cond [($bignum-positive? x) (let ([r (foreign-call "ikrt_exact_bignum_sqrt" x)]) (values (car r) (cdr r)))] [else (die who "invalid argument" x)])] [else (die who "invalid argument" x)]))) (define numerator (lambda (x) (cond [(ratnum? x) ($ratnum-n x)] [(or (fixnum? x) (bignum? x)) x] [(flonum? x) (flnumerator x)] [else (die 'numerator "not an exact integer" x)]))) (define denominator (lambda (x) (cond [(ratnum? x) ($ratnum-d x)] [(or (fixnum? x) (bignum? x)) 1] [(flonum? x) (fldenominator x)] [else (die 'denominator "not an exact integer" x)]))) (define (floor x) (define (ratnum-floor x) (let ([n (numerator x)] [d (denominator x)]) (let ([q (quotient n d)]) (if (>= n 0) q (- q 1))))) (cond [(flonum? x) ;;; optimize for integer flonums (let ([e (or ($flonum->exact x) (die 'floor "number has no real value" x))]) (cond [(ratnum? e) (exact->inexact (ratnum-floor e))] [else x]))] [(ratnum? x) (ratnum-floor x)] [(or (fixnum? x) (bignum? x)) x] [else (die 'floor "not a number" x)])) (define (ceiling x) (define (ratnum-ceiling x) (let ([n (numerator x)] [d (denominator x)]) (let ([q (quotient n d)]) (if (< n 0) q (+ q 1))))) (cond [(flonum? x) ;;; optimize for integer flonums (let ([e (or ($flonum->exact x) (die 'ceiling "number has no real value" x))]) (cond [(ratnum? e) (exact->inexact (ratnum-ceiling e))] [else x]))] [(ratnum? x) (ratnum-ceiling x)] [(or (fixnum? x) (bignum? x)) x] [else (die 'ceiling "not a number" x)])) (define ($ratnum-round x) (let ([n ($ratnum-n x)] [d ($ratnum-d x)]) (let-values ([(q r) (quotient+remainder n d)]) (let ([r2 (+ r r)]) (if (> n 0) (cond [(< r2 d) q] [(> r2 d) (+ q 1)] [else (if (even? q) q (+ q 1))]) (let ([r2 (- r2)]) (cond [(< r2 d) q] [(< r2 d) (- q 1)] [else (if (even? q) q (- q 1))]))))))) (define ($ratnum-truncate x) (let ([n ($ratnum-n x)] [d ($ratnum-d x)]) (quotient n d))) (define (round x) (cond [(flonum? x) ($flround x)] [(ratnum? x) ($ratnum-round x)] [(or (fixnum? x) (bignum? x)) x] [else (die 'round "not a number" x)])) (define (truncate x) ;;; FIXME: fltruncate should preserve the sign of -0.0. ;;; (cond [(flonum? x) (let ([e (or ($flonum->exact x) (die 'truncate "number has no real value" x))]) (cond [(ratnum? e) (exact->inexact ($ratnum-truncate e))] [else x]))] [(ratnum? x) ($ratnum-truncate x)] [(or (fixnum? x) (bignum? x)) x] [else (die 'truncate "not a number" x)])) (define (fltruncate x) ;;; FIXME: fltruncate should preserve the sign of -0.0. (unless (flonum? x) (die 'fltruncate "not a flonum" x)) (let ([v ($flonum->exact x)]) (cond [(ratnum? v) (exact->inexact ($ratnum-truncate v))] [else x]))) (define log (lambda (x) (cond [(fixnum? x) (cond [($fx= x 1) 0] [($fx= x 0) (die 'log "undefined around 0")] [($fx> x 0) (foreign-call "ikrt_fx_log" x)] [else (die 'log "negative argument" x)])] [(flonum? x) (cond [(>= x 0) (foreign-call "ikrt_fl_log" x)] [else (die 'log "negative argument" x)])] [(bignum? x) (unless ($bignum-positive? x) (die 'log "negative argument" x)) (let ([v (log (inexact x))]) (cond [(infinite? v) (let-values ([(s r) (exact-integer-sqrt x)]) ;;; could the [dropped] residual ever affect the answer? (fl* 2.0 (log s)))] [else v]))] [(ratnum? x) ;;; FIXME: incorrect as per bug 180170 (- (log (numerator x)) (log (denominator x)))] [(or (compnum? x) (cflonum? x)) (let ([e 2.718281828459045]) (define (ln x) (/ (log x) (log e))) (let ([xr (real-part x)] [xi (imag-part x)]) (make-rectangular (/ (ln (+ (* xr xr) (* xi xi))) 2) (atan xi xr))))] [else (die 'log "not a number" x)]))) (define string->number (case-lambda [(x) (string->number-radix-10 x)] [(x r) (unless (eqv? r 10) (die 'string->number "BUG: only radix 10 is supported" x r)) (string->number-radix-10 x)])) (define string->number-radix-10 (lambda (x) (define (convert-char c radix) (case radix [(10) (cond [(char<=? #\0 c #\9) (fx- (char->integer c) (char->integer #\0))] [else #f])] [(16) (cond [(char<=? #\0 c #\9) (fx- (char->integer c) (char->integer #\0))] [(char<=? #\a c #\f) (fx- (char->integer c) (fx- (char->integer #\a) 10))] [(char<=? #\A c #\F) (fx- (char->integer c) (fx- (char->integer #\A) 10))] [else #f])] [(8) (cond [(char<=? #\0 c #\7) (fx- (char->integer c) (char->integer #\0))] [else #f])] [(2) (case c [(#\0) 0] [(#\1) 1] [else #f])] [else (die 'convert-char "invalid radix" radix)])) (define (parse-exponent-start x n i radix) (define (parse-exponent x n i radix ac) (cond [(fx= i n) ac] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-exponent x n (fxadd1 i) radix (+ d (* ac radix))))] [else #f]))])) (define (parse-exponent-sign x n i radix) (cond [(fx= i n) #f] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-exponent x n (fxadd1 i) radix d))] [else #f]))])) (cond [(fx= i n) #f] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-exponent x n (fxadd1 i) radix d))] [(char=? c #\+) (parse-exponent-sign x n (fxadd1 i) radix)] [(char=? c #\-) (let ([v (parse-exponent-sign x n (fxadd1 i) radix)]) (and v (- v)))] [else #f]))])) (define (parse-decimal x n i pos? radix exact? ac exp) (cond [(fx= i n) (let ([ac (* (if pos? ac (- ac)) (expt radix exp))]) (exact-conv (or exact? 'i) ac))] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-decimal x n (fxadd1 i) pos? radix exact? (+ (* ac radix) d) (fxsub1 exp)))] [(memv c '(#\e #\E)) (let ([ex (parse-exponent-start x n (fxadd1 i) radix)]) (and ex (exact-conv (or exact? 'i) (* (if pos? ac (- ac)) (expt radix (+ exp ex))))))] [else #f]))])) (define (parse-decimal-no-digits x n i pos? radix exact?) (cond [(fx= i n) #f] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-decimal x n (fxadd1 i) pos? radix exact? d -1))] [else #f]))])) (define (parse-integer x n i pos? radix exact? ac) (define (parse-denom-start x n i radix) (define (parse-denom x n i radix ac) (cond [(fx= n i) ac] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-denom x n (fxadd1 i) radix (+ (* radix ac) d)))] [else #f]))])) (cond [(fx= n i) #f] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-denom x n (fxadd1 i) radix d))] [else #f]))])) (cond [(fx= i n) (let ([ac (exact-conv exact? ac)]) (if pos? ac (- ac)))] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-integer x n (fxadd1 i) pos? radix exact? (+ (* ac radix) d)))] [(char=? c #\.) (parse-decimal x n (fxadd1 i) pos? radix exact? ac 0)] [(char=? c #\/) (let ([denom (parse-denom-start x n (fxadd1 i) radix)]) (and denom (not (= denom 0)) (let ([ac (exact-conv exact? ac)]) (/ (if pos? ac (- ac)) denom))))] [(memv c '(#\e #\E)) (let ([ex (parse-exponent-start x n (fxadd1 i) radix)]) (and ex (let ([ac (* (if pos? ac (- ac)) (expt radix ex))]) (exact-conv (or exact? 'i) ac))))] [else #f]))])) (define (parse-integer-no-digits x n i pos? radix exact?) (cond [(fx= i n) #f] [else (let ([c (string-ref x i)]) (cond [(convert-char c radix) => (lambda (d) (parse-integer x n (fxadd1 i) pos? radix exact? d))] [(char=? c #\.) (parse-decimal-no-digits x n (fxadd1 i) pos? radix exact?)] [else #f]))])) (define (exact-conv exact? x) (and x (if (eq? exact? 'i) (exact->inexact x) x))) (define (start x n i exact? radix?) (cond [(fx= i n) #f] [else (let ([c (string-ref x i)]) (cond [(char=? c #\-) (parse-integer-no-digits x n (fxadd1 i) #f (or radix? 10) exact?)] [(char=? c #\+) (parse-integer-no-digits x n (fxadd1 i) #t (or radix? 10) exact?)] [(char=? c #\#) (let ([i (fxadd1 i)]) (cond [(fx= i n) #f] [else (let ([c (string-ref x i)]) (case c [(#\x #\X) (and (not radix?) (start x n (fxadd1 i) exact? 16))] [(#\b #\B) (and (not radix?) (start x n (fxadd1 i) exact? 2))] [(#\o #\O) (and (not radix?) (start x n (fxadd1 i) exact? 8))] [(#\d #\D) (and (not radix?) (start x n (fxadd1 i) exact? 10))] [(#\e #\E) (and (not exact?) (start x n (fxadd1 i) 'e radix?))] [(#\i #\I) (and (not exact?) (start x n (fxadd1 i) 'i radix?))] [else #f]))]))] [(char=? c #\.) (parse-decimal-no-digits x n (fxadd1 i) #t (or radix? 10) exact?)] [(convert-char c (or radix? 10)) => (lambda (d) (parse-integer x n (fxadd1 i) #t (or radix? 10) exact? d))] [else #f]))])) ;;; (unless (string? x) (die 'string->number "not a string" x)) (let ([n (string-length x)]) (cond [(fx= n (string-length "+xxx.0")) (cond [(string-ci=? x "+inf.0") +inf.0] [(string-ci=? x "-inf.0") -inf.0] [(string-ci=? x "+nan.0") +nan.0] [(string-ci=? x "-nan.0") -nan.0] [else (start x n 0 #f #f)])] [(fx> n 0) (start x n 0 #f #f)] [else #f])))) (define (random n) (if (fixnum? n) (if (fx> n 1) (foreign-call "ikrt_fxrandom" n) (if (fx= n 1) 0 (die 'random "incorrect argument" n))) (die 'random "not a fixnum" n))) (define (shift-right-arithmetic n m who) (cond [(fixnum? m) (cond [(fixnum? n) (cond [($fx>= m 0) ($fxsra n m)] [else (die who "offset must be non-negative" m)])] [(bignum? n) (cond [($fx> m 0) (foreign-call "ikrt_bignum_shift_right" n m)] [($fx= m 0) n] [else (die who "offset must be non-negative" m)])] [else (die who "not an exact integer" n)])] [(bignum? m) (cond [(fixnum? n) (if ($fx>= n 0) 0 -1)] [(bignum? n) (if ($bignum-positive? n) 0 -1)] [else (die who "not an exact integer" n)])] [else (die who "not an exact integer offset" m)])) (define (sra n m) (shift-right-arithmetic n m 'sra)) (define (shift-left-logical n m who) (unless (fixnum? m) (die who "shift amount is not a fixnum")) (cond [(fixnum? n) (cond [($fx> m 0) (foreign-call "ikrt_fixnum_shift_left" n m)] [($fx= m 0) n] [else (die who "offset must be non-negative" m)])] [(bignum? n) (cond [($fx> m 0) (foreign-call "ikrt_bignum_shift_left" n m)] [($fx= m 0) n] [else (die who "offset must be non-negative" m)])] [else (die who "not an exact integer" n)])) (define (sll n m) (shift-left-logical n m 'sll)) (define (bitwise-arithmetic-shift-right n m) (shift-right-arithmetic n m 'bitwise-arithmetic-shift-right)) (define (bitwise-arithmetic-shift-left n m) (shift-left-logical n m 'bitwise-arithmetic-shift-left)) (define (bitwise-arithmetic-shift n m) (define who 'bitwise-arithmetic-shift) (unless (fixnum? m) (die who "shift amount is not a fixnum")) (cond [(fixnum? n) (cond [($fx> m 0) (foreign-call "ikrt_fixnum_shift_left" n m)] [($fx= m 0) n] [else (let ([m^ (- m)]) (unless (fixnum? m^) (die who "shift amount is too big" m)) ($fxsra n m^))])] [(bignum? n) (cond [($fx> m 0) (foreign-call "ikrt_bignum_shift_left" n m)] [($fx= m 0) n] [else (let ([m^ (- m)]) (unless (fixnum? m^) (die who "shift amount is too big" m)) (foreign-call "ikrt_bignum_shift_right" n m^))])] [else (die who "not an exact integer" n)])) (define (exp x) (cond [(flonum? x) (flexp x)] [(fixnum? x) (if ($fx= x 0) 1 (flexp (fixnum->flonum x)))] [(bignum? x) (flexp (bignum->flonum x))] [(ratnum? x) (flexp (ratnum->flonum x))] [(or (compnum? x) (cflonum? x)) ;; e^x = e^(xr + xi i) ;; = e^xr cos(xi) + e^xr sin(xi) i (let ([xr (real-part x)] [xi (imag-part x)]) (let ([e^xr (exp xr)]) (make-rectangular (* e^xr (cos xi)) (* e^xr (sin xi)))))] [else (die 'exp "not a number" x)])) (define (bitwise-length n) (cond [(fixnum? n) (fxlength n)] [(bignum? n) (foreign-call "ikrt_bignum_length" n)] [else (die 'bitwise-length "not an exact integer" n)])) (define (bitwise-copy-bit n idx bit) (define who 'bitwise-copy-bit) (define (do-copy-bit n idx bit) (case bit [(0) (cond [(bitwise-bit-set? n idx) (bitwise-and n (bitwise-not (sll 1 idx)))] [else n])] [(1) (cond [(bitwise-bit-set? n idx) n] [(>= n 0) (+ n (sll 1 idx))] [else (bitwise-not (bitwise-and (bitwise-not n) (bitwise-not (sll 1 idx))))])] [else (die who "bit must be either 0 or 1" bit)])) (cond [(fixnum? idx) (cond [(fx< idx 0) (die who "negative bit index" idx)] [(or (fixnum? n) (bignum? n)) (do-copy-bit n idx bit)] [else (die who "not an exact integer" n)])] [(bignum? idx) (unless (or (fixnum? n) (bignum? n)) (die who "not an exact integer" n)) (if ($bignum-positive? idx) (case bit [(0) (if (>= n 0) n (die who "unrepresentable result"))] [(1) (if (< n 0) n (die who "unrepresentable result"))] [else (die who "bit must be either 0 or 1" bit)]) (die who "negative bit index" idx))] [else (die who "index is not an exact integer" idx)])) (define (bitwise-bit-field n idx1 idx2) (define who 'bitwise-bit-field) (cond [(and (fixnum? idx1) (fx>= idx1 0)) (cond [(and (fixnum? idx2) (fx>= idx2 0)) (cond [(fx<= idx1 idx2) (cond [(or (fixnum? n) (bignum? n)) (bitwise-and (sra n idx1) (- (sll 1 (- idx2 idx1)) 1))] [else (die who "not an exact integer" n)])] [else (die who "invalid order for indices" idx1 idx2)])] [else (if (not (fixnum? idx2)) (die who "invalid index" idx2) (die who "negative index" idx2))])] [else (if (not (fixnum? idx1)) (die who "invalid index" idx1) (die who "negative index" idx1))])) ) (library (ikarus flonum-conversion) (export string->flonum flonum->string) (import (rnrs bytevectors) (ikarus system $bytevectors) (ikarus system $flonums) (except (ikarus) flonum->string string->flonum )) (module (flonum->string) (module (flonum->digits) (define flonum->digits (lambda (f e min-e p b B) ;;; flonum v = f * b^e ;;; p = precision (p >= 1) (let ([round? (even? f)]) (if (>= e 0) (if (not (= f (expt b (- p 1)))) (let ([be (expt b e)]) (scale (* f be 2) 2 be be 0 B round? f e)) (let* ([be (expt b e)] [be1 (* be b)]) (scale (* f be1 2) (* b 2) be1 be 0 B round? f e))) (if (or (= e min-e) (not (= f (expt b (- p 1))))) (scale (* f 2) (* (expt b (- e)) 2) 1 1 0 B round? f e) (scale (* f b 2) (* (expt b (- 1 e)) 2) b 1 0 B round? f e)))))) (define (len n) (let f ([n n] [i 0]) (cond [(zero? n) i] [else (f (quotient n 2) (+ i 1))]))) (define scale (lambda (r s m+ m- k B round? f e) (let ([est (inexact->exact (ceiling (- (* (+ e (len f) -1) (invlog2of B)) 1e-10)))]) (if (>= est 0) (fixup r (* s (exptt B est)) m+ m- est B round?) (let ([scale (exptt B (- est))]) (fixup (* r scale) s (* m+ scale) (* m- scale) est B round?)))))) (define fixup (lambda (r s m+ m- k B round?) (if ((if round? >= >) (+ r m+) s) ; too low? (values (+ k 1) (generate r s m+ m- B round?)) (values k (generate (* r B) s (* m+ B) (* m- B) B round?))))) (define (chr x) (vector-ref '#(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) x)) (define generate (lambda (r s m+ m- B round?) (let-values ([(q r) (quotient+remainder r s)]) (let ([tc1 ((if round? <= <) r m-)] [tc2 ((if round? >= >) (+ r m+) s)]) (if (not tc1) (if (not tc2) (cons (chr q) (generate (* r B) s (* m+ B) (* m- B) B round?)) (list (chr (+ q 1)))) (if (not tc2) (list (chr q)) (if (< (* r 2) s) (list (chr q)) (list (chr (+ q 1)))))))))) (define invlog2of (let ([table (make-vector 37)] [log2 (log 2)]) (do ([B 2 (+ B 1)]) ((= B 37)) (vector-set! table B (/ log2 (log B)))) (lambda (B) (if (<= 2 B 36) (vector-ref table B) (/ log2 (log B)))))) (define exptt (let ([table (make-vector 326)]) (do ([k 0 (+ k 1)] [v 1 (* v 10)]) ((= k 326)) (vector-set! table k v)) (lambda (B k) (if (and (= B 10) (<= 0 k 325)) (vector-ref table k) (expt B k)))))) (define (format-flonum pos? expt digits) (define (next x) (if (null? x) (values #\0 '()) (values (car x) (cdr x)))) (define (format-flonum-no-expt expt d0 d*) (cond [(= expt 1) (cons d0 (if (null? d*) '(#\. #\0) (cons #\. d*)))] [else (cons d0 (let-values ([(d0 d*) (next d*)]) (format-flonum-no-expt (- expt 1) d0 d*)))])) (define (format-flonum-no-expt/neg expt d*) (cond [(= expt 0) d*] [else (cons #\0 (format-flonum-no-expt/neg (+ expt 1) d*))])) (define (sign pos? ls) (if pos? (list->string ls) (list->string (cons #\- ls)))) (let ([d0 (car digits)] [d* (cdr digits)]) (cond [(null? d*) (if (char=? d0 #\0) (if pos? "0.0" "-0.0") (if (= expt 1) (if pos? (string d0 #\. #\0) (string #\- d0 #\. #\0)) (if (= expt 0) (if pos? (string #\0 #\. d0) (string #\- #\0 #\. d0)) (string-append (if pos? "" "-") (string d0) "e" (fixnum->string (- expt 1))))))] [(and (null? d*) (char=? d0 #\0)) (if pos? "0.0" "-0.0")] [(<= 1 expt 9) (sign pos? (format-flonum-no-expt expt d0 d*))] [(<= -3 expt 0) (sign pos? (cons* #\0 #\. (format-flonum-no-expt/neg expt digits)))] [else (string-append (if pos? "" "-") (string d0) "." (list->string d*) "e" (fixnum->string (- expt 1)))]))) (define (flo->string pos? m e p) (let-values ([(expt digits) (flonum->digits m e 10 p 2 10)]) (format-flonum pos? expt digits))) (define (flonum->string x) (let-values ([(pos? be m) (flonum-parts x)]) (cond [(<= 1 be 2046) ; normalized flonum (flo->string pos? (+ m (expt 2 52)) (- be 1075) 53)] [(= be 0) (flo->string pos? m -1074 52)] [(= be 2047) (if (= m 0) (if pos? "+inf.0" "-inf.0") ;;; Gee! nans have no sign! "+nan.0")] [else (die 'flonum->string "cannot happen")])))) ;;; (define (string->flonum x) (cond [(string? x) (foreign-call "ikrt_bytevector_to_flonum" (string->utf8 x))] [else (die 'string->flonum "not a string" x)])) ) (library (ikarus rationalize) (export rationalize) (import (except (ikarus) rationalize)) (define (rationalize x eps) (define who 'rationalize) (define (simplest x y) (cond [(< y x) (simplest y x)] [(= x y) x] [(> x 0) (let ([n (numerator x)] [d (denominator x)] [n^ (numerator y)] [d^ (denominator y)]) (simplest^ n d n^ d^))] [(< y 0) (let ([n (numerator x)] [d (denominator x)] [n^ (numerator y)] [d^ (denominator y)]) (- (simplest^ (- n^) d^ (- n) d)))] [else 1])) (define (simplest^ n d n^ d^) (let-values ([(q r) (div-and-mod n d)]) (if (= r 0) q (let-values ([(q^ r^) (div-and-mod n^ d^)]) (if (= q q^) (let ([v (simplest^ d^ r^ d r)]) (let ([n^^ (numerator v)] [d^^ (denominator v)]) (/ (+ (* q n^^) d^^) n^^))) (+ q 1)))))) (define (go x eps) (simplest (- x eps) (+ x eps))) (cond [(flonum? x) (if (flfinite? x) (cond [(flonum? eps) (if (flfinite? eps) (go x eps) +nan.0)] [(or (fixnum? eps) (bignum? eps) (ratnum? eps)) (go x eps)] [else (die who "not a number" eps)]) (cond [(flonum? eps) (if (flfinite? eps) x +nan.0)] [(or (fixnum? eps) (bignum? eps) (ratnum? eps)) x] [else (die who "not a number" eps)]))] [(or (fixnum? x) (bignum? x) (ratnum? x)) (cond [(flonum? eps) (if (flfinite? eps) (go x eps) +nan.0)] [(or (fixnum? eps) (bignum? eps) (ratnum? eps)) (go x eps)] [else (die who "not a number" eps)])] [else (die who "not a number" x)]))) (library (ikarus r6rs-fu div/mod) (export div mod div-and-mod div0 mod0 div0-and-mod0) (import (except (ikarus) div mod div-and-mod div0 mod0 div0-and-mod0)) (define (div-and-mod* n m who) (import (ikarus system $fx) (only (ikarus system $flonums) $fl=) (ikarus flonums)) (define (int-div-and-mod n m) (let ([d0 (quotient n m)]) (let ([m0 (- n (* d0 m))]) (if (>= m0 0) (values d0 m0) (if (>= m 0) (values (- d0 1) (+ m0 m)) (values (+ d0 1) (- m0 m))))))) (define (rat-div-and-mod n m) (let ([x (/ n m)]) (cond [(or (fixnum? x) (bignum? x)) (values x 0)] [else (let ([n0 (numerator x)] [d0 (denominator x)]) (let ([q (quotient n0 d0)]) (let ([r (- n (* q m))]) (if (>= r 0) (values q r) (if (> m 0) (values (- q 1) (+ r m)) (values (+ q 1) (- r m)))))))]))) (cond [(fixnum? m) (cond [($fx= m 0) (die who "division by 0")] [(or (fixnum? n) (bignum? n)) (int-div-and-mod n m)] [(flonum? n) (fldiv-and-mod n (fixnum->flonum m))] [(ratnum? n) (rat-div-and-mod n m)] [else (die who "not a number" n)])] [(bignum? m) (cond [(or (fixnum? n) (bignum? n)) (int-div-and-mod n m)] [(flonum? n) (let ([v ($flonum->exact n)]) (unless v (die who "invalid argument" n)) (let-values ([(a b) (div-and-mod* v m who)]) (values (inexact a) (inexact b))))] [(ratnum? n) (rat-div-and-mod n m)] [else (die who "not a number" n)])] [(ratnum? m) (cond [(or (fixnum? n) (bignum? n) (ratnum? n)) (rat-div-and-mod n m)] [(flonum? n) (let ([v ($flonum->exact n)]) (unless v (die who "invalid argument" n)) (let-values ([(a b) (div-and-mod* v m who)]) (values (inexact a) (inexact b))))] [else (die who "not a number" n)])] [(flonum? m) (cond [($fl= m 0.0) (die who "division by 0.0")] [(flonum? n) (fldiv-and-mod n m)] [(fixnum? n) (fldiv-and-mod (fixnum->flonum n) m)] [(or (bignum? n) (ratnum? n)) (let ([v ($flonum->exact m)]) (unless v (die who "invalid argument" m)) (let-values ([(a b) (div-and-mod* n v who)]) (values (inexact a) (inexact b))))] [else (die who "not a number" n)])] [else (die who "not a number" m)])) (define (div-and-mod n m) (div-and-mod* n m 'div-and-mod)) (define (div n m) (import (ikarus system $fx)) (cond [(and (fixnum? n) (fixnum? m)) (cond [(eq? m 0) (error 'div "division by 0")] [else (let ([d0 ($fxquotient n m)]) (if ($fx>= n ($fx* d0 m)) d0 (if ($fx>= m 0) ($fx- d0 1) ($fx+ d0 1))))])] [else (let-values ([(a b) (div-and-mod* n m 'div)]) a)])) (define (mod n m) (import (ikarus system $fx)) (cond [(and (fixnum? n) (fixnum? m)) (cond [(eq? m 0) (error 'mod "division by 0")] [else (let ([d0 ($fxquotient n m)]) (let ([m0 ($fx- n ($fx* d0 m))]) (if ($fx>= m0 0) m0 (if ($fx>= m 0) ($fx+ m0 m) ($fx- m0 m)))))])] [else (let-values ([(a b) (div-and-mod* n m 'mod)]) b)])) (define (div0-and-mod0 x y) (let-values ([(d m) (div-and-mod* x y 'div0-and-mod0)]) (if (> y 0) (if (< m (/ y 2)) (values d m) (values (+ d 1) (- m y))) (if (> m (/ y -2)) (values (- d 1) (+ m y)) (values d m))))) (define (div0 x y) (let-values ([(d m) (div-and-mod* x y 'div0)]) (if (> y 0) (if (< m (/ y 2)) d (+ d 1)) (if (> m (/ y -2)) (- d 1) d)))) (define (mod0 x y) (let-values ([(d m) (div-and-mod* x y 'mod0)]) (if (> y 0) (if (< m (/ y 2)) m (- m y)) (if (> m (/ y -2)) (+ m y) m)))) ) (library (ikarus flonums div-and-mod) (export fldiv flmod fldiv-and-mod fldiv0 flmod0 fldiv0-and-mod0) (import (ikarus system $flonums) (ikarus system $fx) (except (ikarus) fldiv flmod fldiv-and-mod fldiv0 flmod0 fldiv0-and-mod0)) (define ($flmod n m) (let ([d0 (fltruncate ($fl/ n m))]) (let ([m0 ($fl- n ($fl* d0 m))]) (if ($fl>= m0 0.0) m0 (if ($fl>= m 0.0) ($fl+ m0 m) ($fl- m0 m)))))) (define ($fldiv n m) (let ([d0 (fltruncate ($fl/ n m))]) (if ($fl>= n ($fl* d0 m)) d0 (if ($fl>= m 0.0) ($fl- d0 1.0) ($fl+ d0 1.0))))) (define ($fldiv-and-mod n m) (let ([d0 (fltruncate ($fl/ n m))]) (let ([m0 ($fl- n ($fl* d0 m))]) (if ($fl>= m0 0.0) (values d0 m0) (if ($fl>= m 0.0) (values ($fl- d0 1.0) ($fl+ m0 m)) (values ($fl+ d0 1.0) ($fl- m0 m))))))) (define (fldiv n m) (if (flonum? n) (if (flonum? m) ($fldiv n m) (die 'fldiv "not a flonum" m)) (die 'fldiv "not a flonum" n))) (define (flmod n m) (if (flonum? n) (if (flonum? m) ($flmod n m) (die 'flmod "not a flonum" m)) (die 'flmod "not a flonum" n))) (define (fldiv-and-mod n m) (if (flonum? n) (if (flonum? m) ($fldiv-and-mod n m) (die 'fldiv-and-mod "not a flonum" m)) (die 'fldiv-and-mod "not a flonum" n))) (define ($fldiv0-and-mod0 n m) (let ([d0 (fltruncate ($fl/ n m))]) (let ([m0 ($fl- n ($fl* d0 m))]) (if ($fl>= m 0.0) (if ($fl< m0 ($fl/ m 2.0)) (if ($fl>= m0 ($fl/ m -2.0)) (values d0 m0) (values ($fl- d0 1.0) ($fl+ m0 m))) (values ($fl+ d0 1.0) ($fl- m0 m))) (if ($fl< m0 ($fl/ m -2.0)) (if ($fl>= m0 ($fl/ m 2.0)) (values d0 m0) (values ($fl+ d0 1.0) ($fl- m0 m))) (values ($fl- d0 1.0) ($fl+ m0 m))))))) (define ($fldiv0 n m) (let ([d0 (fltruncate ($fl/ n m))]) (let ([m0 ($fl- n ($fl* d0 m))]) (if ($fl>= m 0.0) (if ($fl< m0 ($fl/ m 2.0)) (if ($fl>= m0 ($fl/ m -2.0)) d0 ($fl- d0 1.0)) ($fl+ d0 1.0)) (if ($fl< m0 ($fl/ m -2.0)) (if ($fl>= m0 ($fl/ m 2.0)) d0 ($fl+ d0 1.0)) ($fl- d0 1.0)))))) (define ($flmod0 n m) (let ([d0 (fltruncate ($fl/ n m))]) (let ([m0 ($fl- n ($fl* d0 m))]) (if ($fl>= m 0.0) (if ($fl< m0 ($fl/ m 2.0)) (if ($fl>= m0 ($fl/ m -2.0)) m0 ($fl+ m0 m)) ($fl- m0 m)) (if ($fl< m0 ($fl/ m -2.0)) (if ($fl>= m0 ($fl/ m 2.0)) m0 ($fl- m0 m)) ($fl+ m0 m)))))) (define (fldiv0 n m) (if (flonum? n) (if (flonum? m) ($fldiv0 n m) (die 'fldiv0 "not a flonum" m)) (die 'fldiv0 "not a flonum" n))) (define (flmod0 n m) (if (flonum? n) (if (flonum? m) ($flmod0 n m) (die 'flmod0 "not a flonum" m)) (die 'flmod0 "not a flonum" n))) (define (fldiv0-and-mod0 n m) (if (flonum? n) (if (flonum? m) ($fldiv0-and-mod0 n m) (die 'fldiv0-and-mod0 "not a flonum" m)) (die 'fldiv0-and-mod0 "not a flonum" n)))) (library (ikarus bitwise misc) (export fxfirst-bit-set bitwise-bit-set? bitwise-first-bit-set fxbit-count bitwise-bit-count fxlength fxbit-set? fxcopy-bit fxcopy-bit-field fxbit-field) (import (ikarus system $fx) (ikarus system $bignums) (ikarus system $flonums) (except (ikarus) fxfirst-bit-set bitwise-bit-set? bitwise-first-bit-set fxbit-count bitwise-bit-count fxlength fxbit-set? fxcopy-bit fxcopy-bit-field fxbit-field)) (module (bitwise-first-bit-set fxfirst-bit-set) (define (byte-first-bit-set x i) (import (ikarus system $bytevectors)) (define-syntax make-first-bit-set-bytevector (lambda (x) (define (fst n) (cond [(zero? n) 0] [(even? n) (fst (bitwise-arithmetic-shift-right n 1))] [else (+ 1 (fst (bitwise-arithmetic-shift-right n 1)))])) (u8-list->bytevector (let f ([i 0]) (cond [(= i 256) '()] [else (cons (fst i) (f (+ i 1)))]))))) (define bv (make-first-bit-set-bytevector)) ($fx+ i ($bytevector-u8-ref bv i))) (define ($fxloop x i) (let ([y ($fxlogand x 255)]) (if ($fx= y 0) ($fxloop ($fxsra x 8) ($fx+ i 8)) (byte-first-bit-set y i)))) (define ($bnloop x i idx) (let ([b ($bignum-byte-ref x idx)]) (if ($fxzero? b) ($bnloop x ($fx+ i 8) ($fx+ idx 1)) (byte-first-bit-set b i)))) (define ($fxfirst-bit-set x) (if ($fx> x 0) ($fxloop x 0) (if ($fx= x 0) -1 (if ($fx> x (least-fixnum)) ($fxloop ($fx- 0 x) 0) ($bnloop (- x) 0 0))))) (define (fxfirst-bit-set x) (cond [(fixnum? x) ($fxfirst-bit-set x)] [else (die 'fxfirst-bit-set "not a fixnum" x)])) (define (bitwise-first-bit-set x) (cond [(fixnum? x) ($fxfirst-bit-set x)] [(bignum? x) ($bnloop x 0 0)] [else (die 'bitwise-first-bit-set "not an exact integer" x)]))) (module (fxbit-count bitwise-bit-count) (define (pos-fxbitcount n) ;;; nifty parrallel count from: ;;; http://infolab.stanford.edu/~manku/bitcount/bitcount.html (let ([m0 #x15555555] [m1 #x13333333] [m2 #x0f0f0f0f]) (let* ([n ($fx+ ($fxlogand n m0) ($fxlogand ($fxsra n 1) m0))] [n ($fx+ ($fxlogand n m1) ($fxlogand ($fxsra n 2) m1))] [n ($fx+ ($fxlogand n m2) ($fxlogand ($fxsra n 4) m2))]) ($fxmodulo n 255)))) (define ($fxbitcount n) (if ($fx< n 0) (fxlognot (pos-fxbitcount (fxlognot n))) (pos-fxbitcount n))) (define (bnbitcount n) (define (poscount x idx c) (let ([c (+ c ($fx+ (pos-fxbitcount ($fxlogor ($fxsll ($bignum-byte-ref x ($fx+ idx 3)) 8) ($bignum-byte-ref x ($fx+ idx 2)))) (pos-fxbitcount ($fxlogor ($fxsll ($bignum-byte-ref x ($fxadd1 idx)) 8) ($bignum-byte-ref x idx)))))]) (if ($fx= idx 0) c (poscount x ($fx- idx 4) c)))) (if ($bignum-positive? n) (poscount n ($fx- ($bignum-size n) 4) 0) (let ([n (bitwise-not n)]) (bitwise-not (poscount n ($fx- ($bignum-size n) 4) 0))))) (define (fxbit-count n) (cond [(fixnum? n) ($fxbitcount n)] [else (die 'fxbit-count "not a fixnum" n)])) (define (bitwise-bit-count n) (cond [(fixnum? n) ($fxbitcount n)] [(bignum? n) (bnbitcount n)] [else (die 'bitwise-bit-count "not an exact integer" n)]))) (define (fxlength x) (if (fixnum? x) (let ([fl ($fixnum->flonum (if ($fx< x 0) ($fxlognot x) x))]) (let ([sbe ($fxlogor ($fxsll ($flonum-u8-ref fl 0) 4) ($fxsra ($flonum-u8-ref fl 1) 4))]) (cond [($fx= sbe 0) 0] [else ($fx- sbe 1022)]))) (die 'fxlength "not a fixnum" x))) (define (fxbit-set? x i) (define who 'fxbit-set?) (if (fixnum? x) (if (fixnum? i) (if (and ($fx<= 0 i) ($fx< i (fixnum-width))) (not ($fxzero? ($fxlogand ($fxsra x i) 1))) (die who "index out of range" i)) (die who "index is not a fixnum" i)) (die who "not a fixnum" x))) (define (bitwise-bit-set? x i) (define who 'bitwise-bit-set?) (cond [(fixnum? i) (when ($fx< i 0) (die who "index must be non-negative" i)) (cond [(fixnum? x) (if ($fx< i (fixnum-width)) ($fx= ($fxlogand ($fxsra x i) 1) 1) ($fx< x 0))] [(bignum? x) (let ([n ($bignum-size x)]) (let ([m ($fx* n 8)]) (if ($fx< m i) (not ($bignum-positive? x)) (if ($bignum-positive? x) (let ([b ($bignum-byte-ref x ($fxsra i 3))]) ($fx= ($fxlogand ($fxsra b ($fxlogand i 7)) 1) 1)) (= 1 (bitwise-and (bitwise-arithmetic-shift-right x i) 1))))))] [else (die who "not an exact integer" x)])] [(bignum? i) (unless ($bignum-positive? i) (die who "index must be non-negative")) (cond [(fixnum? x) ($fx< x 0)] [(bignum? x) (= 1 (bitwise-and (bitwise-arithmetic-shift-right x i) 1))] [else (die who "not an exact integer" x)])] [else (die who "index is not an exact integer" i)])) (define (fxcopy-bit x i b) (define who 'fxcopy-bit) (if (fixnum? x) (if (fixnum? i) (if (and ($fx<= 0 i) ($fx< i (fixnum-width))) (case b [(0) ($fxlogand x ($fxlognot ($fxsll 1 i)))] [(1) ($fxlogor x ($fxsll 1 i))] [else (die who "invalid bit value" b)]) (die who "index out of range" i)) (die who "index is not a fixnum" i)) (die who "not a fixnum" x))) (define (fxcopy-bit-field x i j b) (define who 'fxcopy-bit-field) (if (fixnum? x) (if (fixnum? i) (if ($fx<= 0 i) (if (fixnum? j) (if ($fx< j (fixnum-width)) (if ($fx<= i j) (if (fixnum? b) (let ([m ($fxlogxor ($fxsub1 ($fxsll 1 i)) ($fxsub1 ($fxsll 1 j)))]) ($fxlogor ($fxlogand m b) ($fxlogand ($fxlognot m) x))) (die who "not a fixnum" b)) (if ($fx<= 0 j) (die who "index out of range" j) (die who "indices not in order" i j))) (die who "index out of range" j)) (die who "not a fixnum" j)) (die who "index out of range" i)) (die who "not a fixnum" i)) (die who "not a fixnum" x))) (define (fxbit-field x i j) (define who 'fxbit-field) (if (fixnum? x) (if (fixnum? i) (if ($fx<= 0 i) (if (fixnum? j) (if ($fx< j (fixnum-width)) (if ($fx<= i j) ($fxsra ($fxlogand x ($fxsub1 ($fxsll 1 j))) i) (if ($fx<= 0 j) (die who "index out of range" j) (die who "indices not in order" i j))) (die who "index out of range" j)) (die who "not a fixnum" j)) (die who "index out of range" i)) (die who "not a fixnum" i)) (die who "not a fixnum" x))) ) (library (ikarus complex-numbers) (export make-rectangular $make-rectangular real-part imag-part magnitude) (import (except (ikarus) make-rectangular real-part imag-part magnitude) (except (ikarus system $compnums) $make-rectangular)) (define ($make-rectangular r i) ;;; should be called with 2 exacts or two inexacts (if (flonum? i) (if (fl=? i 0.0) r ($make-cflonum r i)) (if (eqv? i 0) r ($make-compnum r i)))) (define (make-rectangular r i) (define who 'make-rectangular) (define (err x) (die who "invalid argument" x)) (cond [(flonum? i) (cond [(flonum? r) ($make-rectangular r i)] [(or (fixnum? r) (bignum? r) (ratnum? r)) ($make-rectangular (inexact r) i)] [else (err r)])] [(or (fixnum? i) (bignum? i) (ratnum? i)) (cond [(or (fixnum? r) (bignum? r) (ratnum? r)) ($make-rectangular r i)] [(flonum? r) ($make-rectangular r (inexact i))] [else (err r)])] [else (err i)])) (define magnitude (lambda (x) (cond [(or (fixnum? x) (bignum? x) (ratnum? x) (flonum? x)) (abs x)] [(compnum? x) (let ([r ($compnum-real x)] [i ($compnum-imag x)]) (sqrt (+ (* r r) (* i i))))] [(cflonum? x) (let ([r ($cflonum-real x)] [i ($cflonum-imag x)]) (sqrt (+ (* r r) (* i i))))] [else (die 'magnitude "not a number" x)]))) (define real-part (lambda (x) (cond [(fixnum? x) x] [(bignum? x) x] [(ratnum? x) x] [(flonum? x) x] [(compnum? x) ($compnum-real x)] [(cflonum? x) ($cflonum-real x)] [else (die 'real-part "not a number" x)]))) (define imag-part (lambda (x) (cond [(fixnum? x) 0] [(bignum? x) 0] [(ratnum? x) 0] [(flonum? x) 0.0] [(compnum? x) ($compnum-imag x)] [(cflonum? x) ($cflonum-imag x)] [else (die 'imag-part "not a number" x)]))) )