- Update version 4.2.0 from 4 bug patches to 9 bug patches - Update of rootfile not required - Bug fix changelog 5 The mpfr_reldiff function, which computes |b−c|/b, is buggy on special values, e.g. on the following (b,c) values: (+Inf,+Inf) gives ±0 instead of NaN (like NaN/Inf); (+0,+0) gives 1 instead of NaN (like 0/0); (+0,1) gives 1 instead of Inf (like 1/0). Moreover, the sign of 0 for (+Inf,+Inf) or (−Inf,−Inf) is not set, i.e. it is just the sign of the destination before the call; as a consequence, results are not even consistent. These bugs are fixed by the reldiff patch. Corresponding changeset in the 4.2 branch: 81e4d4427. 6 The reuse tests are incomplete: the sign of a result zero is not checked, so that it can miss bugs (one of the mpfr_reldiff bugs mentioned above, in particular). The tests-reuse patch adds a check of the sign of zero and contains other minor improvements. Corresponding changeset in the 4.2 branch: e6d47b8f5. 7 The general code for the power function (mpfr_pow_general internal function) has two bugs in particular cases: the first one is an incorrect computation of the error bound when there has been an intermediate underflow or overflow (in such a case, the computation is performed again with a rescaling, thus with an additional error term, but there is a bug in the computation of this term), so that the result may be rounded incorrectly (in particular, a spurious overflow is possible); the second one occurs in a corner case (destination precision 1, rounding to nearest, and where the rounded result assuming an unbounded exponent range would be 2emin−2 and the exact result is larger than this value), with the only consequence being a missing underflow exception (the underflow flag is not set). These two bugs are fixed by the pow_general patch, which also provides testcases. Note: The second bug was introduced by commit 936df8ef6 in MPFR 4.1.0 (the code simplification was incorrect, and there were no associated tests in the testsuite). Corresponding changesets in the 4.2 branch: 85bc7331c, 5fa407a6c, 9a16c173e. 8 The mpfr_compound_si function can take a huge amount of memory and time in some cases (when the argument x is a large even integer and xn is represented exactly in the target precision) and does not correctly detect overflows and underflows. This is fixed by the compound patch, which also provides various tests. Corresponding changesets in the 4.2 branch: 7635c4a35, 74d86a61f, 952fb0f5c, a4894f68d, 7bb748775, f5cb40571, d87459969. 9 MPFR can crash when a formatted output function is called with %.2147483648Rg in the format string. For instance: mpfr_snprintf (NULL, 0, "%.2147483648Rg\n", x); This is fixed by the printf_large_prec_for_g patch, which also provides testcases. Corresponding changesets in the 4.2 branch: 686f82776, 769ad91a6.
Signed-off-by: Adolf Belka adolf.belka@ipfire.org --- lfs/mpfr | 2 +- ...mpfr-4.2.0-cumulative-patches-1-to-4.patch | 521 ----- ...mpfr-4.2.0-cumulative-patches-1-to-9.patch | 2046 +++++++++++++++++ 3 files changed, 2047 insertions(+), 522 deletions(-) delete mode 100644 src/patches/mpfr-4.2.0-cumulative-patches-1-to-4.patch create mode 100644 src/patches/mpfr-4.2.0-cumulative-patches-1-to-9.patch
diff --git a/lfs/mpfr b/lfs/mpfr index c799086d9..e2a1062c1 100644 --- a/lfs/mpfr +++ b/lfs/mpfr @@ -70,7 +70,7 @@ $(subst %,%_BLAKE2,$(objects)) : $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) @$(PREBUILD) @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE) - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/mpfr-4.2.0-cumulative-patches-1-to-4.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/mpfr-4.2.0-cumulative-patches-1-to-9.patch cd $(DIR_APP) && $(CONFIGURE_ARGS) ./configure \ --prefix=/usr \ --enable-thread-safe diff --git a/src/patches/mpfr-4.2.0-cumulative-patches-1-to-4.patch b/src/patches/mpfr-4.2.0-cumulative-patches-1-to-4.patch deleted file mode 100644 index e12ed4708..000000000 --- a/src/patches/mpfr-4.2.0-cumulative-patches-1-to-4.patch +++ /dev/null @@ -1,521 +0,0 @@ -diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES ---- mpfr-4.2.0-a/PATCHES 2023-04-17 21:17:39.748645280 +0000 -+++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:17:39.792645218 +0000 -@@ -0,0 +1 @@ -+tsprintf-thousands -diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION ---- mpfr-4.2.0-a/VERSION 2023-01-06 10:55:57.000000000 +0000 -+++ mpfr-4.2.0-b/VERSION 2023-04-17 21:17:39.792645218 +0000 -@@ -1 +1 @@ --4.2.0 -+4.2.0-p1 -diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h ---- mpfr-4.2.0-a/src/mpfr.h 2023-01-06 10:55:57.000000000 +0000 -+++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:17:39.788645224 +0000 -@@ -27,7 +27,7 @@ - #define MPFR_VERSION_MAJOR 4 - #define MPFR_VERSION_MINOR 2 - #define MPFR_VERSION_PATCHLEVEL 0 --#define MPFR_VERSION_STRING "4.2.0" -+#define MPFR_VERSION_STRING "4.2.0-p1" - - /* User macros: - MPFR_USE_FILE: Define it to make MPFR define functions dealing -diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c ---- mpfr-4.2.0-a/src/version.c 2023-01-06 10:55:57.000000000 +0000 -+++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:17:39.792645218 +0000 -@@ -25,5 +25,5 @@ - const char * - mpfr_get_version (void) - { -- return "4.2.0"; -+ return "4.2.0-p1"; - } -diff -Naurd mpfr-4.2.0-a/tests/tsprintf.c mpfr-4.2.0-b/tests/tsprintf.c ---- mpfr-4.2.0-a/tests/tsprintf.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/tests/tsprintf.c 2023-04-17 21:17:39.784645229 +0000 -@@ -1715,7 +1715,25 @@ - check_sprintf ("000000001,000", "%'013.4Rg", x); - - #ifdef PRINTF_GROUPFLAG -- check_vsprintf ("+01,234,567 :", "%0+ -'13.10Pd:", (mpfr_prec_t) 1234567); -+ /* Do not test the thousands separator with a precision field larger -+ than the number of digits (thus needing leading zeros), such as -+ "%0+ -'13.10Pd:" (used up to MPFR 4.2.0), since the GNU libc is -+ buggy: https://sourceware.org/bugzilla/show_bug.cgi?id=23432 -+ We don't know about the other implementations. -+ This new test works fine with glibc up to 2.36, but fails with 2.37 -+ (as reported by Klaus Dittrich in the MPFR mailing-list); this is -+ actually a bug introduced in glibc 2.37, not in MPFR: -+ https://sourceware.org/bugzilla/show_bug.cgi?id=30068 -+ Since this bug can yield a buffer overflow (CVE-2023-25139), possibly -+ affecting MPFR users, let us rather require a fix in glibc. This bug -+ has been fixed in the 2.37 branch: -+ https://sourceware.org/git/?p=glibc.git;a=commit;h=07b9521fc6 -+ If we wanted to check that and avoid a failure of the test because of -+ a buggy C library (while MPFR would be consistent with the C library), -+ we could compare the MPFR output with both the correct output and the -+ output from the C library (possibly buggy). But to do that in a clean -+ way, this would require a change in the check_vsprintf() call. */ -+ check_vsprintf ("+1,234,567 :", "%0+ -'13Pd:", (mpfr_prec_t) 1234567); - #endif - - mpfr_clear (x); -diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES ---- mpfr-4.2.0-a/PATCHES 2023-04-17 21:18:00.464616127 +0000 -+++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:18:00.512616059 +0000 -@@ -0,0 +1 @@ -+ui_pow_ui-overflow -diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION ---- mpfr-4.2.0-a/VERSION 2023-04-17 21:17:39.792645218 +0000 -+++ mpfr-4.2.0-b/VERSION 2023-04-17 21:18:00.512616059 +0000 -@@ -1 +1 @@ --4.2.0-p1 -+4.2.0-p2 -diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h ---- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:17:39.788645224 +0000 -+++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:18:00.508616065 +0000 -@@ -27,7 +27,7 @@ - #define MPFR_VERSION_MAJOR 4 - #define MPFR_VERSION_MINOR 2 - #define MPFR_VERSION_PATCHLEVEL 0 --#define MPFR_VERSION_STRING "4.2.0-p1" -+#define MPFR_VERSION_STRING "4.2.0-p2" - - /* User macros: - MPFR_USE_FILE: Define it to make MPFR define functions dealing -diff -Naurd mpfr-4.2.0-a/src/ui_pow_ui.c mpfr-4.2.0-b/src/ui_pow_ui.c ---- mpfr-4.2.0-a/src/ui_pow_ui.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/src/ui_pow_ui.c 2023-04-17 21:18:00.504616070 +0000 -@@ -23,7 +23,7 @@ - #include "mpfr-impl.h" - - int --mpfr_ui_pow_ui (mpfr_ptr x, unsigned long int y, unsigned long int n, -+mpfr_ui_pow_ui (mpfr_ptr x, unsigned long int k, unsigned long int n, - mpfr_rnd_t rnd) - { - mpfr_exp_t err; -@@ -35,22 +35,28 @@ - MPFR_ZIV_DECL (loop); - MPFR_SAVE_EXPO_DECL (expo); - -+ MPFR_LOG_FUNC -+ (("k=%lu n=%lu rnd=%d", k, n, rnd), -+ ("y[%Pu]=%.*Rg inexact=%d", -+ mpfr_get_prec (x), mpfr_log_prec, x, inexact)); -+ - if (MPFR_UNLIKELY (n <= 1)) - { - if (n == 1) -- return mpfr_set_ui (x, y, rnd); /* y^1 = y */ -+ return mpfr_set_ui (x, k, rnd); /* k^1 = k */ - else -- return mpfr_set_ui (x, 1, rnd); /* y^0 = 1 for any y */ -+ return mpfr_set_ui (x, 1, rnd); /* k^0 = 1 for any k */ - } -- else if (MPFR_UNLIKELY (y <= 1)) -+ else if (MPFR_UNLIKELY (k <= 1)) - { -- if (y == 1) -+ if (k == 1) - return mpfr_set_ui (x, 1, rnd); /* 1^n = 1 for any n > 0 */ - else - return mpfr_set_ui (x, 0, rnd); /* 0^n = 0 for any n > 0 */ - } - -- for (size_n = 0, m = n; m; size_n++, m >>= 1); -+ for (size_n = 0, m = n; m != 0; size_n++, m >>= 1) -+ ; - - MPFR_SAVE_EXPO_MARK (expo); - prec = MPFR_PREC (x) + 3 + size_n; -@@ -60,23 +66,55 @@ - for (;;) - { - int i = size_n; -+ unsigned int inex_res; - -- inexact = mpfr_set_ui (res, y, MPFR_RNDU); -+ inex_res = mpfr_set_ui (res, k, MPFR_RNDU); - err = 1; - /* now 2^(i-1) <= n < 2^i: i=1+floor(log2(n)) */ - for (i -= 2; i >= 0; i--) - { -- inexact |= mpfr_sqr (res, res, MPFR_RNDU); -+ inex_res |= mpfr_sqr (res, res, MPFR_RNDU); - err++; - if (n & (1UL << i)) -- inexact |= mpfr_mul_ui (res, res, y, MPFR_RNDU); -+ inex_res |= mpfr_mul_ui (res, res, k, MPFR_RNDU); - } -+ -+ if (MPFR_UNLIKELY (MPFR_IS_INF (res))) -+ { -+ mpfr_t kf; -+ mpz_t z; -+ int size_k; -+ MPFR_BLOCK_DECL (flags); -+ -+ /* Let's handle the overflow by calling mpfr_pow_z. -+ Alternatively, we could call mpfr_pow_ui; this would -+ need a bit shorter code below, but mpfr_pow_ui handles -+ the overflow by calling mpfr_pow_z, so that calling -+ mpfr_pow_z directly should be a bit more efficient. */ -+ -+ MPFR_ZIV_FREE (loop); -+ mpfr_clear (res); -+ for (size_k = 0, m = k; m != 0; size_k++, m >>= 1) -+ ; -+ mpfr_init2 (kf, size_k); -+ inexact = mpfr_set_ui (kf, k, MPFR_RNDN); -+ MPFR_ASSERTD (inexact == 0); -+ mpz_init (z); -+ mpz_set_ui (z, n); -+ MPFR_BLOCK (flags, inexact = mpfr_pow_z (x, kf, z, rnd);); -+ mpz_clear (z); -+ mpfr_clear (kf); -+ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, flags); -+ goto end; -+ } -+ - /* since the loop is executed floor(log2(n)) times, - we have err = 1+floor(log2(n)). - Since prec >= MPFR_PREC(x) + 4 + floor(log2(n)), prec > err */ - err = prec - err; - -- if (MPFR_LIKELY (inexact == 0 -+ MPFR_LOG_VAR (res); -+ if (MPFR_LIKELY (!inex_res - || MPFR_CAN_ROUND (res, err, MPFR_PREC (x), rnd))) - break; - -@@ -90,6 +128,7 @@ - - mpfr_clear (res); - -+ end: - MPFR_SAVE_EXPO_FREE (expo); - return mpfr_check_range (x, inexact, rnd); - } -diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c ---- mpfr-4.2.0-a/src/version.c 2023-04-17 21:17:39.792645218 +0000 -+++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:18:00.512616059 +0000 -@@ -25,5 +25,5 @@ - const char * - mpfr_get_version (void) - { -- return "4.2.0-p1"; -+ return "4.2.0-p2"; - } -diff -Naurd mpfr-4.2.0-a/tests/tlog10.c mpfr-4.2.0-b/tests/tlog10.c ---- mpfr-4.2.0-a/tests/tlog10.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/tests/tlog10.c 2023-04-17 21:18:00.504616070 +0000 -@@ -49,6 +49,60 @@ - #define TEST_RANDOM_POS 8 - #include "tgeneric.c" - -+/* On 2023-02-13, one gets an infinite loop in mpfr_log10 on both -+ 32-bit and 64-bit hosts when the precision is not large enough -+ (precision 12 and below). */ -+static void -+bug20230213 (void) -+{ -+ mpfr_exp_t old_emin, old_emax, e; -+ mpfr_t t, x, y0, y1, y2; -+ int prec; -+ -+ old_emin = mpfr_get_emin (); -+ old_emax = mpfr_get_emax (); -+ -+ set_emin (MPFR_EMIN_MIN); -+ set_emax (MPFR_EMAX_MAX); -+ e = mpfr_get_emax () - 1; -+ -+ /* The precisions of t and y0 should be large enough to avoid -+ a hard-to-round case for the target precisions. */ -+ mpfr_inits2 (64, t, y0, (mpfr_ptr) 0); -+ mpfr_set_exp_t (y0, e, MPFR_RNDN); -+ mpfr_log_ui (t, 10, MPFR_RNDN); -+ mpfr_div (y0, y0, t, MPFR_RNDN); -+ mpfr_log_ui (t, 2, MPFR_RNDN); -+ mpfr_mul (y0, y0, t, MPFR_RNDN); -+ -+ for (prec = 16; prec >= MPFR_PREC_MIN; prec--) -+ { -+ mpfr_inits2 (prec, x, y1, y2, (mpfr_ptr) 0); -+ mpfr_set (y1, y0, MPFR_RNDN); -+ -+ mpfr_set_ui_2exp (x, 1, e, MPFR_RNDN); -+ mpfr_log10 (y2, x, MPFR_RNDN); -+ MPFR_ASSERTN (MPFR_IS_PURE_FP (y2)); -+ MPFR_ASSERTN (MPFR_IS_POS (y2)); -+ -+ if (! mpfr_equal_p (y1, y2)) -+ { -+ printf ("Error in bug20230213.\n"); -+ printf ("Expected "); -+ mpfr_dump (y1); -+ printf ("Got "); -+ mpfr_dump (y2); -+ exit (1); -+ } -+ mpfr_clears (x, y1, y2, (mpfr_ptr) 0); -+ } -+ -+ mpfr_clears (t, y0, (mpfr_ptr) 0); -+ -+ set_emin (old_emin); -+ set_emax (old_emax); -+} -+ - int - main (int argc, char *argv[]) - { -@@ -112,6 +166,8 @@ - mpfr_clear (x); - mpfr_clear (y); - -+ bug20230213 (); -+ - data_check ("data/log10", mpfr_log10, "mpfr_log10"); - - tests_end_mpfr (); -diff -Naurd mpfr-4.2.0-a/tests/tui_pow.c mpfr-4.2.0-b/tests/tui_pow.c ---- mpfr-4.2.0-a/tests/tui_pow.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/tests/tui_pow.c 2023-04-17 21:18:00.504616070 +0000 -@@ -142,6 +142,37 @@ - mpfr_clear (t); - } - -+static void -+huge (void) -+{ -+ mpfr_exp_t old_emin, old_emax; -+ mpfr_t x; -+ -+ old_emin = mpfr_get_emin (); -+ old_emax = mpfr_get_emax (); -+ -+ set_emin (MPFR_EMIN_MIN); -+ set_emax (MPFR_EMAX_MAX); -+ -+ mpfr_init2 (x, 8); -+ -+ /* The purpose of this test is more to check that mpfr_ui_pow_ui -+ terminates (without taking much memory) rather than checking -+ the value of x. On 2023-02-13, the +Inf case was not handled -+ in the Ziv iteration, yielding an infinite loop, affecting -+ mpfr_log10 in particular. See -+ commit 90de094f0d9c309daca707aa227470d810866616 -+ */ -+ mpfr_ui_pow_ui (x, 5, ULONG_MAX, MPFR_RNDN); -+ if (MPFR_EMAX_MAX <= ULONG_MAX) /* true with default _MPFR_EXP_FORMAT */ -+ MPFR_ASSERTN (MPFR_IS_INF (x)); -+ -+ mpfr_clear (x); -+ -+ set_emin (old_emin); -+ set_emax (old_emax); -+} -+ - int - main (int argc, char *argv[]) - { -@@ -180,6 +211,7 @@ - } - - test1 (); -+ huge (); - - { - mpfr_t z, t; -diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES ---- mpfr-4.2.0-a/PATCHES 2023-04-17 21:18:26.860579184 +0000 -+++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:18:26.904579122 +0000 -@@ -0,0 +1 @@ -+multibyte-decimal_point -diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION ---- mpfr-4.2.0-a/VERSION 2023-04-17 21:18:00.512616059 +0000 -+++ mpfr-4.2.0-b/VERSION 2023-04-17 21:18:26.904579122 +0000 -@@ -1 +1 @@ --4.2.0-p2 -+4.2.0-p3 -diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h ---- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:18:00.508616065 +0000 -+++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:18:26.900579128 +0000 -@@ -27,7 +27,7 @@ - #define MPFR_VERSION_MAJOR 4 - #define MPFR_VERSION_MINOR 2 - #define MPFR_VERSION_PATCHLEVEL 0 --#define MPFR_VERSION_STRING "4.2.0-p2" -+#define MPFR_VERSION_STRING "4.2.0-p3" - - /* User macros: - MPFR_USE_FILE: Define it to make MPFR define functions dealing -diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c ---- mpfr-4.2.0-a/src/version.c 2023-04-17 21:18:00.512616059 +0000 -+++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:18:26.904579122 +0000 -@@ -25,5 +25,5 @@ - const char * - mpfr_get_version (void) - { -- return "4.2.0-p2"; -+ return "4.2.0-p3"; - } -diff -Naurd mpfr-4.2.0-a/tests/tfprintf.c mpfr-4.2.0-b/tests/tfprintf.c ---- mpfr-4.2.0-a/tests/tfprintf.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/tests/tfprintf.c 2023-04-17 21:18:26.896579133 +0000 -@@ -61,6 +61,12 @@ - exit (1); \ - } - -+#if MPFR_LCONV_DPTS -+#define DPLEN ((int) strlen (localeconv()->decimal_point)) -+#else -+#define DPLEN 1 -+#endif -+ - /* limit for random precision in random() */ - const int prec_max_printf = 5000; - -@@ -195,12 +201,12 @@ - lo, &ulo); - check_length (2, ulo, 36, lu); - check_vfprintf (fout, "a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); -- check_length (3, ush, 46, hu); -+ check_length (3, ush, 45 + DPLEN, hu); - check_vfprintf (fout, "a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); -- check_length (4, i, 29, d); -+ check_length (4, i, 28 + DPLEN, d); - check_vfprintf (fout, "a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, - &sz); -- check_length (5, (unsigned long) sz, 34, lu); /* no format specifier "%zu" in C90 */ -+ check_length (5, (unsigned long) sz, 33 + DPLEN, lu); /* no format specifier "%zu" in C90 */ - check_vfprintf (fout, "a. %Pu, b. %c, c. %Zi%Zn", prec, ch, mpz, &mpz); - check_length_with_cmp (6, mpz, 17, mpz_cmp_ui (mpz, 17), Zi); - check_vfprintf (fout, "%% a. %#.0RNg, b. %Qx%Rn, c. %p", mpfr, mpq, &mpfr, -@@ -224,7 +230,7 @@ - - #ifdef PRINTF_L - check_vfprintf (fout, "a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); -- check_length (9, (unsigned long) sz, 30, lu); /* no format specifier "%zu" in C90 */ -+ check_length (9, (unsigned long) sz, 29 + DPLEN, lu); /* no format specifier "%zu" in C90 */ - #endif - - #ifndef NPRINTF_HH -diff -Naurd mpfr-4.2.0-a/tests/tprintf.c mpfr-4.2.0-b/tests/tprintf.c ---- mpfr-4.2.0-a/tests/tprintf.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/tests/tprintf.c 2023-04-17 21:18:26.896579133 +0000 -@@ -68,6 +68,12 @@ - exit (1); \ - } - -+#if MPFR_LCONV_DPTS -+#define DPLEN ((int) strlen (localeconv()->decimal_point)) -+#else -+#define DPLEN 1 -+#endif -+ - /* limit for random precision in random() */ - const int prec_max_printf = 5000; - /* boolean: is stdout redirected to a file ? */ -@@ -316,11 +322,11 @@ - check_vprintf ("a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, lo, &ulo); - check_length (2, ulo, 36, lu); - check_vprintf ("a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); -- check_length (3, ush, 46, hu); -+ check_length (3, ush, 45 + DPLEN, hu); - check_vprintf ("a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); -- check_length (4, i, 29, d); -+ check_length (4, i, 28 + DPLEN, d); - check_vprintf ("a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, &sz); -- check_length (5, (unsigned long) sz, 34, lu); /* no format specifier '%zu' in C90 */ -+ check_length (5, (unsigned long) sz, 33 + DPLEN, lu); /* no format specifier '%zu' in C90 */ - check_vprintf ("a. %Pu, b. %c, c. %RUG, d. %Zi%Zn", prec, ch, mpfr, mpz, &mpz); - check_length_with_cmp (6, mpz, 24, mpz_cmp_ui (mpz, 24), Zi); - check_vprintf ("%% a. %#.0RNg, b. %Qx%Rn c. %p", -@@ -344,7 +350,7 @@ - - #ifdef PRINTF_L - check_vprintf ("a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); -- check_length (9, (unsigned long) sz, 30, lu); /* no format specifier '%zu' in C90 */ -+ check_length (9, (unsigned long) sz, 29 + DPLEN, lu); /* no format specifier '%zu' in C90 */ - #endif - - #ifndef NPRINTF_HH -diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES ---- mpfr-4.2.0-a/PATCHES 2023-04-17 21:19:01.988530337 +0000 -+++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:19:02.032530276 +0000 -@@ -0,0 +1 @@ -+rec_sqrt-zivloop -diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION ---- mpfr-4.2.0-a/VERSION 2023-04-17 21:18:26.904579122 +0000 -+++ mpfr-4.2.0-b/VERSION 2023-04-17 21:19:02.032530276 +0000 -@@ -1 +1 @@ --4.2.0-p3 -+4.2.0-p4 -diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h ---- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:18:26.900579128 +0000 -+++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:19:02.032530276 +0000 -@@ -27,7 +27,7 @@ - #define MPFR_VERSION_MAJOR 4 - #define MPFR_VERSION_MINOR 2 - #define MPFR_VERSION_PATCHLEVEL 0 --#define MPFR_VERSION_STRING "4.2.0-p3" -+#define MPFR_VERSION_STRING "4.2.0-p4" - - /* User macros: - MPFR_USE_FILE: Define it to make MPFR define functions dealing -diff -Naurd mpfr-4.2.0-a/src/rec_sqrt.c mpfr-4.2.0-b/src/rec_sqrt.c ---- mpfr-4.2.0-a/src/rec_sqrt.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/src/rec_sqrt.c 2023-04-17 21:19:02.024530287 +0000 -@@ -463,6 +463,7 @@ - int s, cy, inex; - mpfr_limb_ptr x; - MPFR_TMP_DECL(marker); -+ MPFR_ZIV_DECL (loop); - - MPFR_LOG_FUNC - (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (u), mpfr_log_prec, u, rnd_mode), -@@ -530,6 +531,7 @@ - wp = rp + 11; - if (wp < rn * GMP_NUMB_BITS) - wp = rn * GMP_NUMB_BITS; -+ MPFR_ZIV_INIT (loop, wp); - for (;;) - { - MPFR_TMP_MARK (marker); -@@ -561,8 +563,9 @@ - } - MPFR_TMP_FREE(marker); - -- wp += GMP_NUMB_BITS; -+ MPFR_ZIV_NEXT (loop, wp); - } -+ MPFR_ZIV_FREE (loop); - cy = mpfr_round_raw (MPFR_MANT(r), x, wp, 0, rp, rnd_mode, &inex); - MPFR_EXP(r) = - (MPFR_EXP(u) - 1 - s) / 2; - if (MPFR_UNLIKELY(cy != 0)) -diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c ---- mpfr-4.2.0-a/src/version.c 2023-04-17 21:18:26.904579122 +0000 -+++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:19:02.032530276 +0000 -@@ -25,5 +25,5 @@ - const char * - mpfr_get_version (void) - { -- return "4.2.0-p3"; -+ return "4.2.0-p4"; - } -diff -Naurd mpfr-4.2.0-a/tests/trec_sqrt.c mpfr-4.2.0-b/tests/trec_sqrt.c ---- mpfr-4.2.0-a/tests/trec_sqrt.c 2023-01-05 17:09:48.000000000 +0000 -+++ mpfr-4.2.0-b/tests/trec_sqrt.c 2023-04-17 21:19:02.028530282 +0000 -@@ -242,6 +242,8 @@ - data_check ("data/rec_sqrt", mpfr_rec_sqrt, "mpfr_rec_sqrt"); - bad_cases (mpfr_rec_sqrt, pm2, "mpfr_rec_sqrt", 0, -256, 255, 4, 128, - 800, 50); -+ bad_cases (mpfr_rec_sqrt, pm2, "mpfr_rec_sqrt", 0, -256, 255, 9999, 9999, -+ 120000, 1); - - end: - tests_end_mpfr (); diff --git a/src/patches/mpfr-4.2.0-cumulative-patches-1-to-9.patch b/src/patches/mpfr-4.2.0-cumulative-patches-1-to-9.patch new file mode 100644 index 000000000..07fcf2592 --- /dev/null +++ b/src/patches/mpfr-4.2.0-cumulative-patches-1-to-9.patch @@ -0,0 +1,2046 @@ +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-04-17 21:17:39.748645280 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:17:39.792645218 +0000 +@@ -0,0 +1 @@ ++tsprintf-thousands +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-01-06 10:55:57.000000000 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-04-17 21:17:39.792645218 +0000 +@@ -1 +1 @@ +-4.2.0 ++4.2.0-p1 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-01-06 10:55:57.000000000 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:17:39.788645224 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0" ++#define MPFR_VERSION_STRING "4.2.0-p1" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-01-06 10:55:57.000000000 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:17:39.792645218 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0"; ++ return "4.2.0-p1"; + } +diff -Naurd mpfr-4.2.0-a/tests/tsprintf.c mpfr-4.2.0-b/tests/tsprintf.c +--- mpfr-4.2.0-a/tests/tsprintf.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tsprintf.c 2023-04-17 21:17:39.784645229 +0000 +@@ -1715,7 +1715,25 @@ + check_sprintf ("000000001,000", "%'013.4Rg", x); + + #ifdef PRINTF_GROUPFLAG +- check_vsprintf ("+01,234,567 :", "%0+ -'13.10Pd:", (mpfr_prec_t) 1234567); ++ /* Do not test the thousands separator with a precision field larger ++ than the number of digits (thus needing leading zeros), such as ++ "%0+ -'13.10Pd:" (used up to MPFR 4.2.0), since the GNU libc is ++ buggy: https://sourceware.org/bugzilla/show_bug.cgi?id=23432 ++ We don't know about the other implementations. ++ This new test works fine with glibc up to 2.36, but fails with 2.37 ++ (as reported by Klaus Dittrich in the MPFR mailing-list); this is ++ actually a bug introduced in glibc 2.37, not in MPFR: ++ https://sourceware.org/bugzilla/show_bug.cgi?id=30068 ++ Since this bug can yield a buffer overflow (CVE-2023-25139), possibly ++ affecting MPFR users, let us rather require a fix in glibc. This bug ++ has been fixed in the 2.37 branch: ++ https://sourceware.org/git/?p=glibc.git;a=commit;h=07b9521fc6 ++ If we wanted to check that and avoid a failure of the test because of ++ a buggy C library (while MPFR would be consistent with the C library), ++ we could compare the MPFR output with both the correct output and the ++ output from the C library (possibly buggy). But to do that in a clean ++ way, this would require a change in the check_vsprintf() call. */ ++ check_vsprintf ("+1,234,567 :", "%0+ -'13Pd:", (mpfr_prec_t) 1234567); + #endif + + mpfr_clear (x); +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-04-17 21:18:00.464616127 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:18:00.512616059 +0000 +@@ -0,0 +1 @@ ++ui_pow_ui-overflow +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-04-17 21:17:39.792645218 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-04-17 21:18:00.512616059 +0000 +@@ -1 +1 @@ +-4.2.0-p1 ++4.2.0-p2 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:17:39.788645224 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:18:00.508616065 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p1" ++#define MPFR_VERSION_STRING "4.2.0-p2" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/ui_pow_ui.c mpfr-4.2.0-b/src/ui_pow_ui.c +--- mpfr-4.2.0-a/src/ui_pow_ui.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/src/ui_pow_ui.c 2023-04-17 21:18:00.504616070 +0000 +@@ -23,7 +23,7 @@ + #include "mpfr-impl.h" + + int +-mpfr_ui_pow_ui (mpfr_ptr x, unsigned long int y, unsigned long int n, ++mpfr_ui_pow_ui (mpfr_ptr x, unsigned long int k, unsigned long int n, + mpfr_rnd_t rnd) + { + mpfr_exp_t err; +@@ -35,22 +35,28 @@ + MPFR_ZIV_DECL (loop); + MPFR_SAVE_EXPO_DECL (expo); + ++ MPFR_LOG_FUNC ++ (("k=%lu n=%lu rnd=%d", k, n, rnd), ++ ("y[%Pu]=%.*Rg inexact=%d", ++ mpfr_get_prec (x), mpfr_log_prec, x, inexact)); ++ + if (MPFR_UNLIKELY (n <= 1)) + { + if (n == 1) +- return mpfr_set_ui (x, y, rnd); /* y^1 = y */ ++ return mpfr_set_ui (x, k, rnd); /* k^1 = k */ + else +- return mpfr_set_ui (x, 1, rnd); /* y^0 = 1 for any y */ ++ return mpfr_set_ui (x, 1, rnd); /* k^0 = 1 for any k */ + } +- else if (MPFR_UNLIKELY (y <= 1)) ++ else if (MPFR_UNLIKELY (k <= 1)) + { +- if (y == 1) ++ if (k == 1) + return mpfr_set_ui (x, 1, rnd); /* 1^n = 1 for any n > 0 */ + else + return mpfr_set_ui (x, 0, rnd); /* 0^n = 0 for any n > 0 */ + } + +- for (size_n = 0, m = n; m; size_n++, m >>= 1); ++ for (size_n = 0, m = n; m != 0; size_n++, m >>= 1) ++ ; + + MPFR_SAVE_EXPO_MARK (expo); + prec = MPFR_PREC (x) + 3 + size_n; +@@ -60,23 +66,55 @@ + for (;;) + { + int i = size_n; ++ unsigned int inex_res; + +- inexact = mpfr_set_ui (res, y, MPFR_RNDU); ++ inex_res = mpfr_set_ui (res, k, MPFR_RNDU); + err = 1; + /* now 2^(i-1) <= n < 2^i: i=1+floor(log2(n)) */ + for (i -= 2; i >= 0; i--) + { +- inexact |= mpfr_sqr (res, res, MPFR_RNDU); ++ inex_res |= mpfr_sqr (res, res, MPFR_RNDU); + err++; + if (n & (1UL << i)) +- inexact |= mpfr_mul_ui (res, res, y, MPFR_RNDU); ++ inex_res |= mpfr_mul_ui (res, res, k, MPFR_RNDU); + } ++ ++ if (MPFR_UNLIKELY (MPFR_IS_INF (res))) ++ { ++ mpfr_t kf; ++ mpz_t z; ++ int size_k; ++ MPFR_BLOCK_DECL (flags); ++ ++ /* Let's handle the overflow by calling mpfr_pow_z. ++ Alternatively, we could call mpfr_pow_ui; this would ++ need a bit shorter code below, but mpfr_pow_ui handles ++ the overflow by calling mpfr_pow_z, so that calling ++ mpfr_pow_z directly should be a bit more efficient. */ ++ ++ MPFR_ZIV_FREE (loop); ++ mpfr_clear (res); ++ for (size_k = 0, m = k; m != 0; size_k++, m >>= 1) ++ ; ++ mpfr_init2 (kf, size_k); ++ inexact = mpfr_set_ui (kf, k, MPFR_RNDN); ++ MPFR_ASSERTD (inexact == 0); ++ mpz_init (z); ++ mpz_set_ui (z, n); ++ MPFR_BLOCK (flags, inexact = mpfr_pow_z (x, kf, z, rnd);); ++ mpz_clear (z); ++ mpfr_clear (kf); ++ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, flags); ++ goto end; ++ } ++ + /* since the loop is executed floor(log2(n)) times, + we have err = 1+floor(log2(n)). + Since prec >= MPFR_PREC(x) + 4 + floor(log2(n)), prec > err */ + err = prec - err; + +- if (MPFR_LIKELY (inexact == 0 ++ MPFR_LOG_VAR (res); ++ if (MPFR_LIKELY (!inex_res + || MPFR_CAN_ROUND (res, err, MPFR_PREC (x), rnd))) + break; + +@@ -90,6 +128,7 @@ + + mpfr_clear (res); + ++ end: + MPFR_SAVE_EXPO_FREE (expo); + return mpfr_check_range (x, inexact, rnd); + } +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-04-17 21:17:39.792645218 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:18:00.512616059 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p1"; ++ return "4.2.0-p2"; + } +diff -Naurd mpfr-4.2.0-a/tests/tlog10.c mpfr-4.2.0-b/tests/tlog10.c +--- mpfr-4.2.0-a/tests/tlog10.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tlog10.c 2023-04-17 21:18:00.504616070 +0000 +@@ -49,6 +49,60 @@ + #define TEST_RANDOM_POS 8 + #include "tgeneric.c" + ++/* On 2023-02-13, one gets an infinite loop in mpfr_log10 on both ++ 32-bit and 64-bit hosts when the precision is not large enough ++ (precision 12 and below). */ ++static void ++bug20230213 (void) ++{ ++ mpfr_exp_t old_emin, old_emax, e; ++ mpfr_t t, x, y0, y1, y2; ++ int prec; ++ ++ old_emin = mpfr_get_emin (); ++ old_emax = mpfr_get_emax (); ++ ++ set_emin (MPFR_EMIN_MIN); ++ set_emax (MPFR_EMAX_MAX); ++ e = mpfr_get_emax () - 1; ++ ++ /* The precisions of t and y0 should be large enough to avoid ++ a hard-to-round case for the target precisions. */ ++ mpfr_inits2 (64, t, y0, (mpfr_ptr) 0); ++ mpfr_set_exp_t (y0, e, MPFR_RNDN); ++ mpfr_log_ui (t, 10, MPFR_RNDN); ++ mpfr_div (y0, y0, t, MPFR_RNDN); ++ mpfr_log_ui (t, 2, MPFR_RNDN); ++ mpfr_mul (y0, y0, t, MPFR_RNDN); ++ ++ for (prec = 16; prec >= MPFR_PREC_MIN; prec--) ++ { ++ mpfr_inits2 (prec, x, y1, y2, (mpfr_ptr) 0); ++ mpfr_set (y1, y0, MPFR_RNDN); ++ ++ mpfr_set_ui_2exp (x, 1, e, MPFR_RNDN); ++ mpfr_log10 (y2, x, MPFR_RNDN); ++ MPFR_ASSERTN (MPFR_IS_PURE_FP (y2)); ++ MPFR_ASSERTN (MPFR_IS_POS (y2)); ++ ++ if (! mpfr_equal_p (y1, y2)) ++ { ++ printf ("Error in bug20230213.\n"); ++ printf ("Expected "); ++ mpfr_dump (y1); ++ printf ("Got "); ++ mpfr_dump (y2); ++ exit (1); ++ } ++ mpfr_clears (x, y1, y2, (mpfr_ptr) 0); ++ } ++ ++ mpfr_clears (t, y0, (mpfr_ptr) 0); ++ ++ set_emin (old_emin); ++ set_emax (old_emax); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -112,6 +166,8 @@ + mpfr_clear (x); + mpfr_clear (y); + ++ bug20230213 (); ++ + data_check ("data/log10", mpfr_log10, "mpfr_log10"); + + tests_end_mpfr (); +diff -Naurd mpfr-4.2.0-a/tests/tui_pow.c mpfr-4.2.0-b/tests/tui_pow.c +--- mpfr-4.2.0-a/tests/tui_pow.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tui_pow.c 2023-04-17 21:18:00.504616070 +0000 +@@ -142,6 +142,37 @@ + mpfr_clear (t); + } + ++static void ++huge (void) ++{ ++ mpfr_exp_t old_emin, old_emax; ++ mpfr_t x; ++ ++ old_emin = mpfr_get_emin (); ++ old_emax = mpfr_get_emax (); ++ ++ set_emin (MPFR_EMIN_MIN); ++ set_emax (MPFR_EMAX_MAX); ++ ++ mpfr_init2 (x, 8); ++ ++ /* The purpose of this test is more to check that mpfr_ui_pow_ui ++ terminates (without taking much memory) rather than checking ++ the value of x. On 2023-02-13, the +Inf case was not handled ++ in the Ziv iteration, yielding an infinite loop, affecting ++ mpfr_log10 in particular. See ++ commit 90de094f0d9c309daca707aa227470d810866616 ++ */ ++ mpfr_ui_pow_ui (x, 5, ULONG_MAX, MPFR_RNDN); ++ if (MPFR_EMAX_MAX <= ULONG_MAX) /* true with default _MPFR_EXP_FORMAT */ ++ MPFR_ASSERTN (MPFR_IS_INF (x)); ++ ++ mpfr_clear (x); ++ ++ set_emin (old_emin); ++ set_emax (old_emax); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -180,6 +211,7 @@ + } + + test1 (); ++ huge (); + + { + mpfr_t z, t; +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-04-17 21:18:26.860579184 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:18:26.904579122 +0000 +@@ -0,0 +1 @@ ++multibyte-decimal_point +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-04-17 21:18:00.512616059 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-04-17 21:18:26.904579122 +0000 +@@ -1 +1 @@ +-4.2.0-p2 ++4.2.0-p3 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:18:00.508616065 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:18:26.900579128 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p2" ++#define MPFR_VERSION_STRING "4.2.0-p3" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-04-17 21:18:00.512616059 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:18:26.904579122 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p2"; ++ return "4.2.0-p3"; + } +diff -Naurd mpfr-4.2.0-a/tests/tfprintf.c mpfr-4.2.0-b/tests/tfprintf.c +--- mpfr-4.2.0-a/tests/tfprintf.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tfprintf.c 2023-04-17 21:18:26.896579133 +0000 +@@ -61,6 +61,12 @@ + exit (1); \ + } + ++#if MPFR_LCONV_DPTS ++#define DPLEN ((int) strlen (localeconv()->decimal_point)) ++#else ++#define DPLEN 1 ++#endif ++ + /* limit for random precision in random() */ + const int prec_max_printf = 5000; + +@@ -195,12 +201,12 @@ + lo, &ulo); + check_length (2, ulo, 36, lu); + check_vfprintf (fout, "a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); +- check_length (3, ush, 46, hu); ++ check_length (3, ush, 45 + DPLEN, hu); + check_vfprintf (fout, "a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); +- check_length (4, i, 29, d); ++ check_length (4, i, 28 + DPLEN, d); + check_vfprintf (fout, "a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, + &sz); +- check_length (5, (unsigned long) sz, 34, lu); /* no format specifier "%zu" in C90 */ ++ check_length (5, (unsigned long) sz, 33 + DPLEN, lu); /* no format specifier "%zu" in C90 */ + check_vfprintf (fout, "a. %Pu, b. %c, c. %Zi%Zn", prec, ch, mpz, &mpz); + check_length_with_cmp (6, mpz, 17, mpz_cmp_ui (mpz, 17), Zi); + check_vfprintf (fout, "%% a. %#.0RNg, b. %Qx%Rn, c. %p", mpfr, mpq, &mpfr, +@@ -224,7 +230,7 @@ + + #ifdef PRINTF_L + check_vfprintf (fout, "a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); +- check_length (9, (unsigned long) sz, 30, lu); /* no format specifier "%zu" in C90 */ ++ check_length (9, (unsigned long) sz, 29 + DPLEN, lu); /* no format specifier "%zu" in C90 */ + #endif + + #ifndef NPRINTF_HH +diff -Naurd mpfr-4.2.0-a/tests/tprintf.c mpfr-4.2.0-b/tests/tprintf.c +--- mpfr-4.2.0-a/tests/tprintf.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tprintf.c 2023-04-17 21:18:26.896579133 +0000 +@@ -68,6 +68,12 @@ + exit (1); \ + } + ++#if MPFR_LCONV_DPTS ++#define DPLEN ((int) strlen (localeconv()->decimal_point)) ++#else ++#define DPLEN 1 ++#endif ++ + /* limit for random precision in random() */ + const int prec_max_printf = 5000; + /* boolean: is stdout redirected to a file ? */ +@@ -316,11 +322,11 @@ + check_vprintf ("a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, lo, &ulo); + check_length (2, ulo, 36, lu); + check_vprintf ("a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); +- check_length (3, ush, 46, hu); ++ check_length (3, ush, 45 + DPLEN, hu); + check_vprintf ("a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); +- check_length (4, i, 29, d); ++ check_length (4, i, 28 + DPLEN, d); + check_vprintf ("a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, &sz); +- check_length (5, (unsigned long) sz, 34, lu); /* no format specifier '%zu' in C90 */ ++ check_length (5, (unsigned long) sz, 33 + DPLEN, lu); /* no format specifier '%zu' in C90 */ + check_vprintf ("a. %Pu, b. %c, c. %RUG, d. %Zi%Zn", prec, ch, mpfr, mpz, &mpz); + check_length_with_cmp (6, mpz, 24, mpz_cmp_ui (mpz, 24), Zi); + check_vprintf ("%% a. %#.0RNg, b. %Qx%Rn c. %p", +@@ -344,7 +350,7 @@ + + #ifdef PRINTF_L + check_vprintf ("a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); +- check_length (9, (unsigned long) sz, 30, lu); /* no format specifier '%zu' in C90 */ ++ check_length (9, (unsigned long) sz, 29 + DPLEN, lu); /* no format specifier '%zu' in C90 */ + #endif + + #ifndef NPRINTF_HH +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-04-17 21:19:01.988530337 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-04-17 21:19:02.032530276 +0000 +@@ -0,0 +1 @@ ++rec_sqrt-zivloop +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-04-17 21:18:26.904579122 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-04-17 21:19:02.032530276 +0000 +@@ -1 +1 @@ +-4.2.0-p3 ++4.2.0-p4 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:18:26.900579128 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-04-17 21:19:02.032530276 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p3" ++#define MPFR_VERSION_STRING "4.2.0-p4" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/rec_sqrt.c mpfr-4.2.0-b/src/rec_sqrt.c +--- mpfr-4.2.0-a/src/rec_sqrt.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/src/rec_sqrt.c 2023-04-17 21:19:02.024530287 +0000 +@@ -463,6 +463,7 @@ + int s, cy, inex; + mpfr_limb_ptr x; + MPFR_TMP_DECL(marker); ++ MPFR_ZIV_DECL (loop); + + MPFR_LOG_FUNC + (("x[%Pu]=%.*Rg rnd=%d", mpfr_get_prec (u), mpfr_log_prec, u, rnd_mode), +@@ -530,6 +531,7 @@ + wp = rp + 11; + if (wp < rn * GMP_NUMB_BITS) + wp = rn * GMP_NUMB_BITS; ++ MPFR_ZIV_INIT (loop, wp); + for (;;) + { + MPFR_TMP_MARK (marker); +@@ -561,8 +563,9 @@ + } + MPFR_TMP_FREE(marker); + +- wp += GMP_NUMB_BITS; ++ MPFR_ZIV_NEXT (loop, wp); + } ++ MPFR_ZIV_FREE (loop); + cy = mpfr_round_raw (MPFR_MANT(r), x, wp, 0, rp, rnd_mode, &inex); + MPFR_EXP(r) = - (MPFR_EXP(u) - 1 - s) / 2; + if (MPFR_UNLIKELY(cy != 0)) +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-04-17 21:18:26.904579122 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-04-17 21:19:02.032530276 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p3"; ++ return "4.2.0-p4"; + } +diff -Naurd mpfr-4.2.0-a/tests/trec_sqrt.c mpfr-4.2.0-b/tests/trec_sqrt.c +--- mpfr-4.2.0-a/tests/trec_sqrt.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/trec_sqrt.c 2023-04-17 21:19:02.028530282 +0000 +@@ -242,6 +242,8 @@ + data_check ("data/rec_sqrt", mpfr_rec_sqrt, "mpfr_rec_sqrt"); + bad_cases (mpfr_rec_sqrt, pm2, "mpfr_rec_sqrt", 0, -256, 255, 4, 128, + 800, 50); ++ bad_cases (mpfr_rec_sqrt, pm2, "mpfr_rec_sqrt", 0, -256, 255, 9999, 9999, ++ 120000, 1); + + end: + tests_end_mpfr (); +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-05-12 15:05:00.989811960 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-05-12 15:05:01.085811835 +0000 +@@ -0,0 +1 @@ ++reldiff +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-04-17 21:19:02.032530276 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-05-12 15:05:01.085811835 +0000 +@@ -1 +1 @@ +-4.2.0-p4 ++4.2.0-p5 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-04-17 21:19:02.032530276 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-05-12 15:05:01.077811846 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p4" ++#define MPFR_VERSION_STRING "4.2.0-p5" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/reldiff.c mpfr-4.2.0-b/src/reldiff.c +--- mpfr-4.2.0-a/src/reldiff.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/src/reldiff.c 2023-05-12 15:05:01.069811856 +0000 +@@ -30,31 +30,25 @@ + + if (MPFR_ARE_SINGULAR (b, c)) + { +- if (MPFR_IS_NAN(b) || MPFR_IS_NAN(c)) +- { +- MPFR_SET_NAN(a); +- return; +- } +- else if (MPFR_IS_INF(b)) ++ if (MPFR_IS_NAN (b) || MPFR_IS_INF (b) || MPFR_IS_NAN (c) || ++ (MPFR_IS_ZERO (b) && MPFR_IS_ZERO (c))) + { +- if (MPFR_IS_INF (c) && (MPFR_SIGN (c) == MPFR_SIGN (b))) +- MPFR_SET_ZERO(a); +- else +- MPFR_SET_NAN(a); ++ MPFR_SET_NAN (a); + return; + } +- else if (MPFR_IS_INF(c)) ++ if (MPFR_IS_ZERO (b) || MPFR_IS_INF (c)) + { + MPFR_SET_SAME_SIGN (a, b); + MPFR_SET_INF (a); + return; + } +- else if (MPFR_IS_ZERO(b)) /* reldiff = abs(c)/c = sign(c) */ +- { +- mpfr_set_si (a, MPFR_INT_SIGN (c), rnd_mode); +- return; +- } +- /* Fall through */ ++ /* The case c = 0 with b regular, which should give sign(b) exactly, ++ cannot be optimized here as it is documented in the MPFR manual ++ that this function just computes abs(b-c)/b using the precision ++ of a and the rounding mode rnd_mode for all operations. So let's ++ prefer the potentially "incorrect" result. Note that the correct ++ result is not necessarily better because if could break properties ++ (like monotonicity?) implied by the documentation. */ + } + + if (a == b) +@@ -64,8 +58,8 @@ + } + + mpfr_sub (a, b, c, rnd_mode); +- mpfr_abs (a, a, rnd_mode); /* for compatibility with MPF */ +- mpfr_div (a, a, (a == b) ? b_copy : b, rnd_mode); ++ MPFR_SET_SIGN (a, 1); ++ mpfr_div (a, a, a == b ? b_copy : b, rnd_mode); + + if (a == b) + mpfr_clear (b_copy); +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-04-17 21:19:02.032530276 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-05-12 15:05:01.081811839 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p4"; ++ return "4.2.0-p5"; + } +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-05-12 15:06:11.789722083 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-05-12 15:06:11.885721962 +0000 +@@ -0,0 +1 @@ ++tests-reuse +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-05-12 15:05:01.085811835 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-05-12 15:06:11.885721962 +0000 +@@ -1 +1 @@ +-4.2.0-p5 ++4.2.0-p6 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-05-12 15:05:01.077811846 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-05-12 15:06:11.877721972 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p5" ++#define MPFR_VERSION_STRING "4.2.0-p6" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-05-12 15:05:01.081811839 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-05-12 15:06:11.885721962 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p5"; ++ return "4.2.0-p6"; + } +diff -Naurd mpfr-4.2.0-a/tests/reuse.c mpfr-4.2.0-b/tests/reuse.c +--- mpfr-4.2.0-a/tests/reuse.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/reuse.c 2023-05-12 15:06:11.869721983 +0000 +@@ -78,22 +78,16 @@ + mpfr_const_pi (x, MPFR_RNDN); + MPFR_SET_EXP (x, MPFR_GET_EXP (x)-1); + break; +- default: ++ case 11: + mpfr_urandomb (x, RANDS); + if (RAND_BOOL ()) + mpfr_neg (x, x, MPFR_RNDN); + break; ++ default: ++ MPFR_ASSERTN (0); + } + } + +-/* same as mpfr_cmp, but returns 0 for both NaN's */ +-static int +-mpfr_compare (mpfr_srcptr a, mpfr_srcptr b) +-{ +- return (MPFR_IS_NAN(a)) ? !MPFR_IS_NAN(b) : +- (MPFR_IS_NAN(b) || mpfr_cmp(a, b)); +-} +- + static void + test3 (int (*testfunc)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_rnd_t), + const char *foo, mpfr_prec_t prec, mpfr_rnd_t rnd) +@@ -112,10 +106,10 @@ + + /* for each variable, consider each of the following 6 possibilities: + NaN, +Infinity, -Infinity, +0, -0 or a random number */ +- for (i=0; i < SPECIAL_MAX*SPECIAL_MAX ; i++) ++ for (i = 0; i < SPECIAL_MAX * SPECIAL_MAX; i++) + { +- set_special (ref2, i%SPECIAL_MAX); +- set_special (ref3, i/SPECIAL_MAX); ++ set_special (ref2, i % SPECIAL_MAX); ++ set_special (ref3, i / SPECIAL_MAX); + + /* reference call: foo(a, b, c) */ + testfunc (ref1, ref2, ref3, rnd); +@@ -124,11 +118,11 @@ + mpfr_set (res1, ref2, rnd); /* exact operation */ + testfunc (res1, res1, ref3, rnd); + +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, a, c) with %s for ", foo, + mpfr_print_rnd_mode (rnd)); +- DISP("a=",ref2); DISP2(", c=",ref3); ++ DISP("a=", ref2); DISP2(", c=", ref3); + printf ("expected "); mpfr_dump (ref1); + printf ("got "); mpfr_dump (res1); + exit (1); +@@ -137,11 +131,12 @@ + /* foo(a, b, a) */ + mpfr_set (res1, ref3, rnd); + testfunc (res1, ref2, res1, rnd); +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, b, a) for ", foo); +- DISP("b=",ref2); DISP2(", a=", ref3); +- DISP("expected ", ref1); DISP2(", got ",res1); ++ DISP("b=", ref2); DISP2(", a=", ref3); ++ printf ("expected "); mpfr_dump (ref1); ++ printf ("got "); mpfr_dump (res1); + exit (1); + } + +@@ -151,11 +146,12 @@ + mpfr_set (res1, ref2, rnd); + testfunc (res1, res1, res1, rnd); + +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, a, a) for ", foo); +- DISP2("a=",ref2); +- DISP("expected ", ref1); DISP2(", got ", res1); ++ DISP2("a=", ref2); ++ printf ("expected "); mpfr_dump (ref1); ++ printf ("got "); mpfr_dump (res1); + exit (1); + } + } +@@ -187,13 +183,13 @@ + /* for each variable, consider each of the following 6 possibilities: + NaN, +Infinity, -Infinity, +0, -0 or a random number */ + +- for (i=0; i<SPECIAL_MAX; i++) ++ for (i = 0; i < SPECIAL_MAX; i++) + { + set_special (op1, i); +- for (j=0; j<SPECIAL_MAX; j++) ++ for (j = 0; j < SPECIAL_MAX; j++) + { + set_special (op2, j); +- for (k=0; k<SPECIAL_MAX; k++) ++ for (k = 0; k < SPECIAL_MAX; k++) + { + set_special (op3, k); + +@@ -204,11 +200,12 @@ + mpfr_set (res, op1, rnd); /* exact operation */ + testfunc (res, res, op2, op3, rnd); + +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, b, c) for ", foo); + DISP("a=", op1); DISP(", b=", op2); DISP2(", c=", op3); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + +@@ -216,11 +213,12 @@ + mpfr_set (res, op2, rnd); + testfunc (res, op1, res, op3, rnd); + +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, b, c) for ", foo); + DISP("a=", op1); DISP(", b=", op2); DISP2(", c=", op3); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + +@@ -228,35 +226,38 @@ + mpfr_set (res, op3, rnd); + testfunc (res, op1, op2, res, rnd); + +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, b, c) for ", foo); + DISP("a=", op1); DISP(", b=", op2); DISP2(", c=", op3); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + +- /* foo(a, a, a,c) */ ++ /* foo(a, a, a, c) */ + testfunc (ref, op1, op1, op3, rnd); + mpfr_set (res, op1, rnd); + testfunc (res, res, res, op3, rnd); +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, b, c) for ", foo); + DISP("a=", op1); DISP(", a=", op2); DISP2(", c=", op3); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + +- /* foo(a, a, b,a) */ ++ /* foo(a, a, b, a) */ + testfunc (ref, op1, op2, op1, rnd); + mpfr_set (res, op1, rnd); + testfunc (res, res, op2, res, rnd); +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, b, c) for ", foo); + DISP("a=", op1); DISP(", a=", op2); DISP2(", c=", op3); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + +@@ -264,11 +265,12 @@ + testfunc (ref, op1, op2, op2, rnd); + mpfr_set (res, op2, rnd); + testfunc (res, op1, res, res, rnd); +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, b, c) for ", foo); + DISP("a=", op1); DISP(", a=", op2); DISP2(", c=", op3); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + +@@ -276,11 +278,12 @@ + testfunc (ref, op1, op1, op1, rnd); + mpfr_set (res, op1, rnd); + testfunc (res, res, res, res, rnd); +- if (mpfr_compare (res, ref)) ++ if (! SAME_VAL (res, ref)) + { + printf ("Error for %s(a, a, a, a) for ", foo); + DISP2("a=", op1); +- DISP("expected ", ref); DISP2(", got ", res); ++ printf ("expected "); mpfr_dump (ref); ++ printf ("got "); mpfr_dump (res); + exit (1); + } + } +@@ -313,10 +316,10 @@ + + /* ref2 can be NaN, +Inf, -Inf, +0, -0 or any number + ref3 can be 0 or any number */ +- for (i=0; i<SPECIAL_MAX*2; i++) ++ for (i = 0; i < SPECIAL_MAX * 2; i++) + { +- set_special (ref2, i%SPECIAL_MAX); +- ref3 = i/SPECIAL_MAX == 0 ? 0 : randlimb (); ++ set_special (ref2, i % SPECIAL_MAX); ++ ref3 = i / SPECIAL_MAX == 0 ? 0 : randlimb (); + + /* reference call: foo(a, b, c) */ + testfunc (ref1, ref2, ref3, rnd); +@@ -325,10 +328,10 @@ + mpfr_set (res1, ref2, rnd); /* exact operation */ + testfunc (res1, res1, ref3, rnd); + +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, a, c) for c=%u\n", foo, ref3); +- DISP2("a=",ref2); ++ DISP2("a=", ref2); + printf ("expected "); mpfr_dump (ref1); + printf ("got "); mpfr_dump (res1); + exit (1); +@@ -356,10 +359,10 @@ + mpfr_init2 (ref3, prec); + mpfr_init2 (res1, prec); + +- for (i=0; i<SPECIAL_MAX*2; i++) ++ for (i = 0; i < SPECIAL_MAX * 2; i++) + { +- set_special (ref3, i%SPECIAL_MAX); +- ref2 = i/SPECIAL_MAX==0 ? 0 : randlimb (); ++ set_special (ref3, i % SPECIAL_MAX); ++ ref2 = i / SPECIAL_MAX == 0 ? 0 : randlimb (); + + /* reference call: foo(a, b, c) */ + testfunc (ref1, ref2, ref3, rnd); +@@ -367,7 +370,7 @@ + /* foo(a, b, a) */ + mpfr_set (res1, ref3, rnd); /* exact operation */ + testfunc (res1, ref2, res1, rnd); +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, b, a) for b=%u \n", foo, ref2); + DISP2("a=", ref3); +@@ -397,7 +400,7 @@ + mpfr_init2 (ref2, prec); + mpfr_init2 (res1, prec); + +- for (i=0; i<SPECIAL_MAX; i++) ++ for (i = 0; i < SPECIAL_MAX; i++) + { + set_special (ref2, i); + +@@ -407,7 +410,7 @@ + /* foo(a, a) */ + mpfr_set (res1, ref2, rnd); /* exact operation */ + testfunc (res1, res1, rnd); +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, a) for ", foo); + DISP2("a=", ref2); +@@ -437,7 +440,7 @@ + mpfr_init2 (ref2, prec); + mpfr_init2 (res1, prec); + +- for (i=0; i<SPECIAL_MAX; i++) ++ for (i = 0; i < SPECIAL_MAX; i++) + { + set_special (ref2, i); + +@@ -447,10 +450,10 @@ + /* foo(a, a) */ + mpfr_set (res1, ref2, MPFR_RNDN); /* exact operation */ + testfunc (res1, res1); +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for %s(a, a) for ", foo); +- DISP2("a=",ref2); ++ DISP2("a=", ref2); + DISP("expected", ref1); DISP2(", got ", res1); + exit (1); + } +@@ -479,7 +482,7 @@ + mpfr_init2 (res1, prec); + mpfr_init2 (res2, prec); + +- for (i=0; i<SPECIAL_MAX; i++) ++ for (i = 0; i < SPECIAL_MAX; i++) + { + set_special (ref3, i); + +@@ -489,12 +492,12 @@ + /* foo(a, b, a) */ + mpfr_set (res1, ref3, rnd); /* exact operation */ + testfunc (res1, res2, res1, rnd); +- if (mpfr_compare (res1, ref1) || mpfr_compare (res2, ref2)) ++ if (! SAME_VAL (res1, ref1) || ! SAME_VAL (res2, ref2)) + { + printf ("Error for %s(a, b, a) for rnd=%s, ", foo, + mpfr_print_rnd_mode (rnd)); +- DISP2("a=",ref3); +- DISP("expected (", ref1); DISP(",",ref2); ++ DISP2("a=", ref3); ++ DISP("expected (", ref1); DISP(",", ref2); + DISP("), got (", res1); DISP(",", res2); printf(")\n"); + exit (1); + } +@@ -502,11 +505,11 @@ + /* foo(a, b, b) */ + mpfr_set (res2, ref3, rnd); /* exact operation */ + testfunc (res1, res2, res2, rnd); +- if (mpfr_compare (res1, ref1) || mpfr_compare (res2, ref2)) ++ if (! SAME_VAL (res1, ref1) || ! SAME_VAL (res2, ref2)) + { + printf ("Error for %s(a, b, b) for ", foo); +- DISP2("b=",ref3); +- DISP("expected (", ref1); DISP(",",ref2); ++ DISP2("b=", ref3); ++ DISP("expected (", ref1); DISP(",", ref2); + DISP("), got (", res1); DISP(",", res2); printf(")\n"); + exit (1); + } +@@ -561,10 +564,10 @@ + mpfr_set (res1, ref2, rnd); /* exact operation */ + mpfr_pow (res1, res1, ref3, rnd); + +- if (mpfr_compare (res1, ref1)) ++ if (! SAME_VAL (res1, ref1)) + { + printf ("Error for pow_int(a, a, c) for "); +- DISP("a=",ref2); DISP2(", c=",ref3); ++ DISP("a=", ref2); DISP2(", c=", ref3); + printf ("expected "); mpfr_dump (ref1); + printf ("got "); mpfr_dump (res1); + exit (1); +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-05-12 15:08:39.233546717 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-05-12 15:08:39.325546612 +0000 +@@ -0,0 +1 @@ ++pow_general +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-05-12 15:06:11.885721962 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-05-12 15:08:39.325546612 +0000 +@@ -1 +1 @@ +-4.2.0-p6 ++4.2.0-p7 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-05-12 15:06:11.877721972 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-05-12 15:08:39.321546616 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p6" ++#define MPFR_VERSION_STRING "4.2.0-p7" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/pow.c mpfr-4.2.0-b/src/pow.c +--- mpfr-4.2.0-a/src/pow.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/src/pow.c 2023-05-12 15:08:39.309546630 +0000 +@@ -131,7 +131,6 @@ + /* Declaration of the size variable */ + mpfr_prec_t Nz = MPFR_PREC(z); /* target precision */ + mpfr_prec_t Nt; /* working precision */ +- mpfr_exp_t err; /* error */ + MPFR_ZIV_DECL (ziv_loop); + + MPFR_LOG_FUNC +@@ -171,12 +170,14 @@ + MPFR_ZIV_INIT (ziv_loop, Nt); + for (;;) + { ++ mpfr_exp_t err, exp_t; + MPFR_BLOCK_DECL (flags1); + + /* compute exp(y*ln|x|), using MPFR_RNDU to get an upper bound, so + that we can detect underflows. */ + mpfr_log (t, absx, MPFR_IS_NEG (y) ? MPFR_RNDD : MPFR_RNDU); /* ln|x| */ + mpfr_mul (t, y, t, MPFR_RNDU); /* y*ln|x| */ ++ exp_t = MPFR_GET_EXP (t); + if (k_non_zero) + { + MPFR_LOG_MSG (("subtract k * ln(2)\n", 0)); +@@ -188,14 +189,16 @@ + MPFR_LOG_VAR (t); + } + /* estimate of the error -- see pow function in algorithms.tex. +- The error on t is at most 1/2 + 3*2^(EXP(t)+1) ulps, which is +- <= 2^(EXP(t)+3) for EXP(t) >= -1, and <= 2 ulps for EXP(t) <= -2. ++ The error on t before the subtraction of k*log(2) is at most ++ 1/2 + 3*2^(EXP(t)+1) ulps, which is <= 2^(EXP(t)+3) for EXP(t) >= -1, ++ and <= 2 ulps for EXP(t) <= -2. + Additional error if k_no_zero: treal = t * errk, with + 1 - |k| * 2^(-Nt) <= exp(-|k| * 2^(-Nt)) <= errk <= 1, + i.e., additional absolute error <= 2^(EXP(k)+EXP(t)-Nt). +- Total error <= 2^err1 + 2^err2 <= 2^(max(err1,err2)+1). */ +- err = MPFR_NOTZERO (t) && MPFR_GET_EXP (t) >= -1 ? +- MPFR_GET_EXP (t) + 3 : 1; ++ Total ulp error <= 2^err1 + 2^err2 <= 2^(max(err1,err2)+1), ++ where err1 = EXP(t)+3 for EXP(t) >= -1, and 1 otherwise, ++ and err2 = EXP(k). */ ++ err = MPFR_NOTZERO (t) && exp_t >= -1 ? exp_t + 3 : 1; + if (k_non_zero) + { + if (MPFR_GET_EXP (k) > err) +@@ -328,11 +331,17 @@ + */ + if (rnd_mode == MPFR_RNDN && inexact < 0 && lk < 0 && + MPFR_GET_EXP (z) == __gmpfr_emin - 1 - lk && mpfr_powerof2_raw (z)) +- /* Rounding to nearest, real result > z * 2^k = 2^(emin - 2), +- * underflow case: we will obtain the correct result and exceptions +- * by replacing z by nextabove(z). +- */ +- mpfr_nextabove (z); ++ /* Rounding to nearest, exact result > z * 2^k = 2^(emin - 2), ++ * and underflow case because the rounded result assuming an ++ * unbounded exponent range is 2^(emin - 2). We need to round ++ * to 2^(emin - 1), i.e. to round toward +inf. ++ * Note: the old code was using "mpfr_nextabove (z);" instead of ++ * setting rnd_mode to MPFR_RNDU for the call to mpfr_mul_2si, but ++ * this was incorrect in precision 1 because in this precision, ++ * mpfr_nextabove gave 2^(emin - 1), which is representable, ++ * so that mpfr_mul_2si did not generate the wanted underflow ++ * (the value was correct, but the underflow flag was missing). */ ++ rnd_mode = MPFR_RNDU; + MPFR_CLEAR_FLAGS (); + inex2 = mpfr_mul_2si (z, z, lk, rnd_mode); + if (inex2) /* underflow or overflow */ +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-05-12 15:06:11.885721962 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-05-12 15:08:39.325546612 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p6"; ++ return "4.2.0-p7"; + } +diff -Naurd mpfr-4.2.0-a/tests/texp10.c mpfr-4.2.0-b/tests/texp10.c +--- mpfr-4.2.0-a/tests/texp10.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/texp10.c 2023-05-12 15:08:39.309546630 +0000 +@@ -190,6 +190,187 @@ + mpfr_clear (y); + } + ++/* Bug in mpfr_pow_general found by ofuf_thresholds (on 2023-02-13 for ++ a 32-bit exponent, changed on 2023-03-06 for a 64-bit exponent too), ++ fixed in commit b62966df913f73f08b3c5252e1d0c702bc20442f. ++ With a 32-bit exponent, failure for i=0. ++ expected 0.1111E1073741823 ++ got @Inf@ ++ expected flags = inexact (8) ++ got flags = overflow inexact (10) ++ With a 64-bit exponent, failure for i=1. ++ expected 0.11111111111111111111111E4611686018427387903 ++ got @Inf@ ++ expected flags = inexact (8) ++ got flags = overflow inexact (10) ++ Note: ofuf_thresholds was added to the master branch, but for the ++ time being, there are issues with these tests. ++*/ ++static void ++bug20230213 (void) ++{ ++ const char *s[2] = { ++ "0x1.34413504b3ccdbd5dd8p+28", ++ "0x1.34413509f79fef2c4e0dd14a7ae0ecfbacdbp+60" ++ }; ++ mpfr_t x1, x2, y1, y2; ++ mpfr_prec_t px[2] = { 74, 147 }; ++ mpfr_prec_t py[2] = { 4, 23 }; ++ mpfr_exp_t old_emax, emax; ++ mpfr_flags_t flags1, flags2; ++ int i; ++ ++ old_emax = mpfr_get_emax (); ++ ++ for (i = 0; i < 2; i++) ++ { ++ if (i != 0) ++ set_emax (MPFR_EMAX_MAX); ++ ++ emax = mpfr_get_emax (); ++ ++ mpfr_inits2 (px[i], x1, x2, (mpfr_ptr) 0); ++ mpfr_inits2 (py[i], y1, y2, (mpfr_ptr) 0); ++ ++ mpfr_setmax (y1, emax); ++ mpfr_log10 (x1, y1, MPFR_RNDD); ++ mpfr_set_str (x2, s[i], 0, MPFR_RNDN); ++ /* For i == 0, emax == 2^30, so that the value can be checked. ++ For i != 0, check the value for the case emax == 2^62. ++ The "0UL" ensures that the shifts are valid. */ ++ if (i == 0 || (((0UL + MPFR_EMAX_MAX) >> 31) >> 30) == 1) ++ { ++ /* printf ("Checking x1 for i=%d\n", i); */ ++ MPFR_ASSERTN (mpfr_equal_p (x1, x2)); ++ } ++ ++ /* Let MAXF be the maximum finite value (y1 above). ++ Since x1 < log10(MAXF), one should have exp10(x1) < MAXF, and ++ therefore, y2 = RU(exp10(x1)) <= RU(MAXF) = MAXF (no overflow). */ ++ flags1 = MPFR_FLAGS_INEXACT; ++ mpfr_clear_flags (); ++ mpfr_exp10 (y2, x1, MPFR_RNDU); ++ flags2 = __gmpfr_flags; ++ ++ if (! (mpfr_lessequal_p (y2, y1) && flags2 == flags1)) ++ { ++ printf ("Error in bug20230213 for i=%d\n", i); ++ printf ("emax = %" MPFR_EXP_FSPEC "d\n", (mpfr_eexp_t) emax); ++ printf ("expected "); mpfr_dump (y1); ++ printf ("got "); mpfr_dump (y2); ++ printf ("expected flags ="); ++ flags_out (flags1); ++ printf ("got flags ="); ++ flags_out (flags2); ++ exit (1); ++ } ++ ++ mpfr_clears (x1, x2, y1, y2, (mpfr_ptr) 0); ++ } ++ ++ set_emax (old_emax); ++} ++ ++/* Bug in mpfr_pow_general in precision 1 in the particular case of ++ rounding to nearest, z * 2^k = 2^(emin - 2) and real result larger ++ than this value; fixed in ff5012b61d5e5fee5156c57b8aa8fc1739c2a771 ++ (which is simplified in 4f5de980be290687ac1409aa02873e9e0dd1a030); ++ initially found by ofuf_thresholds (though the test was incorrect). ++ With a 32-bit exponent, failure for i=0. ++ With a 64-bit exponent, failure for i=1. ++ The result was correct, but the underflow flag was missing. ++ Note: ofuf_thresholds was added to the master branch, but for the ++ time being, there are issues with these tests. ++*/ ++static void ++bug20230427 (void) ++{ ++ const char *s[2] = { ++ "-0.1001101000100000100110101000011E29", ++ "-0.100110100010000010011010100001001111101111001111111101111001101E61" ++ }; ++ mpfr_t x, y, z, t1, t2; ++ mpfr_exp_t old_emin; ++ mpfr_flags_t flags, ex_flags; ++ int i, inex; ++ ++ old_emin = mpfr_get_emin (); ++ ++ mpfr_init2 (x, 63); ++ mpfr_inits2 (1, y, z, (mpfr_ptr) 0); ++ mpfr_inits2 (128, t1, t2, (mpfr_ptr) 0); ++ ++ for (i = 0; i < 2; i++) ++ { ++ if (i == 0) ++ { ++ /* Basic check: the default emin should be -2^30 (exactly). */ ++ if (mpfr_get_emin () != -1073741823) ++ abort (); ++ } ++ else ++ { ++ /* This test assumes that MPFR_EMIN_MIN = -2^62 (exactly). ++ The "0UL" ensures that the shifts are valid. */ ++ if ((((0UL - MPFR_EMIN_MIN) >> 31) >> 30) != 1) ++ break; ++ ++ set_emin (MPFR_EMIN_MIN); ++ } ++ ++ mpfr_set_str_binary (x, s[i]); ++ ++ /* We will test 10^x rounded to nearest in precision 1. ++ Check that 2^(emin - 2) < 10^x < (3/2) * 2^(emin - 2). ++ This is approximate, but by outputting the values, one can check ++ that one is not too close to the boundaries: ++ emin - 2 = -4611686018427387905 ++ log2(10^x) ~= -4611686018427387904.598 ++ emin - 2 + log2(3/2) ~= -4611686018427387904.415 ++ Thus the result should be the smallest positive number 2^(emin - 1) ++ because 10^x is closer to this number than to 0, the midpoint being ++ 2^(emin - 2). And there should be an underflow in precision 1 because ++ the result rounded to nearest in an unbounded exponent range should ++ have been 2^(emin - 2), the midpoint being (3/2) * 2^(emin - 2). ++ */ ++ mpfr_set_ui (t1, 10, MPFR_RNDN); ++ mpfr_log2 (t2, t1, MPFR_RNDN); ++ mpfr_mul (t1, t2, x, MPFR_RNDN); ++ inex = mpfr_set_exp_t (t2, mpfr_get_emin () - 2, MPFR_RNDN); ++ MPFR_ASSERTN (inex == 0); ++ MPFR_ASSERTN (mpfr_greater_p (t1, t2)); /* log2(10^x) > emin - 2 */ ++ inex = mpfr_sub (t1, t1, t2, MPFR_RNDN); ++ MPFR_ASSERTN (inex == 0); ++ mpfr_set_ui (t2, 3, MPFR_RNDN); ++ mpfr_log2 (t2, t2, MPFR_RNDN); ++ mpfr_sub_ui (t2, t2, 1, MPFR_RNDN); /* log2(3/2) */ ++ MPFR_ASSERTN (mpfr_less_p (t1, t2)); ++ ++ mpfr_clear_flags (); ++ mpfr_exp10 (y, x, MPFR_RNDN); ++ flags = __gmpfr_flags; ++ ex_flags = MPFR_FLAGS_UNDERFLOW | MPFR_FLAGS_INEXACT; ++ ++ mpfr_setmin (z, mpfr_get_emin ()); /* z = 0.1@emin */ ++ if (! (mpfr_equal_p (y, z) && flags == ex_flags)) ++ { ++ printf ("Error in bug20230427 for i=%d\n", i); ++ printf ("expected "); mpfr_dump (z); ++ printf ("got "); mpfr_dump (y); ++ printf ("emin = %" MPFR_EXP_FSPEC "d\n", ++ (mpfr_eexp_t) mpfr_get_emin ()); ++ printf ("expected flags ="); ++ flags_out (ex_flags); ++ printf ("got flags ="); ++ flags_out (flags); ++ exit (1); ++ } ++ } ++ ++ mpfr_clears (x, y, z, t1, t2, (mpfr_ptr) 0); ++ set_emin (old_emin); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -199,6 +380,9 @@ + + tests_start_mpfr (); + ++ bug20230213 (); ++ bug20230427 (); ++ + special_overflow (); + emax_m_eps (); + exp_range (); +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-05-17 17:17:28.512360351 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-05-17 17:17:28.600360192 +0000 +@@ -0,0 +1 @@ ++compound +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-05-12 15:08:39.325546612 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-05-17 17:17:28.600360192 +0000 +@@ -1 +1 @@ +-4.2.0-p7 ++4.2.0-p8 +diff -Naurd mpfr-4.2.0-a/src/compound.c mpfr-4.2.0-b/src/compound.c +--- mpfr-4.2.0-a/src/compound.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/src/compound.c 2023-05-17 17:17:28.588360213 +0000 +@@ -55,9 +55,9 @@ + mpfr_compound_si (mpfr_ptr y, mpfr_srcptr x, long n, mpfr_rnd_t rnd_mode) + { + int inexact, compared, k, nloop; +- mpfr_t t; +- mpfr_exp_t e; +- mpfr_prec_t prec; ++ mpfr_t t, u; ++ mpfr_prec_t py, prec, extra; ++ mpfr_rnd_t rnd1; + MPFR_ZIV_DECL (loop); + MPFR_SAVE_EXPO_DECL (expo); + +@@ -136,64 +136,185 @@ + + MPFR_SAVE_EXPO_MARK (expo); + +- prec = MPFR_PREC(y); +- prec += MPFR_INT_CEIL_LOG2 (prec) + 6; ++ py = MPFR_GET_PREC (y); ++ prec = py + MPFR_INT_CEIL_LOG2 (py) + 6; + + mpfr_init2 (t, prec); ++ mpfr_init2 (u, prec); + + k = MPFR_INT_CEIL_LOG2(SAFE_ABS (unsigned long, n)); /* thus |n| <= 2^k */ + ++ /* We compute u=log2p1(x) with prec+extra bits, since we lose some bits ++ in 2^u. */ ++ extra = 0; ++ rnd1 = VSIGN (n) == MPFR_SIGN (x) ? MPFR_RNDD : MPFR_RNDU; ++ + MPFR_ZIV_INIT (loop, prec); + for (nloop = 0; ; nloop++) + { +- /* we compute (1+x)^n as 2^(n*log2p1(x)) */ +- inexact = mpfr_log2p1 (t, x, MPFR_RNDN) != 0; +- e = MPFR_GET_EXP(t); +- /* |t - log2(1+x)| <= 1/2*ulp(t) = 2^(e-prec-1) */ +- inexact |= mpfr_mul_si (t, t, n, MPFR_RNDN) != 0; +- /* |t - n*log2(1+x)| <= 2^(e2-prec-1) + |n|*2^(e-prec-1) +- <= 2^(e2-prec-1) + 2^(e+k-prec-1) <= 2^(e+k-prec) +- where |n| <= 2^k, and e2 is the new exponent of t. */ +- MPFR_ASSERTD(MPFR_GET_EXP(t) <= e + k); +- e += k; +- /* |t - n*log2(1+x)| <= 2^(e-prec) */ +- /* detect overflow */ +- if (nloop == 0 && mpfr_cmp_si (t, __gmpfr_emax) >= 0) ++ unsigned int inex; ++ mpfr_exp_t e, e2, ex; ++ mpfr_prec_t precu = MPFR_ADD_PREC (prec, extra); ++ mpfr_prec_t new_extra; ++ mpfr_rnd_t rnd2; ++ ++ /* We compute (1+x)^n as 2^(n*log2p1(x)), ++ and we round toward 1, thus we round n*log2p1(x) toward 0, ++ thus for x*n > 0 we round log2p1(x) toward -Inf, and for x*n < 0 ++ we round log2p1(x) toward +Inf. */ ++ inex = mpfr_log2p1 (u, x, rnd1) != 0; ++ e = MPFR_GET_EXP (u); ++ /* |u - log2(1+x)| <= ulp(t) = 2^(e-precu) */ ++ inex |= mpfr_mul_si (u, u, n, MPFR_RNDZ) != 0; ++ e2 = MPFR_GET_EXP (u); ++ /* |u - n*log2(1+x)| <= 2^(e2-precu) + |n|*2^(e-precu) ++ <= 2^(e2-precu) + 2^(e+k-precu) <= 2^(e+k+1-precu) ++ where |n| <= 2^k, and e2 is the new exponent of u. */ ++ MPFR_ASSERTD (e2 <= e + k); ++ e += k + 1; ++ MPFR_ASSERTN (e2 <= MPFR_PREC_MAX); ++ new_extra = e2 > 0 ? e2 : 0; ++ /* |u - n*log2(1+x)| <= 2^(e-precu) */ ++ /* detect overflow: since we rounded n*log2p1(x) toward 0, ++ if n*log2p1(x) >= __gmpfr_emax, we are sure there is overflow. */ ++ if (mpfr_cmp_si (u, __gmpfr_emax) >= 0) + { + MPFR_ZIV_FREE (loop); + mpfr_clear (t); ++ mpfr_clear (u); + MPFR_SAVE_EXPO_FREE (expo); + return mpfr_overflow (y, rnd_mode, 1); + } +- /* detect underflow */ +- if (nloop == 0 && mpfr_cmp_si (t, __gmpfr_emin - 1) <= 0) ++ /* detect underflow: similarly, since we rounded n*log2p1(x) toward 0, ++ if n*log2p1(x) < __gmpfr_emin-1, we are sure there is underflow. */ ++ if (mpfr_cmp_si (u, __gmpfr_emin - 1) < 0) + { + MPFR_ZIV_FREE (loop); + mpfr_clear (t); ++ mpfr_clear (u); + MPFR_SAVE_EXPO_FREE (expo); + return mpfr_underflow (y, +- (rnd_mode == MPFR_RNDN) ? MPFR_RNDZ : rnd_mode, 1); ++ rnd_mode == MPFR_RNDN ? MPFR_RNDZ : rnd_mode, 1); + } + /* Detect cases where result is 1 or 1+ulp(1) or 1-1/2*ulp(1): +- |2^t - 1| = |exp(t*log(2)) - 1| <= |t|*log(2) < |t| */ +- if (nloop == 0 && MPFR_GET_EXP(t) < - (mpfr_exp_t) MPFR_PREC(y)) ++ |2^u - 1| = |exp(u*log(2)) - 1| <= |u|*log(2) < |u| */ ++ if (nloop == 0 && MPFR_GET_EXP(u) < - py) + { +- /* since ulp(1) = 2^(1-PREC(y)), we have |t| < 1/4*ulp(1) */ ++ /* since ulp(1) = 2^(1-py), we have |u| < 1/4*ulp(1) */ + /* mpfr_compound_near_one must be called in the extended + exponent range, so that 1 is representable. */ +- inexact = mpfr_compound_near_one (y, MPFR_SIGN (t), rnd_mode); ++ inexact = mpfr_compound_near_one (y, MPFR_SIGN (u), rnd_mode); + goto end; + } +- inexact |= mpfr_exp2 (t, t, MPFR_RNDA) != 0; +- /* |t - (1+x)^n| <= ulp(t) + |t|*log(2)*2^(e-prec) +- < 2^(EXP(t)-prec) + 2^(EXP(t)+e-prec) */ +- e = (e >= 0) ? e + 1 : 1; ++ /* FIXME: mpfr_exp2 could underflow to the smallest positive number ++ since MPFR_RNDA is used, and this case will not be detected by ++ MPFR_CAN_ROUND (see BUGS). Either fix that, or do early underflow ++ detection (which may be necessary). */ ++ /* round 2^u toward 1 */ ++ rnd2 = MPFR_IS_POS (u) ? MPFR_RNDD : MPFR_RNDU; ++ inex |= mpfr_exp2 (t, u, rnd2) != 0; ++ /* we had |u - n*log2(1+x)| < 2^(e-precu) ++ thus u = n*log2(1+x) + delta with |delta| < 2^(e-precu) ++ then 2^u = (1+x)^n * 2^delta with |delta| < 2^(e-precu). ++ For |delta| < 0.5, |2^delta - 1| <= |delta| thus ++ |t - (1+x)^n| <= ulp(t) + |t|*2^(e-precu) ++ < 2^(EXP(t)-prec) + 2^(EXP(t)+e-precu) */ ++ e = (precu - prec >= e) ? 1 : e + 1 - (precu - prec); + /* now |t - (1+x)^n| < 2^(EXP(t)+e-prec) */ + +- if (MPFR_LIKELY (inexact == 0 || +- MPFR_CAN_ROUND (t, prec - e, MPFR_PREC(y), rnd_mode))) ++ if (MPFR_LIKELY (!inex || MPFR_CAN_ROUND (t, prec - e, py, rnd_mode))) + break; + ++ /* If t fits in the target precision (or with 1 more bit), then we can ++ round, assuming the working precision is large enough, but the above ++ MPFR_CAN_ROUND() will fail because we cannot determine the ternary ++ value. However since we rounded t toward 1, we can determine it. ++ Since the error in the approximation t is at most 2^e ulp(t), ++ this error should be less than 1/2 ulp(y), thus we should have ++ prec - py >= e + 1. */ ++ if (mpfr_min_prec (t) <= py + 1 && prec - py >= e + 1) ++ { ++ /* we add/subtract one ulp to get the correct rounding */ ++ if (rnd2 == MPFR_RNDD) /* t was rounded downwards */ ++ mpfr_nextabove (t); ++ else ++ mpfr_nextbelow (t); ++ break; ++ } ++ ++ /* Detect particular cases where Ziv's strategy may take too much ++ memory and be too long, i.e. when x^n fits in the target precision ++ (+ 1 additional bit for rounding to nearest) and the exact result ++ (1+x)^n is very close to x^n. ++ Necessarily, x is a large even integer and n > 0 (thus n > 1). ++ Since this does not depend on the working precision, we only ++ check this at the first iteration (nloop == 0). ++ Hence the first "if" below and the kx < ex test of the second "if" ++ (x is an even integer iff its least bit 1 has exponent >= 1). ++ The second test of the second "if" corresponds to another simple ++ condition that implies that x^n fits in the target precision. ++ Here are the details: ++ Let k be the minimum length of the significand of x, and x' the odd ++ (integer) significand of x. This means that 2^(k-1) <= x' < 2^k. ++ Thus 2^(n*(k-1)) <= (x')^n < 2^(k*n), and x^n has between n*(k-1)+1 ++ and k*n bits. So x^n can fit into p bits only if p >= n*(k-1)+1, ++ i.e. n*(k-1) <= p-1. ++ Note that x >= 2^k, so that x^n >= 2^(k*n). Since raw overflow ++ has already been detected, k*n cannot overflow if computed with ++ the mpfr_exp_t type. Hence the second test of the second "if", ++ which cannot overflow. */ ++ MPFR_ASSERTD (n < 0 || n > 1); ++ if (nloop == 0 && n > 1 && (ex = MPFR_GET_EXP (x)) >= 17) ++ { ++ mpfr_prec_t kx = mpfr_min_prec (x); ++ mpfr_prec_t p = py + (rnd_mode == MPFR_RNDN); ++ ++ MPFR_LOG_MSG (("Check if x^n fits... n=%ld kx=%Pd p=%Pd\n", ++ n, kx, p)); ++ if (kx < ex && n * (mpfr_exp_t) (kx - 1) <= p - 1) ++ { ++ mpfr_t v; ++ ++ /* Check whether x^n really fits into p bits. */ ++ mpfr_init2 (v, p); ++ inexact = mpfr_pow_ui (v, x, n, MPFR_RNDZ); ++ if (inexact == 0) ++ { ++ MPFR_LOG_MSG (("x^n fits into p bits\n", 0)); ++ /* (x+1)^n = x^n * (1 + 1/x)^n ++ For directed rounding, we can round when (1 + 1/x)^n ++ < 1 + 2^-p, and then the result is x^n, ++ except for rounding up. Indeed, if (1 + 1/x)^n < 1 + 2^-p, ++ 1 <= (x+1)^n < x^n * (1 + 2^-p) = x^n + x^n/2^p ++ < x^n + ulp(x^n). ++ For rounding to nearest, we can round when (1 + 1/x)^n ++ < 1 + 2^-p, and then the result is x^n when x^n fits ++ into p-1 bits, and nextabove(x^n) otherwise. */ ++ mpfr_ui_div (t, 1, x, MPFR_RNDU); ++ mpfr_add_ui (t, t, 1, MPFR_RNDU); ++ mpfr_pow_ui (t, t, n, MPFR_RNDU); ++ mpfr_sub_ui (t, t, 1, MPFR_RNDU); ++ /* t cannot be zero */ ++ if (MPFR_GET_EXP(t) < - py) ++ { ++ mpfr_set (y, v, MPFR_RNDZ); ++ if ((rnd_mode == MPFR_RNDN && mpfr_min_prec (v) == p) ++ || rnd_mode == MPFR_RNDU || rnd_mode == MPFR_RNDA) ++ { ++ /* round up */ ++ mpfr_nextabove (y); ++ inexact = 1; ++ } ++ else ++ inexact = -1; ++ mpfr_clear (v); ++ goto end; ++ } ++ } ++ mpfr_clear (v); ++ } ++ } ++ + /* Exact cases like compound(0.5,2) = 9/4 must be detected, since + except for 1+x power of 2, the log2p1 above will be inexact, + so that in the Ziv test, inexact != 0 and MPFR_CAN_ROUND will +@@ -211,6 +332,8 @@ + + MPFR_ZIV_NEXT (loop, prec); + mpfr_set_prec (t, prec); ++ extra = new_extra; ++ mpfr_set_prec (u, MPFR_ADD_PREC (prec, extra)); + } + + inexact = mpfr_set (y, t, rnd_mode); +@@ -218,6 +341,7 @@ + end: + MPFR_ZIV_FREE (loop); + mpfr_clear (t); ++ mpfr_clear (u); + + MPFR_SAVE_EXPO_FREE (expo); + return mpfr_check_range (y, inexact, rnd_mode); +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-05-12 15:08:39.321546616 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-05-17 17:17:28.596360199 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p7" ++#define MPFR_VERSION_STRING "4.2.0-p8" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-05-12 15:08:39.325546612 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-05-17 17:17:28.600360192 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p7"; ++ return "4.2.0-p8"; + } +diff -Naurd mpfr-4.2.0-a/tests/tcompound.c mpfr-4.2.0-b/tests/tcompound.c +--- mpfr-4.2.0-a/tests/tcompound.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tcompound.c 2023-05-17 17:17:28.588360213 +0000 +@@ -238,18 +238,263 @@ + mpfr_clear (y); + } + +-static int +-mpfr_compound2 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) ++/* Failure with mpfr_compound_si from 2021-02-15 due to ++ incorrect underflow detection. */ ++static void ++bug_20230206 (void) + { +- return mpfr_compound_si (y, x, 2, rnd_mode); ++ if (MPFR_PREC_MIN == 1) ++ { ++ mpfr_t x, y1, y2; ++ int inex1, inex2; ++ mpfr_flags_t flags1, flags2; ++#if MPFR_PREC_BITS >= 64 ++ mpfr_exp_t emin; ++#endif ++ ++ mpfr_inits2 (1, x, y1, y2, (mpfr_ptr) 0); ++ mpfr_set_ui_2exp (x, 1, -1, MPFR_RNDN); /* x = 1/2 */ ++ ++ /* This first test is useful mainly for a 32-bit mpfr_exp_t type ++ (no failure with a 64-bit mpfr_exp_t type since the underflow ++ threshold in the extended exponent range is much lower). */ ++ ++ mpfr_set_ui_2exp (y1, 1, -1072124363, MPFR_RNDN); ++ inex1 = -1; ++ flags1 = MPFR_FLAGS_INEXACT; ++ mpfr_clear_flags (); ++ /* -1832808704 ~= -2^30 / log2(3/2) */ ++ inex2 = mpfr_compound_si (y2, x, -1832808704, MPFR_RNDN); ++ flags2 = __gmpfr_flags; ++ if (!(mpfr_equal_p (y1, y2) && ++ SAME_SIGN (inex1, inex2) && ++ flags1 == flags2)) ++ { ++ printf ("Error in bug_20230206 (1):\n"); ++ printf ("Expected "); ++ mpfr_dump (y1); ++ printf (" with inex = %d, flags =", inex1); ++ flags_out (flags1); ++ printf ("Got "); ++ mpfr_dump (y2); ++ printf (" with inex = %d, flags =", inex2); ++ flags_out (flags2); ++ exit (1); ++ } ++ ++ /* This second test is for a 64-bit mpfr_exp_t type ++ (it is disabled with a 32-bit mpfr_exp_t type). */ ++ ++ /* The "#if" makes sure that 64-bit constants are supported, avoiding ++ a compilation failure. The "if" makes sure that the constant is ++ representable in a long (this would not be the case with 32-bit ++ unsigned long and 64-bit limb). It also ensures that mpfr_exp_t ++ has at least 64 bits. */ ++#if MPFR_PREC_BITS >= 64 ++ emin = mpfr_get_emin (); ++ set_emin (MPFR_EMIN_MIN); ++ mpfr_set_ui_2exp (y1, 1, -4611686018427366846, MPFR_RNDN); ++ inex1 = 1; ++ flags1 = MPFR_FLAGS_INEXACT; ++ mpfr_clear_flags (); ++ /* -7883729320669216768 ~= -2^62 / log2(3/2) */ ++ inex2 = mpfr_compound_si (y2, x, -7883729320669216768, MPFR_RNDN); ++ flags2 = __gmpfr_flags; ++ if (!(mpfr_equal_p (y1, y2) && ++ SAME_SIGN (inex1, inex2) && ++ flags1 == flags2)) ++ { ++ printf ("Error in bug_20230206 (2):\n"); ++ printf ("Expected "); ++ mpfr_dump (y1); ++ printf (" with inex = %d, flags =", inex1); ++ flags_out (flags1); ++ printf ("Got "); ++ mpfr_dump (y2); ++ printf (" with inex = %d, flags =", inex2); ++ flags_out (flags2); ++ exit (1); ++ } ++ set_emin (emin); ++#endif ++ ++ mpfr_clears (x, y1, y2, (mpfr_ptr) 0); ++ } + } + ++/* Reported by Patrick Pelissier on 2023-02-11 for the master branch ++ (tgeneric_ui.c with GMP_CHECK_RANDOMIZE=1412991715). ++ On a 32-bit host, one gets Inf (overflow) instead of 0.1E1071805703. ++*/ ++static void ++bug_20230211 (void) ++{ ++ mpfr_t x, y1, y2; ++ int inex1, inex2; ++ mpfr_flags_t flags1, flags2; ++ ++ mpfr_inits2 (1, x, y1, y2, (mpfr_ptr) 0); ++ mpfr_set_ui_2exp (x, 1, -1, MPFR_RNDN); /* x = 1/2 */ ++ mpfr_set_ui_2exp (y1, 1, 1071805702, MPFR_RNDN); ++ inex1 = 1; ++ flags1 = MPFR_FLAGS_INEXACT; ++ mpfr_clear_flags (); ++ inex2 = mpfr_compound_si (y2, x, 1832263949, MPFR_RNDN); ++ flags2 = __gmpfr_flags; ++ if (!(mpfr_equal_p (y1, y2) && ++ SAME_SIGN (inex1, inex2) && ++ flags1 == flags2)) ++ { ++ printf ("Error in bug_20230211:\n"); ++ printf ("Expected "); ++ mpfr_dump (y1); ++ printf (" with inex = %d, flags =", inex1); ++ flags_out (flags1); ++ printf ("Got "); ++ mpfr_dump (y2); ++ printf (" with inex = %d, flags =", inex2); ++ flags_out (flags2); ++ exit (1); ++ } ++ mpfr_clears (x, y1, y2, (mpfr_ptr) 0); ++} ++ ++/* Integer overflow with compound.c d04caeae04c6a83276916c4fbac1fe9b0cec3c8b ++ (2023-02-23) or 952fb0f5cc2df1fffde3eb54c462fdae5f123ea6 in the 4.2 branch ++ on "n * (kx - 1) + 1". Note: if the only effect is just a random value, ++ this probably doesn't affect the result (one might enter the "if" while ++ one shouldn't, but the real check is done inside the "if"). This test ++ fails if -fsanitize=undefined -fno-sanitize-recover is used or if the ++ processor emits a signal in case of integer overflow. ++ This test has been made obsolete by the "kx < ex" condition ++ in 2cb3123891dd46fe0258d4aec7f8655b8ec69aaf (master branch) ++ or f5cb40571bc3d1559f05b230cf4ffecaf0952852 (4.2 branch). */ ++static void ++bug_20230517 (void) ++{ ++ mpfr_exp_t old_emax; ++ mpfr_t x; ++ ++ old_emax = mpfr_get_emax (); ++ set_emax (MPFR_EMAX_MAX); ++ ++ mpfr_init2 (x, 123456); ++ mpfr_set_ui (x, 65536, MPFR_RNDN); ++ mpfr_nextabove (x); ++ mpfr_compound_si (x, x, LONG_MAX >> 16, MPFR_RNDN); ++ mpfr_clear (x); ++ ++ set_emax (old_emax); ++} ++ ++/* Inverse function on non-special cases... ++ One has x = (1+y)^n with y > -1 and x > 0. Thus y = x^(1/n) - 1. ++ The inverse function is useful ++ - to build and check hard-to-round cases (see bad_cases() in tests.c); ++ - to test the behavior close to the overflow and underflow thresholds. ++ The case x = 0 actually needs to be handled as it may occur with ++ bad_cases() due to rounding. ++*/ + static int +-mpfr_compound3 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode) ++inv_compound (mpfr_ptr y, mpfr_srcptr x, long n, mpfr_rnd_t rnd_mode) + { +- return mpfr_compound_si (y, x, 3, rnd_mode); ++ mpfr_t t; ++ int inexact; ++ mpfr_prec_t precy, prect; ++ MPFR_ZIV_DECL (loop); ++ MPFR_SAVE_EXPO_DECL (expo); ++ ++ MPFR_ASSERTN (n != 0); ++ ++ if (MPFR_UNLIKELY (MPFR_IS_ZERO (x))) ++ { ++ if (n > 0) ++ return mpfr_set_si (y, -1, rnd_mode); ++ else ++ { ++ MPFR_SET_INF (y); ++ MPFR_SET_POS (y); ++ MPFR_RET (0); ++ } ++ } ++ ++ MPFR_SAVE_EXPO_MARK (expo); ++ ++ if (mpfr_equal_p (x, __gmpfr_one)) ++ { ++ MPFR_SAVE_EXPO_FREE (expo); ++ mpfr_set_zero (y, 1); ++ MPFR_RET (0); ++ } ++ ++ precy = MPFR_GET_PREC (y); ++ prect = precy + 20; ++ mpfr_init2 (t, prect); ++ ++ MPFR_ZIV_INIT (loop, prect); ++ for (;;) ++ { ++ mpfr_exp_t expt1, expt2, err; ++ unsigned int inext; ++ ++ if (mpfr_rootn_si (t, x, n, MPFR_RNDN) == 0) ++ { ++ /* With a huge t, this case would yield inext != 0 and a ++ MPFR_CAN_ROUND failure until a huge precision is reached ++ (as the result is very close to an exact point). Fortunately, ++ since t is exact, we can obtain the correctly rounded result ++ by doing the second operation to the target precision directly. ++ */ ++ inexact = mpfr_sub_ui (y, t, 1, rnd_mode); ++ goto end; ++ } ++ expt1 = MPFR_GET_EXP (t); ++ /* |error| <= 2^(expt1-prect-1) */ ++ inext = mpfr_sub_ui (t, t, 1, MPFR_RNDN); ++ if (MPFR_UNLIKELY (MPFR_IS_ZERO (t))) ++ goto cont; /* cannot round yet */ ++ expt2 = MPFR_GET_EXP (t); ++ err = 1; ++ if (expt2 < expt1) ++ err += expt1 - expt2; ++ /* |error(rootn)| <= 2^(err+expt2-prect-2) ++ and if mpfr_sub_ui is inexact: ++ |error| <= 2^(err+expt2-prect-2) + 2^(expt2-prect-1) ++ <= (2^(err-1) + 1) * 2^(expt2-prect-1) ++ <= 2^((err+1)+expt2-prect-2) */ ++ if (inext) ++ err++; ++ /* |error| <= 2^(err+expt2-prect-2) */ ++ if (MPFR_CAN_ROUND (t, prect + 2 - err, precy, rnd_mode)) ++ break; ++ ++ cont: ++ MPFR_ZIV_NEXT (loop, prect); ++ mpfr_set_prec (t, prect); ++ } ++ ++ inexact = mpfr_set (y, t, rnd_mode); ++ ++ end: ++ MPFR_ZIV_FREE (loop); ++ mpfr_clear (t); ++ MPFR_SAVE_EXPO_FREE (expo); ++ return mpfr_check_range (y, inexact, rnd_mode); + } + ++#define DEFN(N) \ ++ static int mpfr_compound##N (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t r) \ ++ { return mpfr_compound_si (y, x, N, r); } \ ++ static int inv_compound##N (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t r) \ ++ { return inv_compound (y, x, N, r); } ++ ++DEFN(2) ++DEFN(3) ++DEFN(4) ++DEFN(5) ++DEFN(17) ++DEFN(120) ++ + #define TEST_FUNCTION mpfr_compound2 + #define test_generic test_generic_compound2 + #include "tgeneric.c" +@@ -258,17 +503,55 @@ + #define test_generic test_generic_compound3 + #include "tgeneric.c" + ++#define TEST_FUNCTION mpfr_compound4 ++#define test_generic test_generic_compound4 ++#include "tgeneric.c" ++ ++#define TEST_FUNCTION mpfr_compound5 ++#define test_generic test_generic_compound5 ++#include "tgeneric.c" ++ ++#define TEST_FUNCTION mpfr_compound17 ++#define test_generic test_generic_compound17 ++#include "tgeneric.c" ++ ++#define TEST_FUNCTION mpfr_compound120 ++#define test_generic test_generic_compound120 ++#include "tgeneric.c" ++ + int + main (void) + { + tests_start_mpfr (); + + check_ieee754 (); ++ bug_20230206 (); ++ bug_20230211 (); ++ bug_20230517 (); + + test_generic_si (MPFR_PREC_MIN, 100, 100); + + test_generic_compound2 (MPFR_PREC_MIN, 100, 100); + test_generic_compound3 (MPFR_PREC_MIN, 100, 100); ++ test_generic_compound4 (MPFR_PREC_MIN, 100, 100); ++ test_generic_compound5 (MPFR_PREC_MIN, 100, 100); ++ test_generic_compound17 (MPFR_PREC_MIN, 100, 100); ++ test_generic_compound120 (MPFR_PREC_MIN, 100, 100); ++ ++ /* Note: For small n, we need a psup high enough to avoid too many ++ "f exact while f^(-1) inexact" occurrences in bad_cases(). */ ++ bad_cases (mpfr_compound2, inv_compound2, "mpfr_compound2", ++ 0, -256, 255, 4, 128, 240, 40); ++ bad_cases (mpfr_compound3, inv_compound3, "mpfr_compound3", ++ 0, -256, 255, 4, 128, 120, 40); ++ bad_cases (mpfr_compound4, inv_compound4, "mpfr_compound4", ++ 0, -256, 255, 4, 128, 80, 40); ++ bad_cases (mpfr_compound5, inv_compound5, "mpfr_compound5", ++ 0, -256, 255, 4, 128, 80, 40); ++ bad_cases (mpfr_compound17, inv_compound17, "mpfr_compound17", ++ 0, -256, 255, 4, 128, 80, 40); ++ bad_cases (mpfr_compound120, inv_compound120, "mpfr_compound120", ++ 0, -256, 255, 4, 128, 80, 40); + + tests_end_mpfr (); + return 0; +diff -Naurd mpfr-4.2.0-a/tests/tests.c mpfr-4.2.0-b/tests/tests.c +--- mpfr-4.2.0-a/tests/tests.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/tests/tests.c 2023-05-17 17:17:28.588360213 +0000 +@@ -1086,10 +1086,9 @@ + } + if (inex_inv) + { +- printf ("bad_cases: f exact while f^(-1) inexact,\n" +- "due to a poor choice of the parameters.\n"); +- exit (1); +- /* alternatively, goto next_i */ ++ if (dbg) ++ printf ("bad_cases: f exact while f^(-1) inexact\n"); ++ goto does_not_match; + } + inex = 0; + break; +@@ -1112,6 +1111,10 @@ + if (mpfr_nanflag_p () || mpfr_overflow_p () || mpfr_underflow_p () + || ! mpfr_equal_p (z, y)) + { ++ /* This may occur when psup is not large enough: evaluating ++ x = (f^(-1))(y) then z = f(x) may not give back y if the ++ precision of x is too small. */ ++ does_not_match: + if (dbg) + { + printf ("bad_cases: inverse doesn't match for %s\ny = ", +diff -Naurd mpfr-4.2.0-a/PATCHES mpfr-4.2.0-b/PATCHES +--- mpfr-4.2.0-a/PATCHES 2023-05-17 17:19:35.484201703 +0000 ++++ mpfr-4.2.0-b/PATCHES 2023-05-17 17:19:35.596201603 +0000 +@@ -0,0 +1 @@ ++printf_large_prec_for_g +diff -Naurd mpfr-4.2.0-a/VERSION mpfr-4.2.0-b/VERSION +--- mpfr-4.2.0-a/VERSION 2023-05-17 17:17:28.600360192 +0000 ++++ mpfr-4.2.0-b/VERSION 2023-05-17 17:19:35.596201603 +0000 +@@ -1 +1 @@ +-4.2.0-p8 ++4.2.0-p9 +diff -Naurd mpfr-4.2.0-a/src/mpfr.h mpfr-4.2.0-b/src/mpfr.h +--- mpfr-4.2.0-a/src/mpfr.h 2023-05-17 17:17:28.596360199 +0000 ++++ mpfr-4.2.0-b/src/mpfr.h 2023-05-17 17:19:35.592201606 +0000 +@@ -27,7 +27,7 @@ + #define MPFR_VERSION_MAJOR 4 + #define MPFR_VERSION_MINOR 2 + #define MPFR_VERSION_PATCHLEVEL 0 +-#define MPFR_VERSION_STRING "4.2.0-p8" ++#define MPFR_VERSION_STRING "4.2.0-p9" + + /* User macros: + MPFR_USE_FILE: Define it to make MPFR define functions dealing +diff -Naurd mpfr-4.2.0-a/src/vasprintf.c mpfr-4.2.0-b/src/vasprintf.c +--- mpfr-4.2.0-a/src/vasprintf.c 2023-01-05 17:09:48.000000000 +0000 ++++ mpfr-4.2.0-b/src/vasprintf.c 2023-05-17 17:19:35.576201620 +0000 +@@ -1888,7 +1888,7 @@ + precision T-1. + where T is the threshold computed below and X is the exponent + that would be displayed with style 'e' and precision T-1. */ +- int threshold; ++ mpfr_intmax_t threshold; + mpfr_exp_t x, e, k; + struct decimal_info dec_info; + +@@ -1920,9 +1920,15 @@ + e = e <= 0 ? k : (e + 2) / 3 + (k <= 0 ? 0 : k); + MPFR_ASSERTD (e >= 1); + ++ if (e > threshold) ++ e = threshold; ++ ++ /* error if e does not fit in size_t (for mpfr_get_str) */ ++ if (e > (size_t) -1) ++ goto error; ++ + dec_info.str = mpfr_get_str (NULL, &dec_info.exp, 10, +- e < threshold ? e : threshold, +- p, spec.rnd_mode); ++ e, p, spec.rnd_mode); + register_string (np->sl, dec_info.str); + /* mpfr_get_str corresponds to a significand between 0.1 and 1, + whereas here we want a significand between 1 and 10. */ +diff -Naurd mpfr-4.2.0-a/src/version.c mpfr-4.2.0-b/src/version.c +--- mpfr-4.2.0-a/src/version.c 2023-05-17 17:17:28.600360192 +0000 ++++ mpfr-4.2.0-b/src/version.c 2023-05-17 17:19:35.592201606 +0000 +@@ -25,5 +25,5 @@ + const char * + mpfr_get_version (void) + { +- return "4.2.0-p8"; ++ return "4.2.0-p9"; + } +diff -Naurd mpfr-4.2.0-a/tests/tsprintf.c mpfr-4.2.0-b/tests/tsprintf.c +--- mpfr-4.2.0-a/tests/tsprintf.c 2023-04-17 21:17:39.784645229 +0000 ++++ mpfr-4.2.0-b/tests/tsprintf.c 2023-05-17 17:19:35.576201620 +0000 +@@ -1620,6 +1620,30 @@ + mpfr_clear (x); + } + ++/* On 2023-03-22, on a 64-bit Linux machine (thus with 32-bit int), ++ the case %.2147483648Rg yields an incorrect size computation and ++ MPFR wants to allocate 18446744071562070545 bytes. With assertion ++ checking (--enable-assert), one gets: ++ vasprintf.c:1908: MPFR assertion failed: threshold >= 1 ++ ++ This case should either succeed or fail as reaching an environmental limit ++ like with glibc (note that the precision does not fit in an int). ++*/ ++static void ++large_prec_for_g (void) ++{ ++ mpfr_t x; ++ int r; ++ ++ mpfr_init2 (x, 128); ++ mpfr_set_ui (x, 1, MPFR_RNDN); ++ r = mpfr_snprintf (NULL, 0, "%.2147483647Rg\n", x); ++ MPFR_ASSERTN (r == 2); ++ r = mpfr_snprintf (NULL, 0, "%.2147483648Rg\n", x); ++ MPFR_ASSERTN (r == 2 || r < 0); ++ mpfr_clear (x); ++} ++ + #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE) + + /* The following tests should be equivalent to those from test_locale() +@@ -1793,6 +1817,7 @@ + percent_n (); + mixed (); + check_length_overflow (); ++ large_prec_for_g (); + test_locale (); + + if (getenv ("MPFR_CHECK_LIBC_PRINTF"))