xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tmul_2exp.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* Test file for mpfr_{mul,div}_2{ui,si}.
2 
3 Copyright 1999, 2001-2004, 2006-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5 
6 This file is part of the GNU MPFR Library.
7 
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #include "mpfr-test.h"
24 
25 static const char * const val[] = {
26   "1.0001@100","4.0004000000000@102", "4.0004000000000@97",
27   "1.ABF012345@-100","6.afc048d140000@-98","6.afc048d140000@-103",
28   "F.FFFFFFFFF@10000","3.fffffffffc000@10003","3.fffffffffc000@9998",
29   "1.23456789ABCDEF@42","4.8d159e26af37c@44","4.8d159e26af37c@39",
30   "17@42","5.c000000000000@45","5.c000000000000@40",
31   "42@-17","1.0800000000000@-13","1.0800000000000@-18"
32 };
33 
34 static int
test_mul(int i,int div,mpfr_ptr y,mpfr_srcptr x,unsigned long int n,mpfr_rnd_t r)35 test_mul (int i, int div, mpfr_ptr y, mpfr_srcptr x,
36           unsigned long int n, mpfr_rnd_t r)
37 {
38   return
39     i == 0 ? (div ? mpfr_div_2ui : mpfr_mul_2ui) (y, x, n, r) :
40     i == 1 ? (div ? mpfr_div_2si : mpfr_mul_2si) (y, x, n, r) :
41     i == 2 ? (div ? mpfr_mul_2si : mpfr_div_2si) (y, x, -n, r) :
42     (exit (1), 0);
43 }
44 
45 static void
underflow(mpfr_exp_t e)46 underflow (mpfr_exp_t e)
47 {
48   mpfr_t x, y, z1, z2;
49   mpfr_exp_t emin;
50   int i, k, s;
51   int prec;
52   int rnd;
53   int div;
54   int inex1, inex2;
55   unsigned int flags1, flags2;
56 
57   /* Test mul_2si(x, e - k), div_2si(x, k - e) and div_2ui(x, k - e) with
58    * emin = e, x = s * (1 + i/16), i in { -1, 0, 1 }, s in { -1, 1 }, and
59    * k = 1 to 4, by comparing the result with the one of a simple division.
60    */
61   emin = mpfr_get_emin ();
62   set_emin (e);
63   mpfr_inits2 (8, x, y, (mpfr_ptr) 0);
64   for (i = 15; i <= 17; i++)
65     for (s = 1; s >= -1; s -= 2)
66       {
67         inex1 = mpfr_set_si_2exp (x, s * i, -4, MPFR_RNDN);
68         MPFR_ASSERTN (inex1 == 0);
69         for (prec = 6; prec >= 3; prec -= 3)
70           {
71             mpfr_inits2 (prec, z1, z2, (mpfr_ptr) 0);
72             RND_LOOP_NO_RNDF (rnd)
73               for (k = 1; k <= 4; k++)
74                 {
75                   /* The following one is assumed to be correct. */
76                   inex1 = mpfr_mul_2si (y, x, e, MPFR_RNDN);
77                   MPFR_ASSERTN (inex1 == 0);
78                   inex1 = mpfr_set_ui (z1, 1 << k, MPFR_RNDN);
79                   MPFR_ASSERTN (inex1 == 0);
80                   mpfr_clear_flags ();
81                   /* Do not use mpfr_div_ui to avoid the optimization
82                      by mpfr_div_2si. */
83                   inex1 = mpfr_div (z1, y, z1, (mpfr_rnd_t) rnd);
84                   flags1 = __gmpfr_flags;
85 
86                   for (div = 0; div <= 2; div++)
87                     {
88                       mpfr_clear_flags ();
89                       inex2 =
90                         div == 0 ?
91                         mpfr_mul_2si (z2, x, e - k, (mpfr_rnd_t) rnd) :
92                         div == 1 ?
93                         mpfr_div_2si (z2, x, k - e, (mpfr_rnd_t) rnd) :
94                         mpfr_div_2ui (z2, x, k - e, (mpfr_rnd_t) rnd);
95                       flags2 = __gmpfr_flags;
96                       if (flags1 == flags2 && SAME_SIGN (inex1, inex2) &&
97                           mpfr_equal_p (z1, z2))
98                         continue;
99                       printf ("Error in underflow(");
100                       if (e == MPFR_EMIN_MIN)
101                         printf ("MPFR_EMIN_MIN");
102                       else if (e == emin)
103                         printf ("default emin");
104                       else
105                         printf ("%" MPFR_EXP_FSPEC "d", (mpfr_eexp_t) e);
106                       printf (") with mpfr_%s,\nx = %d/16, prec = %d, k = %d,"
107                               " %s\n", div == 0 ? "mul_2si" : div == 1 ?
108                               "div_2si" : "div_2ui", s * i, prec, k,
109                               mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
110                       printf ("Expected ");
111                       mpfr_out_str (stdout, 16, 0, z1, MPFR_RNDN);
112                       printf (", inex = %d, flags = %u\n",
113                               VSIGN (inex1), flags1);
114                       printf ("Got      ");
115                       mpfr_out_str (stdout, 16, 0, z2, MPFR_RNDN);
116                       printf (", inex = %d, flags = %u\n",
117                               VSIGN (inex2), flags2);
118                       exit (1);
119                     }  /* div */
120                 }  /* k */
121             mpfr_clears (z1, z2, (mpfr_ptr) 0);
122           }  /* prec */
123       }  /* i */
124   mpfr_clears (x, y, (mpfr_ptr) 0);
125   set_emin (emin);
126 }
127 
128 static void
underflow0(void)129 underflow0 (void)
130 {
131   underflow (-256);
132   if (mpfr_get_emin () != MPFR_EMIN_MIN)
133     underflow (mpfr_get_emin ());
134   underflow (MPFR_EMIN_MIN);
135 }
136 
137 static void
large(mpfr_exp_t e)138 large (mpfr_exp_t e)
139 {
140   mpfr_t x, y, z;
141   mpfr_exp_t emax;
142   int inex;
143   unsigned int flags;
144 
145   emax = mpfr_get_emax ();
146   set_emax (e);
147   mpfr_init2 (x, 8);
148   mpfr_init2 (y, 8);
149   mpfr_init2 (z, 4);
150 
151   mpfr_set_inf (x, 1);
152   mpfr_nextbelow (x);
153 
154   mpfr_mul_2si (y, x, -1, MPFR_RNDU);
155   mpfr_prec_round (y, 4, MPFR_RNDU);
156 
157   mpfr_clear_flags ();
158   inex = mpfr_mul_2si (z, x, -1, MPFR_RNDU);
159   flags = __gmpfr_flags;
160 
161   if (inex <= 0 || flags != MPFR_FLAGS_INEXACT || ! mpfr_equal_p (y, z))
162     {
163       printf ("Error in large(");
164       if (e == MPFR_EMAX_MAX)
165         printf ("MPFR_EMAX_MAX");
166       else if (e == emax)
167         printf ("default emax");
168       else
169         printf ("%" MPFR_EXP_FSPEC "d", (mpfr_eexp_t) e);
170       printf (") for mpfr_mul_2si\n");
171       printf ("Expected inex > 0, flags = %u,\n         y = ",
172               (unsigned int) MPFR_FLAGS_INEXACT);
173       mpfr_dump (y);
174       printf ("Got      inex = %d, flags = %u,\n         y = ",
175               inex, flags);
176       mpfr_dump (z);
177       exit (1);
178     }
179 
180   mpfr_clear_flags ();
181   inex = mpfr_div_2si (z, x, 1, MPFR_RNDU);
182   flags = __gmpfr_flags;
183 
184   if (inex <= 0 || flags != MPFR_FLAGS_INEXACT || ! mpfr_equal_p (y, z))
185     {
186       printf ("Error in large(");
187       if (e == MPFR_EMAX_MAX)
188         printf ("MPFR_EMAX_MAX");
189       else if (e == emax)
190         printf ("default emax");
191       else
192         printf ("%" MPFR_EXP_FSPEC "d", (mpfr_eexp_t) e);
193       printf (") for mpfr_div_2si\n");
194       printf ("Expected inex > 0, flags = %u,\n         y = ",
195               (unsigned int) MPFR_FLAGS_INEXACT);
196       mpfr_dump (y);
197       printf ("Got      inex = %d, flags = %u,\n         y = ",
198               inex, flags);
199       mpfr_dump (z);
200       exit (1);
201     }
202 
203   mpfr_clear_flags ();
204   inex = mpfr_div_2ui (z, x, 1, MPFR_RNDU);
205   flags = __gmpfr_flags;
206 
207   if (inex <= 0 || flags != MPFR_FLAGS_INEXACT || ! mpfr_equal_p (y, z))
208     {
209       printf ("Error in large(");
210       if (e == MPFR_EMAX_MAX)
211         printf ("MPFR_EMAX_MAX");
212       else if (e == emax)
213         printf ("default emax");
214       else
215         printf ("%" MPFR_EXP_FSPEC "d", (mpfr_eexp_t) e);
216       printf (") for mpfr_div_2ui\n");
217       printf ("Expected inex > 0, flags = %u,\n         y = ",
218               (unsigned int) MPFR_FLAGS_INEXACT);
219       mpfr_dump (y);
220       printf ("Got      inex = %d, flags = %u,\n         y = ",
221               inex, flags);
222       mpfr_dump (z);
223       exit (1);
224     }
225 
226   mpfr_clears (x, y, z, (mpfr_ptr) 0);
227   set_emax (emax);
228 }
229 
230 static void
large0(void)231 large0 (void)
232 {
233   mpfr_exp_t emin;
234 
235   emin = mpfr_get_emin ();
236 
237   while (1)
238     {
239       large (256);
240       if (mpfr_get_emax () != MPFR_EMAX_MAX)
241         large (mpfr_get_emax ());
242       large (MPFR_EMAX_MAX);
243       if (mpfr_get_emin () == MPFR_EMIN_MIN)
244         break;
245       /* Redo the test with __gmpfr_emin set to MPFR_EMIN_MIN, which can
246          be useful to trigger integer overflows as in div_2ui.c r12272. */
247       set_emin (MPFR_EMIN_MIN);
248     }
249 
250   set_emin (emin);
251 }
252 
253 /* Cases where the function overflows on n = 0 when rounding is like
254    away from zero. */
255 static void
overflow0(mpfr_exp_t emax)256 overflow0 (mpfr_exp_t emax)
257 {
258   mpfr_exp_t old_emax;
259   mpfr_t x, y1, y2;
260   int neg, r, op;
261   static const char *sop[4] = { "mul_2ui", "mul_2si", "div_2ui", "div_2si" };
262 
263   old_emax = mpfr_get_emax ();
264   set_emax (emax);
265 
266   mpfr_init2 (x, 8);
267   mpfr_inits2 (6, y1, y2, (mpfr_ptr) 0);
268 
269   mpfr_set_inf (x, 1);
270   mpfr_nextbelow (x);
271 
272   for (neg = 0; neg <= 1; neg++)
273     {
274       RND_LOOP_NO_RNDF (r)
275         {
276           int inex1, inex2;
277           mpfr_flags_t flags1, flags2;
278 
279           /* Even if there isn't an overflow (rounding ~ toward zero),
280              the result is the same as the one of an overflow. */
281           inex1 = mpfr_overflow (y1, (mpfr_rnd_t) r, neg ? -1 : 1);
282           flags1 = MPFR_FLAGS_INEXACT;
283           if (mpfr_inf_p (y1))
284             flags1 |= MPFR_FLAGS_OVERFLOW;
285           for (op = 0; op < 4; op++)
286             {
287               mpfr_clear_flags ();
288               inex2 =
289                 op == 0 ? mpfr_mul_2ui (y2, x, 0, (mpfr_rnd_t) r) :
290                 op == 1 ? mpfr_mul_2si (y2, x, 0, (mpfr_rnd_t) r) :
291                 op == 2 ? mpfr_div_2ui (y2, x, 0, (mpfr_rnd_t) r) :
292                 op == 3 ? mpfr_div_2si (y2, x, 0, (mpfr_rnd_t) r) :
293                 (MPFR_ASSERTN (0), 0);
294               flags2 = __gmpfr_flags;
295               if (!(mpfr_equal_p (y1, y2) &&
296                     SAME_SIGN (inex1, inex2) &&
297                     flags1 == flags2))
298                 {
299                   printf ("Error in overflow0 for %s, mpfr_%s, emax = %"
300                           MPFR_EXP_FSPEC "d,\nx = ",
301                           mpfr_print_rnd_mode ((mpfr_rnd_t) r), sop[op],
302                           (mpfr_eexp_t) emax);
303                   mpfr_dump (x);
304                   printf ("Expected ");
305                   mpfr_dump (y1);
306                   printf ("  with inex = %d, flags =", inex1);
307                   flags_out (flags1);
308                   printf ("Got      ");
309                   mpfr_dump (y2);
310                   printf ("  with inex = %d, flags =", inex2);
311                   flags_out (flags2);
312                   exit (1);
313                 }
314             }
315         }
316       mpfr_neg (x, x, MPFR_RNDN);
317     }
318 
319   mpfr_clears (x, y1, y2, (mpfr_ptr) 0);
320   set_emax (old_emax);
321 }
322 
323 static void
coverage_div_2ui(void)324 coverage_div_2ui (void)
325 {
326   mpfr_t x, y;
327 
328   mpfr_init2 (x, 2);
329   mpfr_init2 (y, 2);
330   mpfr_set_ui_2exp (x, 1, mpfr_get_emax () - 1, MPFR_RNDN);
331   mpfr_div_2ui (y, x, (unsigned long) LONG_MAX + 1, MPFR_RNDN);
332   MPFR_ASSERTN(mpfr_zero_p (y));
333   MPFR_ASSERTN(mpfr_signbit (y) == 0);
334   mpfr_clear (x);
335   mpfr_clear (y);
336 }
337 
338 int
main(int argc,char * argv[])339 main (int argc, char *argv[])
340 {
341   mpfr_t w,z;
342   unsigned long k;
343   int i;
344 
345   tests_start_mpfr ();
346 
347   coverage_div_2ui ();
348   mpfr_inits2 (53, w, z, (mpfr_ptr) 0);
349 
350   for (i = 0; i < 3; i++)
351     {
352       mpfr_set_inf (w, 1);
353       test_mul (i, 0, w, w, 10, MPFR_RNDZ);
354       if (!MPFR_IS_INF(w))
355         {
356           printf ("Result is not Inf (i = %d)\n", i);
357           exit (1);
358         }
359 
360       mpfr_set_nan (w);
361       test_mul (i, 0, w, w, 10, MPFR_RNDZ);
362       if (!MPFR_IS_NAN(w))
363         {
364           printf ("Result is not NaN (i = %d)\n", i);
365           exit (1);
366         }
367 
368       for (k = 0 ; k < numberof(val) ; k+=3)
369         {
370           mpfr_set_str (w, val[k], 16, MPFR_RNDN);
371           test_mul (i, 0, z, w, 10, MPFR_RNDZ);
372           if (mpfr_cmp_str (z, val[k+1], 16, MPFR_RNDN))
373             {
374               printf ("ERROR for x * 2^n (i = %d) for %s\n", i, val[k]);
375               printf ("Expected: %s\n"
376                       "Got     : ", val[k+1]);
377               mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
378               putchar ('\n');
379               exit (1);
380             }
381           test_mul (i, 1, z, w, 10, MPFR_RNDZ);
382           if (mpfr_cmp_str (z, val[k+2], 16, MPFR_RNDN))
383             {
384               printf ("ERROR for x / 2^n (i = %d) for %s\n", i, val[k]);
385               printf ("Expected: %s\n"
386                       "Got     : ", val[k+2]);
387               mpfr_out_str (stdout, 16, 0, z, MPFR_RNDN);
388               putchar ('\n');
389               exit (1);
390             }
391         }
392 
393       mpfr_set_inf (w, 1);
394       mpfr_nextbelow (w);
395       test_mul (i, 0, w, w, 1, MPFR_RNDN);
396       if (!mpfr_inf_p (w))
397         {
398           printf ("Overflow error (i = %d)!\n", i);
399           exit (1);
400         }
401       mpfr_set_ui (w, 0, MPFR_RNDN);
402       mpfr_nextabove (w);
403       test_mul (i, 1, w, w, 1, MPFR_RNDN);
404       if (mpfr_cmp_ui (w, 0))
405         {
406           printf ("Underflow error (i = %d)!\n", i);
407           exit (1);
408         }
409     }
410 
411   if (MPFR_EXP_MAX >= LONG_MAX/2 && MPFR_EXP_MIN <= LONG_MAX/2-LONG_MAX-1)
412     {
413       unsigned long lmp1 = (unsigned long) LONG_MAX + 1;
414 
415       mpfr_set_ui (w, 1, MPFR_RNDN);
416       mpfr_mul_2ui (w, w, LONG_MAX/2, MPFR_RNDZ);
417       mpfr_div_2ui (w, w, lmp1, MPFR_RNDZ);
418       mpfr_mul_2ui (w, w, lmp1 - LONG_MAX/2, MPFR_RNDZ);
419       if (!mpfr_cmp_ui (w, 1))
420         {
421           printf ("Underflow LONG_MAX error!\n");
422           exit (1);
423         }
424     }
425 
426   mpfr_clears (w, z, (mpfr_ptr) 0);
427 
428   underflow0 ();
429   large0 ();
430 
431   if (mpfr_get_emax () != MPFR_EMAX_MAX)
432     overflow0 (mpfr_get_emax ());
433   overflow0 (MPFR_EMAX_MAX);
434   overflow0 (-1);
435 
436   tests_end_mpfr ();
437   return 0;
438 }
439