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