From cd5656fadb67f3e085f0666471e3c3625c20a7da Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Fri, 6 Feb 2026 21:49:35 -0700 Subject: [PATCH 1/4] Fix bug with copysign movability flags --- ops/core.rkt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ops/core.rkt b/ops/core.rkt index 3757ca0..c115ae0 100644 --- a/ops/core.rkt +++ b/ops/core.rkt @@ -678,10 +678,15 @@ ;; 0 is both positive and negative because we don't handle signed zero well (define can-neg (or (= (mpfr-sign (ival-lo-val y)) -1) can-zero)) (define can-pos (or (= (mpfr-sign (ival-hi-val y)) 1) can-zero)) + (define sign-immovable? (and can-neg can-pos (ival-lo-fixed? y) (ival-hi-fixed? y))) (define err? (or (ival-err? y) xerr?)) (define err (or (ival-err y) xerr)) (match* (can-neg can-pos) - [(#t #t) (ival (rnd 'down epunary bfneg xhi) (rnd 'up epunary bfcopy xhi) err? err)] + [(#t #t) + (define out (ival (rnd 'down epunary bfneg xhi) (rnd 'up epunary bfcopy xhi) err? err)) + (if sign-immovable? + out + (ival-mobilize out))] [(#t #f) (ival (rnd 'down epunary bfneg xhi) (rnd 'up epunary bfneg xlo) err? err)] [(#f #t) (ival xlo xhi err? err)] [(#f #f) From 5c3ed59b1eb51f7c988237c48d9bff390177b7de Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Fri, 6 Feb 2026 22:31:28 -0700 Subject: [PATCH 2/4] Add a test to catch this copysign bug --- test.rkt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test.rkt b/test.rkt index 0cd0c7f..c989419 100644 --- a/test.rkt +++ b/test.rkt @@ -315,7 +315,10 @@ (with-check-info (['split-argument k] ['ilo ilo] ['ihi ihi] ['iylo iylo] ['iyhi iyhi]) (check-ival-equals? iy (parameterize ([bf-precision out-prec]) - (ival-union iylo iyhi)))))) + (ival-union iylo iyhi))) + ;; Refining an input argument should refine the output. + (check ival-refines? iy iylo) + (check ival-refines? iy iyhi)))) (when (or (ival-lo-fixed? iy) (ival-hi-fixed? iy)) (define iy* (parameterize ([bf-precision 128]) From 6b1a5a99f3f694c3e2cb53efa1cbeec9811652d1 Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Fri, 6 Feb 2026 22:41:43 -0700 Subject: [PATCH 3/4] Fix fmin/fmax movability --- ops/core.rkt | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/ops/core.rkt b/ops/core.rkt index c115ae0..4f79744 100644 --- a/ops/core.rkt +++ b/ops/core.rkt @@ -661,16 +661,46 @@ (ival (endpoint lo #f) (endpoint hi #f) err? err)) (define (ival-fmin x y) - (ival (endpoint-min2 (ival-lo x) (ival-lo y) 'down) - (endpoint-min2 (ival-hi x) (ival-hi y) 'up) - (or (ival-err? x) (ival-err? y)) - (or (ival-err x) (ival-err y)))) + (match-define (ival (endpoint xlo xlo!) (endpoint xhi xhi!) xerr? xerr) x) + (match-define (ival (endpoint ylo ylo!) (endpoint yhi yhi!) yerr? yerr) y) + (define lo (bf 0)) + (define hi (bf 0)) + (define lo-exact? (= 0 (mpfr-min! lo xlo ylo 'down))) + (define hi-exact? (= 0 (mpfr-min! hi xhi yhi 'up))) + ;; For lower endpoints (which can only move upward under refinement), + ;; a fixed minimum is stable if one fixed endpoint is <= the other. + (define lo-stable? + (cond + [(and xlo! ylo!) #t] + [xlo! (bflte? xlo ylo)] + [ylo! (bflte? ylo xlo)] + [else #f])) + (define lo! (and lo-exact? lo-stable?)) + ;; For upper endpoints (which can only move downward), a fixed minimum is + ;; only guaranteed when both endpoints are fixed. + (define hi! (and hi-exact? xhi! yhi!)) + (ival (endpoint lo lo!) (endpoint hi hi!) (or xerr? yerr?) (or xerr yerr))) (define (ival-fmax x y) - (ival (endpoint-max2 (ival-lo x) (ival-lo y) 'down) - (endpoint-max2 (ival-hi x) (ival-hi y) 'up) - (or (ival-err? x) (ival-err? y)) - (or (ival-err x) (ival-err y)))) + (match-define (ival (endpoint xlo xlo!) (endpoint xhi xhi!) xerr? xerr) x) + (match-define (ival (endpoint ylo ylo!) (endpoint yhi yhi!) yerr? yerr) y) + (define lo (bf 0)) + (define hi (bf 0)) + (define lo-exact? (= 0 (mpfr-max! lo xlo ylo 'down))) + (define hi-exact? (= 0 (mpfr-max! hi xhi yhi 'up))) + ;; For lower endpoints (which can only move upward), a fixed maximum is + ;; only guaranteed when both endpoints are fixed. + (define lo! (and lo-exact? xlo! ylo!)) + ;; For upper endpoints (which can only move downward), a fixed maximum is + ;; stable if one fixed endpoint is >= the other. + (define hi-stable? + (cond + [(and xhi! yhi!) #t] + [xhi! (bfgte? xhi yhi)] + [yhi! (bfgte? yhi xhi)] + [else #f])) + (define hi! (and hi-exact? hi-stable?)) + (ival (endpoint lo lo!) (endpoint hi hi!) (or xerr? yerr?) (or xerr yerr))) (define (ival-copysign x y) (match-define (ival xlo xhi xerr? xerr) (ival-fabs x)) From 907d03a8a7729509d2a8cc1086abe794f929d686 Mon Sep 17 00:00:00 2001 From: Pavel Panchekha Date: Fri, 6 Feb 2026 22:48:20 -0700 Subject: [PATCH 4/4] Fix movability flags for pow that straddles zero --- ops/core.rkt | 1 + ops/pow.rkt | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ops/core.rkt b/ops/core.rkt index 4f79744..b85e174 100644 --- a/ops/core.rkt +++ b/ops/core.rkt @@ -105,6 +105,7 @@ ival-== ival-!= ival-if + ival-mobilize ival-and ival-or ival-not diff --git a/ops/pow.rkt b/ops/pow.rkt index 9c768ee..fa4b5fb 100644 --- a/ops/pow.rkt +++ b/ops/pow.rkt @@ -161,4 +161,9 @@ [(or (= (mpfr-sign (ival-lo-val x)) 1) (bfzero? (ival-lo-val x))) (ival-pow-pos x y)] [else (define-values (neg pos) (split-ival x 0.bf)) - (ival-union (ival-pow-neg neg y) (ival-pow-pos pos y))])) + (define out (ival-union (ival-pow-neg neg y) (ival-pow-pos pos y))) + ;; If x straddles 0 with movable endpoints, a refinement can drop one + ;; branch entirely, so branch-derived endpoint fixedness is not stable. + (if (and (ival-lo-fixed? x) (ival-hi-fixed? x)) + out + (ival-mobilize out))]))