Home | History | Annotate | Line # | Download | only in tests
tmul.c revision 1.1.1.4
      1      1.1  mrg /* tmul -- test file for mpc_mul.
      2      1.1  mrg 
      3  1.1.1.3  mrg Copyright (C) 2002, 2005, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2020 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 <stdlib.h>
     22      1.1  mrg #ifdef TIMING
     23      1.1  mrg #include <sys/times.h>
     24      1.1  mrg #endif
     25      1.1  mrg #include "mpc-tests.h"
     26      1.1  mrg 
     27      1.1  mrg static void
     28      1.1  mrg cmpmul (mpc_srcptr x, mpc_srcptr y, mpc_rnd_t rnd)
     29      1.1  mrg    /* computes the product of x and y with the naive and Karatsuba methods */
     30      1.1  mrg    /* using the rounding mode rnd and compares the results and return      */
     31      1.1  mrg    /* values.                                                              */
     32      1.1  mrg    /* In our current test suite, the real and imaginary parts of x and y   */
     33      1.1  mrg    /* all have the same precision, and we use this precision also for the  */
     34      1.1  mrg    /* result.                                                              */
     35      1.1  mrg {
     36      1.1  mrg    mpc_t z, t;
     37      1.1  mrg    int   inex_z, inex_t;
     38      1.1  mrg 
     39      1.1  mrg    mpc_init2 (z, MPC_MAX_PREC (x));
     40      1.1  mrg    mpc_init2 (t, MPC_MAX_PREC (x));
     41      1.1  mrg 
     42      1.1  mrg    inex_z = mpc_mul_naive (z, x, y, rnd);
     43      1.1  mrg    inex_t = mpc_mul_karatsuba (t, x, y, rnd);
     44      1.1  mrg 
     45      1.1  mrg    if (mpc_cmp (z, t) != 0 || inex_z != inex_t) {
     46      1.1  mrg       fprintf (stderr, "mul_naive and mul_karatsuba differ for rnd=(%s,%s)\n",
     47      1.1  mrg                mpfr_print_rnd_mode(MPC_RND_RE(rnd)),
     48      1.1  mrg                mpfr_print_rnd_mode(MPC_RND_IM(rnd)));
     49      1.1  mrg       MPC_OUT (x);
     50      1.1  mrg       MPC_OUT (y);
     51      1.1  mrg       MPC_OUT (z);
     52      1.1  mrg       MPC_OUT (t);
     53      1.1  mrg       if (inex_z != inex_t) {
     54      1.1  mrg          fprintf (stderr, "inex_re (z): %s\n", MPC_INEX_STR (inex_z));
     55      1.1  mrg          fprintf (stderr, "inex_re (t): %s\n", MPC_INEX_STR (inex_t));
     56      1.1  mrg       }
     57      1.1  mrg       exit (1);
     58      1.1  mrg    }
     59      1.1  mrg 
     60      1.1  mrg    mpc_clear (z);
     61      1.1  mrg    mpc_clear (t);
     62      1.1  mrg }
     63      1.1  mrg 
     64      1.1  mrg 
     65      1.1  mrg static void
     66      1.1  mrg testmul (long a, long b, long c, long d, mpfr_prec_t prec, mpc_rnd_t rnd)
     67      1.1  mrg {
     68      1.1  mrg   mpc_t x, y;
     69      1.1  mrg 
     70      1.1  mrg   mpc_init2 (x, prec);
     71      1.1  mrg   mpc_init2 (y, prec);
     72      1.1  mrg 
     73      1.1  mrg   mpc_set_si_si (x, a, b, rnd);
     74      1.1  mrg   mpc_set_si_si (y, c, d, rnd);
     75      1.1  mrg 
     76      1.1  mrg   cmpmul (x, y, rnd);
     77      1.1  mrg 
     78      1.1  mrg   mpc_clear (x);
     79      1.1  mrg   mpc_clear (y);
     80      1.1  mrg }
     81      1.1  mrg 
     82      1.1  mrg 
     83      1.1  mrg static void
     84      1.1  mrg check_regular (void)
     85      1.1  mrg {
     86      1.1  mrg   mpc_t x, y;
     87      1.1  mrg   int rnd_re, rnd_im;
     88      1.1  mrg   mpfr_prec_t prec;
     89      1.1  mrg 
     90      1.1  mrg   testmul (247, -65, -223, 416, 8, 24);
     91      1.1  mrg   testmul (5, -896, 5, -32, 3, 2);
     92      1.1  mrg   testmul (-3, -512, -1, -1, 2, 16);
     93      1.1  mrg   testmul (266013312, 121990769, 110585572, 116491059, 27, 0);
     94      1.1  mrg   testmul (170, 9, 450, 251, 8, 0);
     95      1.1  mrg   testmul (768, 85, 169, 440, 8, 16);
     96      1.1  mrg   testmul (145, 1816, 848, 169, 8, 24);
     97      1.1  mrg 
     98      1.1  mrg   mpc_init2 (x, 1000);
     99      1.1  mrg   mpc_init2 (y, 1000);
    100      1.1  mrg 
    101      1.1  mrg   /* Bug 20081114: mpc_mul_karatsuba returned wrong inexact value for
    102      1.1  mrg      imaginary part */
    103      1.1  mrg   mpc_set_prec (x, 7);
    104      1.1  mrg   mpc_set_prec (y, 7);
    105  1.1.1.2  mrg   mpfr_set_str (mpc_realref (x), "0xB4p+733", 16, MPFR_RNDN);
    106  1.1.1.2  mrg   mpfr_set_str (mpc_imagref (x), "0x90p+244", 16, MPFR_RNDN);
    107  1.1.1.2  mrg   mpfr_set_str (mpc_realref (y), "0xECp-146", 16, MPFR_RNDN);
    108  1.1.1.2  mrg   mpfr_set_str (mpc_imagref (y), "0xACp-471", 16, MPFR_RNDN);
    109      1.1  mrg   cmpmul (x, y, MPC_RNDNN);
    110  1.1.1.2  mrg   mpfr_set_str (mpc_realref (x), "0xB4p+733", 16, MPFR_RNDN);
    111  1.1.1.2  mrg   mpfr_set_str (mpc_imagref (x), "0x90p+244", 16, MPFR_RNDN);
    112  1.1.1.2  mrg   mpfr_set_str (mpc_realref (y), "0xACp-471", 16, MPFR_RNDN);
    113  1.1.1.2  mrg   mpfr_set_str (mpc_imagref (y), "-0xECp-146", 16, MPFR_RNDN);
    114      1.1  mrg   cmpmul (x, y, MPC_RNDNN);
    115      1.1  mrg 
    116      1.1  mrg   for (prec = 2; prec < 1000; prec = (mpfr_prec_t) (prec * 1.1 + 1))
    117      1.1  mrg     {
    118      1.1  mrg       mpc_set_prec (x, prec);
    119      1.1  mrg       mpc_set_prec (y, prec);
    120      1.1  mrg 
    121      1.1  mrg       test_default_random (x, -1024, 1024, 128, 0);
    122      1.1  mrg       test_default_random (y, -1024, 1024, 128, 0);
    123      1.1  mrg 
    124      1.1  mrg       for (rnd_re = 0; rnd_re < 4; rnd_re ++)
    125      1.1  mrg         for (rnd_im = 0; rnd_im < 4; rnd_im ++)
    126      1.1  mrg           cmpmul (x, y, MPC_RND (rnd_re, rnd_im));
    127      1.1  mrg     }
    128      1.1  mrg 
    129      1.1  mrg   mpc_clear (x);
    130      1.1  mrg   mpc_clear (y);
    131      1.1  mrg }
    132      1.1  mrg 
    133  1.1.1.3  mrg static void
    134  1.1.1.3  mrg bug20200206 (void)
    135  1.1.1.3  mrg {
    136  1.1.1.3  mrg   mpfr_exp_t emin = mpfr_get_emin ();
    137  1.1.1.3  mrg   mpc_t x, y, z;
    138  1.1.1.3  mrg 
    139  1.1.1.3  mrg   mpfr_set_emin (-1073);
    140  1.1.1.3  mrg   mpc_init2 (x, 53);
    141  1.1.1.3  mrg   mpc_init2 (y, 53);
    142  1.1.1.3  mrg   mpc_init2 (z, 53);
    143  1.1.1.3  mrg   mpfr_set_d (mpc_realref (x), -6.0344722345057644e-272, MPFR_RNDN);
    144  1.1.1.3  mrg   mpfr_set_d (mpc_imagref (x), -4.8536770224196353e-204, MPFR_RNDN);
    145  1.1.1.3  mrg   mpfr_set_d (mpc_realref (y), 1.3834775731431992e-246, MPFR_RNDN);
    146  1.1.1.3  mrg   mpfr_set_d (mpc_imagref (y), 2.9246270396940562e-124, MPFR_RNDN);
    147  1.1.1.3  mrg   mpc_mul (z, x, y, MPC_RNDNN);
    148  1.1.1.3  mrg   if (mpfr_regular_p (mpc_realref (z)) &&
    149  1.1.1.3  mrg       mpfr_get_exp (mpc_realref (z)) < -1073)
    150  1.1.1.3  mrg     {
    151  1.1.1.3  mrg       printf ("Error, mpc_mul returns an out-of-range exponent:\n");
    152  1.1.1.3  mrg       mpfr_dump (mpc_realref (z));
    153  1.1.1.3  mrg       printf ("Bug most probably in MPFR, please upgrade to MPFR 4.1.0 or later\n");
    154  1.1.1.3  mrg       exit (1);
    155  1.1.1.3  mrg     }
    156  1.1.1.3  mrg   mpc_clear (x);
    157  1.1.1.3  mrg   mpc_clear (y);
    158  1.1.1.3  mrg   mpc_clear (z);
    159  1.1.1.3  mrg   mpfr_set_emin (emin);
    160  1.1.1.3  mrg }
    161      1.1  mrg 
    162      1.1  mrg #ifdef TIMING
    163      1.1  mrg static void
    164      1.1  mrg timemul (void)
    165      1.1  mrg {
    166      1.1  mrg   /* measures the time needed with different precisions for naive and */
    167      1.1  mrg   /* Karatsuba multiplication                                         */
    168      1.1  mrg 
    169      1.1  mrg   mpc_t             x, y, z;
    170      1.1  mrg   unsigned long int i, j;
    171      1.1  mrg   const unsigned long int tests = 10000;
    172      1.1  mrg   struct tms        time_old, time_new;
    173      1.1  mrg   double            passed1, passed2;
    174      1.1  mrg 
    175      1.1  mrg   mpc_init (x);
    176      1.1  mrg   mpc_init (y);
    177      1.1  mrg   mpc_init_set_ui_ui (z, 1, 0, MPC_RNDNN);
    178      1.1  mrg 
    179      1.1  mrg   for (i = 1; i < 50; i++)
    180      1.1  mrg     {
    181      1.1  mrg       mpc_set_prec (x, i * BITS_PER_MP_LIMB);
    182      1.1  mrg       mpc_set_prec (y, i * BITS_PER_MP_LIMB);
    183      1.1  mrg       mpc_set_prec (z, i * BITS_PER_MP_LIMB);
    184      1.1  mrg       test_default_random (x, -1, 1, 128, 25);
    185      1.1  mrg       test_default_random (y, -1, 1, 128, 25);
    186      1.1  mrg 
    187      1.1  mrg       times (&time_old);
    188      1.1  mrg       for (j = 0; j < tests; j++)
    189      1.1  mrg         mpc_mul_naive (z, x, y, MPC_RNDNN);
    190      1.1  mrg       times (&time_new);
    191      1.1  mrg       passed1 = ((double) (time_new.tms_utime - time_old.tms_utime)) / 100;
    192      1.1  mrg 
    193      1.1  mrg       times (&time_old);
    194      1.1  mrg       for (j = 0; j < tests; j++)
    195      1.1  mrg         mpc_mul_karatsuba (z, x, y, MPC_RNDNN);
    196      1.1  mrg       times (&time_new);
    197      1.1  mrg       passed2 = ((double) (time_new.tms_utime - time_old.tms_utime)) / 100;
    198      1.1  mrg 
    199      1.1  mrg       printf ("Time for %3li limbs naive/Karatsuba: %5.2f %5.2f\n", i,
    200      1.1  mrg               passed1, passed2);
    201      1.1  mrg     }
    202      1.1  mrg 
    203      1.1  mrg   mpc_clear (x);
    204      1.1  mrg   mpc_clear (y);
    205      1.1  mrg   mpc_clear (z);
    206      1.1  mrg }
    207      1.1  mrg #endif
    208      1.1  mrg 
    209  1.1.1.2  mrg #define MPC_FUNCTION_CALL                                               \
    210  1.1.1.2  mrg   P[0].mpc_inex = mpc_mul (P[1].mpc, P[2].mpc, P[3].mpc, P[4].mpc_rnd)
    211  1.1.1.2  mrg #define MPC_FUNCTION_CALL_SYMMETRIC                                     \
    212  1.1.1.2  mrg   P[0].mpc_inex = mpc_mul (P[1].mpc, P[3].mpc, P[2].mpc, P[4].mpc_rnd)
    213  1.1.1.2  mrg #define MPC_FUNCTION_CALL_REUSE_OP1                                     \
    214  1.1.1.2  mrg   P[0].mpc_inex = mpc_mul (P[1].mpc, P[1].mpc, P[3].mpc, P[4].mpc_rnd)
    215  1.1.1.2  mrg #define MPC_FUNCTION_CALL_REUSE_OP2                                     \
    216  1.1.1.2  mrg   P[0].mpc_inex = mpc_mul (P[1].mpc, P[2].mpc, P[1].mpc, P[4].mpc_rnd)
    217  1.1.1.2  mrg 
    218  1.1.1.2  mrg #include "data_check.tpl"
    219  1.1.1.2  mrg #include "tgeneric.tpl"
    220      1.1  mrg 
    221  1.1.1.4  mrg static void
    222  1.1.1.4  mrg bug20221130 (void)
    223  1.1.1.4  mrg {
    224  1.1.1.4  mrg   mpc_t b, c_conj, res, ref;
    225  1.1.1.4  mrg   mpfr_prec_t prec;
    226  1.1.1.4  mrg   mpc_init2 (b, 20);
    227  1.1.1.4  mrg   mpc_init2 (c_conj, 20);
    228  1.1.1.4  mrg   mpc_init2 (res, 2);
    229  1.1.1.4  mrg   mpc_init2 (ref, 5);
    230  1.1.1.4  mrg   mpc_set_str (b, "(0x1p+0 0x2p+0)", 16, MPC_RNDNN);
    231  1.1.1.4  mrg   mpc_set_str (c_conj, "(-0xap+0 0x1.4p+4)", 16, MPC_RNDNN);
    232  1.1.1.4  mrg   mpc_set_str (ref, "(-0x3.2p+4 0x0p+0)", 16, MPC_RNDNN);
    233  1.1.1.4  mrg   for (prec = 5; prec <= 2000; prec++)
    234  1.1.1.4  mrg   {
    235  1.1.1.4  mrg     mpc_set_prec (res, prec);
    236  1.1.1.4  mrg     mpc_mul (res, b, c_conj, MPC_RNDZZ);
    237  1.1.1.4  mrg     if (mpc_cmp (res, ref) != 0 || mpfr_signbit (mpc_imagref (res)))
    238  1.1.1.4  mrg     {
    239  1.1.1.4  mrg       printf ("Error in bug20221130 for prec=%lu\n", prec);
    240  1.1.1.4  mrg       mpfr_printf ("expected (%Ra %Ra)\n", mpc_realref (ref), mpc_imagref (ref));
    241  1.1.1.4  mrg       mpfr_printf ("got      (%Ra %Ra)\n", mpc_realref (res), mpc_imagref (res));
    242  1.1.1.4  mrg       exit (1);
    243  1.1.1.4  mrg     }
    244  1.1.1.4  mrg   }
    245  1.1.1.4  mrg   mpc_clear (b);
    246  1.1.1.4  mrg   mpc_clear (c_conj);
    247  1.1.1.4  mrg   mpc_clear (res);
    248  1.1.1.4  mrg   mpc_clear (ref);
    249  1.1.1.4  mrg }
    250  1.1.1.4  mrg 
    251      1.1  mrg int
    252      1.1  mrg main (void)
    253      1.1  mrg {
    254      1.1  mrg   test_start ();
    255      1.1  mrg 
    256      1.1  mrg #ifdef TIMING
    257      1.1  mrg   timemul ();
    258      1.1  mrg #endif
    259      1.1  mrg 
    260  1.1.1.3  mrg   bug20200206 ();
    261  1.1.1.4  mrg   bug20221130 ();
    262      1.1  mrg   check_regular ();
    263      1.1  mrg 
    264  1.1.1.2  mrg   data_check_template ("mul.dsc", "mul.dat");
    265  1.1.1.2  mrg 
    266  1.1.1.2  mrg   tgeneric_template ("mul.dsc", 2, 4096, 41, 1024);
    267      1.1  mrg 
    268      1.1  mrg   test_end ();
    269  1.1.1.2  mrg 
    270      1.1  mrg   return 0;
    271      1.1  mrg }
    272