reader: fix imprecision reading some flonums
Reading `1.0e45` produced a different (and less precise) result than `1e35`. The problem was in the reader's fast path for simple flonum conversions, where it converts the mantissa and exponent separately and then combines them. 10^44 is not represented exactly as a flonum, so there's imprecision when multiplicy it by 10 versus multiplying 1e45 by 1. Closes #3548
This commit is contained in:
parent
986c73244e
commit
0561d71e60
|
@ -2652,6 +2652,9 @@
|
|||
(test 10.0 string->number (string-append "1" (make-string 8000 #\0) "/" "1" (make-string 7998 #\0) "#@0"))
|
||||
(test #f zero? (string->number "7.4109846876187e-323"))
|
||||
|
||||
;; Regression test to make sure prevision isn't lost by multiplying 10.0 times 1e44:
|
||||
(test (exact->inexact #e1e45) string->number "1.0e45")
|
||||
|
||||
(test #t andmap (lambda (x) (and (>= x 0) (< x 10))) (map random '(10 10 10 10)))
|
||||
(test (void) random-seed 5)
|
||||
(test (begin (random-seed 23) (list (random 10) (random 20) (random 30)))
|
||||
|
|
|
@ -56049,8 +56049,14 @@ static const char *startup_source =
|
|||
"(let-values()(if(fx= sgn_0 1) 0.0(- 0.0)))"
|
||||
"(if(if(fixnum? n_0)(if(< n_0(expt 2 50))(> n_0(-(expt 2 50))) #f) #f)"
|
||||
"(let-values()"
|
||||
"(let-values(((exp_1)(+ exp_0(* sgn2_0 exp2_0)))"
|
||||
"((m_0)(fx->fl(if(fx= sgn_0 -1)(fx- 0 n_0) n_0))))"
|
||||
"(let-values(((exp_1)(+ exp_0(* sgn2_0 exp2_0))))"
|
||||
"(if(if(fixnum? exp_1)"
|
||||
"(if(fx<= radix_0 10)"
|
||||
"(let-values()(fx<= -15 exp_1 15))"
|
||||
"(let-values()(fx<= -12 exp_1 12)))"
|
||||
" #f)"
|
||||
"(let-values()"
|
||||
"(let-values(((m_0)(fx->fl(if(fx= sgn_0 -1)(fx- 0 n_0) n_0))))"
|
||||
"(if(eqv? exp_1 0)"
|
||||
"(let-values() m_0)"
|
||||
"(if(not(fixnum? exp_1))"
|
||||
|
@ -56058,11 +56064,9 @@ static const char *startup_source =
|
|||
"(let-values()"
|
||||
"(let-values(((fradix_0)(if(fx= radix_0 10) 10.0(fx->fl radix_0))))"
|
||||
"(if(fx< exp_1 0)"
|
||||
"(let-values()"
|
||||
"(if(fx> exp_1(if(fx<= radix_0 10)(let-values() -300)(let-values() -240)))"
|
||||
"(/ m_0(expt fradix_0(fx- 0 exp_1)))"
|
||||
" #f))"
|
||||
"(let-values()(/ m_0(expt fradix_0(fx- 0 exp_1))))"
|
||||
"(let-values()(* m_0(expt fradix_0 exp_1))))))))))"
|
||||
"(let-values() #f))))"
|
||||
"(let-values() #f)))))"
|
||||
"(let-values() #f))))))"
|
||||
"(define-values"
|
||||
|
|
|
@ -64606,22 +64606,25 @@
|
|||
(if (< n_0 1125899906842624) (> n_0 -1125899906842624) #f)
|
||||
#f)
|
||||
(let ((exp_1 (+ exp_0 (* sgn2_0 exp2_0))))
|
||||
(let ((m_0
|
||||
(unsafe-fx->fl (if (fx= sgn_0 -1) (fx- 0 n_0) n_0))))
|
||||
(let ((exp_2 exp_1))
|
||||
(if (eqv? exp_2 0)
|
||||
(if (if (fixnum? exp_1)
|
||||
(if (fx<= radix_0 10)
|
||||
(fx<= -15 exp_1 15)
|
||||
(fx<= -12 exp_1 12))
|
||||
#f)
|
||||
(let ((m_0
|
||||
(unsafe-fx->fl (if (fx= sgn_0 -1) (fx- 0 n_0) n_0))))
|
||||
(if (eqv? exp_1 0)
|
||||
m_0
|
||||
(if (not (fixnum? exp_2))
|
||||
(if (not (fixnum? exp_1))
|
||||
#f
|
||||
(let ((fradix_0
|
||||
(if (fx= radix_0 10)
|
||||
10.0
|
||||
(unsafe-fx->fl radix_0))))
|
||||
(if (fx< exp_2 0)
|
||||
(if (fx> exp_2 (if (fx<= radix_0 10) -300 -240))
|
||||
(/ m_0 (expt fradix_0 (fx- 0 exp_2)))
|
||||
#f)
|
||||
(* m_0 (expt fradix_0 exp_2)))))))))
|
||||
(if (fx< exp_1 0)
|
||||
(/ m_0 (expt fradix_0 (fx- 0 exp_1)))
|
||||
(* m_0 (expt fradix_0 exp_1)))))))
|
||||
#f))
|
||||
#f)))
|
||||
#f))))
|
||||
(define finish.1
|
||||
|
|
|
@ -238,28 +238,27 @@
|
|||
(n . < . (expt 2 50))
|
||||
(n . > . (- (expt 2 50))))
|
||||
;; No loss of precision in mantissa from early flonum conversion
|
||||
(let ([exp (+ exp (* sgn2 exp2))]
|
||||
[m (fx->fl (if (fx= sgn -1)
|
||||
(fx- 0 n)
|
||||
n))])
|
||||
(let ([exp (+ exp (* sgn2 exp2))])
|
||||
(cond
|
||||
[(eqv? exp 0) m]
|
||||
[(not (fixnum? exp)) #f]
|
||||
[else
|
||||
(define fradix (if (fx= radix 10)
|
||||
10.0
|
||||
(fx->fl radix)))
|
||||
(cond
|
||||
[(exp . fx< . 0)
|
||||
;; Stay well away from limits on the exponent to make
|
||||
;; sure there's still no loss of precision. We could
|
||||
;; use `(integer-length n)` to improve the bounds,
|
||||
;; but this seems good enough for the common case.
|
||||
(and (exp . fx> . (cond
|
||||
[(radix . fx<= . 10) -300]
|
||||
[else -240]))
|
||||
(/ m (expt fradix (fx- 0 exp))))]
|
||||
[else (* m (expt fradix exp))])]))]
|
||||
[(and (fixnum? exp)
|
||||
(cond
|
||||
[(radix . fx<= . 10) (fx<= -15 exp 15)]
|
||||
[else (fx<= -12 exp 12)]))
|
||||
;; No loss of precision in radix^exponent as a flonum
|
||||
(let ([m (fx->fl (if (fx= sgn -1)
|
||||
(fx- 0 n)
|
||||
n))])
|
||||
(cond
|
||||
[(eqv? exp 0) m]
|
||||
[(not (fixnum? exp)) #f]
|
||||
[else
|
||||
(define fradix (if (fx= radix 10)
|
||||
10.0
|
||||
(fx->fl radix)))
|
||||
(cond
|
||||
[(exp . fx< . 0) (/ m (expt fradix (fx- 0 exp)))]
|
||||
[else (* m (expt fradix exp))])]))]
|
||||
[else #f]))]
|
||||
[else #f])]
|
||||
[else #f]))
|
||||
|
||||
|
@ -839,7 +838,7 @@
|
|||
(try "#i+inf.f")
|
||||
(try "-inf.f")
|
||||
(try "#e+inf.0")
|
||||
(try "-inf.t")
|
||||
(when (extflonum-available?) (try "-inf.t"))
|
||||
(try "10")
|
||||
(try "10.1")
|
||||
(try "1+2i")
|
||||
|
@ -851,9 +850,9 @@
|
|||
(try "#e#x+e#s+e")
|
||||
(try "-e#l-e")
|
||||
(try "#e#x+e#s+e@-e#l-e")
|
||||
(try "3.1415926535897932385t0")
|
||||
(when (extflonum-available?) (try "3.1415926535897932385t0"))
|
||||
(try "+nan.0+1i")
|
||||
(try "3.0t0")
|
||||
(when (extflonum-available?) (try "3.0t0"))
|
||||
(try "+i")
|
||||
(try "-i")
|
||||
(try "#i3")
|
||||
|
@ -862,7 +861,7 @@
|
|||
(try "1.2+i")
|
||||
(try "1/2+3")
|
||||
(try "1.2+3")
|
||||
(try "#i1.2t0+3i")
|
||||
(when (extflonum-available?) (try "#i1.2t0+3i"))
|
||||
(try "#i-0")
|
||||
(try "#i0")
|
||||
(try "-0#")
|
||||
|
@ -885,11 +884,12 @@
|
|||
(try "1@+inf.0")
|
||||
(try "1/1@+inf.0")
|
||||
;(try "#d1/0+3.0i")
|
||||
(try "3.0t0+1/0i")
|
||||
(try "1/0+3.0t0i")
|
||||
(try "+inf.t0+1/0i")
|
||||
(try "1/0+inf.t0i")
|
||||
(try "3.#t0")
|
||||
(when (extflonum-available?)
|
||||
(try "3.0t0+1/0i")
|
||||
(try "1/0+3.0t0i")
|
||||
(try "+inf.t0+1/0i")
|
||||
(try "1/0+inf.t0i")
|
||||
(try "3.#t0"))
|
||||
(try "-1-2i")
|
||||
(try "-4.242154731064108e-5-6.865001427422244e-5i")
|
||||
(try "1e300+1e300i")
|
||||
|
|
Loading…
Reference in New Issue
Block a user