1/* Test that routines allow reusing a source variable as destination.
2
3Copyright 1996, 2000-2002, 2012, 2015 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "gmp-impl.h"
25#include "tests.h"
26
27#if __GMP_LIBGMP_DLL
28
29/* FIXME: When linking to a DLL libgmp, mpq_add etc can't be used as
30   initializers for global variables because they're effectively global
31   variables (function pointers) themselves.  Perhaps calling a test
32   function successively with mpq_add etc would be better.  */
33
34int
35main (void)
36{
37  printf ("Test suppressed for windows DLL\n");
38  exit (0);
39}
40
41
42#else /* ! DLL_EXPORT */
43
44#ifndef SIZE
45#define SIZE 16
46#endif
47
48void dump_abort (const char *, mpq_t, mpq_t);
49
50typedef void (*dss_func) (mpq_ptr, mpq_srcptr, mpq_srcptr);
51
52dss_func dss_funcs[] =
53{
54  mpq_div, mpq_add, mpq_mul, mpq_sub,
55};
56
57const char *dss_func_names[] =
58{
59  "mpq_div", "mpq_add", "mpq_mul", "mpq_sub",
60};
61
62typedef void (*ds_func) (mpq_ptr, mpq_srcptr);
63
64ds_func ds_funcs[] =
65{
66  mpq_abs, mpq_neg,
67};
68
69const char *ds_func_names[] =
70{
71  "mpq_abs", "mpq_neg",
72};
73
74typedef void (*dsi_func) (mpq_ptr, mpq_srcptr, unsigned long int);
75
76dsi_func dsi_funcs[] =
77{
78  mpq_mul_2exp, mpq_div_2exp
79};
80
81const char *dsi_func_names[] =
82{
83  "mpq_mul_2exp", "mpq_div_2exp"
84};
85
86int
87main (int argc, char **argv)
88{
89  int i;
90  int pass, reps = 100;
91  mpq_t in1, in2, out1;
92  unsigned long int randbits, in2i;
93  mpq_t res1, res2;
94  gmp_randstate_ptr  rands;
95
96  tests_start ();
97
98  TESTS_REPS (reps, argv, argc);
99
100  rands = RANDS;
101
102  mpq_init (in1);
103  mpq_init (in2);
104  mpq_init (out1);
105  mpq_init (res1);
106  mpq_init (res2);
107
108  for (pass = 1; pass <= reps; pass++)
109    {
110      randbits = urandom ();
111
112      if (randbits & 1)
113	{
114	  mpq_clear (in1);
115	  mpq_init (in1);
116	}
117      randbits >>= 1;
118      mpz_errandomb (mpq_numref(in1), rands, 512L);
119      mpz_errandomb_nonzero (mpq_denref(in1), rands, 512L);
120      if (randbits & 1)
121	mpz_neg (mpq_numref(in1),mpq_numref(in1));
122      randbits >>= 1;
123      mpq_canonicalize (in1);
124
125      if (randbits & 1)
126	{
127	  mpq_clear (in2);
128	  mpq_init (in2);
129	}
130      randbits >>= 1;
131      mpz_errandomb (mpq_numref(in2), rands, 512L);
132      mpz_errandomb_nonzero (mpq_denref(in2), rands, 512L);
133      if (randbits & 1)
134	mpz_neg (mpq_numref(in2),mpq_numref(in2));
135      randbits >>= 1;
136      mpq_canonicalize (in2);
137
138      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
139	{
140	  /* Don't divide by 0.  */
141	  if (i == 0 && mpq_cmp_ui (in2, 0, 1) == 0)
142	    continue;
143
144	  if (randbits & 1)
145	    {
146	      mpq_clear (res1);
147	      mpq_init (res1);
148	    }
149	  randbits >>= 1;
150
151	  (dss_funcs[i]) (res1, in1, in2);
152	  MPQ_CHECK_FORMAT(res1);
153
154	  mpq_set (out1, in1);
155	  (dss_funcs[i]) (out1, out1, in2);
156	  MPQ_CHECK_FORMAT(out1);
157
158	  if (mpq_cmp (res1, out1) != 0)
159	    dump_abort (dss_func_names[i], res1, out1);
160
161	  mpq_set (out1, in2);
162	  (dss_funcs[i]) (out1, in1, out1);
163	  MPQ_CHECK_FORMAT(out1);
164
165	  if (mpq_cmp (res1, out1) != 0)
166	    dump_abort (dss_func_names[i], res1, out1);
167
168	  mpq_set (out1, in2);
169	  (dss_funcs[i]) (res1, out1, in2);
170	  MPQ_CHECK_FORMAT(res1);
171
172	  (dss_funcs[i]) (res2, in2, in2);
173	  MPQ_CHECK_FORMAT(res2);
174
175	  (dss_funcs[i]) (out1, out1, out1);
176	  MPQ_CHECK_FORMAT(out1);
177
178	  if (mpq_cmp (res1, res2) != 0)
179	    dump_abort (dss_func_names[i], res1, res2);
180	  if (mpq_cmp (res1, out1) != 0)
181	    dump_abort (dss_func_names[i], res1, out1);
182	}
183
184      for (i = 0; i < sizeof (ds_funcs) / sizeof (ds_func); i++)
185	{
186	  if (randbits & 1)
187	    {
188	      mpq_clear (res1);
189	      mpq_init (res1);
190	    }
191	  randbits >>= 1;
192	  (ds_funcs[i]) (res1, in1);
193	  MPQ_CHECK_FORMAT(res1);
194
195	  mpq_set (out1, in1);
196	  (ds_funcs[i]) (out1, out1);
197	  MPQ_CHECK_FORMAT(out1);
198
199	  if (mpq_cmp (res1, out1) != 0)
200	    dump_abort (ds_func_names[i], res1, out1);
201	}
202
203      in2i = urandom () % 65536;
204      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
205	{
206	  if (randbits & 1)
207	    {
208	      mpq_clear (res1);
209	      mpq_init (res1);
210	    }
211	  randbits >>= 1;
212
213	  (dsi_funcs[i]) (res1, in1, in2i);
214	  MPQ_CHECK_FORMAT(res1);
215
216	  mpq_set (out1, in1);
217	  (dsi_funcs[i]) (out1, out1, in2i);
218	  MPQ_CHECK_FORMAT(out1);
219
220	  if (mpq_cmp (res1, out1) != 0)
221	    dump_abort (dsi_func_names[i], res1, out1);
222	}
223
224    }
225
226  mpq_clear (in1);
227  mpq_clear (in2);
228  mpq_clear (out1);
229  mpq_clear (res1);
230  mpq_clear (res2);
231
232  tests_end ();
233  exit (0);
234}
235
236void
237dump_abort (const char *name, mpq_t res1, mpq_t res2)
238{
239  printf ("failure in %s:\n", name);
240  mpq_trace ("  res1  ", res1);
241  mpq_trace ("  res2  ", res2);
242  abort ();
243}
244
245#endif /* ! DLL_EXPORT */
246