diff options
author | enge <enge@211d60ee-9f03-0410-a15a-8952a2c7a4e4> | 2011-02-22 17:06:30 +0000 |
---|---|---|
committer | enge <enge@211d60ee-9f03-0410-a15a-8952a2c7a4e4> | 2011-02-22 17:06:30 +0000 |
commit | 32cf6b343afbe2858fbebc5f40dd9f5958e5bb85 (patch) | |
tree | cb08e2f5bd074c954e086158d2f734d941885f15 /src/mul.c | |
parent | 96857ee2c540258bbe892a2b218f377a947164f6 (diff) | |
download | mpc-32cf6b343afbe2858fbebc5f40dd9f5958e5bb85.tar.gz |
mul.c: basically implemented handling of overflows; some cases still missing
git-svn-id: svn://scm.gforge.inria.fr/svn/mpc/trunk@945 211d60ee-9f03-0410-a15a-8952a2c7a4e4
Diffstat (limited to 'src/mul.c')
-rw-r--r-- | src/mul.c | 62 |
1 files changed, 60 insertions, 2 deletions
@@ -21,6 +21,13 @@ MA 02111-1307, USA. */ #include "mpc-impl.h" +#define mpz_add_si(z,x,y) do { \ + if (y >= 0) \ + mpz_add_ui (z, x, (long int) y); \ + else \ + mpz_sub_ui (z, x, (long int) (-y)); \ + } while (0); + /* compute z=x*y when x has an infinite part */ static int mul_infinite (mpc_ptr z, mpc_srcptr x, mpc_srcptr y) @@ -203,8 +210,59 @@ mul_naive_overflow (mpc_ptr z, mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd) inex_re = signu; } else { - /* the difficult case; FIXME */ - inex_re = mpfr_sub (MPC_RE (rop), u, v, MPC_RND_RE (rnd)); + /* the difficult case |u|, |v| == inf and signu == signv; + redo the computations with mpz_t exponents */ + mpfr_t xr, xi, yr, yi; + mpz_t eu, ev; + + /* Write x=xr+i*xi, y=yr+i*yi; normalise the real and imaginary parts + by shifting and keep track of the shifts in the exponents of u and v */ + mpz_init (eu); + mpz_init (ev); + mpfr_init2 (xr, MPC_PREC_RE (x)); + mpfr_init2 (xi, MPC_PREC_IM (x)); + mpfr_init2 (yr, MPC_PREC_RE (y)); + mpfr_init2 (yi, MPC_PREC_IM (y)); + mpfr_set (xr, MPC_RE (x), GMP_RNDN); + mpz_set_si (eu, (long int) mpfr_get_exp (xr)); + mpfr_set_exp (xr, (mp_prec_t) 0); + mpfr_set (yr, MPC_RE (y), GMP_RNDN); + mpz_add_si (eu, eu, mpfr_get_exp (yr)); + mpfr_set_exp (yr, (mp_prec_t) 0); + mpfr_set (xi, MPC_IM (x), GMP_RNDN); + mpz_set_si (ev, (long int) mpfr_get_exp (xi)); + mpfr_set_exp (xi, (mp_prec_t) 0); + mpfr_set (yi, MPC_IM (y), GMP_RNDN); + mpz_add_si (ev, ev, mpfr_get_exp (yi)); + mpfr_set_exp (yi, (mp_prec_t) 0); + + /* recompute u and v and move exponents to eu and ev */ + mpfr_mul (u, xr, yr, GMP_RNDN); + mpz_add_si (eu, eu, (long int) mpfr_get_exp (u)); + mpfr_set_exp (u, 0); + mpfr_mul (v, xi, yi, GMP_RNDN); + mpz_add_si (ev, ev, (long int) mpfr_get_exp (v)); + mpfr_set_exp (v, 0); + + if (mpz_cmp (eu, ev) > 0) { + mpfr_set_inf (MPC_RE (rop), signu); + inex_re = signu; + } + else if (mpz_cmp (eu, ev) < 0) { + mpfr_set_inf (MPC_RE (rop), -signv); + inex_re = -signv; + } + else /* both exponents are equal */ { + inex_re = mpfr_sub (MPC_RE (rop), u, v, MPC_RND_RE (rnd)); + /* FIXME: shift by eu */ + } + + mpz_clear (eu); + mpz_clear (ev); + mpfr_clear (xr); + mpfr_clear (xi); + mpfr_clear (yr); + mpfr_clear (yi); } /* Im(z) = Re(x)*Im(y) + Im(x)*Re(y) */ |