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