summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS9
-rw-r--r--NEWS1
-rw-r--r--TODO4
-rw-r--r--doc/mpc.texi2
-rw-r--r--src/mpc-impl.h1
-rw-r--r--src/norm.c149
-rw-r--r--tests/norm.dat80
7 files changed, 176 insertions, 70 deletions
diff --git a/BUGS b/BUGS
index 8c74438..14ef613 100644
--- a/BUGS
+++ b/BUGS
@@ -1,8 +1,7 @@
- Overflow and underflow are not considered in all functions, which might
lead to some infinite loops.
-- Except for mpc_mul,
- no checks are made for intermediate over- or underflows, which may occur
- in the middle of the algorithms although the final result may be
+- Also, checks are not always made for intermediate over- or underflows, which
+ may occur in the middle of the algorithms although the final result may be
representable.
For instance, if in the computation of Im (cos(x+i*y)) = -sin(x)*sinh(y)
an overflow occurs in sinh(y), the value sign(Im (cos(x+i*y))) * inf
@@ -10,3 +9,7 @@
sin(x)*sinh(y) is representable. If furthermore an underflow occurred
in sin(x) (which has not been observed in practice), then the return
value would be NaN*(+-inf)=NaN.
+
+Currently, the following functions have been rewritten to solve these
+problems:
+mul, norm
diff --git a/NEWS b/NEWS
index 6d37ce9..0ad286d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,5 @@
Changes in version 1.0:
+ - First release as a GNU package
- License change: LGPLv3+ for code, GFDLv1.3+ for documentation
- Bug fixes:
- mul now returns correct results even if there are over- or underflows
diff --git a/TODO b/TODO
index a161112..82f5fce 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,7 @@ return the exact ternary value in mpc_div:
- for directed rounding modes it is easy (assuming we are able to detect
exact cases)
- rounding to nearest to n bits is equivalent to directed rounding to n+1 bits
-Also for mpc_norm and mpc_abs.
+Also for mpc_abs.
From Andreas Enge 31 August 2011:
implement mul_karatsuba with three multiplications at precision around p,
@@ -16,6 +16,8 @@ rewrite fma more efficiently to work with lower (close to target) precision
From Andreas Enge 30 August 2011:
As soon as dependent on mpfr>=3, remove auxiliary functions from
get_version.c and update mpc.h.
+Use MPFR_RND? instead of GMP_RND?, and remove workarounds for MPFR_RNDA from
+mpc-impl.h.
Bench:
- from Andreas Enge 9 June 2009:
diff --git a/doc/mpc.texi b/doc/mpc.texi
index 2388393..f8c6f42 100644
--- a/doc/mpc.texi
+++ b/doc/mpc.texi
@@ -909,8 +909,6 @@ The returned value is zero iff the result is exact.
Set the floating-point number @var{rop} to the norm of @var{op}
(i.e., the square of its absolute value),
rounded in the direction @var{rnd}.
-The returned value is zero iff the result is exact.
-Note that the destination is of type @code{mpfr_t}, not @code{mpc_t}.
@end deftypefun
@deftypefun int mpc_mul_2exp (mpc_t @var{rop}, mpc_t @var{op1}, unsigned long int @var{op2}, mpc_rnd_t @var{rnd})
diff --git a/src/mpc-impl.h b/src/mpc-impl.h
index dbd2a9c..baa7a72 100644
--- a/src/mpc-impl.h
+++ b/src/mpc-impl.h
@@ -32,6 +32,7 @@ along with this program. If not, see http://www.gnu.org/licenses/ .
* Miscellaneous useful macros
*/
+#define MPC_MIN(h,i) ((h) < (i) ? (h) : (i))
#define MPC_MAX(h,i) ((h) > (i) ? (h) : (i))
/* Safe absolute value (to avoid possible integer overflow) */
diff --git a/src/norm.c b/src/norm.c
index e8699ce..c2b633a 100644
--- a/src/norm.c
+++ b/src/norm.c
@@ -1,6 +1,6 @@
/* mpc_norm -- Square of the norm of a complex number.
-Copyright (C) 2002, 2005, 2008, 2009, 2010 INRIA
+Copyright (C) 2002, 2005, 2008, 2009, 2010, 2011 INRIA
This file is part of GNU MPC.
@@ -24,67 +24,90 @@ along with this program. If not, see http://www.gnu.org/licenses/ .
int
mpc_norm (mpfr_ptr a, mpc_srcptr b, mpfr_rnd_t rnd)
{
- mpfr_t u, v;
- mpfr_prec_t prec;
- int inexact, overflow, underflow;
-
- prec = mpfr_get_prec (a);
-
- /* handling of special values; consistent with abs in that
- norm = abs^2; so norm (+-inf, nan) = norm (nan, +-inf) = +inf */
- if ( (mpfr_nan_p (MPC_RE (b)) || mpfr_nan_p (MPC_IM (b)))
- || (mpfr_inf_p (MPC_RE (b)) || mpfr_inf_p (MPC_IM (b))))
- return mpc_abs (a, b, rnd);
-
- mpfr_init (u);
- mpfr_init (v);
-
- if (!mpfr_zero_p(MPC_RE(b)) && !mpfr_zero_p(MPC_IM(b)) &&
- 2 * SAFE_ABS (mpfr_exp_t,
- mpfr_get_exp (MPC_RE (b)) - mpfr_get_exp (MPC_IM (b)))
- > (mpfr_exp_t)prec)
- /* If real and imaginary part have very different magnitudes, then the */
- /* generic code increases the precision too much. Instead, compute the */
- /* squarings _exactly_. */
- {
- mpfr_set_prec (u, 2 * MPC_PREC_RE (b));
- mpfr_set_prec (v, 2 * MPC_PREC_IM (b));
- mpfr_sqr (u, MPC_RE (b), GMP_RNDN);
- mpfr_sqr (v, MPC_IM (b), GMP_RNDN);
- inexact = mpfr_add (a, u, v, rnd);
- }
- else if (mpfr_zero_p(MPC_RE(b)) && mpfr_zero_p(MPC_IM(b)))
- {
- inexact = mpfr_set_ui (a, 0, rnd);
- }
- else
- {
- do
- {
- prec += mpc_ceil_log2 (prec) + 3;
-
- mpfr_set_prec (u, prec);
- mpfr_set_prec (v, prec);
-
- inexact = mpfr_sqr (u, MPC_RE(b), GMP_RNDN); /* err<=1/2ulp */
- inexact |= mpfr_sqr (v, MPC_IM(b), GMP_RNDN); /* err<=1/2ulp*/
- inexact |= mpfr_add (u, u, v, GMP_RNDN); /* err <= 3/2 ulps */
-
- overflow = mpfr_inf_p (u);
- underflow = mpfr_zero_p (u);
+ int inexact;
+
+ /* handling of special values; consistent with abs in that
+ norm = abs^2; so norm (+-inf, nan) = norm (nan, +-inf) = +inf */
+ if (!mpc_fin_p (b))
+ return mpc_abs (a, b, rnd);
+ else if (mpfr_zero_p (MPC_RE (b))) {
+ if (mpfr_zero_p (MPC_IM (b)))
+ return mpfr_set_ui (a, 0, rnd); /* +0 */
+ else
+ return mpfr_sqr (a, MPC_IM (b), rnd);
+ }
+ else if (mpfr_zero_p (MPC_IM (b)))
+ return mpfr_sqr (a, MPC_RE (b), rnd);
+
+ else /* everything finite and non-zero */ {
+ mpfr_t u, v, res;
+ mpfr_prec_t prec, prec_u, prec_v;
+ int loops;
+ const int max_loops = 2;
+ /* switch to exact squarings when loops==max_loops */
+
+ prec = mpfr_get_prec (a);
+
+ mpfr_init (u);
+ mpfr_init (v);
+ mpfr_init (res);
+
+ loops = 0;
+ mpfr_clear_underflow ();
+ mpfr_clear_overflow ();
+ do {
+ loops++;
+ prec += mpc_ceil_log2 (prec) + 3;
+ if (loops >= max_loops) {
+ prec_u = 2 * MPC_PREC_RE (b);
+ prec_v = 2 * MPC_PREC_IM (b);
+ }
+ else {
+ prec_u = MPC_MIN (prec, 2 * MPC_PREC_RE (b));
+ prec_v = MPC_MIN (prec, 2 * MPC_PREC_IM (b));
+ }
+
+ mpfr_set_prec (u, prec_u);
+ mpfr_set_prec (v, prec_v);
+ mpfr_set_prec (res, prec);
+
+ inexact = mpfr_sqr (u, MPC_RE(b), GMP_RNDD); /* err <= 1 ulp in prec */
+ inexact |= mpfr_sqr (v, MPC_IM(b), GMP_RNDD); /* err <= 1 ulp in prec */
+ if (loops < max_loops)
+ inexact |= mpfr_add (res, u, v, GMP_RNDD); /* err <= 3 ulp in prec */
+
+ } while (loops < max_loops
+ && inexact
+ && !mpfr_can_round (res, prec - 2, GMP_RNDD, GMP_RNDU,
+ mpfr_get_prec (a) + (rnd == GMP_RNDN)));
+
+ if (mpfr_overflow_p ()) {
+ /* replace by "correctly rounded overflow" */
+ mpfr_set_ui (a, 1ul, GMP_RNDN);
+ inexact = mpfr_mul_2ui (a, a, mpfr_get_emax (), rnd);
}
- while (!overflow && !underflow && inexact &&
- mpfr_can_round (u, prec - 2, GMP_RNDN, rnd, mpfr_get_prec (a)) == 0);
-
- inexact |= mpfr_set (a, u, rnd);
-
- if (overflow)
- inexact = 1;
- if (underflow)
- inexact = -1;
- }
- mpfr_clear (u);
- mpfr_clear (v);
-
- return inexact;
+ else if (mpfr_underflow_p ()) {
+ /* squarings were exact except for underflow */
+ inexact = mpfr_add (a, u, v, rnd);
+ if (!inexact) {
+ if (rnd == GMP_RNDN || rnd == GMP_RNDD || rnd == GMP_RNDZ)
+ inexact = -1;
+ else {
+ mpfr_nextabove (a);
+ inexact = 1;
+ }
+ }
+ }
+ else if (loops == max_loops)
+ /* squarings were exact */
+ inexact = mpfr_add (a, u, v, rnd);
+ else /* no problems, ternary value due to mpfr_can_round trick */
+ inexact = mpfr_set (a, res, rnd);
+
+ mpfr_clear (u);
+ mpfr_clear (v);
+ mpfr_clear (res);
+ }
+
+ return inexact;
}
diff --git a/tests/norm.dat b/tests/norm.dat
index 7a99a0f..5a6a2dd 100644
--- a/tests/norm.dat
+++ b/tests/norm.dat
@@ -1,6 +1,6 @@
# Data file for mpc_norm.
#
-# Copyright (C) 2008, 2010 INRIA
+# Copyright (C) 2008, 2010, 2011 INRIA
#
# This file is part of GNU MPC.
#
@@ -77,3 +77,81 @@
# infinite loop reported by E. Thome
- 250 +0 250 -0xf.fdda3457c3e69e5841461d505b42987feb42867a4a2d2872179c4efa20054c0@-136943039 250 -0xc.670d1beda685fdd771b6246e32ff49ec4fd70aec25367444e00933e6965d3c0@-136943040 N
+
+# inexact values: norm (2+i)=5, in the middle between two values at precision 2
+- 2 4 2 2 2 1 D
+- 2 4 2 2 2 1 Z
++ 2 6 2 2 2 1 U
+- 2 4 2 2 2 1 N
+
+# over- and underflows
++ 10 inf 10 0 10 0b1@536870912 N
++ 10 inf 10 0 10 0b1@536870912 U
+- 10 0b1.111111111@1073741822 10 0 10 0b1@536870912 D
+- 10 0b1.111111111@1073741822 10 0 10 0b1@536870912 Z
+- 10 0 10 0 10 0b1@-536870913 N
+- 10 0 10 0 10 0b1@-536870913 D
+- 10 0 10 0 10 0b1@-536870913 Z
++ 10 0b1.000000000e-1073741824 10 0 10 0b1@-536870913 U
+
++ 10 inf 10 0b1@536870912 10 0 N
++ 10 inf 10 0b1@536870912 10 0 U
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 0 D
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 0 Z
+- 10 0 10 0b1@-536870913 10 0 N
+- 10 0 10 0b1@-536870913 10 0 D
+- 10 0 10 0b1@-536870913 10 0 Z
++ 10 0b1.000000000e-1073741824 10 0b1@-536870913 10 0 U
+
++ 10 inf 10 1 10 0b1@536870912 N
++ 10 inf 10 1 10 0b1@536870912 U
+- 10 0b1.111111111@1073741822 10 1 10 0b1@536870912 D
+- 10 0b1.111111111@1073741822 10 1 10 0b1@536870912 Z
+- 10 1 10 1 10 0b1@-536870913 N
+- 10 1 10 1 10 0b1@-536870913 D
+- 10 1 10 1 10 0b1@-536870913 Z
++ 10 0b1.000000001 10 1 10 0b1@-536870913 U
+
++ 10 inf 10 0b1@536870912 10 1 N
++ 10 inf 10 0b1@536870912 10 1 U
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 1 D
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 1 Z
+- 10 1 10 0b1@-536870913 10 1 N
+- 10 1 10 0b1@-536870913 10 1 D
+- 10 1 10 0b1@-536870913 10 1 Z
++ 10 0b1.000000001 10 0b1@-536870913 10 1 U
+
++ 3 inf 10 0b1.1 10 0b1@536870912 N
++ 3 inf 10 0b1.1 10 0b1@536870912 U
+- 3 0b1.11@1073741822 10 0b1.1 10 0b1@536870912 D
+- 3 0b1.11@1073741822 10 0b1.1 10 0b1@536870912 Z
+- 3 2 10 0b1.1 10 0b1@-536870913 N
+- 3 2 10 0b1.1 10 0b1@-536870913 D
+- 3 2 10 0b1.1 10 0b1@-536870913 Z
++ 3 0b1.01@1 10 0b1.1 10 0b1@-536870913 U
+
++ 3 inf 10 0b1@536870912 10 0b1.1 N
++ 3 inf 10 0b1@536870912 10 0b1.1 U
+- 3 0b1.11@1073741822 10 0b1@536870912 10 0b1.1 D
+- 3 0b1.11@1073741822 10 0b1@536870912 10 0b1.1 Z
+- 3 2 10 0b1@-536870913 10 0b1.1 N
+- 3 2 10 0b1@-536870913 10 0b1.1 D
+- 3 2 10 0b1@-536870913 10 0b1.1 Z
++ 3 0b1.01@1 10 0b1@-536870913 10 0b1.1 U
+
++ 10 inf 10 0b1@-536870913 10 0b1@536870912 N
++ 10 inf 10 0b1@-536870913 10 0b1@536870912 U
+- 10 0b1.111111111@1073741822 10 0b1@-536870913 10 0b1@536870912 D
+- 10 0b1.111111111@1073741822 10 0b1@-536870912 10 0b1@536870912 Z
++ 10 inf 10 0b1@536870912 10 0b1@-536870913 N
++ 10 inf 10 0b1@536870912 10 0b1@-536870913 U
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 0b1@-536870913 D
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 0b1@-536870913 Z
++ 10 inf 10 0b1@536870912 10 0b1@536870912 N
++ 10 inf 10 0b1@536870912 10 0b1@536870912 U
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 0b1@536870912 D
+- 10 0b1.111111111@1073741822 10 0b1@536870912 10 0b1@536870912 Z
+- 10 0 10 0b1@-536870913 10 0b1@-536870913 N
+- 10 0 10 0b1@-536870913 10 0b1@-536870913 D
+- 10 0 10 0b1@-536870913 10 0b1@-536870913 Z
++ 10 0b1@-1073741824 10 0b1@-536870913 10 0b1@-536870913 U