Home | History | Annotate | Line # | Download | only in tests
      1  1.1  mrg /* tballs -- test file for complex ball arithmetic.
      2  1.1  mrg 
      3  1.1  mrg Copyright (C) 2018, 2020, 2021, 2022 INRIA
      4  1.1  mrg 
      5  1.1  mrg This file is part of GNU MPC.
      6  1.1  mrg 
      7  1.1  mrg GNU MPC is free software; you can redistribute it and/or modify it under
      8  1.1  mrg the terms of the GNU Lesser General Public License as published by the
      9  1.1  mrg Free Software Foundation; either version 3 of the License, or (at your
     10  1.1  mrg option) any later version.
     11  1.1  mrg 
     12  1.1  mrg GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
     13  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     14  1.1  mrg FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
     15  1.1  mrg more details.
     16  1.1  mrg 
     17  1.1  mrg You should have received a copy of the GNU Lesser General Public License
     18  1.1  mrg along with this program. If not, see http://www.gnu.org/licenses/ .
     19  1.1  mrg */
     20  1.1  mrg 
     21  1.1  mrg #include "mpc-tests.h"
     22  1.1  mrg #include "mpc-impl.h"
     23  1.1  mrg    /* For the alternative AGM implementation, we need all the power of
     24  1.1  mrg       this include file. */
     25  1.1  mrg 
     26  1.1  mrg static int
     27  1.1  mrg mpc_mpcb_agm (mpc_ptr rop, mpc_srcptr opa, mpc_srcptr opb, mpc_rnd_t rnd)
     28  1.1  mrg    /* Alternative implementation of mpc_agm that uses complex balls. */
     29  1.1  mrg {
     30  1.1  mrg    mpfr_prec_t prec;
     31  1.1  mrg    mpc_t b0, diff;
     32  1.1  mrg    mpcb_t a, b, an, bn, anp1, bnp1, res;
     33  1.1  mrg    mpfr_exp_t exp_an, exp_diff;
     34  1.1  mrg    mpcr_t rab;
     35  1.1  mrg    int cmp, equal, re_zero, im_zero, ok, inex;
     36  1.1  mrg 
     37  1.1  mrg    if (!mpc_fin_p (opa) || !mpc_fin_p (opb)
     38  1.1  mrg        || mpc_zero_p (opa) || mpc_zero_p (opb)
     39  1.1  mrg        || mpc_cmp (opa, opb) == 0
     40  1.1  mrg        || (   mpfr_sgn (mpc_realref (opa)) == -mpfr_sgn (mpc_realref (opb))
     41  1.1  mrg            && mpfr_sgn (mpc_imagref (opa)) == -mpfr_sgn (mpc_imagref (opb))
     42  1.1  mrg            && mpfr_cmpabs (mpc_realref (opa), mpc_realref (opb)) == 0
     43  1.1  mrg            && mpfr_cmpabs (mpc_imagref (opa), mpc_imagref (opb)) == 0)
     44  1.1  mrg        || (   mpfr_zero_p (mpc_imagref (opa))
     45  1.1  mrg            && mpfr_zero_p (mpc_imagref (opb))
     46  1.1  mrg            && mpfr_sgn (mpc_realref (opa)) == mpfr_sgn (mpc_realref (opb)))
     47  1.1  mrg        || (   mpfr_zero_p (mpc_realref (opa))
     48  1.1  mrg            && mpfr_zero_p (mpc_realref (opb))
     49  1.1  mrg            && mpfr_sgn (mpc_imagref (opa)) == mpfr_sgn (mpc_imagref (opb))))
     50  1.1  mrg       /* Special cases that are handled separately by mpc_agm; there is
     51  1.1  mrg          no need to rewrite them. */
     52  1.1  mrg       return mpc_agm (rop, opa, opb, rnd);
     53  1.1  mrg 
     54  1.1  mrg    /* Exclude the case of angle 0, also handled separately by mpc_agm. */
     55  1.1  mrg    mpc_init2 (b0, 2);
     56  1.1  mrg    mpc_div (b0, opb, opa, MPC_RNDZZ);
     57  1.1  mrg    if (mpfr_zero_p (mpc_imagref (b0)) && mpfr_sgn (mpc_realref (b0)) > 0) {
     58  1.1  mrg       mpc_clear (b0);
     59  1.1  mrg       return mpc_agm (rop, opa, opb, rnd);
     60  1.1  mrg    }
     61  1.1  mrg    mpc_clear (b0);
     62  1.1  mrg 
     63  1.1  mrg    cmp = mpc_cmp_abs (opa, opb);
     64  1.1  mrg 
     65  1.1  mrg    mpcb_init (a);
     66  1.1  mrg    mpcb_init (b);
     67  1.1  mrg    mpcb_init (an);
     68  1.1  mrg    mpcb_init (bn);
     69  1.1  mrg    mpcb_init (anp1);
     70  1.1  mrg    mpcb_init (bnp1);
     71  1.1  mrg    mpcb_init (res);
     72  1.1  mrg    prec = MPC_MAX (MPC_MAX (MPC_MAX_PREC (opa), MPC_MAX_PREC (opb)),
     73  1.1  mrg       MPC_MAX_PREC (rop) + 20);
     74  1.1  mrg       /* So copying opa and opb will be exact, and there is a small safety
     75  1.1  mrg          margin for the result. */
     76  1.1  mrg    do {
     77  1.1  mrg       mpcb_set_prec (a, prec);
     78  1.1  mrg       mpcb_set_prec (b, prec);
     79  1.1  mrg       mpcb_set_prec (an, prec);
     80  1.1  mrg       mpcb_set_prec (bn, prec);
     81  1.1  mrg       mpcb_set_prec (anp1, prec);
     82  1.1  mrg       mpcb_set_prec (bnp1, prec);
     83  1.1  mrg       mpcb_set_prec (res, prec);
     84  1.1  mrg       /* TODO: Think about the mpcb_set variants; mpcb_set_c, for instance,
     85  1.1  mrg          modifies the precision. It is probably better to add a precision
     86  1.1  mrg          parameter to mpcb_init and potentially round with mpcb_set_xxx. */
     87  1.1  mrg       mpc_set (a->c, opa, MPC_RNDNN); /* exact */
     88  1.1  mrg       mpcr_set_zero (a->r);
     89  1.1  mrg       mpc_set (b->c, opb, MPC_RNDNN);
     90  1.1  mrg       mpcr_set_zero (b->r);
     91  1.1  mrg       mpc_set_ui_ui (an->c, 1, 0, MPC_RNDNN);
     92  1.1  mrg       mpcr_set_zero (an->r);
     93  1.1  mrg       if (cmp >= 0)
     94  1.1  mrg          mpcb_div (bn, b, a);
     95  1.1  mrg       else
     96  1.1  mrg          mpcb_div (bn, a, b);
     97  1.1  mrg 
     98  1.1  mrg       /* Iterate until there is a fixed point or (often one iteration
     99  1.1  mrg          earlier) the arithmetic and the geometric mean coincide. */
    100  1.1  mrg       do {
    101  1.1  mrg          mpcb_add (anp1, an, bn);
    102  1.1  mrg          mpcb_div_2ui (anp1, anp1, 1);
    103  1.1  mrg          mpcb_mul (bnp1, an, bn);
    104  1.1  mrg          mpcb_sqrt (bnp1, bnp1);
    105  1.1  mrg             /* Be aware of the branch cut! The current function does
    106  1.1  mrg                what is needed here. */
    107  1.1  mrg          equal = mpc_cmp (an->c, bn->c) == 0
    108  1.1  mrg                  || (   mpc_cmp (an->c, anp1->c) == 0
    109  1.1  mrg                      && mpc_cmp (bn->c, bnp1->c) == 0);
    110  1.1  mrg          mpcb_set (an, anp1);
    111  1.1  mrg          mpcb_set (bn, bnp1);
    112  1.1  mrg       } while (!equal);
    113  1.1  mrg 
    114  1.1  mrg       /* Check whether we can conclude, see the error analysis in
    115  1.1  mrg          algorithms.tex. */
    116  1.1  mrg       if (mpcr_inf_p (anp1->r))
    117  1.1  mrg          ok = 0;
    118  1.1  mrg       else {
    119  1.1  mrg          mpc_init2 (diff, prec);
    120  1.1  mrg          mpc_sub (diff, an->c, bn->c, MPC_RNDZZ);
    121  1.1  mrg             /* FIXME: We would need to round away, but this is not yet
    122  1.1  mrg                implemented. */
    123  1.1  mrg          re_zero = mpfr_zero_p (mpc_realref (diff));
    124  1.1  mrg          if (!re_zero)
    125  1.1  mrg             MPFR_ADD_ONE_ULP (mpc_realref (diff));
    126  1.1  mrg          im_zero = mpfr_zero_p (mpc_imagref (diff));
    127  1.1  mrg          if (!im_zero)
    128  1.1  mrg             MPFR_ADD_ONE_ULP (mpc_imagref (diff));
    129  1.1  mrg 
    130  1.1  mrg          mpcb_set (res, anp1);
    131  1.1  mrg 
    132  1.1  mrg          if (re_zero && im_zero)
    133  1.1  mrg             mpcr_set_zero (rab);
    134  1.1  mrg          else {
    135  1.1  mrg             exp_an = MPC_MIN (mpfr_get_exp (mpc_realref (an->c)),
    136  1.1  mrg                               mpfr_get_exp (mpc_imagref (an->c))) - 1;
    137  1.1  mrg             if (re_zero)
    138  1.1  mrg                exp_diff = mpfr_get_exp (mpc_imagref (diff)) + 1;
    139  1.1  mrg             else if (im_zero)
    140  1.1  mrg                exp_diff = mpfr_get_exp (mpc_realref (diff)) + 1;
    141  1.1  mrg             else
    142  1.1  mrg                exp_diff = MPC_MAX (mpfr_get_exp (mpc_realref (diff)),
    143  1.1  mrg                                    mpfr_get_exp (mpc_imagref (diff)) + 1);
    144  1.1  mrg             mpcr_set_one (rab);
    145  1.1  mrg             (rab->exp) += (exp_diff - exp_an);
    146  1.1  mrg                /* TODO: Should be done by an mpcr function. */
    147  1.1  mrg          }
    148  1.1  mrg          mpcr_add (rab, rab, an->r);
    149  1.1  mrg          (rab->exp)++;
    150  1.1  mrg          mpcr_add (res->r, rab, bn->r);
    151  1.1  mrg             /* r = 2 * (rab + an->r) + bn->r */
    152  1.1  mrg          if (cmp >= 0)
    153  1.1  mrg             mpcb_mul (res, res, a);
    154  1.1  mrg          else
    155  1.1  mrg             mpcb_mul (res, res, b);
    156  1.1  mrg          ok = mpcb_can_round (res, MPC_PREC_RE (rop), MPC_PREC_IM (rop),
    157  1.1  mrg             rnd);
    158  1.1  mrg 
    159  1.1  mrg          mpc_clear (diff);
    160  1.1  mrg       }
    161  1.1  mrg 
    162  1.1  mrg       if (!ok)
    163  1.1  mrg          prec += prec + mpcr_get_exp (res->r);
    164  1.1  mrg    } while (!ok);
    165  1.1  mrg 
    166  1.1  mrg    inex = mpcb_round (rop, res, rnd);
    167  1.1  mrg 
    168  1.1  mrg    mpcb_clear (a);
    169  1.1  mrg    mpcb_clear (b);
    170  1.1  mrg    mpcb_clear (an);
    171  1.1  mrg    mpcb_clear (bn);
    172  1.1  mrg    mpcb_clear (anp1);
    173  1.1  mrg    mpcb_clear (bnp1);
    174  1.1  mrg    mpcb_clear (res);
    175  1.1  mrg 
    176  1.1  mrg    return inex;
    177  1.1  mrg }
    178  1.1  mrg 
    179  1.1  mrg 
    180  1.1  mrg static int
    181  1.1  mrg test_agm (void)
    182  1.1  mrg {
    183  1.1  mrg    mpfr_prec_t prec;
    184  1.1  mrg    mpc_t a, b, agm1, agm2;
    185  1.1  mrg    mpc_rnd_t rnd = MPC_RNDDU;
    186  1.1  mrg    int inex, inexb, ok;
    187  1.1  mrg 
    188  1.1  mrg    prec = 1000;
    189  1.1  mrg 
    190  1.1  mrg    mpc_init2 (a, prec);
    191  1.1  mrg    mpc_init2 (b, prec);
    192  1.1  mrg    mpc_set_si_si (a, 100, 0, MPC_RNDNN);
    193  1.1  mrg    mpc_set_si_si (b, 0, 100, MPC_RNDNN);
    194  1.1  mrg    mpc_init2 (agm1, prec);
    195  1.1  mrg    mpc_init2 (agm2, prec);
    196  1.1  mrg 
    197  1.1  mrg    inex = mpc_agm (agm1, a, b, rnd);
    198  1.1  mrg    inexb = mpc_mpcb_agm (agm2, a, b, rnd);
    199  1.1  mrg 
    200  1.1  mrg    ok = (inex == inexb) && (mpc_cmp (agm1, agm2) == 0);
    201  1.1  mrg 
    202  1.1  mrg    mpc_clear (a);
    203  1.1  mrg    mpc_clear (b);
    204  1.1  mrg    mpc_clear (agm1);
    205  1.1  mrg    mpc_clear (agm2);
    206  1.1  mrg 
    207  1.1  mrg    return !ok;
    208  1.1  mrg }
    209  1.1  mrg 
    210  1.1  mrg 
    211  1.1  mrg int
    212  1.1  mrg main (void)
    213  1.1  mrg {
    214  1.1  mrg    return test_agm ();
    215  1.1  mrg }
    216  1.1  mrg 
    217