xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/troot.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* Test file for mpfr_root (also used for mpfr_rootn_ui).
2 
3 Copyright 2005-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 /* Note: troot.c is included by trootn_ui.c with TF = mpfr_rootn_ui */
24 #ifdef TF
25 # define TF_IS_MPFR_ROOT 0
26 #else
27 # define TF_IS_MPFR_ROOT 1
28 # define TF mpfr_root
29 # define _MPFR_NO_DEPRECATED_ROOT
30 #endif
31 
32 #include "mpfr-test.h"
33 
34 #include <time.h>
35 
36 /* return the cpu time in seconds */
37 static double
cputime(void)38 cputime (void)
39 {
40   return (double) clock () / (double) CLOCKS_PER_SEC;
41 }
42 
43 #define DEFN(N)                                                         \
44   static int root##N (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)        \
45   { return TF (y, x, N, rnd); }                                         \
46   static int pow##N (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)         \
47   { return mpfr_pow_ui (y, x, N, rnd); }
48 
49 DEFN(2)
50 DEFN(3)
51 DEFN(4)
52 DEFN(5)
53 DEFN(17)
54 DEFN(120)
55 
56 static void
special(void)57 special (void)
58 {
59   mpfr_t x, y;
60   int i;
61 
62   mpfr_init (x);
63   mpfr_init (y);
64 
65   /* root(NaN) = NaN */
66   mpfr_set_nan (x);
67   i = TF (y, x, 17, MPFR_RNDN);
68   if (!mpfr_nan_p (y))
69     {
70       printf ("Error: root(NaN,17) <> NaN\n");
71       exit (1);
72     }
73   MPFR_ASSERTN (i == 0);
74 
75   /* root(+Inf) = +Inf */
76   mpfr_set_inf (x, 1);
77   i = TF (y, x, 42, MPFR_RNDN);
78   if (!mpfr_inf_p (y) || mpfr_sgn (y) < 0)
79     {
80       printf ("Error: root(+Inf,42) <> +Inf\n");
81       exit (1);
82     }
83   MPFR_ASSERTN (i == 0);
84 
85   /* root(-Inf, 17) = -Inf */
86   mpfr_set_inf (x, -1);
87   i = TF (y, x, 17, MPFR_RNDN);
88   if (!mpfr_inf_p (y) || mpfr_sgn (y) > 0)
89     {
90       printf ("Error: root(-Inf,17) <> -Inf\n");
91       exit (1);
92     }
93   MPFR_ASSERTN (i == 0);
94 
95   /* root(-Inf, 42) =  NaN */
96   mpfr_set_inf (x, -1);
97   i = TF (y, x, 42, MPFR_RNDN);
98   if (!mpfr_nan_p (y))
99     {
100       printf ("Error: root(-Inf,42) <> -Inf\n");
101       exit (1);
102     }
103   MPFR_ASSERTN (i == 0);
104 
105   /* root(+/-0, k) = +/-0, with the sign depending on TF.
106    * Before calling the function, we set y to NaN with the wrong sign,
107    * so that if the code of the function forgets to do something, this
108    * will be detected.
109    */
110   mpfr_set_zero (x, 1);  /* x is +0 */
111   MPFR_SET_NAN (y);
112   MPFR_SET_NEG (y);
113   i = TF (y, x, 17, MPFR_RNDN);
114   if (MPFR_NOTZERO (y) || MPFR_IS_NEG (y))
115     {
116       printf ("Error: root(+0,17) <> +0\n");
117       exit (1);
118     }
119   MPFR_ASSERTN (i == 0);
120   MPFR_SET_NAN (y);
121   MPFR_SET_NEG (y);
122   i = TF (y, x, 42, MPFR_RNDN);
123   if (MPFR_NOTZERO (y) || MPFR_IS_NEG (y))
124     {
125       printf ("Error: root(+0,42) <> +0\n");
126       exit (1);
127     }
128   MPFR_ASSERTN (i == 0);
129   mpfr_set_zero (x, -1);  /* x is -0 */
130   MPFR_SET_NAN (y);
131   MPFR_SET_POS (y);
132   i = TF (y, x, 17, MPFR_RNDN);
133   if (MPFR_NOTZERO (y) || MPFR_IS_POS (y))
134     {
135       printf ("Error: root(-0,17) <> -0\n");
136       exit (1);
137     }
138   MPFR_ASSERTN (i == 0);
139   MPFR_SET_NAN (y);
140   if (TF_IS_MPFR_ROOT)
141     MPFR_SET_POS (y);
142   else
143     MPFR_SET_NEG (y);
144   i = TF (y, x, 42, MPFR_RNDN);
145   if (MPFR_NOTZERO (y) ||
146       (TF_IS_MPFR_ROOT ? MPFR_IS_POS (y) : MPFR_IS_NEG (y)))
147     {
148       printf ("Error: root(-0,42) <> %c0\n",
149               TF_IS_MPFR_ROOT ? '-' : '+');
150       exit (1);
151     }
152   MPFR_ASSERTN (i == 0);
153 
154   mpfr_set_prec (x, 53);
155   mpfr_set_str (x, "8.39005285514734966412e-01", 10, MPFR_RNDN);
156   TF (x, x, 3, MPFR_RNDN);
157   if (mpfr_cmp_str1 (x, "9.43166207799662426048e-01"))
158     {
159       printf ("Error in root3 (1)\n");
160       printf ("expected 9.43166207799662426048e-01\n");
161       printf ("got      ");
162       mpfr_dump (x);
163       exit (1);
164     }
165 
166   mpfr_set_prec (x, 32);
167   mpfr_set_prec (y, 32);
168   mpfr_set_str_binary (x, "0.10000100001100101001001001011001");
169   TF (x, x, 3, MPFR_RNDN);
170   mpfr_set_str_binary (y, "0.11001101011000100111000111111001");
171   if (mpfr_cmp (x, y))
172     {
173       printf ("Error in root3 (2)\n");
174       exit (1);
175     }
176 
177   mpfr_set_prec (x, 32);
178   mpfr_set_prec (y, 32);
179   mpfr_set_str_binary (x, "-0.1100001110110000010101011001011");
180   TF (x, x, 3, MPFR_RNDD);
181   mpfr_set_str_binary (y, "-0.11101010000100100101000101011001");
182   if (mpfr_cmp (x, y))
183     {
184       printf ("Error in root3 (3)\n");
185       exit (1);
186     }
187 
188   mpfr_set_prec (x, 82);
189   mpfr_set_prec (y, 27);
190   mpfr_set_str_binary (x, "0.1010001111011101011011000111001011001101100011110110010011011011011010011001100101e-7");
191   TF (y, x, 3, MPFR_RNDD);
192   mpfr_set_str_binary (x, "0.101011110001110001000100011E-2");
193   if (mpfr_cmp (x, y))
194     {
195       printf ("Error in root3 (4)\n");
196       exit (1);
197     }
198 
199   mpfr_set_prec (x, 204);
200   mpfr_set_prec (y, 38);
201   mpfr_set_str_binary (x, "0.101000000001101000000001100111111011111001110110100001111000100110100111001101100111110001110001011011010110010011100101111001111100001010010100111011101100000011011000101100010000000011000101001010001001E-5");
202   TF (y, x, 3, MPFR_RNDD);
203   mpfr_set_str_binary (x, "0.10001001111010011011101000010110110010E-1");
204   if (mpfr_cmp (x, y))
205     {
206       printf ("Error in root3 (5)\n");
207       exit (1);
208     }
209 
210   /* Worst case found on 2006-11-25 */
211   mpfr_set_prec (x, 53);
212   mpfr_set_prec (y, 53);
213   mpfr_set_str_binary (x, "1.0100001101101101001100110001001000000101001101100011E28");
214   TF (y, x, 35, MPFR_RNDN);
215   mpfr_set_str_binary (x, "1.1100000010110101100011101011000010100001101100100011E0");
216   if (mpfr_cmp (x, y))
217     {
218       printf ("Error in rootn (y, x, 35, MPFR_RNDN) for\n"
219               "x = 1.0100001101101101001100110001001000000101001101100011E28\n"
220               "Expected ");
221       mpfr_dump (x);
222       printf ("Got      ");
223       mpfr_dump (y);
224       exit (1);
225     }
226   /* Worst cases found on 2006-11-26 */
227   mpfr_set_str_binary (x, "1.1111010011101110001111010110000101110000110110101100E17");
228   TF (y, x, 36, MPFR_RNDD);
229   mpfr_set_str_binary (x, "1.0110100111010001101001010111001110010100111111000010E0");
230   if (mpfr_cmp (x, y))
231     {
232       printf ("Error in rootn (y, x, 36, MPFR_RNDD) for\n"
233               "x = 1.1111010011101110001111010110000101110000110110101100E17\n"
234               "Expected ");
235       mpfr_dump (x);
236       printf ("Got      ");
237       mpfr_dump (y);
238       exit (1);
239     }
240   mpfr_set_str_binary (x, "1.1100011101101101100010110001000001110001111110010000E23");
241   TF (y, x, 36, MPFR_RNDU);
242   mpfr_set_str_binary (x, "1.1001010100001110000110111111100011011101110011000100E0");
243   if (mpfr_cmp (x, y))
244     {
245       printf ("Error in rootn (y, x, 36, MPFR_RNDU) for\n"
246               "x = 1.1100011101101101100010110001000001110001111110010000E23\n"
247               "Expected ");
248       mpfr_dump (x);
249       printf ("Got      ");
250       mpfr_dump (y);
251       exit (1);
252     }
253 
254   /* Check for k = 1 */
255   mpfr_set_ui (x, 17, MPFR_RNDN);
256   i = TF (y, x, 1, MPFR_RNDN);
257   if (mpfr_cmp_ui (x, 17) || i != 0)
258     {
259       printf ("Error in root for 17^(1/1)\n");
260       exit (1);
261     }
262 
263   mpfr_set_ui (x, 0, MPFR_RNDN);
264   i = TF (y, x, 0, MPFR_RNDN);
265   if (!MPFR_IS_NAN (y) || i != 0)
266     {
267       printf ("Error in root for (+0)^(1/0)\n");
268       exit (1);
269     }
270   mpfr_neg (x, x, MPFR_RNDN);
271   i = TF (y, x, 0, MPFR_RNDN);
272   if (!MPFR_IS_NAN (y) || i != 0)
273     {
274       printf ("Error in root for (-0)^(1/0)\n");
275       exit (1);
276     }
277 
278   mpfr_set_ui (x, 1, MPFR_RNDN);
279   i = TF (y, x, 0, MPFR_RNDN);
280   if (!MPFR_IS_NAN (y) || i != 0)
281     {
282       printf ("Error in root for 1^(1/0)\n");
283       exit (1);
284     }
285 
286   /* Check for k==2 */
287   mpfr_set_si (x, -17, MPFR_RNDD);
288   i = TF (y, x, 2, MPFR_RNDN);
289   if (!MPFR_IS_NAN (y) || i != 0)
290     {
291       printf ("Error in root for (-17)^(1/2)\n");
292       exit (1);
293     }
294 
295   mpfr_clear (x);
296   mpfr_clear (y);
297 }
298 
299 /* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=812779
300  * https://bugzilla.gnome.org/show_bug.cgi?id=756960
301  * is a GNOME Calculator bug (mpfr_root applied on a negative integer,
302  * which is converted to an unsigned integer), but the strange result
303  * is also due to a bug in MPFR.
304  */
305 static void
bigint(void)306 bigint (void)
307 {
308   mpfr_t x, y;
309 
310   mpfr_inits2 (64, x, y, (mpfr_ptr) 0);
311 
312   mpfr_set_ui (x, 10, MPFR_RNDN);
313   if (sizeof (unsigned long) * CHAR_BIT == 64)
314     {
315       TF (x, x, ULONG_MAX, MPFR_RNDN);
316       mpfr_set_ui_2exp (y, 1, -63, MPFR_RNDN);
317       mpfr_add_ui (y, y, 1, MPFR_RNDN);
318       if (! mpfr_equal_p (x, y))
319         {
320           printf ("Error in bigint for ULONG_MAX\n");
321           printf ("Expected ");
322           mpfr_dump (y);
323           printf ("Got      ");
324           mpfr_dump (x);
325           exit (1);
326         }
327     }
328 
329   mpfr_set_ui (x, 10, MPFR_RNDN);
330   TF (x, x, 1234567890, MPFR_RNDN);
331   mpfr_set_str_binary (y,
332     "1.00000000000000000000000000001000000000101011000101000110010001");
333   if (! mpfr_equal_p (x, y))
334     {
335       printf ("Error in bigint for 1234567890\n");
336       printf ("Expected ");
337       mpfr_dump (y);
338       printf ("Got      ");
339       mpfr_dump (x);
340       exit (1);
341     }
342 
343   mpfr_clears (x, y, (mpfr_ptr) 0);
344 }
345 
346 #define TEST_FUNCTION TF
347 #define INTEGER_TYPE unsigned long
348 #define INT_RAND_FUNCTION() \
349   (INTEGER_TYPE) (RAND_BOOL () ? randlimb () : randlimb () % 3 + 2)
350 #include "tgeneric_ui.c"
351 
352 static void
exact_powers(unsigned long bmax,unsigned long kmax)353 exact_powers (unsigned long bmax, unsigned long kmax)
354 {
355   long b, k;
356   mpz_t z;
357   mpfr_t x, y;
358   int inex, neg;
359 
360   mpz_init (z);
361   for (b = 2; b <= bmax; b++)
362     for (k = 1; k <= kmax; k++)
363       {
364         mpz_ui_pow_ui (z, b, k);
365         mpfr_init2 (x, mpz_sizeinbase (z, 2));
366         mpfr_set_ui (x, b, MPFR_RNDN);
367         mpfr_pow_ui (x, x, k, MPFR_RNDN);
368         mpz_set_ui (z, b);
369         mpfr_init2 (y, mpz_sizeinbase (z, 2));
370         for (neg = 0; neg <= 1; neg++)
371           {
372             inex = TF (y, x, k, MPFR_RNDN);
373             if (inex != 0)
374               {
375                 printf ("Error in exact_powers, b=%ld, k=%ld\n", b, k);
376                 printf ("Expected inex=0, got %d\n", inex);
377                 exit (1);
378               }
379             if (neg && (k & 1) == 0)
380               {
381                 if (!MPFR_IS_NAN (y))
382                   {
383                     printf ("Error in exact_powers, b=%ld, k=%ld\n", b, k);
384                     printf ("Expected y=NaN\n");
385                     printf ("Got      ");
386                     mpfr_out_str (stdout, 10, 0, y, MPFR_RNDN);
387                     printf ("\n");
388                     exit (1);
389                   }
390               }
391             else if (MPFR_IS_NAN (y) || mpfr_cmp_si (y, b) != 0)
392               {
393                 printf ("Error in exact_powers, b=%ld, k=%ld\n", b, k);
394                 printf ("Expected y=%ld\n", b);
395                 printf ("Got      ");
396                 mpfr_out_str (stdout, 10, 0, y, MPFR_RNDN);
397                 printf ("\n");
398                 exit (1);
399               }
400             mpfr_neg (x, x, MPFR_RNDN);
401             b = -b;
402           }
403         mpfr_clear (x);
404         mpfr_clear (y);
405       }
406   mpz_clear (z);
407 }
408 
409 /* Compare root(x,2^h) with pow(x,2^(-h)). */
410 static void
cmp_pow(void)411 cmp_pow (void)
412 {
413   mpfr_t x, y1, y2;
414   int h;
415 
416   mpfr_inits2 (128, x, y1, y2, (mpfr_ptr) 0);
417 
418   for (h = 1; h < sizeof (unsigned long) * CHAR_BIT; h++)
419     {
420       unsigned long k = (unsigned long) 1 << h;
421       int i;
422 
423       for (i = 0; i < 10; i++)
424         {
425           mpfr_rnd_t rnd;
426           mpfr_flags_t flags1, flags2;
427           int inex1, inex2;
428 
429           tests_default_random (x, 0, __gmpfr_emin, __gmpfr_emax, 1);
430           rnd = RND_RAND_NO_RNDF ();
431           mpfr_set_ui_2exp (y1, 1, -h, MPFR_RNDN);
432           mpfr_clear_flags ();
433           inex1 = mpfr_pow (y1, x, y1, rnd);
434           flags1 = __gmpfr_flags;
435           mpfr_clear_flags ();
436           inex2 = TF (y2, x, k, rnd);
437           flags2 = __gmpfr_flags;
438           if (!(mpfr_equal_p (y1, y2) && SAME_SIGN (inex1, inex2) &&
439                 flags1 == flags2))
440             {
441               printf ("Error in cmp_pow on h=%d, i=%d, rnd=%s\n",
442                       h, i, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
443               printf ("x = ");
444               mpfr_dump (x);
445               printf ("pow  = ");
446               mpfr_dump (y1);
447               printf ("with inex = %d, flags =", inex1);
448               flags_out (flags1);
449               printf ("root = ");
450               mpfr_dump (y2);
451               printf ("with inex = %d, flags =", inex2);
452               flags_out (flags2);
453               exit (1);
454             }
455         }
456     }
457 
458   mpfr_clears (x, y1, y2, (mpfr_ptr) 0);
459 }
460 
461 static void
bug20171214(void)462 bug20171214 (void)
463 {
464   mpfr_t x, y;
465   int inex;
466 
467   mpfr_init2 (x, 805);
468   mpfr_init2 (y, 837);
469   mpfr_set_ui (x, 1, MPFR_RNDN);
470   inex = TF (y, x, 120, MPFR_RNDN);
471   MPFR_ASSERTN (inex == 0);
472   MPFR_ASSERTN (mpfr_cmp_ui (y, 1) == 0);
473   mpfr_set_si (x, -1, MPFR_RNDN);
474   inex = TF (y, x, 121, MPFR_RNDN);
475   MPFR_ASSERTN (inex == 0);
476   MPFR_ASSERTN (mpfr_cmp_si (y, -1) == 0);
477   mpfr_clear (x);
478   mpfr_clear (y);
479 }
480 
481 int
main(int argc,char * argv[])482 main (int argc, char *argv[])
483 {
484   mpfr_t x;
485   int r;
486   mpfr_prec_t p;
487   unsigned long k;
488 
489   if (argc == 3) /* troot prec k */
490     {
491       double st1, st2;
492       unsigned long k;
493       int l;
494       mpfr_t y;
495       p = strtoul (argv[1], NULL, 10);
496       k = strtoul (argv[2], NULL, 10);
497       mpfr_init2 (x, p);
498       mpfr_init2 (y, p);
499       mpfr_const_pi (y, MPFR_RNDN);
500       TF (x, y, k, MPFR_RNDN); /* to warm up cache */
501       st1 = cputime ();
502       for (l = 0; cputime () - st1 < 1.0; l++)
503         TF (x, y, k, MPFR_RNDN);
504       st1 = (cputime () - st1) / l;
505       printf ("%-15s took %.2es\n", MAKE_STR(TF), st1);
506 
507       /* compare with x^(1/k) = exp(1/k*log(x)) */
508       /* first warm up cache */
509       mpfr_swap (x, y);
510       mpfr_log (y, x, MPFR_RNDN);
511       mpfr_div_ui (y, y, k, MPFR_RNDN);
512       mpfr_exp (y, y, MPFR_RNDN);
513 
514       st2 = cputime ();
515       for (l = 0; cputime () - st2 < 1.0; l++)
516         {
517           mpfr_log (y, x, MPFR_RNDN);
518           mpfr_div_ui (y, y, k, MPFR_RNDN);
519           mpfr_exp (y, y, MPFR_RNDN);
520         }
521       st2 = (cputime () - st2) / l;
522       printf ("exp(1/k*log(x)) took %.2es\n", st2);
523 
524       mpfr_clear (x);
525       mpfr_clear (y);
526       return 0;
527     }
528 
529   tests_start_mpfr ();
530 
531   bug20171214 ();
532   exact_powers (3, 1000);
533   special ();
534   bigint ();
535   cmp_pow ();
536 
537   mpfr_init (x);
538 
539   for (p = MPFR_PREC_MIN; p < 100; p++)
540     {
541       mpfr_set_prec (x, p);
542       RND_LOOP (r)
543         {
544           mpfr_set_ui (x, 1, MPFR_RNDN);
545           k = 2 + randlimb () % 4; /* 2 <= k <= 5 */
546           TF (x, x, k, (mpfr_rnd_t) r);
547           if (mpfr_cmp_ui (x, 1))
548             {
549               printf ("Error in rootn[%lu] for x=1, rnd=%s\ngot ",
550                       k, mpfr_print_rnd_mode ((mpfr_rnd_t) r));
551               mpfr_out_str (stdout, 2, 0, x, MPFR_RNDN);
552               printf ("\n");
553               exit (1);
554             }
555           mpfr_set_si (x, -1, MPFR_RNDN);
556           if (k % 2)
557             {
558               TF (x, x, k, (mpfr_rnd_t) r);
559               if (mpfr_cmp_si (x, -1))
560                 {
561                   printf ("Error in rootn[%lu] for x=-1, rnd=%s\ngot ",
562                           k, mpfr_print_rnd_mode ((mpfr_rnd_t) r));
563                   mpfr_out_str (stdout, 2, 0, x, MPFR_RNDN);
564                   printf ("\n");
565                   exit (1);
566                 }
567             }
568 
569           if (p >= 5)
570             {
571               int i;
572               for (i = -12; i <= 12; i++)
573                 {
574                   mpfr_set_ui (x, 27, MPFR_RNDN);
575                   mpfr_mul_2si (x, x, 3*i, MPFR_RNDN);
576                   TF (x, x, 3, MPFR_RNDN);
577                   if (mpfr_cmp_si_2exp (x, 3, i))
578                     {
579                       printf ("Error in rootn[3] for "
580                               "x = 27.0 * 2^(%d), rnd=%s\ngot ",
581                               3*i, mpfr_print_rnd_mode ((mpfr_rnd_t) r));
582                       mpfr_out_str (stdout, 2, 0, x, MPFR_RNDN);
583                       printf ("\ninstead of 3 * 2^(%d)\n", i);
584                       exit (1);
585                     }
586                 }
587             }
588         }
589     }
590   mpfr_clear (x);
591 
592   test_generic_ui (MPFR_PREC_MIN, 200, 30);
593 
594   /* The sign of the random value y (used to generate a potential bad case)
595      is negative with a probability 256/512 = 1/2 for odd n, and never
596      negative (probability 0/512) for even n (if y is negative, then
597      (y^(2k))^(1/(2k)) is different from y, so that this would yield
598      an error). */
599   bad_cases (root2, pow2, "rootn[2]", 0, -256, 255, 4, 128, 80, 40);
600   bad_cases (root3, pow3, "rootn[3]", 256, -256, 255, 4, 128, 200, 40);
601   bad_cases (root4, pow4, "rootn[4]", 0, -256, 255, 4, 128, 320, 40);
602   bad_cases (root5, pow5, "rootn[5]", 256, -256, 255, 4, 128, 440, 40);
603   bad_cases (root17, pow17, "rootn[17]", 256, -256, 255, 4, 128, 800, 40);
604   bad_cases (root120, pow120, "rootn[120]", 0, -256, 255, 4, 128, 800, 40);
605 
606   tests_end_mpfr ();
607   return 0;
608 }
609