1 /* Test mpf_sqrt, mpf_mul.
2 
3 Copyright 1996, 2001, 2004 Free Software Foundation, Inc.
4 
5 This file is part of the GNU MP Library test suite.
6 
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11 
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include "gmp-impl.h"
24 #include "tests.h"
25 
26 #ifndef SIZE
27 #define SIZE 16
28 #endif
29 
30 void
check_rand1(int argc,char ** argv)31 check_rand1 (int argc, char **argv)
32 {
33   mp_size_t size;
34   mp_exp_t exp;
35   int reps = 20000;
36   int i;
37   mpf_t x, y, y2;
38   mp_size_t bprec = 100;
39   mpf_t rerr, max_rerr, limit_rerr;
40 
41   if (argc > 1)
42     {
43       reps = strtol (argv[1], 0, 0);
44       if (argc > 2)
45 	bprec = strtol (argv[2], 0, 0);
46     }
47 
48   mpf_set_default_prec (bprec);
49 
50   mpf_init_set_ui (limit_rerr, 1);
51   mpf_div_2exp (limit_rerr, limit_rerr, bprec);
52 #if VERBOSE
53   mpf_dump (limit_rerr);
54 #endif
55   mpf_init (rerr);
56   mpf_init_set_ui (max_rerr, 0);
57 
58   mpf_init (x);
59   mpf_init (y);
60   mpf_init (y2);
61   for (i = 0; i < reps; i++)
62     {
63       size = urandom () % SIZE;
64       exp = urandom () % SIZE;
65       mpf_random2 (x, size, exp);
66 
67       mpf_sqrt (y, x);
68       MPF_CHECK_FORMAT (y);
69       mpf_mul (y2, y, y);
70 
71       mpf_reldiff (rerr, x, y2);
72       if (mpf_cmp (rerr, max_rerr) > 0)
73 	{
74 	  mpf_set (max_rerr, rerr);
75 #if VERBOSE
76 	  mpf_dump (max_rerr);
77 #endif
78 	  if (mpf_cmp (rerr, limit_rerr) > 0)
79 	    {
80 	      printf ("ERROR after %d tests\n", i);
81 	      printf ("   x = "); mpf_dump (x);
82 	      printf ("   y = "); mpf_dump (y);
83 	      printf ("  y2 = "); mpf_dump (y2);
84 	      printf ("   rerr       = "); mpf_dump (rerr);
85 	      printf ("   limit_rerr = "); mpf_dump (limit_rerr);
86               printf ("in hex:\n");
87               mp_trace_base = 16;
88 	      mpf_trace ("   x  ", x);
89 	      mpf_trace ("   y  ", y);
90 	      mpf_trace ("   y2 ", y2);
91 	      mpf_trace ("   rerr      ", rerr);
92 	      mpf_trace ("   limit_rerr", limit_rerr);
93 	      abort ();
94 	    }
95 	}
96     }
97 
98   mpf_clear (limit_rerr);
99   mpf_clear (rerr);
100   mpf_clear (max_rerr);
101 
102   mpf_clear (x);
103   mpf_clear (y);
104   mpf_clear (y2);
105 }
106 
107 void
check_rand2(void)108 check_rand2 (void)
109 {
110   unsigned long      max_prec = 20;
111   unsigned long      min_prec = __GMPF_BITS_TO_PREC (1);
112   gmp_randstate_ptr  rands = RANDS;
113   unsigned long      x_prec, r_prec;
114   mpf_t              x, r, s;
115   int                i;
116 
117   mpf_init (x);
118   mpf_init (r);
119   mpf_init (s);
120   refmpf_set_prec_limbs (s, 2*max_prec+10);
121 
122   for (i = 0; i < 500; i++)
123     {
124       /* input precision */
125       x_prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
126       refmpf_set_prec_limbs (x, x_prec);
127 
128       /* result precision */
129       r_prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
130       refmpf_set_prec_limbs (r, r_prec);
131 
132       mpf_random2 (x, x_prec, 1000);
133 
134       mpf_sqrt (r, x);
135       MPF_CHECK_FORMAT (r);
136 
137       /* Expect to prec limbs of result.
138          In the current implementation there's no stripping of low zero
139          limbs in mpf_sqrt, so size should be exactly prec.  */
140       if (SIZ(r) != r_prec)
141         {
142           printf ("mpf_sqrt wrong number of result limbs\n");
143           mpf_trace ("  x", x);
144           mpf_trace ("  r", r);
145           printf    ("  r_prec=%lu\n", r_prec);
146           printf    ("  SIZ(r)  %ld\n", (long) SIZ(r));
147           printf    ("  PREC(r) %ld\n", (long) PREC(r));
148           abort ();
149         }
150 
151       /* Must have r^2 <= x, since r has been truncated. */
152       mpf_mul (s, r, r);
153       if (! (mpf_cmp (s, x) <= 0))
154         {
155           printf    ("mpf_sqrt result too big\n");
156           mpf_trace ("  x", x);
157           printf    ("  r_prec=%lu\n", r_prec);
158           mpf_trace ("  r", r);
159           mpf_trace ("  s", s);
160           abort ();
161         }
162 
163       /* Must have (r+ulp)^2 > x, or else r is too small. */
164       refmpf_add_ulp (r);
165       mpf_mul (s, r, r);
166       if (! (mpf_cmp (s, x) > 0))
167         {
168           printf    ("mpf_sqrt result too small\n");
169           mpf_trace ("  x", x);
170           printf    ("  r_prec=%lu\n", r_prec);
171           mpf_trace ("  r+ulp", r);
172           mpf_trace ("  s", s);
173           abort ();
174         }
175     }
176 
177   mpf_clear (x);
178   mpf_clear (r);
179   mpf_clear (s);
180 }
181 
182 int
main(int argc,char ** argv)183 main (int argc, char **argv)
184 {
185   tests_start ();
186   mp_trace_base = -16;
187 
188   check_rand1 (argc, argv);
189   check_rand2 ();
190 
191   tests_end ();
192   exit (0);
193 }
194