diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2008-08-20 22:55:52 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2008-08-20 22:55:52 +0000 |
commit | 0ebdb8915371840594d35f33c08e989352534898 (patch) | |
tree | c2e4a4d712d5054b8f984a6c8881b19d8fe043c2 | |
parent | c7eff12c0c1473e35e2bb66180ae18f57c5de835 (diff) | |
download | mpfr-0ebdb8915371840594d35f33c08e989352534898.tar.gz |
Merged changesets concerning mpfr_hypot, from trunk: 5291, 5292, 5297,
5299, 5301, 5302, 5308, 5310, 5311, 5319, 5336, 5464, 5465, 5473, 5563,
5564, 5566. Details:
* hypot.c: rewrite, fixing the following bugs:
- the inexact flag was not always set as required;
- mpfr_hypot could loop on tiny values due to internal underflow;
- for generic overflows, the overflow flag was lost (note: this
bug is independent of the bug fixed in r5546 since the overflow
does not come after a can_round).
* tests/thypot.c:
- changed custom random tests to tgeneric ones;
- added testcases for the above bugs.
* algorithms.tex: mpfr_hypot proof rewritten.
* BUGS: added a bug concerning mpfr_hypot.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/2.3@5568 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r-- | BUGS | 5 | ||||
-rw-r--r-- | algorithms.tex | 129 | ||||
-rw-r--r-- | hypot.c | 103 | ||||
-rw-r--r-- | tests/thypot.c | 235 |
4 files changed, 310 insertions, 162 deletions
@@ -37,6 +37,11 @@ Known bugs: * Some functions do not use MPFR_SAVE_EXPO_* macros, thus do not behave correctly in a reduced exponent range. +* Function hypot gives incorrect result when on the one hand the difference + between parameters' exponents is near 2*MPFR_EMAX_MAX and on the other hand + the output precision or the precision of the parameter with greatest + absolute value is greater than 2*MPFR_EMAX_MAX-4. + Potential bugs: * Possible incorrect results due to internal underflow, which can lead to diff --git a/algorithms.tex b/algorithms.tex index 9567fb01f..125078a6c 100644 --- a/algorithms.tex +++ b/algorithms.tex @@ -2168,20 +2168,121 @@ The \texttt{mpfr\_hypot} function implements the euclidean distance function: \[ \textnormal{hypot} (x,y) = \sqrt{x^2+y^2}. \] -The algorithm used is as follows, where all roundings are done towards zero: -\begin{eqnarray}\nonumber -u&\leftarrow&\circ(x^2)\\\nonumber -v&\leftarrow&\circ(y^2)\\\nonumber -w&\leftarrow&\circ(u+v)\\\nonumber -s&\leftarrow&\circ(\sqrt{w}) -\end{eqnarray} -Since the inputs $x$ and $y$ are exact, we have $|u-x^2| \leq \ulp(u)$ -and $|v-y^2| \leq \ulp(v)$; -then $|w-(x^2+y^2)| \leq \ulp(w) + |u-x^2| + |v-y^2| \leq 3 \ulp(w)$ -since $w$ is greater or equal to $u$ and $v$. -For the last step $s \leftarrow \circ(\sqrt{w})$, we use the last formula -from~\textsection\ref{generic:sqrt}, which gives -$|s-\sqrt{x^2+y^2}| \leq 4 \ulp(s)$. +If one of the variable is zero, then hypot is computed using the absolute +value of the other variable. Assume that $0 < y \leq x$. Using the first +degree Taylor polynomial, we have +\[ +0 < \sqrt{x^2+y^2}-x < \frac{y^2}{2x}. +\] + +Let $p_x, p_y$ the precisions of input variables $x$ and $y$ respectively, +$p_z$ the output precision and $z=\circ_{p_z}(\sqrt{x^2+y^2})$ the expected +result. Let us assume, as it is the case in MPFR, that the minimal and +maximal acceptable exponents (respectively $e_{min}$ and $e_{max}$) verify $2 +< e_{max}$ and $e_{max} = -e_{min}$. + +When rounding to nearest, if $p_x \leq p_z$ and $\frac{p_z+1}{2} < \Exp(x) - +\Exp(y)$, we have $\frac{y^2}{2x} < \frac{1}{2}\ulp_{p_z}(x)$ ; if $p_z < +p_x$, the condition $\frac{p_x+1}{2} < \Exp(x) - \Exp(y)$ ensures that +$\frac{y^2}{2x} < \frac{1}{2} \ulp_{p_x}(x)$. In both cases, these +inequalities show that $z=\N_{p_z}(x)$, except that tie case is rounded +towards plus infinity since hypot($x$,$y$) is greater than but not equal to +$x$. + +With other rounding modes, the conditions $p_z/2 < \Exp(x) - \Exp(y)$ if $p_x +\leq p_z$, and $p_x/2 < \Exp(x) - \Exp(y)$ if $p_z < p_x$ mean in a similar +way that $z=\circ_{p_z}(x)$, except that we need to add one ulp to the result +when rounding towards plus infinity and $x$ is exactly representable with +$p_z$ bits of precision. + +When none of the above conditions is satisfied and when $\Exp(x) - \Exp(y) +\leq e_{max} - 2$, we use the following algorithm: + +\begin{quote} + Algorithm {\tt hypot\_1}\\ + Input: $x$ and $y$ with $|y| \leq |x|$, + $p$ the working precision with $p \geq p_z$.\\ + Output: $\sqrt{x^2+y^2}$ with $\left\{ + \begin{array}{l} + p-4 \textnormal{ bits of precision if } p <\max(p_x, p_y),\\ + p-2 \textnormal{ bits of precision if } \max(p_x, p_y) \leq p. + \end{array}\right.$\\ + $s \leftarrow \lfloor e_{max}/2\rfloor - \Exp(x) -1$\\ + $x_s \leftarrow \Z(x\times 2^s)$\\ + $y_s \leftarrow \Z(y\times 2^s)$\\ + $u \leftarrow \Z(x_s^2)$\\ + $v \leftarrow \Z(y_s^2)$\\ + $w \leftarrow \Z(u+v)$\\ + $t \leftarrow \Z(\sqrt{w})$\\ + $z \leftarrow \Z(t/2^s)$ +\end{quote} + +In order to avoid undue overflow during computation, we shift inputs' +exponents by $s = \lfloor\frac{e_{max}}{2}\rfloor -1 -\Exp(x)$ before +computing squares and shift back the output's exponent by $-s$ using the fact +that $\sqrt{(x.2^s)^2+(y.2^s)^2}/2^s = \sqrt{x^2+y^2}$. We show below that no +overflow nor underflow goes on. + +We check first that the exponent shift do not cause overflow and, in the same +time, that the squares of the shifted inputs do never overflow. For $x$, we +have $\Exp(x) + s = \lfloor e_{max}/2\rfloor - 1$, so $\Exp(x_s^2) < e_{max} - +1$ and neither $x_s$ nor $x_s^2$ overflows. For $y$, note that we have $y_s +\leq x_s$ because $y \leq x$, thus $y_s$ and $y_s^2$ do not overflow. + +Secondly, let us see that the exponent shift do not cause underflow. For $x$, +we know that $0 \leq \Exp(x) + s$, thus neither $x_s$ nor $x_s^2$ +underflows. For $y$, the condition $\Exp(x) - \Exp(y) \leq e_{max} - 2$ +ensures that $-e_{max}/2 \leq \Exp(y) + s$ which shows that $y_s$ and its +square do not underflow. + +Thirdly, the addition does not overflow because $u + v < 2 x_s^2$ and it was +shown above that $x_s^2 < 2^{e_{max} - 1}$. It cannot underflow because both +operands are positive. + +Fourthly, as $x_s < t$, the square root does not underflow. Due to the +exponent shift, we have $1 \leq x_s$, then $w$ is greater than 1 and thus +greater than its square root $t$, so the square root does overflow. + +Finally, let us show that the back shift do not raise underflow nor overflow +unless the exact result is greater than or equal to $2^{e_{max}}$. Because no +underflow has occured so far $\Exp(x) \leq \Exp(t) - s$ which shows that it +does not underflow. And all roundings being towards zero we have $z \leq +\sqrt{x^2 + y^2}$, so if $2^{e_{max}} \leq z$, then the exact value is also +greater than or equal to $2^{e_{max}}$. + +Let us analyse now the error of the algorithm hypot\_1:\\ +\begin{tabular}{l p{2em} l c r | r} + & & & & $p < \min(p_x, p_y)$ & $\max(p_x, p_y) \leq p$\\ + $x_s \leftarrow \Z(x\times 2^s)$ & & $\error(x_s)$ & $\leq$ & + 1 $\ulp(x_s)$ & + exact\\ + $y_s \leftarrow \Z(y\times 2^s)$ & & $\error(y_s)$ & $\leq$ & + 1 $\ulp(y_s)$ & + exact\\ + $u \leftarrow \Z(x_s^2)$ & & $\error(u)$ & $\leq$ & + 6 $\ulp(u)$ & + 1 $\ulp(u)$\\ + $v \leftarrow \Z(y_s^2)$ & & $\error(v)$ & $\leq$ & + 6 $\ulp(v)$ & + 1 $\ulp(v)$\\ + $w \leftarrow \Z(u+v)$ & & $\error(w)$ & $\leq$ & + 13 $\ulp(w)$ & + 3 $\ulp(w)$\\ + $t \leftarrow \Z(\sqrt{w})$ & & $\error(t)$ & $\leq$ & + 14 $\ulp(t)$ & + 4 $\ulp(t)$\\ + $z \leftarrow \Z(t/2^s)$& & exact.\\ +\end{tabular}\\ +And in the intermediate case, if $\min(p_x,p_y) \leq p < \max(p_x,p_y)$, we +have\\ +\begin{tabular}{l p{2em} l c r l} + $w \leftarrow \Z(u+v)$ & & + $\error(w)$ & $\leq$ & 8 $\ulp(w)$\\ + $t \leftarrow \Z(\sqrt{w})$ & & + $\error(t)$ & $\leq$ & 9 $\ulp(t)$.\\ +\end{tabular}\\ +Thus, 2 bits of precision are lost when $\max(p_x, p_y) \leq p$ and 4 bits +when $p$ does not verify this relation. \subsection{The floating multiply-add function} @@ -31,12 +31,15 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) { int inexact, exact; mpfr_t t, te, ti; /* auxiliary variables */ - mp_prec_t Nx, Ny, Nz; /* size variables */ + mp_prec_t N, Nz; /* size variables */ mp_prec_t Nt; /* precision of the intermediary variable */ - mp_exp_t Ex, Ey, sh; + mp_prec_t threshold; + mp_exp_t Ex, sh; mp_exp_unsigned_t diff_exp; + MPFR_SAVE_EXPO_DECL (expo); MPFR_ZIV_DECL (loop); + MPFR_BLOCK_DECL (flags); /* particular cases */ if (MPFR_ARE_SINGULAR (x, y)) @@ -71,25 +74,16 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) /* now |x| >= |y| */ Ex = MPFR_GET_EXP (x); - Ey = MPFR_GET_EXP (y); - diff_exp = (mp_exp_unsigned_t) Ex - Ey; + diff_exp = (mp_exp_unsigned_t) Ex - MPFR_GET_EXP (y); - Nx = MPFR_PREC (x); /* Precision of input variable */ + N = MPFR_PREC (x); /* Precision of input variable */ Nz = MPFR_PREC (z); /* Precision of output variable */ + threshold = + rnd_mode == GMP_RNDN ? (MAX (N, Nz) + 1) <<1 : MAX (N, Nz) <<1; - /* we have x < 2^Ex thus x^2 < 2^(2*Ex), - and ulp(x) = 2^(Ex-Nx) thus ulp(x^2) >= 2^(2*Ex-2*Nx). - y does not overlap with the result when - x^2+y^2 < (|x| + 1/2*ulp(x,Nz))^2 = x^2 + |x|*ulp(x,Nz) + 1/4*ulp(x,Nz)^2, - i.e. a sufficient condition is y^2 < |x|*ulp(x,Nz), - or 2^(2*Ey) <= 2^(2*Ex-1-Nz), i.e. 2*diff_exp > Nz. - Warning: this is true only for Nx <= Nz, otherwise the trailing bits - of x may be already very close to 1/2*ulp(x,Nz)! - If Nx > Nz, then we can notice that it is possible to round on Nx bits - if 2*diff_exp > Nx (see above as if Nz = Nx), therefore on Nz bits. - Hence the condition: 2*diff_exp > MAX(Nz,Nx). - */ - if (diff_exp > MAX (Nz, Nx) / 2) + /* Is |x| a suitable approximation to the precision Nz ? + (see algorithms.tex for explanations) */ + if (diff_exp > threshold) /* result is |x| or |x|+ulp(|x|,Nz) */ { if (MPFR_UNLIKELY (rnd_mode == GMP_RNDU)) @@ -98,73 +92,76 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) z = abs(x), and we need to add one ulp due to y. */ if (mpfr_abs (z, x, rnd_mode) == 0) mpfr_nexttoinf (z); - return 1; + MPFR_RET (1); } else /* GMP_RNDZ, GMP_RNDD, GMP_RNDN */ { - if (MPFR_LIKELY (Nz >= Nx)) + if (MPFR_LIKELY (Nz >= N)) { mpfr_abs (z, x, rnd_mode); /* exact */ - return -1; + MPFR_RET (-1); } else { MPFR_SET_EXP (z, Ex); MPFR_SET_SIGN (z, 1); - MPFR_RNDRAW_GEN (inexact, z, MPFR_MANT (x), Nx, rnd_mode, 1, + MPFR_RNDRAW_GEN (inexact, z, MPFR_MANT (x), N, rnd_mode, 1, goto addoneulp, - if (MPFR_UNLIKELY (++MPFR_EXP (z) > __gmpfr_emax)) - return mpfr_overflow (z, rnd_mode, 1); - ); - return inexact ? inexact : -1; + if (MPFR_UNLIKELY (++MPFR_EXP (z) > __gmpfr_emax)) + return mpfr_overflow (z, rnd_mode, 1); + ); + + if (MPFR_UNLIKELY (inexact == 0)) + inexact = -1; + MPFR_RET (inexact); } } } /* General case */ - Ny = MPFR_PREC(y); /* Precision of input variable */ + /* FIXME: the following algorithm is correct only for + diff_exp <= MPFR_EMAX_MAX - 2 */ + + N = MAX (MPFR_PREC (x), MPFR_PREC (y)); - /* compute the working precision -- see algorithms.ps */ - Nt = MAX (MAX (MAX (Nx, Ny), Nz), 8); - /* FIXME: if Nx or Ny are very large with respect to the target precision - Nz, this may be overkill! */ - Nt = Nt + MPFR_INT_CEIL_LOG2 (Nt) + 2; + /* working precision */ + Nt = Nz + MPFR_INT_CEIL_LOG2 (Nz) + 4; - /* initialise the intermediary variables */ mpfr_init2 (t, Nt); mpfr_init2 (te, Nt); mpfr_init2 (ti, Nt); MPFR_SAVE_EXPO_MARK (expo); - sh = MAX (0, MIN (Ex, Ey)); + /* Scale x and y to avoid overflow/underflow in x^2 and y^2. */ + sh = mpfr_get_emax()/2 -Ex -1; MPFR_ZIV_INIT (loop, Nt); for (;;) { - /* computations of hypot */ - mpfr_div_2ui (te, x, sh, GMP_RNDZ); /* exact since Nt >= Nx */ - mpfr_div_2ui (ti, y, sh, GMP_RNDZ); /* exact since Nt >= Ny */ - exact = mpfr_mul (te, te, te, GMP_RNDZ); /* x^2 */ - exact |= mpfr_mul (ti, ti, ti, GMP_RNDZ); /* y^2 */ - exact |= mpfr_add (t, te, ti, GMP_RNDZ); /* x^2+y^2 */ - exact |= mpfr_sqrt (t, t, GMP_RNDZ); /* sqrt(x^2+y^2)*/ + mp_prec_t err; + exact = mpfr_mul_2si (te, x, sh, GMP_RNDZ); + exact |= mpfr_mul_2si (ti, y, sh, GMP_RNDZ); + exact |= mpfr_sqr (te, te, GMP_RNDZ); + exact |= mpfr_sqr (ti, ti, GMP_RNDZ); + exact |= mpfr_add (t, te, ti, GMP_RNDZ); + exact |= mpfr_sqrt (t, t, GMP_RNDZ); + + err = Nt < N ? 4 : 2; if (MPFR_LIKELY (exact == 0 - || MPFR_CAN_ROUND (t, Nt-2, Nz, rnd_mode))) + || MPFR_CAN_ROUND (t, Nt-err, Nz, rnd_mode))) break; - /* reactualization of the precision */ MPFR_ZIV_NEXT (loop, Nt); mpfr_set_prec (t, Nt); mpfr_set_prec (te, Nt); mpfr_set_prec (ti, Nt); - } MPFR_ZIV_FREE (loop); - inexact = mpfr_mul_2ui (z, t, sh, rnd_mode); + MPFR_BLOCK (flags, inexact = mpfr_div_2si (z, t, sh, rnd_mode)); MPFR_ASSERTD (exact == 0 || inexact != 0); mpfr_clear (t); @@ -172,14 +169,18 @@ mpfr_hypot (mpfr_ptr z, mpfr_srcptr x, mpfr_srcptr y, mp_rnd_t rnd_mode) mpfr_clear (te); /* - exact inexact - 0 0 result is exact, ternary flag is 0 - 0 non zero t is exact, ternary flag given by inexact - 1 0 impossible (see above) - 1 non zero ternary flag given by inexact - */ + exact inexact + 0 0 result is exact, ternary flag is 0 + 0 non zero t is exact, ternary flag given by inexact + 1 0 impossible (see above) + 1 non zero ternary flag given by inexact + */ MPFR_SAVE_EXPO_FREE (expo); + if (MPFR_OVERFLOW (flags)) + mpfr_set_overflow (); + /* hypot(x,y) >= |x|, thus underflow is not possible. */ + return mpfr_check_range (z, inexact, rnd_mode); } diff --git a/tests/thypot.c b/tests/thypot.c index a13ef030b..69fb90942 100644 --- a/tests/thypot.c +++ b/tests/thypot.c @@ -26,7 +26,8 @@ MA 02110-1301, USA. */ #include "mpfr-test.h" -#define TEST_FUNCTION mpfr_hypot +/* Non-zero when extended exponent range */ +static int ext = 0; static void special (void) @@ -94,19 +95,34 @@ test_large (void) mpfr_set_prec (t, 53); mpfr_set_prec (y, 53); mpfr_set_str_binary (x, "0.11101100011110000011101000010101010011001101000001100E-1021"); - mpfr_set_str_binary (t, "0.11111001010011000001110110001101011100001000010010100E-1021"); - mpfr_hypot (y, x, t, GMP_RNDN); + mpfr_set_str_binary (y, "0.11111001010011000001110110001101011100001000010010100E-1021"); + mpfr_hypot (t, x, y, GMP_RNDN); + mpfr_set_str_binary (z, "0.101010111100110111101110111110100110010011001010111E-1020"); + if (mpfr_cmp (z, t)) + { + printf ("Error in test_large: got\n"); + mpfr_out_str (stdout, 2, 0, t, GMP_RNDN); + printf ("\ninstead of\n"); + mpfr_out_str (stdout, 2, 0, z, GMP_RNDN); + printf ("\n"); + exit (1); + } mpfr_set_prec (x, 240); mpfr_set_prec (y, 22); + mpfr_set_prec (z, 2); mpfr_set_prec (t, 2); mpfr_set_str_binary (x, "0.100111011010010010110100000100000001100010011100110101101111111101011110111011011101010110100101111000111100010100110000100101011110111011100110100110100101110101101100011000001100000001111101110100100100011011011010110111100110010101000111e-7"); - mpfr_set_str_binary (y, "0.1111000010000011000111e-10"); + mpfr_set_str_binary (y, "0.1111000010000011000111E-10"); mpfr_hypot (t, x, y, GMP_RNDN); - mpfr_set_str_binary (y, "0.11E-7"); - if (mpfr_cmp (t, y)) + mpfr_set_str_binary (z, "0.11E-7"); + if (mpfr_cmp (z, t)) { - printf ("Error in mpfr_hypot (1)\n"); + printf ("Error in test_large: got\n"); + mpfr_out_str (stdout, 2, 0, t, GMP_RNDN); + printf ("\ninstead of\n"); + mpfr_out_str (stdout, 2, 0, z, GMP_RNDN); + printf ("\n"); exit (1); } @@ -117,6 +133,50 @@ test_large (void) } static void +test_small (void) +{ + mpfr_t x, y, z1, z2; + int inex1, inex2; + unsigned int flags; + + /* Test hypot(x,x) with x = 2^(emin-1). Result is x * sqrt(2). */ + mpfr_inits2 (8, x, y, z1, z2, (mpfr_ptr) 0); + mpfr_set_si_2exp (x, 1, mpfr_get_emin () - 1, GMP_RNDN); + mpfr_set_si_2exp (y, 1, mpfr_get_emin () - 1, GMP_RNDN); + mpfr_set_ui (z1, 2, GMP_RNDN); + inex1 = mpfr_sqrt (z1, z1, GMP_RNDN); + inex2 = mpfr_mul (z1, z1, x, GMP_RNDN); + MPFR_ASSERTN (inex2 == 0); + mpfr_clear_flags (); + inex2 = mpfr_hypot (z2, x, y, GMP_RNDN); + flags = __gmpfr_flags; + if (mpfr_cmp (z1, z2) != 0) + { + printf ("Error in test_small%s\nExpected ", + ext ? ", extended exponent range" : ""); + mpfr_out_str (stdout, 2, 0, z1, GMP_RNDN); + printf ("\nGot "); + mpfr_out_str (stdout, 2, 0, z2, GMP_RNDN); + printf ("\n"); + exit (1); + } + if (! SAME_SIGN (inex1, inex2)) + { + printf ("Bad ternary value in test_small%s\nExpected %d, got %d\n", + ext ? ", extended exponent range" : "", inex1, inex2); + exit (1); + } + if (flags != MPFR_FLAGS_INEXACT) + { + printf ("Bad flags in test_small%s\nExpected %u, got %u\n", + ext ? ", extended exponent range" : "", + (unsigned int) MPFR_FLAGS_INEXACT, flags); + exit (1); + } + mpfr_clears (x, y, z1, z2, (mpfr_ptr) 0); +} + +static void test_large_small (void) { mpfr_t x, y, z; @@ -131,7 +191,8 @@ test_large_small (void) inexact = mpfr_hypot (z, x, y, GMP_RNDN); if (inexact >= 0 || mpfr_cmp (x, z)) { - printf ("Error 1 in test_large_small\n"); + printf ("Error 1 in test_large_small%s\n", + ext ? ", extended exponent range" : ""); exit (1); } @@ -139,7 +200,8 @@ test_large_small (void) inexact = mpfr_hypot (z, x, y, GMP_RNDN); if (mpfr_cmp (x, z) >= 0) { - printf ("Error 2 in test_large_small\n"); + printf ("Error 2 in test_large_small%s\n", + ext ? ", extended exponent range" : ""); printf ("x = "); mpfr_out_str (stdout, 2, 0, x, GMP_RNDN); printf ("\n"); @@ -159,105 +221,84 @@ test_large_small (void) mpfr_clear (z); } -int -main (int argc, char *argv[]) +static void +check_overflow (void) { - unsigned int prec, err, yprec, n, p0 = 2, p1 = 100, N = 100; - mp_rnd_t rnd; - mpfr_t x1, x2, y, z, t; - int inexact, compare, compare2; + mpfr_t x, y; + int inex, r; - tests_start_mpfr (); + mpfr_inits2 (8, x, y, (mpfr_ptr) 0); + mpfr_set_ui (x, 1, GMP_RNDN); + mpfr_setmax (x, mpfr_get_emax ()); - special (); - - mpfr_init (x1); - mpfr_init (x2); - mpfr_init (y); - mpfr_init (z); - mpfr_init (t); - - /* thypot prec - perform one random computation with precision prec */ - if (argc >= 2) + RND_LOOP(r) { - p0 = p1 = atoi (argv[1]); - N = 1; + mpfr_clear_overflow (); + inex = mpfr_hypot (y, x, x, r); + if (!mpfr_overflow_p ()) + { + printf ("No overflow in check_overflow for %s%s\n", + mpfr_print_rnd_mode ((mp_rnd_t) r), + ext ? ", extended exponent range" : ""); + exit (1); + } + MPFR_ASSERTN (MPFR_IS_POS (y)); + if (r == GMP_RNDZ || r == GMP_RNDD) + { + MPFR_ASSERTN (inex < 0); + MPFR_ASSERTN (!mpfr_inf_p (y)); + mpfr_nexttoinf (y); + } + else + { + MPFR_ASSERTN (inex > 0); + } + MPFR_ASSERTN (mpfr_inf_p (y)); } - for (prec = p0; prec <= p1; prec++) - { - mpfr_set_prec (x1, prec); - mpfr_set_prec (x2, prec); - mpfr_set_prec (z, prec); - mpfr_set_prec (t, prec); - yprec = prec + 10; + mpfr_clears (x, y, (mpfr_ptr) 0); +} - for (n=0; n<N; n++) - { - mpfr_random(x1); - mpfr_random(x2); - if (randlimb () % 2) - mpfr_neg (x1, x1, GMP_RNDN); - if (randlimb () % 2) - mpfr_neg (x2, x2, GMP_RNDN); - rnd = (mp_rnd_t) RND_RAND (); - mpfr_set_prec (y, yprec); - - compare =TEST_FUNCTION (y, x1,x2, rnd); - err = (rnd == GMP_RNDN) ? yprec + 1 : yprec; - if (mpfr_can_round (y, err, rnd, rnd, prec)) - { - mpfr_set (t, y, rnd); - inexact = TEST_FUNCTION (z, x1,x2, rnd); - if (mpfr_cmp (t, z)) - { - printf ("results differ for x1="); - mpfr_out_str (stdout, 2, prec, x1, GMP_RNDN); - printf ("\n and x2="); - mpfr_out_str (stdout, 2, prec, x2, GMP_RNDN); - printf (" \n prec=%u rnd_mode=%s\n", prec, - mpfr_print_rnd_mode (rnd)); - printf (" got "); - mpfr_out_str (stdout, 2, prec, z, GMP_RNDN); - puts (""); - printf (" expected "); - mpfr_out_str (stdout, 2, prec, t, GMP_RNDN); - puts (""); - printf (" approximation was "); - mpfr_print_binary (y); - puts (""); - exit (1); - } - compare2 = mpfr_cmp (t, y); - /* if rounding to nearest, cannot know the sign of t - f(x) - because of composed rounding: y = o(f(x)) and t = o(y) */ - if ((rnd != GMP_RNDN) && (compare * compare2 >= 0)) - compare = compare + compare2; - else - compare = inexact; /* cannot determine sign(t-f(x)) */ - if (((inexact == 0) && (compare != 0)) || - ((inexact > 0) && (compare <= 0)) || - ((inexact < 0) && (compare >= 0))) - { - printf ("Wrong inexact flag for rnd=%s: expected %d, got %d" - "\n", mpfr_print_rnd_mode (rnd), compare, inexact); - printf ("x1="); mpfr_print_binary (x1); puts (""); - printf ("x2="); mpfr_print_binary (x2); puts (""); - printf ("t="); mpfr_print_binary (t); puts (""); - exit (1); - } - } - } +#define TWO_ARGS +#define TEST_FUNCTION mpfr_hypot +#include "tgeneric.c" + +static void +alltst (void) +{ + mp_exp_t emin, emax; + + ext = 0; + test_small (); + test_large_small (); + check_overflow (); + + emin = mpfr_get_emin (); + emax = mpfr_get_emax (); + set_emin (MPFR_EMIN_MIN); + set_emax (MPFR_EMAX_MAX); + if (mpfr_get_emin () != emin || mpfr_get_emax () != emax) + { + ext = 1; + test_small (); + test_large_small (); + check_overflow (); + set_emin (emin); + set_emax (emax); } +} - mpfr_clear (x1); - mpfr_clear (x2); - mpfr_clear (y); - mpfr_clear (z); - mpfr_clear (t); +int +main (int argc, char *argv[]) +{ + tests_start_mpfr (); + + special (); test_large (); - test_large_small (); + alltst (); + + test_generic (2, 100, 10); tests_end_mpfr (); return 0; |