xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpz/t-div_2exp.c (revision fdd524d4ccd2bb0c6f67401e938dabf773eb0372)
1 /* Test mpz_[cft]div_[qr]_2exp.
2 
3 Copyright 2001 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 http://www.gnu.org/licenses/.  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 
23 #include "gmp.h"
24 #include "gmp-impl.h"
25 #include "tests.h"
26 
27 
28 /* If the remainder is in the correct range and q*d+r is correct, then q
29    must have rounded correctly.  */
30 
31 void
32 check_one (mpz_srcptr a, unsigned long d)
33 {
34   mpz_t  q, r, p, d2exp;
35   int    inplace;
36 
37   mpz_init (d2exp);
38   mpz_init (q);
39   mpz_init (r);
40   mpz_init (p);
41 
42   mpz_set_ui (d2exp, 1L);
43   mpz_mul_2exp (d2exp, d2exp, d);
44 
45 #define INPLACE(fun,dst,src,d)  \
46   if (inplace)                  \
47     {                           \
48       mpz_set (dst, src);       \
49       fun (dst, dst, d);        \
50     }                           \
51   else                          \
52     fun (dst, src, d);
53 
54   for (inplace = 0; inplace <= 1; inplace++)
55     {
56       INPLACE (mpz_fdiv_q_2exp, q, a, d);
57       INPLACE (mpz_fdiv_r_2exp, r, a, d);
58 
59       mpz_mul_2exp (p, q, d);
60       mpz_add (p, p, r);
61       if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0)
62 	{
63 	  printf ("mpz_fdiv_r_2exp result out of range\n");
64 	  goto error;
65 	}
66       if (mpz_cmp (p, a) != 0)
67 	{
68 	  printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n");
69 	  goto error;
70 	}
71 
72 
73       INPLACE (mpz_cdiv_q_2exp, q, a, d);
74       INPLACE (mpz_cdiv_r_2exp, r, a, d);
75 
76       mpz_mul_2exp (p, q, d);
77       mpz_add (p, p, r);
78       if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0)
79 	{
80 	  printf ("mpz_cdiv_r_2exp result out of range\n");
81 	  goto error;
82 	}
83       if (mpz_cmp (p, a) != 0)
84 	{
85 	  printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n");
86 	  goto error;
87 	}
88 
89 
90       INPLACE (mpz_tdiv_q_2exp, q, a, d);
91       INPLACE (mpz_tdiv_r_2exp, r, a, d);
92 
93       mpz_mul_2exp (p, q, d);
94       mpz_add (p, p, r);
95       if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a))
96 	{
97 	  printf ("mpz_tdiv_r_2exp result wrong sign\n");
98 	  goto error;
99 	}
100       if (mpz_cmpabs (r, d2exp) >= 0)
101 	{
102 	  printf ("mpz_tdiv_r_2exp result out of range\n");
103 	  goto error;
104 	}
105       if (mpz_cmp (p, a) != 0)
106 	{
107 	  printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n");
108 	  goto error;
109 	}
110     }
111 
112   mpz_clear (d2exp);
113   mpz_clear (q);
114   mpz_clear (r);
115   mpz_clear (p);
116   return;
117 
118 
119  error:
120   mpz_trace ("a", a);
121   printf    ("d=%lu\n", d);
122   mpz_trace ("q", q);
123   mpz_trace ("r", r);
124   mpz_trace ("p", p);
125 
126   mp_trace_base = -16;
127   mpz_trace ("a", a);
128   printf    ("d=0x%lX\n", d);
129   mpz_trace ("q", q);
130   mpz_trace ("r", r);
131   mpz_trace ("p", p);
132 
133   abort ();
134 }
135 
136 
137 void
138 check_all (mpz_ptr a, unsigned long d)
139 {
140   check_one (a, d);
141   mpz_neg (a, a);
142   check_one (a, d);
143 }
144 
145 
146 void
147 check_various (void)
148 {
149   static const unsigned long  table[] = {
150     0, 1, 2, 3, 4, 5,
151     GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
152     2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
153     3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
154     4*GMP_NUMB_BITS-1, 4*GMP_NUMB_BITS, 4*GMP_NUMB_BITS+1
155   };
156 
157   int            i, j;
158   unsigned long  n, d;
159   mpz_t          a;
160 
161   mpz_init (a);
162 
163   /* a==0, and various d */
164   mpz_set_ui (a, 0L);
165   for (i = 0; i < numberof (table); i++)
166     check_one (a, table[i]);
167 
168   /* a==2^n, and various d */
169   for (i = 0; i < numberof (table); i++)
170     {
171       n = table[i];
172       mpz_set_ui (a, 1L);
173       mpz_mul_2exp (a, a, n);
174 
175       for (j = 0; j < numberof (table); j++)
176 	{
177 	  d = table[j];
178 	  check_all (a, d);
179 	}
180     }
181 
182   mpz_clear (a);
183 }
184 
185 
186 void
187 check_random (int argc, char *argv[])
188 {
189   gmp_randstate_ptr  rands = RANDS;
190   int            reps = 100;
191   mpz_t          a;
192   unsigned long  d;
193   int            i;
194 
195   if (argc == 2)
196     reps = atoi (argv[1]);
197 
198   mpz_init (a);
199 
200   for (i = 0; i < reps; i++)
201     {
202       /* exponentially within 2 to 257 bits */
203       mpz_erandomb (a, rands, urandom () % 8 + 2);
204 
205       d = urandom () % 256;
206 
207       check_all (a, d);
208     }
209 
210   mpz_clear (a);
211 }
212 
213 
214 int
215 main (int argc, char *argv[])
216 {
217   tests_start ();
218 
219   check_various ();
220   check_random (argc, argv);
221 
222   tests_end ();
223   exit (0);
224 }
225