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