Raymond Toy pushed to branch issue-276-xoroshiro128starstar at cmucl / cmucl
Commits:
-
33cf472e
by Raymond Toy at 2024-03-08T15:31:41+00:00
-
e16b28cc
by Raymond Toy at 2024-03-08T15:31:47+00:00
-
9fee7762
by Raymond Toy at 2024-03-08T15:52:35+00:00
-
8faafb32
by Raymond Toy at 2024-03-08T15:52:37+00:00
-
0d6882c7
by Raymond Toy at 2024-03-10T20:12:37+00:00
-
34f33e19
by Raymond Toy at 2024-03-10T20:12:38+00:00
-
a2e2a586
by Raymond Toy at 2024-03-11T23:16:30+00:00
6 changed files:
- src/code/float.lisp
- src/code/reader.lisp
- src/i18n/locale/cmucl.pot
- src/lisp/gencgc.c
- src/lisp/os.h
- tests/float.lisp
Changes:
... | ... | @@ -1137,7 +1137,8 @@ |
1137 | 1137 | (floatit (ash bits -1))
|
1138 | 1138 | #+nil
|
1139 | 1139 | (progn
|
1140 | - (format t "1: f0, f1 = ~A ~A~%" f0 f1)
|
|
1140 | + (format t "x = ~A~%" x)
|
|
1141 | + (format t "1: f0, f1 = ~A~%" f0)
|
|
1141 | 1142 | (format t " scale = ~A~%" (1+ scale)))
|
1142 | 1143 |
|
1143 | 1144 | (scale-float f0 (1+ scale))))
|
... | ... | @@ -1146,14 +1147,30 @@ |
1146 | 1147 | (floatit bits)
|
1147 | 1148 | #+nil
|
1148 | 1149 | (progn
|
1149 | - (format t "2: f0, f1 = ~A ~A~%" f0 f1)
|
|
1150 | + (format t "2: f0, f1 = ~A~%" f0)
|
|
1150 | 1151 | (format t " scale = ~A~%" scale)
|
1151 | - (format t "scale-float f0 = ~A~%" (scale-float f0 scale))
|
|
1152 | - (when f1
|
|
1153 | - (format t "scale-float f1 = ~A~%"
|
|
1154 | - (scale-float f1 (- scale 53)))))
|
|
1155 | -
|
|
1156 | - (scale-float f0 scale))))))
|
|
1152 | + (format t "scale-float f0 = ~A~%" (scale-float f0 scale)))
|
|
1153 | + (let ((min-exponent
|
|
1154 | + ;; Compute the min (unbiased) exponent
|
|
1155 | + (ecase format
|
|
1156 | + (single-float
|
|
1157 | + (- vm:single-float-normal-exponent-min
|
|
1158 | + vm:single-float-bias
|
|
1159 | + vm:single-float-digits))
|
|
1160 | + (double-float
|
|
1161 | + (- vm:double-float-normal-exponent-min
|
|
1162 | + vm:double-float-bias
|
|
1163 | + vm:double-float-digits)))))
|
|
1164 | + ;; F0 is always between 0.5 and 1. If
|
|
1165 | + ;; SCALE is the min exponent, we have a
|
|
1166 | + ;; denormal number just less than the
|
|
1167 | + ;; least-positive float. We want to
|
|
1168 | + ;; return the least-positive-float so
|
|
1169 | + ;; multiply F0 by 2 (without adjusting
|
|
1170 | + ;; SCALE) to get the nearest float.
|
|
1171 | + (if (= scale min-exponent)
|
|
1172 | + (scale-float (* 2 f0) scale)
|
|
1173 | + (scale-float f0 scale))))))))
|
|
1157 | 1174 | (floatit (bits)
|
1158 | 1175 | (let ((sign (if plusp 0 1)))
|
1159 | 1176 | (case format
|
... | ... | @@ -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)
|
... | ... | @@ -8728,11 +8728,11 @@ msgid "Internal error in floating point reader." |
8728 | 8728 | msgstr ""
|
8729 | 8729 | |
8730 | 8730 | #: src/code/reader.lisp
|
8731 | -msgid "Underflow"
|
|
8731 | +msgid "Number not representable as a ~S: ~S"
|
|
8732 | 8732 | msgstr ""
|
8733 | 8733 | |
8734 | 8734 | #: src/code/reader.lisp
|
8735 | -msgid "Number not representable as a ~S: ~S"
|
|
8735 | +msgid "Underflow"
|
|
8736 | 8736 | msgstr ""
|
8737 | 8737 | |
8738 | 8738 | #: src/code/reader.lisp
|
... | ... | @@ -6756,10 +6756,9 @@ scavenge_newspace_generation_one_scan(int generation) |
6756 | 6756 | {
|
6757 | 6757 | int i;
|
6758 | 6758 | |
6759 | -#if 0
|
|
6760 | - fprintf(stderr, "Starting one full scan of newspace generation %d\n",
|
|
6761 | - generation);
|
|
6762 | -#endif
|
|
6759 | + DPRINTF(gencgc_verbose,
|
|
6760 | + (stderr, "Starting one full scan of newspace generation %d\n",
|
|
6761 | + generation));
|
|
6763 | 6762 | |
6764 | 6763 | for (i = 0; i < last_free_page; i++) {
|
6765 | 6764 | if (PAGE_ALLOCATED(i) && !PAGE_UNBOXED(i)
|
... | ... | @@ -6864,10 +6863,10 @@ scavenge_newspace_generation_one_scan(int generation) |
6864 | 6863 | i = last_page;
|
6865 | 6864 | }
|
6866 | 6865 | }
|
6867 | -#if 0
|
|
6868 | - fprintf(stderr, "Finished one full scan of newspace generation %d\n",
|
|
6869 | - generation);
|
|
6870 | -#endif
|
|
6866 | + |
|
6867 | + DPRINTF(gencgc_verbose,
|
|
6868 | + (stderr, "Finished one full scan of newspace generation %d\n",
|
|
6869 | + generation));
|
|
6871 | 6870 | }
|
6872 | 6871 | |
6873 | 6872 | /* Scan all weak objects and reset weak object lists */
|
... | ... | @@ -6896,9 +6895,8 @@ scavenge_newspace_generation(int generation) |
6896 | 6895 | struct new_area (*previous_new_areas)[] = NULL;
|
6897 | 6896 | int previous_new_areas_index;
|
6898 | 6897 | |
6899 | -#if 0
|
|
6900 | - fprintf(stderr, "Start scavenge_newspace_generation %d\n", generation);
|
|
6901 | -#endif
|
|
6898 | + DPRINTF(gencgc_verbose,
|
|
6899 | + (stderr, "Start scavenge_newspace_generation %d\n", generation));
|
|
6902 | 6900 | |
6903 | 6901 | #define SC_NS_GEN_CK 0
|
6904 | 6902 | #if SC_NS_GEN_CK
|
... | ... | @@ -7078,9 +7076,9 @@ scavenge_newspace_generation(int generation) |
7078 | 7076 | "*** scav.new.gen. %d: write protected page %d written to? dont_move=%d\n",
|
7079 | 7077 | generation, i, PAGE_DONT_MOVE(i));
|
7080 | 7078 | #endif
|
7081 | -#if 0
|
|
7082 | - fprintf(stderr, "Finished scavenge_newspace_generation %d\n", generation);
|
|
7083 | -#endif
|
|
7079 | + |
|
7080 | + DPRINTF(gencgc_verbose,
|
|
7081 | + (stderr, "Finished scavenge_newspace_generation %d\n", generation));
|
|
7084 | 7082 | }
|
7085 | 7083 |
|
7086 | 7084 | |
... | ... | @@ -7839,20 +7837,26 @@ garbage_collect_generation(int generation, int raise) |
7839 | 7837 | scavenge_control_stack();
|
7840 | 7838 | #endif
|
7841 | 7839 | |
7840 | + DPRINTF(gencgc_verbose,
|
|
7841 | + (stderr, "Scavenging interrupt handlers ...\n"));
|
|
7842 | + |
|
7842 | 7843 | scavenge_interrupt_handlers();
|
7843 | 7844 | |
7844 | -#ifdef PRINTNOISE
|
|
7845 | - printf("Scavenging the binding stack (%d bytes) ...\n",
|
|
7846 | - ((lispobj *) get_binding_stack_pointer() -
|
|
7847 | - binding_stack) * sizeof(lispobj));
|
|
7848 | -#endif
|
|
7845 | + DPRINTF(gencgc_verbose,
|
|
7846 | + (stderr, "Done scavenging interrupt handlers\n"));
|
|
7847 | + |
|
7848 | + DPRINTF(gencgc_verbose,
|
|
7849 | + (stderr, "Scavenging the binding stack (%d bytes) ...\n",
|
|
7850 | + ((lispobj *) get_binding_stack_pointer() -
|
|
7851 | + binding_stack) * sizeof(lispobj)));
|
|
7852 | + |
|
7849 | 7853 | /* Scavenge the binding stack. */
|
7850 | 7854 | scavenge(binding_stack,
|
7851 | 7855 | (lispobj *) get_binding_stack_pointer() - binding_stack);
|
7852 | 7856 | |
7853 | -#ifdef PRINTNOISE
|
|
7854 | - printf("Done scavenging the binding stack.\n");
|
|
7855 | -#endif
|
|
7857 | + DPRINTF(gencgc_verbose,
|
|
7858 | + (stderr, "Done scavenging the binding stack.\n"));
|
|
7859 | + |
|
7856 | 7860 | /*
|
7857 | 7861 | * Scavenge the scavenge_hooks in case this refers to a hook added
|
7858 | 7862 | * in a prior generation GC. From here on the scavenger_hook will
|
... | ... | @@ -7860,30 +7864,44 @@ garbage_collect_generation(int generation, int raise) |
7860 | 7864 | * doing here.
|
7861 | 7865 | */
|
7862 | 7866 | |
7863 | -#ifdef PRINTNOISE
|
|
7864 | - printf("Scavenging the scavenger hooks ...\n");
|
|
7865 | -#endif
|
|
7867 | + DPRINTF(gencgc_verbose,
|
|
7868 | + (stderr, "Scavenging the scavenger hooks ...\n"));
|
|
7869 | + |
|
7866 | 7870 | scavenge(&scavenger_hooks, 1);
|
7867 | -#ifdef PRINTNOISE
|
|
7868 | - printf("Done scavenging the scavenger hooks.\n");
|
|
7869 | -#endif
|
|
7871 | + |
|
7872 | + DPRINTF(gencgc_verbose,
|
|
7873 | + (stderr, "Done scavenging the scavenger hooks.\n"));
|
|
7870 | 7874 | |
7871 | 7875 | static_space_size = (lispobj *) SymbolValue(STATIC_SPACE_FREE_POINTER)
|
7872 | 7876 | - static_space;
|
7873 | - if (gencgc_verbose > 1)
|
|
7874 | - fprintf(stderr, "Scavenge static space: %ld bytes\n",
|
|
7875 | - static_space_size * sizeof(lispobj));
|
|
7877 | + |
|
7878 | + DPRINTF(gencgc_verbose,
|
|
7879 | + (stderr, "Scavenge static space: %ld bytes\n",
|
|
7880 | + static_space_size * sizeof(lispobj)));
|
|
7881 | + |
|
7876 | 7882 | scavenge(static_space, static_space_size);
|
7877 | 7883 | |
7884 | + DPRINTF(gencgc_verbose,
|
|
7885 | + (stderr, "Done scavenging static space\n"));
|
|
7886 | + |
|
7878 | 7887 | /*
|
7879 | 7888 | * All generations but the generation being GCed need to be
|
7880 | 7889 | * scavenged. The new_space generation needs special handling as
|
7881 | 7890 | * objects may be moved in - it is handle separately below.
|
7882 | 7891 | */
|
7883 | - for (i = 0; i < NUM_GENERATIONS; i++)
|
|
7884 | - if (i != generation && i != new_space)
|
|
7892 | + for (i = 0; i < NUM_GENERATIONS; i++) {
|
|
7893 | + if (i != generation && i != new_space) {
|
|
7894 | + DPRINTF(gencgc_verbose,
|
|
7895 | + (stderr, "Scavenge generation %lu (gen = %d, new space = %d)\n",
|
|
7896 | + i, generation, new_space));
|
|
7897 | + |
|
7885 | 7898 | scavenge_generation(i);
|
7886 | 7899 | |
7900 | + DPRINTF(gencgc_verbose,
|
|
7901 | + (stderr, "Done scavenging generation %lu\n", i));
|
|
7902 | + }
|
|
7903 | + }
|
|
7904 | + |
|
7887 | 7905 | /*
|
7888 | 7906 | * Finally scavenge the new_space generation. Keep going until no
|
7889 | 7907 | * more objects are moved into the new generation.
|
... | ... | @@ -8,7 +8,13 @@ |
8 | 8 | |
9 | 9 | #include "lisp.h"
|
10 | 10 | |
11 | -#define DPRINTF(t,a) { if (t) fprintf a; }
|
|
11 | +#if defined(__GNUC__) || defined(__clang__)
|
|
12 | +#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
|
13 | +#else
|
|
14 | +#define UNLIKELY(x) (x)
|
|
15 | +#endif
|
|
16 | + |
|
17 | +#define DPRINTF(t,a) { if (UNLIKELY(t)) fprintf a; }
|
|
12 | 18 | |
13 | 19 | #ifdef DARWIN
|
14 | 20 | #include "Darwin-os.h"
|
... | ... | @@ -136,5 +136,79 @@ |
136 | 136 | (ext:with-float-traps-masked (:overflow)
|
137 | 137 | (* 100 most-negative-double-float)))))
|
138 | 138 | |
139 | -
|
|
140 | - |
|
\ No newline at end of file | ||
139 | +(define-test float-ratio.single
|
|
140 | + (:tag :issues)
|
|
141 | + ;; least-positive-single-float is 1.4012985e-45. Let's test with
|
|
142 | + ;; some rationals from 7/10*10^-45 to 1.41*10^-45 to make sure they
|
|
143 | + ;; return 0 or least-positive-single-float
|
|
144 | + (let ((expo (expt 10 -45)))
|
|
145 | + ;; Need to make sure underflows are masked.
|
|
146 | + (kernel::with-float-traps-masked (:underflow)
|
|
147 | + ;; 7/10*10^-45 is just under halfway between 0 and least-positive,
|
|
148 | + ;; so the answer is 0.
|
|
149 | + (assert-equal 0f0 (kernel::float-ratio-float (* 7/10 expo) 'single-float))
|
|
150 | + |
|
151 | + ;; These are all more than half way to
|
|
152 | + ;; least-positive-single-float, so they should return that.
|
|
153 | + (assert-equal least-positive-single-float
|
|
154 | + (kernel::float-ratio-float (* 8/10 expo) 'single-float))
|
|
155 | + (assert-equal least-positive-single-float
|
|
156 | + (kernel::float-ratio-float (* 1 expo) 'single-float))
|
|
157 | + (assert-equal least-positive-single-float
|
|
158 | + (kernel::float-ratio-float (* 14/10 expo) 'single-float))
|
|
159 | + (assert-equal least-positive-single-float
|
|
160 | + (kernel::float-ratio-float (* 2 expo) 'single-float)))))
|
|
161 | + |
|
162 | +(define-test float-ratio.double
|
|
163 | + (:tag :issues)
|
|
164 | + ;; least-positive-double-float is 4.9406564584124654d-324. Let's
|
|
165 | + ;; test with some rationals from about 2*10^-324 to 4.94*10^-324 to make
|
|
166 | + ;; sure they return 0 or least-positive-double-float
|
|
167 | + (let ((expo (expt 10 -324)))
|
|
168 | + ;; Need to make sure underflows are masked.
|
|
169 | + (kernel::with-float-traps-masked (:underflow)
|
|
170 | + ;; 247/100*10^-324 is just under halfway between 0 and least-positive,
|
|
171 | + ;; so the answer is 0.
|
|
172 | + (assert-equal 0d0 (kernel::float-ratio-float (* 247/100 expo) 'double-float))
|
|
173 | + |
|
174 | + ;; These are all more than half way to
|
|
175 | + ;; least-positive-double-float, so they should return that.
|
|
176 | + (assert-equal least-positive-double-float
|
|
177 | + (kernel::float-ratio-float (* 248/100 expo) 'double-float))
|
|
178 | + (assert-equal least-positive-double-float
|
|
179 | + (kernel::float-ratio-float (* 4 expo) 'double-float))
|
|
180 | + (assert-equal least-positive-double-float
|
|
181 | + (kernel::float-ratio-float (* 494/100 expo) 'double-float))
|
|
182 | + (assert-equal least-positive-double-float
|
|
183 | + (kernel::float-ratio-float (* 988/100 expo) 'double-float)))))
|
|
184 | +
|
|
185 | +(define-test reader-error.small-single-floats
|
|
186 | + (:tag :issues)
|
|
187 | + ;; Test a number less than half of least-positive-single-float,
|
|
188 | + ;; something a bit smaller, hen then something really small that
|
|
189 | + ;; used to appear to hang cmucl because it was trying to compute the
|
|
190 | + ;; a rational with a huge number of digits.
|
|
191 | + (dolist (num '("1e-46" "1e-80" "1e-999999999"))
|
|
192 | + (assert-error 'reader-error (read-from-string num)
|
|
193 | + num)))
|
|
194 | + |
|
195 | +(define-test reader-error.small-double-floats
|
|
196 | + (:tag :issues)
|
|
197 | + ;; Like reader-error.small-single-floats but for doubles
|
|
198 | + (dolist (num '("1d-324" "1d-600" "1d-999999999"))
|
|
199 | + (assert-error 'reader-error (read-from-string num)
|
|
200 | + num)))
|
|
201 | + |
|
202 | +(define-test reader-error.big-single-floats
|
|
203 | + (:tag :issues)
|
|
204 | + ;; Signal error for a number just a bit larger than
|
|
205 | + ;; most-positive-single-float. And a really big single-float.
|
|
206 | + (assert-error 'reader-error (read-from-string "3.5e38"))
|
|
207 | + (assert-error 'reader-error (read-from-string "1e999999999")))
|
|
208 | + |
|
209 | +(define-test reader-error.big-double-floats
|
|
210 | + (:tag :issues)
|
|
211 | + ;; Signal error for a number just a bit larger than
|
|
212 | + ;; most-positive-double-float. And a really big single-float.
|
|
213 | + (assert-error 'reader-error (read-from-string "1.8d308"))
|
|
214 | + (assert-error 'reader-error (read-from-string "1d999999999"))) |