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