xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpq/t-get_d.c (revision eceb233b9bd0dfebb902ed73b531ae6964fa3f9b)
1 /* Test mpq_get_d and mpq_set_d
2 
3 Copyright 1991, 1993, 1994, 1996, 2000-2003, 2012, 2013 Free Software
4 Foundation, Inc.
5 
6 This file is part of the GNU MP Library test suite.
7 
8 The GNU MP Library test suite is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 3 of the License,
11 or (at your option) any later version.
12 
13 The GNU MP Library test suite is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
16 Public License for more details.
17 
18 You should have received a copy of the GNU General Public License along with
19 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "gmp.h"
25 #include "gmp-impl.h"
26 #include "tests.h"
27 
28 #ifndef SIZE
29 #define SIZE 8
30 #endif
31 
32 /* VAX D floats only have an 8 bit signed exponent, so anything 2^128 or
33    bigger will overflow, that being 4 limbs. */
34 #if defined (__vax) || defined (__vax__) && SIZE > 4
35 #undef SIZE
36 #define SIZE 4
37 #define EPSIZE 3
38 #else
39 #define EPSIZE SIZE
40 #endif
41 
42 void dump (mpq_t);
43 
44 void
45 check_monotonic (int argc, char **argv)
46 {
47   mpq_t a;
48   mp_size_t size;
49   int reps = 100;
50   int i, j;
51   double last_d, new_d;
52   mpq_t qlast_d, qnew_d;
53   mpq_t eps;
54 
55   if (argc == 2)
56      reps = atoi (argv[1]);
57 
58   /* The idea here is to test the monotonousness of mpq_get_d by adding
59      numbers to the numerator and denominator.  */
60 
61   mpq_init (a);
62   mpq_init (eps);
63   mpq_init (qlast_d);
64   mpq_init (qnew_d);
65 
66   for (i = 0; i < reps; i++)
67     {
68       size = urandom () % SIZE - SIZE/2;
69       mpz_random2 (mpq_numref (a), size);
70       do
71 	{
72 	  size = urandom () % SIZE - SIZE/2;
73 	  mpz_random2 (mpq_denref (a), size);
74 	}
75       while (mpz_cmp_ui (mpq_denref (a), 0) == 0);
76 
77       mpq_canonicalize (a);
78 
79       last_d = mpq_get_d (a);
80       mpq_set_d (qlast_d, last_d);
81       for (j = 0; j < 10; j++)
82 	{
83 	  size = urandom () % EPSIZE + 1;
84 	  mpz_random2 (mpq_numref (eps), size);
85 	  size = urandom () % EPSIZE + 1;
86 	  mpz_random2 (mpq_denref (eps), size);
87 	  mpq_canonicalize (eps);
88 
89 	  mpq_add (a, a, eps);
90 	  mpq_canonicalize (a);
91 	  new_d = mpq_get_d (a);
92 	  if (last_d > new_d)
93 	    {
94 	      printf ("\nERROR (test %d/%d): bad mpq_get_d results\n", i, j);
95 	      printf ("last: %.16g\n", last_d);
96 	      printf (" new: %.16g\n", new_d); dump (a);
97 	      abort ();
98 	    }
99 	  mpq_set_d (qnew_d, new_d);
100 	  MPQ_CHECK_FORMAT (qnew_d);
101 	  if (mpq_cmp (qlast_d, qnew_d) > 0)
102 	    {
103 	      printf ("ERROR (test %d/%d): bad mpq_set_d results\n", i, j);
104 	      printf ("last: %.16g\n", last_d); dump (qlast_d);
105 	      printf (" new: %.16g\n", new_d); dump (qnew_d);
106 	      abort ();
107 	    }
108 	  last_d = new_d;
109 	  mpq_set (qlast_d, qnew_d);
110 	}
111     }
112 
113   mpq_clear (a);
114   mpq_clear (eps);
115   mpq_clear (qlast_d);
116   mpq_clear (qnew_d);
117 }
118 
119 double
120 my_ldexp (double d, int e)
121 {
122   for (;;)
123     {
124       if (e > 0)
125 	{
126 	  if (e >= 16)
127 	    {
128 	      d *= 65536.0;
129 	      e -= 16;
130 	    }
131 	  else
132 	    {
133 	      d *= 2.0;
134 	      e -= 1;
135 	    }
136 	}
137       else if (e < 0)
138 	{
139 
140 	  if (e <= -16)
141 	    {
142 	      d /= 65536.0;
143 	      e += 16;
144 	    }
145 	  else
146 	    {
147 	      d /= 2.0;
148 	      e += 1;
149 	    }
150 	}
151       else
152 	return d;
153     }
154 }
155 
156 #define MAXEXP 500
157 
158 #if defined (__vax) || defined (__vax__)
159 #undef MAXEXP
160 #define MAXEXP 30
161 #endif
162 
163 void
164 check_random (int argc, char **argv)
165 {
166   gmp_randstate_ptr rands = RANDS;
167 
168   double d;
169   mpq_t q;
170   mpz_t a, t;
171   int exp;
172 
173   int test, reps = 100000;
174 
175   if (argc == 2)
176      reps = 100 * atoi (argv[1]);
177 
178   mpq_init (q);
179   mpz_init (a);
180   mpz_init (t);
181 
182   for (test = 0; test < reps; test++)
183     {
184       mpz_rrandomb (a, rands, 53);
185       mpz_urandomb (t, rands, 32);
186       exp = mpz_get_ui (t) % (2*MAXEXP) - MAXEXP;
187 
188       d = my_ldexp (mpz_get_d (a), exp);
189       mpq_set_d (q, d);
190       /* Check that n/d = a * 2^exp, or
191 	 d*a 2^{exp} = n */
192       mpz_mul (t, a, mpq_denref (q));
193       if (exp > 0)
194 	mpz_mul_2exp (t, t, exp);
195       else
196 	{
197 	  if (!mpz_divisible_2exp_p (t, -exp))
198 	    goto fail;
199 	  mpz_div_2exp (t, t, -exp);
200 	}
201       if (mpz_cmp (t, mpq_numref (q)) != 0)
202 	{
203 	fail:
204 	  printf ("ERROR (check_random test %d): bad mpq_set_d results\n", test);
205 	  printf ("%.16g\n", d);
206 	  gmp_printf ("%Qd\n", q);
207 	  abort ();
208 	}
209     }
210   mpq_clear (q);
211   mpz_clear (t);
212   mpz_clear (a);
213 }
214 
215 void
216 dump (mpq_t x)
217 {
218   mpz_out_str (stdout, 10, mpq_numref (x));
219   printf ("/");
220   mpz_out_str (stdout, 10, mpq_denref (x));
221   printf ("\n");
222 }
223 
224 /* Check various values 2^n and 1/2^n. */
225 void
226 check_onebit (void)
227 {
228   static const long data[] = {
229     -3*GMP_NUMB_BITS-1, -3*GMP_NUMB_BITS, -3*GMP_NUMB_BITS+1,
230     -2*GMP_NUMB_BITS-1, -2*GMP_NUMB_BITS, -2*GMP_NUMB_BITS+1,
231     -GMP_NUMB_BITS-1, -GMP_NUMB_BITS, -GMP_NUMB_BITS+1,
232     -5, -2, -1, 0, 1, 2, 5,
233     GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
234     2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
235     3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
236   };
237 
238   int     i, neg;
239   long    exp, l;
240   mpq_t   q;
241   double  got, want;
242 
243   mpq_init (q);
244 
245   for (i = 0; i < numberof (data); i++)
246     {
247       exp = data[i];
248 
249       mpq_set_ui (q, 1L, 1L);
250       if (exp >= 0)
251 	mpq_mul_2exp (q, q, exp);
252       else
253 	mpq_div_2exp (q, q, -exp);
254 
255       want = 1.0;
256       for (l = 0; l < exp; l++)
257 	want *= 2.0;
258       for (l = 0; l > exp; l--)
259 	want /= 2.0;
260 
261       for (neg = 0; neg <= 1; neg++)
262 	{
263 	  if (neg)
264 	    {
265 	      mpq_neg (q, q);
266 	      want = -want;
267 	    }
268 
269 	  got = mpq_get_d (q);
270 
271 	  if (got != want)
272 	    {
273 	      printf    ("mpq_get_d wrong on %s2**%ld\n", neg ? "-" : "", exp);
274 	      mpq_trace ("   q    ", q);
275 	      d_trace   ("   want ", want);
276 	      d_trace   ("   got  ", got);
277 	      abort();
278 	    }
279 	}
280     }
281   mpq_clear (q);
282 }
283 
284 int
285 main (int argc, char **argv)
286 {
287   tests_start ();
288 
289   check_onebit ();
290   check_monotonic (argc, argv);
291   check_random (argc, argv);
292 
293   tests_end ();
294   exit (0);
295 }
296