diff --git a/lib/Makefile.am b/lib/Makefile.am index 7bf7eee..f17b22c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,5 +1,7 @@ libikarusdir=$(pkglibdir)/ikarus -dist_libikarus_DATA=ikarus/foreign.ss ikarus/ipc.ss ikarus/include.ss +dist_libikarus_DATA= ikarus/foreign.ss ikarus/ipc.ss \ + ikarus/include.ss \ + ikarus/flonum-parser.sls ikarus/flonum-formatter.sls libCocoadir=$(pkglibdir)/Cocoa dist_libCocoa_DATA=Cocoa/helpers.ss diff --git a/lib/Makefile.in b/lib/Makefile.in index db180c5..f31a54f 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -162,7 +162,10 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ libikarusdir = $(pkglibdir)/ikarus -dist_libikarus_DATA = ikarus/foreign.ss ikarus/ipc.ss ikarus/include.ss +dist_libikarus_DATA = ikarus/foreign.ss ikarus/ipc.ss \ + ikarus/include.ss \ + ikarus/flonum-parser.sls ikarus/flonum-formatter.sls + libCocoadir = $(pkglibdir)/Cocoa dist_libCocoa_DATA = Cocoa/helpers.ss dist_pkglib_DATA = match.ss gl.ss glut.ss \ diff --git a/lib/ikarus/flonum-formatter.sls b/lib/ikarus/flonum-formatter.sls new file mode 100644 index 0000000..5fce653 --- /dev/null +++ b/lib/ikarus/flonum-formatter.sls @@ -0,0 +1,72 @@ +;;; Copyright (c) 2009 Abdulaziz Ghuloum +;;; +;;; Permission is hereby granted, free of charge, to any person obtaining a +;;; copy of this software and associated documentation files (the "Software"), +;;; to deal in the Software without restriction, including without limitation +;;; the rights to use, copy, modify, merge, publish, distribute, sublicense, +;;; and/or sell copies of the Software, and to permit persons to whom the +;;; Software is furnished to do so, subject to the following conditions: +;;; +;;; The above copyright notice and this permission notice shall be included in +;;; all copies or substantial portions of the Software. +;;; +;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +;;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +;;; DEALINGS IN THE SOFTWARE. + +(library (ikarus flonum-formatter) + (export ikarus-format-flonum) + (import (rnrs)) + + (define (ikarus-format-flonum pos? digits expt) + (define fixnum->string number->string) + (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)))])))) diff --git a/lib/ikarus/flonum-parser.sls b/lib/ikarus/flonum-parser.sls new file mode 100644 index 0000000..e2820a8 --- /dev/null +++ b/lib/ikarus/flonum-parser.sls @@ -0,0 +1,167 @@ +;;; The code here is extracted from +;;; ``Printing Floating-Point Numbers Quickly and Accurately'' +;;; http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf +;;; It is believed to be in the public domain. +;;; The copyright below is for the R6RS implementation not part +;;; of the original work. + +;;; Copyright (c) 2009 Abdulaziz Ghuloum +;;; +;;; Permission is hereby granted, free of charge, to any person obtaining a +;;; copy of this software and associated documentation files (the "Software"), +;;; to deal in the Software without restriction, including without limitation +;;; the rights to use, copy, modify, merge, publish, distribute, sublicense, +;;; and/or sell copies of the Software, and to permit persons to whom the +;;; Software is furnished to do so, subject to the following conditions: +;;; +;;; The above copyright notice and this permission notice shall be included in +;;; all copies or substantial portions of the Software. +;;; +;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +;;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +;;; DEALINGS IN THE SOFTWARE. + + + + +;;; (parse-flonum +;;; (lambda (positive? digits:list-of-chars exponent:int) +;;; ---) +;;; (lambda (inf/nan:string) +;;; ---)) +;;; calls one of the two procedures depending on whether the +;;; number has a real value or not. + +(library (ikarus flonum-parser) + (export parse-flonum) + + (import (rnrs)) + + (define fxsll fxarithmetic-shift-left) + (define fxsra fxarithmetic-shift-right) + + (define (flonum-bytes f k) + (let ([bv (make-bytevector 8)]) + (bytevector-ieee-double-set! bv 0 f (endianness big)) + (k (bytevector-u8-ref bv 0) + (bytevector-u8-ref bv 1) + (bytevector-u8-ref bv 2) + (bytevector-u8-ref bv 3) + (bytevector-u8-ref bv 4) + (bytevector-u8-ref bv 5) + (bytevector-u8-ref bv 6) + (bytevector-u8-ref bv 7)))) + + (define (flonum-parts x) + (flonum-bytes x + (lambda (b0 b1 b2 b3 b4 b5 b6 b7) + (values + (zero? (fxand b0 128)) + (+ (fxsll (fxand b0 127) 4) + (fxsra b1 4)) + (+ (+ b7 (fxsll b6 8) (fxsll b5 16)) + (* (+ b4 + (fxsll b3 8) + (fxsll b2 16) + (fxsll (fxand b1 #b1111) 24)) + (expt 2 24))))))) + + (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 (div n 2) (+ i 1))]))) + + (define scale + (lambda (r s m+ m- k B round? f e) + (let ([est (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) (div-and-mod 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 (convert-real-flonum pos? m e p k) + (let-values ([(expt digits) (flonum->digits m e 10 p 2 10)]) + (k pos? digits expt))) + + (define (parse-flonum x k0 k1) + (assert (flonum? x)) + (assert (procedure? k0)) + (assert (procedure? k1)) + (let-values ([(pos? be m) (flonum-parts x)]) + (cond + [(<= 1 be 2046) ; normalized flonum + (convert-real-flonum pos? (+ m (expt 2 52)) (- be 1075) 53 k0)] + [(= be 0) + (convert-real-flonum pos? m -1074 52 k0)] + [(= be 2047) + (k1 (if (= m 0) (if pos? "+inf.0" "-inf.0") "+nan.0"))] + [else (error 'flonum->string "cannot happen")])))) + diff --git a/scheme/last-revision b/scheme/last-revision index 20aaf66..622f2e6 100644 --- a/scheme/last-revision +++ b/scheme/last-revision @@ -1 +1 @@ -1819 +1820