Raymond Toy pushed to branch issue-425-correctly-rounded-math-functions at cmucl / cmucl
Commits:
-
4660c011
by Raymond Toy at 2025-08-14T07:40:17-07:00
-
6a2028c5
by Raymond Toy at 2025-08-14T07:40:17-07:00
-
cb874f7f
by Raymond Toy at 2025-08-14T07:42:48-07:00
-
d2c96f1b
by Raymond Toy at 2025-08-14T07:45:18-07:00
-
2db294b1
by Raymond Toy at 2025-08-14T07:45:18-07:00
-
eb98570f
by Raymond Toy at 2025-08-14T07:55:12-07:00
-
65050c00
by Raymond Toy at 2025-08-18T18:37:51-07:00
-
cd2edae5
by Raymond Toy at 2025-08-19T14:16:31-07:00
-
c65554a5
by Raymond Toy at 2025-08-19T14:16:31-07:00
-
633e64a4
by Raymond Toy at 2025-09-05T07:55:14-07:00
-
7ab74e13
by Raymond Toy at 2025-09-05T07:55:15-07:00
-
62235089
by Raymond Toy at 2025-09-12T08:51:26-07:00
-
61592012
by Raymond Toy at 2025-09-16T17:50:14-07:00
-
4dd79bc9
by Raymond Toy at 2025-09-16T17:50:15-07:00
-
69a8a4b6
by Raymond Toy at 2025-09-16T19:43:12-07:00
-
fb29eb6e
by Raymond Toy at 2025-09-17T08:32:41-07:00
-
d537a8a3
by Raymond Toy at 2025-09-17T08:32:41-07:00
-
131d10d8
by Raymond Toy at 2025-09-17T12:13:35-07:00
16 changed files:
- .gitlab-ci.yml
- bin/make-dist.sh
- + src/bootfiles/21e/boot-2025-07.lisp
- src/code/float-trap.lisp
- src/code/irrat.lisp
- src/code/unix.lisp
- src/code/x86-vm.lisp
- src/compiler/x86/float-sse2.lisp
- src/compiler/x86/parms.lisp
- src/general-info/release-21f.md
- src/i18n/locale/cmucl-x86-vm.pot
- src/lisp/GNUmakefile
- + src/lisp/e_hypot.c
- + tests/float-x86.lisp
- tests/float.lisp
- tests/irrat.lisp
Changes:
1 | 1 | variables:
|
2 | 2 | year: "2025"
|
3 | - month: "07"
|
|
3 | + month: "09"
|
|
4 | 4 | download_url: "https://common-lisp.net/project/cmucl/downloads/snapshots/$year/$month"
|
5 | 5 | version: "$year-$month-x86"
|
6 | 6 | tar_ext: "xz"
|
... | ... | @@ -189,7 +189,7 @@ GTAR_OPTS="-t ${GTAR:-tar}" |
189 | 189 | EXTRA_OPTS="${GROUP:+ -G ${GROUP}} ${OWNER:+ -O ${OWNER}}"
|
190 | 190 | INSTALL_OPTS="${INSTALL_DIR:+ -I ${INSTALL_DIR}}"
|
191 | 191 | MANDIR="${MANDIR:+ -M ${MANDIR}}"
|
192 | -OPTIONS="${GTAR_OPTS} ${EXTRA_OPTS} ${INSTALL_OPTS} ${MANDIR}"
|
|
192 | +OPTIONS="${GTAR_OPTS} ${EXTRA_OPTS} ${INSTALL_OPTS}"
|
|
193 | 193 | |
194 | 194 | set -x
|
195 | 195 | echo Creating distribution for $ARCH $OS
|
1 | +;; Bootstrap file to define some constants we use early in the build.
|
|
2 | + |
|
3 | +(in-package :x86)
|
|
4 | + |
|
5 | +(defconstant x87-float-infinity-control-byte
|
|
6 | + (byte 1 (+ 12 16))
|
|
7 | + "The bit in the x87 FPU control word that controls the infinity mode.")
|
|
8 | +(defconstant x87-float-rounding-mode
|
|
9 | + (byte 2 (+ 10 16))
|
|
10 | + "The bits in the x87 FPU control word for the rounding mode.")
|
|
11 | +(defconstant x87-float-precision-control-byte
|
|
12 | + (byte 2 (+ 8 16))
|
|
13 | + "The bits in the x87 FPU contol word for the FP operation precision.")
|
|
14 | +(defconstant x87-float-traps-byte
|
|
15 | + (byte 6 16)
|
|
16 | + "The bits in the x87 FPU control word indicating the exceptions that
|
|
17 | + are enabled.")
|
|
18 | +(defconstant x87-float-precision-control-alist
|
|
19 | + `((:24-bits . 0)
|
|
20 | + (:reserved . 1)
|
|
21 | + (:53-bits . 2)
|
|
22 | + (:64-bits . 3))
|
|
23 | + "Alist for the x87 precison control. The car is the symbolic
|
|
24 | + precision and the cdr is the value for the precision control field.")
|
|
25 | + |
... | ... | @@ -114,21 +114,24 @@ |
114 | 114 | ;; Set the floating point modes for both X87 and SSE2. This
|
115 | 115 | ;; include the rounding control bits.
|
116 | 116 | (let* ((rc (ldb float-rounding-mode new-mode))
|
117 | - (new-exceptions (logand #x3f new-mode))
|
|
118 | - (new-enables (logand #x3f (ash new-mode -7)))
|
|
119 | - (x87-modes
|
|
120 | - (logior new-exceptions
|
|
121 | - (ash rc 10)
|
|
122 | - (ash new-enables 16)
|
|
123 | - ;; Set precision control to be 64-bit, always. We
|
|
124 | - ;; don't use the x87 registers with sse2, so this
|
|
125 | - ;; is ok and would be the correct setting if we
|
|
126 | - ;; ever support long-floats.
|
|
127 | - (ash 3 (+ 8 16)))))
|
|
128 | - (setf (vm::sse2-floating-point-modes) (ldb (byte 24 0) new-mode))
|
|
129 | - (setf (vm::x87-floating-point-modes) (ldb (byte 24 0) x87-modes)))
|
|
130 | - new-mode)
|
|
131 | - )
|
|
117 | + (new-exceptions (ldb float-exceptions-byte new-mode))
|
|
118 | + (new-enables (ldb float-traps-byte new-mode))
|
|
119 | + (x87-modes 0))
|
|
120 | + ;; From the new mode, update the x87 FPU mode with the same set
|
|
121 | + ;; of accrued exceptions, enabled exceptions, and rounding mode.
|
|
122 | + (setf x87-modes (dpb new-exceptions float-exceptions-byte x87-modes))
|
|
123 | + (setf x87-modes (dpb new-enables x87-float-traps-byte x87-modes))
|
|
124 | + (setf x87-modes (dpb rc x87-float-rounding-mode x87-modes))
|
|
125 | + |
|
126 | + ;; Set precision to 64-bits (double-extended).
|
|
127 | + (setf x87-modes
|
|
128 | + (dpb (cdr (assoc :64-bits x87-float-precision-control-alist))
|
|
129 | + x87-float-precision-control-byte
|
|
130 | + x87-modes))
|
|
131 | + |
|
132 | + (setf (vm::sse2-floating-point-modes) (ldb (byte 16 0) new-mode))
|
|
133 | + (setf (vm::x87-floating-point-modes) (ldb (byte 30 0) x87-modes)))
|
|
134 | + new-mode))
|
|
132 | 135 | |
133 | 136 | #+(and sse2 darwin)
|
134 | 137 | (progn
|
... | ... | @@ -121,7 +121,7 @@ |
121 | 121 | (def-math-rtn ("__ieee754_pow" %pow) 2)
|
122 | 122 | #-(or x86 sparc-v7 sparc-v8 sparc-v9)
|
123 | 123 | (def-math-rtn "sqrt" 1)
|
124 | -(def-math-rtn "hypot" 2)
|
|
124 | +(def-math-rtn ("__ieee754_hypot" %hypot) 2)
|
|
125 | 125 | |
126 | 126 | (def-math-rtn ("fdlibm_log1p" %log1p) 1)
|
127 | 127 | (def-math-rtn ("fdlibm_expm1" %expm1) 1)
|
... | ... | @@ -2166,7 +2166,7 @@ |
2166 | 2166 | |
2167 | 2167 | #+linux
|
2168 | 2168 | (defun unix-getpwuid (uid)
|
2169 | - "Return a USER-INFO structure for the user identified by UID. If
|
|
2169 | + _N"Return a USER-INFO structure for the user identified by UID. If
|
|
2170 | 2170 | not found, NIL is returned with a second value indicating the cause
|
2171 | 2171 | of the failure. In particular, if the second value is 0 (or
|
2172 | 2172 | ENONENT, ESRCH, EBADF, etc.), then the uid was not found."
|
... | ... | @@ -733,3 +733,88 @@ |
733 | 733 | (multiple-value-bind (fop dst src)
|
734 | 734 | (get-fp-operation scp)
|
735 | 735 | (values fop (list dst src))))
|
736 | + |
|
737 | +;; See src/compiler/x86/float-sse2.lisp for a description of the x87
|
|
738 | +;; control and status words.
|
|
739 | + |
|
740 | +(defconstant x87-float-infinity-control-byte
|
|
741 | + (byte 1 (+ 12 16))
|
|
742 | + "The bit in the x87 FPU control word that controls the infinity mode.")
|
|
743 | + |
|
744 | +(defconstant x87-float-rounding-mode
|
|
745 | + (byte 2 (+ 10 16))
|
|
746 | + "The bits in the x87 FPU control word for the rounding mode.")
|
|
747 | + |
|
748 | +(defconstant x87-float-precision-control-byte
|
|
749 | + (byte 2 (+ 8 16))
|
|
750 | + "The bits in the x87 FPU contol word for the FP operation precision.")
|
|
751 | + |
|
752 | +(defconstant x87-float-traps-byte
|
|
753 | + (byte 6 16)
|
|
754 | + "The bits in the x87 FPU control word indicating the exceptions that
|
|
755 | + are enabled.")
|
|
756 | + |
|
757 | +(defconstant x87-float-precision-control-alist
|
|
758 | + `((:24-bits . 0)
|
|
759 | + (:reserved . 1)
|
|
760 | + (:53-bits . 2)
|
|
761 | + (:64-bits . 3))
|
|
762 | + "Alist for the x87 precison control. The car is the symbolic
|
|
763 | + precision and the cdr is the value for the precision control field.")
|
|
764 | + |
|
765 | +(defun print-fp-exceptions-enabled (enabled)
|
|
766 | + (format t "Precision enable: ~30T~A~%" (ldb (byte 1 5) enabled))
|
|
767 | + (format t "Underflow enable: ~30T~A~%" (ldb (byte 1 4) enabled))
|
|
768 | + (format t "Overflow enable: ~30T~A~%" (ldb (byte 1 3) enabled))
|
|
769 | + (format t "Divide-by-zero enable: ~30T~A~%" (ldb (byte 1 2) enabled))
|
|
770 | + (format t "Denormal op enable: ~30T~A~%" (ldb (byte 1 1) enabled))
|
|
771 | + (format t "Invalid op enable: ~30T~A~%" (ldb (byte 1 0) enabled)))
|
|
772 | + |
|
773 | +(defun print-fp-current-exceptions (current)
|
|
774 | + (format t "Precision flag: ~30T~A~%" (ldb (byte 1 5) current))
|
|
775 | + (format t "Underflow flag: ~30T~A~%" (ldb (byte 1 4) current))
|
|
776 | + (format t "Overflow flag: ~30T~A~%" (ldb (byte 1 3) current))
|
|
777 | + (format t "Divide-by-zero flag: ~30T~A~%" (ldb (byte 1 2) current))
|
|
778 | + (format t "Denormal op flag: ~30T~A~%" (ldb (byte 1 1) current))
|
|
779 | + (format t "Invalid op flag: ~30T~A~%" (ldb (byte 1 0) current)))
|
|
780 | + |
|
781 | +(defun print-sse2-fp-modes (&optional (sse-mode (sse2-floating-point-modes)))
|
|
782 | + "Print SSE2 floating modes word in a human-readable fashion."
|
|
783 | + ;; Note that Intel uses masks to disable the exception, but to match
|
|
784 | + ;; the rest of cmucl, these bits are represented as enable bits.
|
|
785 | + (format t "Flush-to-zero: ~30T~A~%" (ldb (byte 1 15) sse-mode))
|
|
786 | + (let ((rc (ldb float-rounding-mode sse-mode)))
|
|
787 | + (format t "Rounding control: ~30T#b~2,'0b ~S~%"
|
|
788 | + rc
|
|
789 | + (car (rassoc rc rounding-mode-alist))))
|
|
790 | + (print-fp-exceptions-enabled (ldb float-traps-byte sse-mode))
|
|
791 | + (print-fp-current-exceptions (ldb float-exceptions-byte sse-mode)))
|
|
792 | + |
|
793 | +(defun print-x87-fp-modes (&optional (x87-mode (x87-floating-point-modes)))
|
|
794 | + "Print X87 floating modes word in a human-readable fashion."
|
|
795 | + ;; Note that Intel uses masks to disable the exception, but to match
|
|
796 | + ;; the rest of cmucl, these bits are represented as enable bits.
|
|
797 | + (format t "Status word:~%")
|
|
798 | + (format t "FPU busy: ~30T~A~%" (ldb (byte 1 15) x87-mode))
|
|
799 | + (format t "Condition code C3: ~30T~A~%" (ldb (byte 1 14) x87-mode))
|
|
800 | + (format t "Top of stack: ~30T~D~%" (ldb (byte 3 11) x87-mode))
|
|
801 | + (format t "Condition code C2: ~30T~A~%" (ldb (byte 1 10) x87-mode))
|
|
802 | + (format t "Condition code C1: ~30T~A~%" (ldb (byte 1 9) x87-mode))
|
|
803 | + (format t "Condition code C0: ~30T~A~%" (ldb (byte 1 8) x87-mode))
|
|
804 | + (format t "Error summary: ~30T~A~%" (ldb (byte 1 7) x87-mode))
|
|
805 | + (format t "Stack fault: ~30T~A~%" (ldb (byte 1 6) x87-mode))
|
|
806 | + (print-fp-current-exceptions (ldb float-exceptions-byte x87-mode))
|
|
807 | + (format t "~%Control word:~%")
|
|
808 | + (format t "Reserved: ~30T#b~2,'0b~%" (ldb (byte 2 (+ 13 16)) x87-mode))
|
|
809 | + (format t "Infinity control: ~30T~A~%" (ldb x87-float-infinity-control-byte x87-mode))
|
|
810 | + (let ((rc (ldb x87-float-rounding-mode x87-mode)))
|
|
811 | + (format t "Rounding control: ~30T#b~2,'0b ~S~%"
|
|
812 | + rc
|
|
813 | + (car (rassoc rc rounding-mode-alist))))
|
|
814 | + (let ((pc (ldb x87-float-precision-control-byte x87-mode)))
|
|
815 | + (format t "Precision control: ~30T#b~2,'0b ~S~%"
|
|
816 | + pc
|
|
817 | + (car (rassoc pc x87-float-precision-control-alist))))
|
|
818 | + (format t "Reserved: ~30T#b~2,'0b~%" (ldb (byte 2 (+ 6 16)) x87-mode))
|
|
819 | + (print-fp-exceptions-enabled (ldb x87-float-traps-byte x87-mode)))
|
|
820 | + |
... | ... | @@ -1288,6 +1288,10 @@ |
1288 | 1288 | ;; 0 invalid operation flag
|
1289 | 1289 | ;;
|
1290 | 1290 | ;; See below for rounding control
|
1291 | +;;
|
|
1292 | +;; Also see float-rounding-mode, float-sticky-bits, float-traps-byte,
|
|
1293 | +;; and float-exceptions-byte in compiler/x86/parms.lisp.
|
|
1294 | + |
|
1291 | 1295 | (defknown sse2-floating-point-modes () float-modes (flushable))
|
1292 | 1296 | (defknown ((setf sse2-floating-point-modes)) (float-modes) float-modes)
|
1293 | 1297 |
... | ... | @@ -205,9 +205,15 @@ |
205 | 205 | ;; need to do it this way because the interface assumes the modes are
|
206 | 206 | ;; in the same order as the MXCSR register.
|
207 | 207 | (defconstant float-rounding-mode (byte 2 13))
|
208 | -(defconstant float-sticky-bits (byte 6 0))
|
|
209 | -(defconstant float-traps-byte (byte 6 7))
|
|
210 | -(defconstant float-exceptions-byte (byte 6 0))
|
|
208 | +(defconstant float-sticky-bits (byte 6 0)
|
|
209 | + "The bits in the FP mode that hold the accrued exceptions that have
|
|
210 | + occurred since the bits were reset.")
|
|
211 | +(defconstant float-traps-byte (byte 6 7)
|
|
212 | + "The bits in the FP mode that hold FP exceptions that are enabled.")
|
|
213 | +(defconstant float-exceptions-byte (byte 6 0)
|
|
214 | + "The bits in the FP mode that hold the current exception. However
|
|
215 | + for x86, there aren't separate bits for this, so we use the stick
|
|
216 | + bits from the accrued exceptions")
|
|
211 | 217 | |
212 | 218 | (progn
|
213 | 219 | ;; SSE2 has a flush-to-zero flag, which we use as the fast bit. Some
|
... | ... | @@ -123,6 +123,7 @@ public domain. |
123 | 123 | * #375 `unix-mkstemp` and `unix-mkdtemp` actually returns the
|
124 | 124 | file names now.
|
125 | 125 | * #379 Support GNU-style command-line option names
|
126 | + * #381 cmucl-unix.pot depends on OS
|
|
126 | 127 | * #382 Command-line options are case-sensitive
|
127 | 128 | * #385 Fixed compiler warning about `%p` in Linux-os.c
|
128 | 129 | * #386 Generate `def-unix-error` forms from OS-specific files.
|
... | ... | @@ -137,6 +138,10 @@ public domain. |
137 | 138 | * #417 PCL complains about repeated aux variables in defmethod
|
138 | 139 | * #418 Update asdf to version 3.3.7.4 (for
|
139 | 140 | package-local-nicknames)
|
141 | + * #424 Use fdlibm `hypot` to fix bug in snapshot 2025-07
|
|
142 | + * #426 Define float-modes type correctly for `(setf (x87-set-floating-point-modes))`
|
|
143 | + * #431 Fix setting of x87 FP modes in `set-floating-point-modes`
|
|
144 | + * #432 `make-dist.sh` passes `-M` to `make-extra-dist.sh` which doesn't accept `-M` option.
|
|
140 | 145 | * Other changes:
|
141 | 146 | * Improvements to the PCL implementation of CLOS:
|
142 | 147 | * Changes to building procedure:
|
... | ... | @@ -77,6 +77,38 @@ msgstr "" |
77 | 77 | msgid "Thread safe push of val onto the list in the vector element."
|
78 | 78 | msgstr ""
|
79 | 79 | |
80 | +#: src/code/x86-vm.lisp
|
|
81 | +msgid "The bit in the x87 FPU control word that controls the infinity mode."
|
|
82 | +msgstr ""
|
|
83 | + |
|
84 | +#: src/code/x86-vm.lisp
|
|
85 | +msgid "The bits in the x87 FPU control word for the rounding mode."
|
|
86 | +msgstr ""
|
|
87 | + |
|
88 | +#: src/code/x86-vm.lisp
|
|
89 | +msgid "The bits in the x87 FPU contol word for the FP operation precision."
|
|
90 | +msgstr ""
|
|
91 | + |
|
92 | +#: src/code/x86-vm.lisp
|
|
93 | +msgid ""
|
|
94 | +"The bits in the x87 FPU control word indicating the exceptions that\n"
|
|
95 | +" are enabled."
|
|
96 | +msgstr ""
|
|
97 | + |
|
98 | +#: src/code/x86-vm.lisp
|
|
99 | +msgid ""
|
|
100 | +"Alist for the x87 precison control. The car is the symbolic\n"
|
|
101 | +" precision and the cdr is the value for the precision control field."
|
|
102 | +msgstr ""
|
|
103 | + |
|
104 | +#: src/code/x86-vm.lisp
|
|
105 | +msgid "Print SSE2 floating modes word in a human-readable fashion."
|
|
106 | +msgstr ""
|
|
107 | + |
|
108 | +#: src/code/x86-vm.lisp
|
|
109 | +msgid "Print X87 floating modes word in a human-readable fashion."
|
|
110 | +msgstr ""
|
|
111 | + |
|
80 | 112 | #: src/code/load.lisp
|
81 | 113 | msgid "Top-Level Form"
|
82 | 114 | msgstr ""
|
... | ... | @@ -136,6 +168,23 @@ msgstr "" |
136 | 168 | msgid "Maximum number of bits in a positive fixnum"
|
137 | 169 | msgstr ""
|
138 | 170 | |
171 | +#: src/compiler/x86/parms.lisp
|
|
172 | +msgid ""
|
|
173 | +"The bits in the FP mode that hold the accrued exceptions that have\n"
|
|
174 | +" occurred since the bits were reset."
|
|
175 | +msgstr ""
|
|
176 | + |
|
177 | +#: src/compiler/x86/parms.lisp
|
|
178 | +msgid "The bits in the FP mode that hold FP exceptions that are enabled."
|
|
179 | +msgstr ""
|
|
180 | + |
|
181 | +#: src/compiler/x86/parms.lisp
|
|
182 | +msgid ""
|
|
183 | +"The bits in the FP mode that hold the current exception. However\n"
|
|
184 | +" for x86, there aren't separate bits for this, so we use the stick\n"
|
|
185 | +" bits from the accrued exceptions"
|
|
186 | +msgstr ""
|
|
187 | + |
|
139 | 188 | #: src/compiler/x86/vm.lisp
|
140 | 189 | msgid "Redefining SC number ~D from ~S to ~S."
|
141 | 190 | msgstr ""
|
... | ... | @@ -28,6 +28,7 @@ FDLIBM = k_sin.c k_cos.c k_tan.c s_sin.c s_cos.c s_tan.c sincos.c \ |
28 | 28 | e_rem_pio2.c k_rem_pio2.c \
|
29 | 29 | e_log10.c s_scalbn.c \
|
30 | 30 | setexception.c \
|
31 | + e_hypot.c \
|
|
31 | 32 | log2.c
|
32 | 33 | |
33 | 34 | SRCS = lisp.c coreparse.c alloc.c monitor.c print.c interr.c \
|
1 | + |
|
2 | +/* @(#)e_hypot.c 1.3 95/01/18 */
|
|
3 | +/*
|
|
4 | + * ====================================================
|
|
5 | + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
|
6 | + *
|
|
7 | + * Developed at SunSoft, a Sun Microsystems, Inc. business.
|
|
8 | + * Permission to use, copy, modify, and distribute this
|
|
9 | + * software is freely granted, provided that this notice
|
|
10 | + * is preserved.
|
|
11 | + * ====================================================
|
|
12 | + */
|
|
13 | + |
|
14 | +/* __ieee754_hypot(x,y)
|
|
15 | + *
|
|
16 | + * Method :
|
|
17 | + * If (assume round-to-nearest) z=x*x+y*y
|
|
18 | + * has error less than sqrt(2)/2 ulp, than
|
|
19 | + * sqrt(z) has error less than 1 ulp (exercise).
|
|
20 | + *
|
|
21 | + * So, compute sqrt(x*x+y*y) with some care as
|
|
22 | + * follows to get the error below 1 ulp:
|
|
23 | + *
|
|
24 | + * Assume x>y>0;
|
|
25 | + * (if possible, set rounding to round-to-nearest)
|
|
26 | + * 1. if x > 2y use
|
|
27 | + * x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
|
|
28 | + * where x1 = x with lower 32 bits cleared, x2 = x-x1; else
|
|
29 | + * 2. if x <= 2y use
|
|
30 | + * t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
|
|
31 | + * where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
|
|
32 | + * y1= y with lower 32 bits chopped, y2 = y-y1.
|
|
33 | + *
|
|
34 | + * NOTE: scaling may be necessary if some argument is too
|
|
35 | + * large or too tiny
|
|
36 | + *
|
|
37 | + * Special cases:
|
|
38 | + * hypot(x,y) is INF if x or y is +INF or -INF; else
|
|
39 | + * hypot(x,y) is NAN if x or y is NAN.
|
|
40 | + *
|
|
41 | + * Accuracy:
|
|
42 | + * hypot(x,y) returns sqrt(x^2+y^2) with error less
|
|
43 | + * than 1 ulps (units in the last place)
|
|
44 | + */
|
|
45 | + |
|
46 | +#include "fdlibm.h"
|
|
47 | + |
|
48 | +static inline void
|
|
49 | +set_hiword(double* d, int hi)
|
|
50 | +{
|
|
51 | + union { int i[2]; double d; } ux;
|
|
52 | + |
|
53 | + ux.d = *d;
|
|
54 | + ux.i[HIWORD] = hi;
|
|
55 | + *d = ux.d;
|
|
56 | +}
|
|
57 | + |
|
58 | +static inline int
|
|
59 | +get_loword(double d)
|
|
60 | +{
|
|
61 | + union { int i[2]; double d; } ux;
|
|
62 | + ux.d = d;
|
|
63 | + return ux.i[LOWORD];
|
|
64 | +}
|
|
65 | + |
|
66 | +static inline int
|
|
67 | +get_hiword(double d)
|
|
68 | +{
|
|
69 | + union { int i[2]; double d; } ux;
|
|
70 | + ux.d = d;
|
|
71 | + |
|
72 | + return ux.i[HIWORD];
|
|
73 | +}
|
|
74 | + |
|
75 | +
|
|
76 | +#ifdef __STDC__
|
|
77 | + double __ieee754_hypot(double x, double y)
|
|
78 | +#else
|
|
79 | + double __ieee754_hypot(x,y)
|
|
80 | + double x, y;
|
|
81 | +#endif
|
|
82 | +{
|
|
83 | + double a=x,b=y,t1,t2,y1,y2,w;
|
|
84 | + int j,k,ha,hb;
|
|
85 | + |
|
86 | + ha = get_hiword(x)&0x7fffffff; /* high word of x */
|
|
87 | + hb = get_hiword(y)&0x7fffffff; /* high word of y */
|
|
88 | + if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
|
|
89 | + set_hiword(&a,ha); /* a <- |a| */
|
|
90 | + set_hiword(&b, hb); /* b <- |b| */
|
|
91 | +
|
|
92 | + if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
|
|
93 | + k=0;
|
|
94 | + if(ha > 0x5f300000) { /* a>2**500 */
|
|
95 | + if(ha >= 0x7ff00000) { /* Inf or NaN */
|
|
96 | + w = a+b; /* for sNaN */
|
|
97 | + if(((ha&0xfffff)|get_loword(a))==0) w = a;
|
|
98 | + if(((hb^0x7ff00000)|get_loword(b))==0) w = b;
|
|
99 | + return w;
|
|
100 | + }
|
|
101 | + /* scale a and b by 2**-600 */
|
|
102 | + ha -= 0x25800000; hb -= 0x25800000; k += 600;
|
|
103 | + set_hiword(&a, ha);
|
|
104 | + set_hiword(&b, hb);
|
|
105 | + }
|
|
106 | + if(hb < 0x20b00000) { /* b < 2**-500 */
|
|
107 | + if(hb <= 0x000fffff) { /* subnormal b or 0 */
|
|
108 | + if((hb|(get_loword(b)))==0) return a;
|
|
109 | + t1=0;
|
|
110 | + set_hiword(&t1, 0x7fd00000); /* t1=2^1022 */
|
|
111 | + b *= t1;
|
|
112 | + a *= t1;
|
|
113 | + k -= 1022;
|
|
114 | + } else { /* scale a and b by 2^600 */
|
|
115 | + ha += 0x25800000; /* a *= 2^600 */
|
|
116 | + hb += 0x25800000; /* b *= 2^600 */
|
|
117 | + k -= 600;
|
|
118 | + set_hiword(&a, ha);
|
|
119 | + set_hiword(&b, hb);
|
|
120 | + }
|
|
121 | + }
|
|
122 | + /* medium size a and b */
|
|
123 | + w = a-b;
|
|
124 | + if (w>b) {
|
|
125 | + t1 = 0;
|
|
126 | + set_hiword(&t1, ha);
|
|
127 | + t2 = a-t1;
|
|
128 | + w = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
|
|
129 | + } else {
|
|
130 | + a = a+a;
|
|
131 | + y1 = 0;
|
|
132 | + set_hiword(&y1, hb);
|
|
133 | + y2 = b - y1;
|
|
134 | + t1 = 0;
|
|
135 | + set_hiword(&t1, ha+0x00100000);
|
|
136 | + t2 = a - t1;
|
|
137 | + w = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
|
|
138 | + }
|
|
139 | + if(k!=0) {
|
|
140 | + t1 = 1.0;
|
|
141 | + set_hiword(&t1, get_hiword(t1) + (k<<20));
|
|
142 | + return t1*w;
|
|
143 | + } else return w;
|
|
144 | +} |
1 | +;; Tests of float functions
|
|
2 | + |
|
3 | +(defpackage :float-x86-tests
|
|
4 | + (:use :cl :lisp-unit))
|
|
5 | + |
|
6 | +(in-package "FLOAT-X86-TESTS")
|
|
7 | + |
|
8 | +(define-test set-floating-point-modes
|
|
9 | + (let ((old-x87-modes (x86::x87-floating-point-modes))
|
|
10 | + (old-sse2-modes (x86::sse2-floating-point-modes))
|
|
11 | + x87-modes sse2-modes)
|
|
12 | + (unwind-protect
|
|
13 | + (progn
|
|
14 | + ;; Set some new traps and rounding mode.
|
|
15 | + (ext:set-floating-point-modes :traps '(:underflow
|
|
16 | + :overflow
|
|
17 | + :invalid
|
|
18 | + :divide-by-zero)
|
|
19 | + :rounding-mode :zero)
|
|
20 | + ;; Save these new FP modes
|
|
21 | + (setf x87-modes (x86::x87-floating-point-modes))
|
|
22 | + (setf sse2-modes (x86::sse2-floating-point-modes)))
|
|
23 | + |
|
24 | + (setf (x86::x87-floating-point-modes) old-x87-modes)
|
|
25 | + (setf (x86::sse2-floating-point-modes) old-sse2-modes))
|
|
26 | + |
|
27 | + (let* ((x87-exceptions-enabled (ldb x86::x87-float-traps-byte x87-modes))
|
|
28 | + (x87-rc (ldb x86::x87-float-rounding-mode x87-modes))
|
|
29 | + (sse2-exceptions-enabled (ldb x86::float-traps-byte sse2-modes))
|
|
30 | + (sse2-rc (ldb x86::float-rounding-mode sse2-modes)))
|
|
31 | + (format t "*X87 FP mode words:~%")
|
|
32 | + (x86::print-x87-fp-modes x87-modes)
|
|
33 | + (format t "~%*SSE2 FP mode words:~%")
|
|
34 | + (x86::print-sse2-fp-modes sse2-modes)
|
|
35 | +
|
|
36 | + ;; Verify that we set the enabled exceptions
|
|
37 | + ;; correctly. First for sse2, then for x87.
|
|
38 | + (assert-false (logbitp 5 sse2-exceptions-enabled)) ; precision
|
|
39 | + (assert-true (logbitp 4 sse2-exceptions-enabled)) ; underflow
|
|
40 | + (assert-true (logbitp 3 sse2-exceptions-enabled)) ; overflow
|
|
41 | + (assert-true (logbitp 2 sse2-exceptions-enabled)) ; divide-by-zero
|
|
42 | + (assert-false (logbitp 1 sse2-exceptions-enabled)) ; denormal
|
|
43 | + (assert-true (logbitp 0 sse2-exceptions-enabled)) ; invalid
|
|
44 | +
|
|
45 | + (assert-false (logbitp 5 x87-exceptions-enabled)) ; precision
|
|
46 | + (assert-true (logbitp 4 x87-exceptions-enabled)) ; underflow
|
|
47 | + (assert-true (logbitp 3 x87-exceptions-enabled)) ; overflow
|
|
48 | + (assert-true (logbitp 2 x87-exceptions-enabled)) ; divide-by-zero
|
|
49 | + (assert-false (logbitp 1 x87-exceptions-enabled)) ; denormal
|
|
50 | + (assert-true (logbitp 0 x87-exceptions-enabled)) ; invalid
|
|
51 | + |
|
52 | + ;; Verify the rounding mode is set to zero
|
|
53 | + (assert-eql :zero (car (rassoc sse2-rc x86::rounding-mode-alist)))
|
|
54 | + (assert-eql :zero (car (rassoc x87-rc x86::rounding-mode-alist)))
|
|
55 | + |
|
56 | + ;; Verify precision for x87
|
|
57 | + (assert-eql :64-bits
|
|
58 | + (car (rassoc (ldb x86::x87-float-precision-control-byte x87-modes)
|
|
59 | + x86::x87-float-precision-control-alist)))))) |
... | ... | @@ -342,4 +342,3 @@ |
342 | 342 | (x86::x87-floating-point-modes)))))
|
343 | 343 | (assert-true (typep new-mode 'x86::float-modes))
|
344 | 344 | (assert-equal new-mode (setf (x86::x87-floating-point-modes) new-mode)))) |
345 | - |
... | ... | @@ -245,6 +245,17 @@ |
245 | 245 | (tanh #c(200w0 200w0))))
|
246 | 246 |
|
247 | 247 |
|
248 | +;; See bug #424
|
|
249 | +(define-test hypot
|
|
250 | + (:tag :issues)
|
|
251 | + (assert-eql 3.8950612975366328d0
|
|
252 | + (kernel:%hypot 2.302585092994046d0 3.141592653589793d0))
|
|
253 | + (let ((result (expt #C(2.302585092994046d0 3.141592653589793d0) 4)))
|
|
254 | + (assert-eql -188.4466069439329d0
|
|
255 | + (realpart result))
|
|
256 | + (assert-eql -132.16721026205448d0
|
|
257 | + (imagpart result))))
|
|
258 | + |
|
248 | 259 | (define-test cos-tiny
|
249 | 260 | (:tag issues)
|
250 | 261 | ;; This test comes from the Maxima testsuite where core-math was not
|
... | ... | @@ -260,3 +271,4 @@ |
260 | 271 | ;; The computed result looked it had like a single-precision accuracy.
|
261 | 272 | (assert-eql -0.37106498060016496d0
|
262 | 273 | (kernel:%log (kernel:make-double-float (+ 1071644672 398457) 0))))
|
274 | + |