Raymond Toy pushed to branch issue-425-correctly-rounded-math-functions-single-float at cmucl / cmucl Commits: f5a798b8 by Raymond Toy at 2026-02-05T17:51:48-08:00 Fix #470: Fix unit test issues on Ubuntu CI - - - - - 5b6d4d73 by Raymond Toy at 2026-02-05T17:51:48-08:00 Merge branch 'issue-470-ubuntu-ci-failures' into 'master' Fix #470: Fix unit test issues on Ubuntu CI Closes #470 See merge request cmucl/cmucl!348 - - - - - 772641b9 by Raymond Toy at 2026-02-05T19:39:14-08:00 Fix #469: Reenable cr_pow - - - - - 6ac1b6b4 by Raymond Toy at 2026-02-05T19:39:14-08:00 Merge branch 'issue-469-enable-cr-pow' into 'master' Fix #469: Reenable cr_pow Closes #469 and #470 See merge request cmucl/cmucl!346 - - - - - 9dec6e71 by Raymond Toy at 2026-02-16T07:40:15-08:00 Fix #468: Make core-math signal the same errors as fdlibm - - - - - ec7e3a25 by Raymond Toy at 2026-02-16T07:40:15-08:00 Merge branch 'issue-468-core-math-signals' into 'master' Fix #468: Make core-math signal the same errors as fdlibm Closes #468, #426, and #425 See merge request cmucl/cmucl!347 - - - - - 6494ef48 by Raymond Toy at 2026-02-16T07:44:39-08:00 Fix #471: Add tests for kernel:%pow - - - - - 69923013 by Raymond Toy at 2026-02-16T07:44:39-08:00 Merge branch 'issue-471-test-cases-for-pow' into 'master' Fix #471: Add tests for kernel:%pow Closes #471 See merge request cmucl/cmucl!349 - - - - - 98e777af by Raymond Toy at 2026-02-17T09:51:43-08:00 Merge branch 'master' into issue-425-correctly-rounded-math-functions-single-float - - - - - 1c92a62c by Raymond Toy at 2026-02-17T10:47:23-08:00 Fix #472: Ansi-tests test.log not found - - - - - 53a087ca by Raymond Toy at 2026-02-17T10:47:23-08:00 Merge branch 'issue-472-ansi-tests-test-log-not-found' into 'master' Fix #472: Ansi-tests test.log not found Closes #472 See merge request cmucl/cmucl!350 - - - - - 4a6755a1 by Raymond Toy at 2026-02-17T10:50:03-08:00 Use core-math powf in lisp_powf We can use core-math powf in lisp_powf since we've worked out the issues with core-math pow in lisp_pow. - - - - - 70bd3787 by Raymond Toy at 2026-02-17T13:34:41-08:00 Merge branch 'master' into issue-425-correctly-rounded-math-functions-single-float - - - - - 6 changed files: - .gitlab-ci.yml - bin/run-unit-tests.sh - src/lisp/irrat.c - tests/fdlibm.lisp - tests/issues.lisp - + tests/test-run-prog/ls-link Changes: ===================================== .gitlab-ci.yml ===================================== @@ -70,16 +70,16 @@ variables: stage: ansi-test artifacts: paths: - - ansi-test/test.out + - ansi-test.out script: - bin/run-ansi-tests.sh -l dist/bin/lisp - + - cp ../ansi-test/test.out ansi-test.out + # Default configuration for running unit tests. .unit_test_template: &unit_test_configuration stage: test artifacts: paths: - - ansi-test/test.out - test.log script: - echo LANG = $LANG @@ -147,7 +147,9 @@ linux:build: - job: linux:install artifacts: true variables: - CONFIG: "x86_linux_clang" + # Fedora 41 must build with gcc because the clang build fails some + # ansi-tests. See [#469]. + CONFIG: "x86_linux" # These rules is needed so that the static analyzer job can run on a # schedule because this is a prerequisite of the analyzer build. A # regular push or merge request does the normal stuff. @@ -171,7 +173,7 @@ linux:cross-build: - linux-4/lisp variables: # This must match the config used for the linux build! - CONFIG: "x86_linux_clang" + CONFIG: "x86_linux" needs: @@ -346,7 +348,10 @@ ubuntu:build: - job: ubuntu:install artifacts: true variables: - CONFIG: "x86_linux_clang" + # Build with gcc on Ubuntu 25.10. It produces a lisp than passes + # the ansi-tests. Clang seems to fail the ansi-tests WRITE.1, + # PRINT.1, and friends when cr_pow is used. + CONFIG: "x86_linux" ubuntu:test: <<: *unit_test_configuration ===================================== bin/run-unit-tests.sh ===================================== @@ -42,9 +42,9 @@ done shift $((OPTIND - 1)) # Create the test directory needed by the issue.45 test. -rm -rf test-tmp -mkdir test-tmp -ln -s /bin/ls test-tmp/ls-link +#rm -rf test-tmp +#mkdir test-tmp +#ln -s /bin/ls test-tmp/ls-link # Set the timestamps on 64-bit-timestamp-2038.txt and # 64-bit-timestamp-2106.txt, but only for OSes where we know this @@ -56,8 +56,9 @@ ln -s /bin/ls test-tmp/ls-link # tests/os.lisp. case `uname -s` in Linux) - touch -d "1 April 2038" tests/resources/64-bit-timestamp-2038.txt - touch -d "1 April 2106" tests/resources/64-bit-timestamp-2106.txt + # -t format is [[CC]YY]MMDDhhmm[.ss] + touch -t 203804010000 tests/resources/64-bit-timestamp-2038.txt + touch -t 210604010000 tests/resources/64-bit-timestamp-2106.txt ;; esac ===================================== src/lisp/irrat.c ===================================== @@ -61,10 +61,22 @@ extern void cr_sincosf(float, float *, float *); * Wrappers for the special functions */ +#define MAYBE_SIGNAL_INVALID(test, val) \ + if ((test)) { \ + return fdlibm_setexception(val, FDLIBM_INVALID); \ + } + +#define MAYBE_SIGNAL_OVERFLOW(x) \ + if (isinf(x)) { \ + return fdlibm_setexception(x, FDLIBM_OVERFLOW); \ + } + double lisp_sin(double x) { #ifdef FEATURE_CORE_MATH + MAYBE_SIGNAL_INVALID(isinf(x), x) + return cr_sin(x); #else return fdlibm_sin(x); @@ -75,6 +87,8 @@ double lisp_cos(double x) { #ifdef FEATURE_CORE_MATH + MAYBE_SIGNAL_INVALID(isinf(x), x) + return cr_cos(x); #else return fdlibm_cos(x); @@ -85,6 +99,8 @@ double lisp_tan(double x) { #ifdef FEATURE_CORE_MATH + MAYBE_SIGNAL_INVALID(isinf(x), x) + return cr_tan(x); #else return fdlibm_tan(x); @@ -135,6 +151,8 @@ double lisp_sinh(double x) { #ifdef FEATURE_CORE_MATH + MAYBE_SIGNAL_OVERFLOW(x) + return cr_sinh(x); #else return __ieee754_sinh(x); @@ -165,6 +183,8 @@ double lisp_asinh(double x) { #ifdef FEATURE_CORE_MATH + MAYBE_SIGNAL_OVERFLOW(x) + return cr_asinh(x); #else return fdlibm_asinh(x); @@ -175,6 +195,10 @@ double lisp_acosh(double x) { #ifdef FEATURE_CORE_MATH + MAYBE_SIGNAL_INVALID(x < 1, x) + + MAYBE_SIGNAL_OVERFLOW(x) + return cr_acosh(x); #else return __ieee754_acosh(x); @@ -224,13 +248,17 @@ lisp_log10(double x) double lisp_pow(double x, double y) { +#ifdef FEATURE_CORE_MATH /* - * cr_pow seems causes ansi-tests to fail in test WRITE.1 among - * others. Somewhere an invalid operation is occurring. Thus - * just use fdlibm for now until we can figure out what's causing - * the failure. + * cr_pow when compiled with older versions of gcc or clang can + * cause failures in the ansi-tests [#469]. Ubuntu 25.10 and Fedora 41 + * (gcc only) are known to have compilers that work well enough + * that the ansi-tests pass. */ + return cr_pow(x, y); +#else return __ieee754_pow(x, y); +#endif } double @@ -448,8 +476,17 @@ lisp_log10f(float x) } float -lisp_powf(double x, double y) +lisp_powf(float x, float y) { +#ifdef FEATURE_CORE_MATH + /* + * cr_pow when compiled with older versions of gcc or clang can + * cause failures in the ansi-tests [#469]. Ubuntu 25.10 and Fedora 41 + * (gcc only) are known to have compilers that work well enough + * that the ansi-tests pass. + */ + return cr_powf(x, y); +#else /* * cr_pow seems causes ansi-tests to fail in test WRITE.1 among * others. Somewhere an invalid operation is occurring. Thus @@ -457,6 +494,7 @@ lisp_powf(double x, double y) * the failure. */ return (float) __ieee754_pow((double) x, (double) y); +#endif } float ===================================== tests/fdlibm.lisp ===================================== @@ -90,12 +90,8 @@ (define-test %acosh.exceptions (:tag :fdlibm) - ;; Core-math returns infinity instead of signaling overflow. - #-core-math (assert-error 'floating-point-overflow (kernel:%acosh ext:double-float-positive-infinity)) - ;; Core-math currently returns QNaN - #-core-math (assert-error 'floating-point-invalid-operation (kernel:%acosh 0d0)) (ext:with-float-traps-masked (:overflow) @@ -108,12 +104,8 @@ (:tag :fdlibm) (assert-error 'floating-point-invalid-operation (kernel:%asinh *snan*)) - ;; Core-math returns the signed infinity instead of signaling an - ;; overflow. - #-core-math (assert-error 'floating-point-overflow (kernel:%asinh ext:double-float-positive-infinity)) - #-core-math (assert-error 'floating-point-overflow (kernel:%asinh ext:double-float-negative-infinity)) (assert-true (ext:float-nan-p (kernel:%asinh *qnan*))) @@ -218,7 +210,6 @@ (ext:with-float-traps-masked (:overflow) (assert-equal ext:double-float-positive-infinity (kernel:%exp 710d0))) - #-core-math (let ((modes (ext:get-floating-point-modes))) (unwind-protect (progn @@ -675,6 +666,14 @@ (define-test %cos.exceptions (:tag :fdlibm) + ;; cos(inf) signals invalid operation + (assert-error 'floating-point-invalid-operation + (kernel:%cos ext:double-float-positive-infinity)) + (assert-error 'floating-point-invalid-operation + (kernel:%cos ext:double-float-negative-infinity)) + ;; cos(nan) is NaN + (assert-true (ext:float-nan-p (kernel:%cos *qnan*))) + ;; cos(x) = 1 for |x| < 2^-27. Signal inexact unless x = 0 (let ((x (scale-float 1d0 -28)) (x0 0d0)) @@ -690,6 +689,14 @@ (define-test %sin.exceptions (:tag :fdlibm) + ;; sin(inf) signals invalid operation + (assert-error 'floating-point-invalid-operation + (kernel:%sin ext:double-float-positive-infinity)) + (assert-error 'floating-point-invalid-operation + (kernel:%sin ext:double-float-negative-infinity)) + ;; sin(nan) is NaN + (assert-true (ext:float-nan-p (kernel:%sin *qnan*))) + ;; sin(x) = x for |x| < 2^-27. Signal inexact unless x = 0 (let ((x (scale-float 1d0 -28)) (x0 0d0)) @@ -705,6 +712,14 @@ (define-test %tan.exceptions (:tag :fdlibm) + ;; tan(inf) signals invalid operation + (assert-error 'floating-point-invalid-operation + (kernel:%tan ext:double-float-positive-infinity)) + (assert-error 'floating-point-invalid-operation + (kernel:%tan ext:double-float-negative-infinity)) + ;; tan(nan) is NaN + (assert-true (ext:float-nan-p (kernel:%sin *qnan*))) + ;; tan(x) = x for |x| < 2^-28. Signal inexact unless x = 0 (let ((x (scale-float 1d0 -29)) (x0 0d0)) @@ -717,3 +732,203 @@ ;; though the result is exactly x. (assert-error 'floating-point-inexact (kernel:%tan x))))) + +;; Test cases from e_pow.c for fdlibm. +(define-test %pow.case.1 + (:tag :fdlibm) + ;; anything ^ 0 is 1 + (assert-equal 1d0 + (kernel:%pow ext:double-float-positive-infinity 0d0)) + (assert-equal 1d0 + (kernel:%pow ext:double-float-negative-infinity 0d0))) + +(define-test %pow.case.2 + (:tag :fdlibm) + ;; anything ^ 1 is itself + (assert-equal ext:double-float-positive-infinity + (kernel:%pow ext:double-float-positive-infinity 1d0)) + (assert-equal ext:double-float-negative-infinity + (kernel:%pow ext:double-float-negative-infinity 1d0))) + +(define-test %pow.case.3 + (:tag :fdlibm) + ;; anything ^ NaN is NaN + (assert-true (ext:float-nan-p + (kernel:%pow pi *qnan*))) + (assert-true (ext:float-nan-p + (kernel:%pow ext:double-float-positive-infinity *qnan*)))) + +(define-test %pow.case.4 + (:tag :fdlibm) + ;; NaN ^ non-zero is NaN + (assert-true (ext:float-nan-p + (kernel:%pow *qnan* pi))) + (assert-true (ext:float-nan-p + (kernel:%pow *qnan* ext:double-float-positive-infinity)))) + +(define-test %pow.case.5 + (:tag :fdlibm) + ;; (|x| > 1) ^ +inf is +inf + (assert-equal ext:double-float-positive-infinity + (kernel:%pow pi ext:double-float-positive-infinity)) + (assert-equal ext:double-float-positive-infinity + (kernel:%pow (- pi) ext:double-float-positive-infinity))) + +(define-test %pow.case.6 + (:tag :fdlibm) + ;; (|x| > 1) ^ -inf is +0 + (assert-equal +0d0 + (kernel:%pow pi ext:double-float-negative-infinity)) + (assert-equal +0d0 + (kernel:%pow (- pi) ext:double-float-negative-infinity))) + +(define-test %pow.case.7 + (:tag :fdlibm) + ;; (|x| < 1) ^ +inf is +0 + (assert-equal +0d0 + (kernel:%pow 0.5d0 ext:double-float-positive-infinity)) + (assert-equal +0d0 + (kernel:%pow -0.5d0 ext:double-float-positive-infinity))) + +(define-test %pow.case.8 + (:tag :fdlibm) + ;; (|x| < 1) ^ -inf is +inf + (assert-equal ext:double-float-positive-infinity + (kernel:%pow 0.5d0 ext:double-float-negative-infinity)) + (assert-equal ext:double-float-positive-infinity + (kernel:%pow -0.5d0 ext:double-float-negative-infinity))) + +(define-test %pow.case.9 + (:tag :fdlibm) + ;; std::pow says 1^exp is 1 for any exp, including NaN. (-1)^(+/-inf) + ;; is 1. No errors signaled. + #+core-math + (progn + (assert-equal 1d0 + (kernel:%pow 1d0 ext:double-float-positive-infinity)) + (assert-equal 1d0 + (kernel:%pow 1d0 ext:double-float-negative-infinity)) + (assert-equal 1d0 + (kernel:%pow 1d0 *qnan*)) + (assert-equal 1d0 + (kernel:%pow -1d0 ext:double-float-positive-infinity)) + (assert-equal 1d0 + (kernel:%pow -1d0 ext:double-float-negative-infinity))) + #-core-math + ;; +-1 ^ +-inf is NaN. + ;; + ;; But the implementation signals invalid operation, so we need to + ;; check for that. + ;; + (progn + (assert-error 'floating-point-invalid-operation + (kernel:%pow 1d0 ext:double-float-positive-infinity)) + (assert-error 'floating-point-invalid-operation + (kernel:%pow 1d0 ext:double-float-negative-infinity)) + (assert-error 'floating-point-invalid-operation + (kernel:%pow -1d0 ext:double-float-positive-infinity)) + (assert-error 'floating-point-invalid-operation + (kernel:%pow -1d0 ext:double-float-negative-infinity)) + (ext:with-float-traps-masked (:invalid) + (assert-true (ext:float-nan-p + (kernel:%pow 1d0 ext:double-float-positive-infinity))) + (assert-true (ext:float-nan-p + (kernel:%pow 1d0 ext:double-float-negative-infinity))) + (assert-true (ext:float-nan-p + (kernel:%pow -1d0 ext:double-float-positive-infinity))) + (assert-true (ext:float-nan-p + (kernel:%pow -1d0 ext:double-float-negative-infinity)))))) + +(define-test %pow.case.10 + (:tag :fdlibm) + ;; +0 ^ (+anything except 0, Nan) is +0 + (assert-equal +0d0 + (kernel:%pow +0d0 10d0)) + (assert-equal +0d0 + (kernel:%pow +0d0 ext:double-float-positive-infinity))) + +(define-test %pow.case.11 + (:tag :fdlibm) + ;; +0 ^ (+anything except 0, Nan, odd integer) is +0 + (assert-equal +0d0 + (kernel:%pow -0d0 10d0)) + (assert-equal +0d0 + (kernel:%pow -0d0 ext:double-float-positive-infinity))) + +(define-test %pow.case.12 + (:tag :fdlibm) + ;; +0 ^ (-anything except 0, Nan) is +inf + ;; + ;; But fdlibm signals error for (+0)^(-10) instead of returning inf. Check this. + (assert-error 'division-by-zero + (kernel:%pow +0d0 -10d0)) + (ext:with-float-traps-masked (:divide-by-zero) + (assert-equal ext:double-float-positive-infinity + (kernel:%pow +0d0 -10d0))) + ;; No signals here. + (assert-equal ext:double-float-positive-infinity + (kernel:%pow +0d0 ext:double-float-negative-infinity))) + +(define-test %pow.case.13 + (:tag :fdlibm) + ;; -0 ^ (-anything except 0, Nan, odd integer) is +inf + ;; + ;; But (-0)^(-10) signals division by zero + (assert-error 'division-by-zero + (kernel:%pow -0d0 -10d0)) + (ext:with-float-traps-masked (:divide-by-zero) + (assert-equal ext:double-float-positive-infinity + (kernel:%pow -0d0 -10d0))) + ;; But no error here. + (assert-equal ext:double-float-positive-infinity + (kernel:%pow +0d0 ext:double-float-negative-infinity))) + +(define-test %pow.case.14 + (:tag :fdlibm) + ;; -0 ^ (odd integer) = -( +0 ^ (odd integer)) + (assert-equal (- (kernel:%pow +0d0 5d0)) + (kernel:%pow -0d0 5d0))) + +(define-test %pow.case.15 + (:tag :fdlibm) + ;; +inf ^ (+anything except 0, NaN) is +inf + (assert-equal ext:double-float-positive-infinity + (kernel:%pow ext:double-float-positive-infinity pi))) + +(define-test %pow.case.16 + (:tag :fdlibm) + ;; +inf ^ (-anything except 0, NaN) is +0 + (assert-equal +0d0 + (kernel:%pow ext:double-float-positive-infinity (- pi)))) + +(define-test %pow.case.17 + (:tag :fdlibm) + ;; -inf ^ (anything) = -0 ^ (-anything) + (assert-equal (ext:with-float-traps-masked (:divide-by-zero) + ;; This produces a divide-by-zero error so mask it + ;; to get a value. + (kernel:%pow -0d0 (- pi))) + (kernel:%pow ext:double-float-negative-infinity pi)) + (assert-equal (kernel:%pow -0d0 pi) + (kernel:%pow ext:double-float-negative-infinity (- pi)))) + +(define-test %pow.case.18 + (:tag :fdlibm) + ;; (-anything) ^ integer is (-1)^integer * (+anything ^ integer) + (dolist (base '(-2d0 -10d0)) + (dolist (power '(5 -5)) + (assert-equal (* (expt -1 power) + (kernel:%pow (- base) (coerce power 'double-float))) + (kernel:%pow base (coerce power 'double-float)) + base power)))) + +(define-test %pow.case.19 + (:tag :fdlibm) + ;; (-anything except 0 and inf) ^ non-integer is NaN + ;; + ;; But this signals invalid, so check for that too. + (assert-error 'floating-point-invalid-operation + (kernel:%pow -2d0 1.5d0)) + (ext:with-float-traps-masked (:invalid) + (assert-true (ext:float-nan-p + (kernel:%pow -2d0 1.5d0))))) ===================================== tests/issues.lisp ===================================== @@ -436,7 +436,7 @@ (define-test issue.45 (:tag :issues) ;; This depends on run-tests to setup the test directory correctly! - (let* ((test-dir #p"test-tmp/") + (let* ((test-dir #p"tests/test-run-prog/") (test-dir-name (namestring test-dir))) (flet ((do-test (program) (with-output-to-string (s) ===================================== tests/test-run-prog/ls-link ===================================== @@ -0,0 +1,2 @@ +#! /bin/sh +exec /bin/ls "$@" View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/fdacacd73cee798c34401bd... -- View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/fdacacd73cee798c34401bd... You're receiving this email because of your account on gitlab.common-lisp.net.
participants (1)
-
Raymond Toy (@rtoy)