... |
... |
@@ -1785,7 +1785,7 @@ the end of the stream." |
1785
|
1785
|
;; Is there an exponent letter?
|
1786
|
1786
|
(cond ((eofp char)
|
1787
|
1787
|
;; If not, we've read the whole number.
|
1788
|
|
- (let ((num (make-float-aux number divisor
|
|
1788
|
+ (let ((num (make-float-aux 0 number divisor
|
1789
|
1789
|
*read-default-float-format*
|
1790
|
1790
|
stream)))
|
1791
|
1791
|
(return-from make-float (if negative-fraction (- num) num))))
|
... |
... |
@@ -1815,7 +1815,7 @@ the end of the stream." |
1815
|
1815
|
#+double-double
|
1816
|
1816
|
(#\W 'kernel:double-double-float)))
|
1817
|
1817
|
num)
|
1818
|
|
- (setq num (make-float-aux (* (expt 10 exponent) number) divisor
|
|
1818
|
+ (setq num (make-float-aux exponent number divisor
|
1819
|
1819
|
float-format stream))
|
1820
|
1820
|
|
1821
|
1821
|
(return-from make-float (if negative-fraction
|
... |
... |
@@ -1823,10 +1823,55 @@ the end of the stream." |
1823
|
1823
|
num))))
|
1824
|
1824
|
(t (error _"Internal error in floating point reader.")))))
|
1825
|
1825
|
|
1826
|
|
-(defun make-float-aux (number divisor float-format stream)
|
|
1826
|
+(defun make-float-aux (exponent number divisor float-format stream)
|
|
1827
|
+ ;; Computes x = number*10^exponent/divisor.
|
|
1828
|
+ ;;
|
|
1829
|
+ ;; First check to see if x can possibly fit into a float of the
|
|
1830
|
+ ;; given format. So compute log2(x) to get an approximate value of
|
|
1831
|
+ ;; the base 2 exponent of x. If it's too large or too small, we can
|
|
1832
|
+ ;; throw an error immediately. We don't need to be super accurate
|
|
1833
|
+ ;; with the limits. The rest of the code will handle it correctly,
|
|
1834
|
+ ;; even if we're too small or too large.
|
|
1835
|
+ (unless (zerop number)
|
|
1836
|
+ (flet ((fast-log2 (n)
|
|
1837
|
+ ;; For an integer, the integer-length is close enough to
|
|
1838
|
+ ;; the log2 of the number.
|
|
1839
|
+ (integer-length n)))
|
|
1840
|
+ ;; log2(x) = log(number*10^exponent/divisor)
|
|
1841
|
+ ;; = exponent*log2(10) + log2(number)-log2(divisor)
|
|
1842
|
+ (let ((log2-num (+ (* exponent #.(kernel::log2 10d0))
|
|
1843
|
+ (fast-log2 number)
|
|
1844
|
+ (- (fast-log2 divisor)))))
|
|
1845
|
+ (multiple-value-bind (log2-low log2-high)
|
|
1846
|
+ (ecase float-format
|
|
1847
|
+ ((short-float single-float)
|
|
1848
|
+ ;; Single-float exponents range is -149 to 127, but we
|
|
1849
|
+ ;; don't need to be super-accurate since we're
|
|
1850
|
+ ;; multiplying the values by 2.
|
|
1851
|
+ (values (* 2 (- vm:single-float-normal-exponent-min
|
|
1852
|
+ vm:single-float-bias
|
|
1853
|
+ vm:single-float-digits))
|
|
1854
|
+ (* 2 (- vm:single-float-normal-exponent-max
|
|
1855
|
+ vm:single-float-bias))))
|
|
1856
|
+ ((double-float long-float
|
|
1857
|
+ #+double-double kernel:double-double-float)
|
|
1858
|
+ (values (* 2 (- vm:double-float-normal-exponent-min
|
|
1859
|
+ vm:double-float-bias
|
|
1860
|
+ vm:double-float-digits))
|
|
1861
|
+ (* 2 (- vm:double-float-normal-exponent-max
|
|
1862
|
+ vm:double-float-bias)))))
|
|
1863
|
+ ;; Double-float exponent range is -1074 to -1023
|
|
1864
|
+ (unless (< log2-low log2-num log2-high)
|
|
1865
|
+ ;; The number is definitely too large or too small to fit.
|
|
1866
|
+ ;; Signal an error.
|
|
1867
|
+ (%reader-error stream _"Number not representable as a ~S: ~S"
|
|
1868
|
+ float-format (read-buffer-to-string)))))))
|
|
1869
|
+
|
|
1870
|
+ ;; Otherwise the number might fit, so we carefully compute the result
|
1827
|
1871
|
(handler-case
|
1828
|
1872
|
(with-float-traps-masked (:underflow)
|
1829
|
|
- (let* ((ratio (/ number divisor))
|
|
1873
|
+ (let* ((ratio (/ (* (expt 10 exponent) number)
|
|
1874
|
+ divisor))
|
1830
|
1875
|
(result (coerce ratio float-format)))
|
1831
|
1876
|
(when (and (zerop result) (not (zerop number)))
|
1832
|
1877
|
;; The number we've read is so small that it gets
|
... |
... |
@@ -1850,7 +1895,7 @@ the end of the stream." |
1850
|
1895
|
result))
|
1851
|
1896
|
(error ()
|
1852
|
1897
|
(%reader-error stream _"Number not representable as a ~S: ~S"
|
1853
|
|
- float-format (/ number divisor)))))
|
|
1898
|
+ float-format (read-buffer-to-string)))))
|
1854
|
1899
|
|
1855
|
1900
|
|
1856
|
1901
|
(defun make-ratio (stream)
|