1/* Test mpf_eq.
2
3Copyright 2009, 2012 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
23#include "gmp-impl.h"
24#include "tests.h"
25
26#define SZ (2 * sizeof(mp_limb_t))
27
28void insert_random_low_zero_limbs (mpf_t, gmp_randstate_ptr);
29void dump_abort (mpf_t, mpf_t, int, int, int, int, int, long);
30void hexdump (mpf_t);
31
32void
33check_data (void)
34{
35  static const struct
36  {
37    struct {
38      int        exp, size;
39      mp_limb_t  d[10];
40    } x, y;
41    mp_bitcnt_t bits;
42    int want;
43
44  } data[] = {
45    { { 0, 0, { 0 } },             { 0, 0, { 0 } },    0, 1 },
46
47    { { 0, 1, { 7 } },             { 0, 1, { 7 } },    0, 1 },
48    { { 0, 1, { 7 } },             { 0, 1, { 7 } },   17, 1 },
49    { { 0, 1, { 7 } },             { 0, 1, { 7 } }, 4711, 1 },
50
51    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    0, 1 },
52    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    2, 1 },
53    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    3, 0 },
54
55    { { 0, 0, { 0 } },             { 0, 1, { 1 } },    0, 0 },
56    { { 0, 1, { 1 } },             { 0,-1 ,{ 1 } },    0, 0 },
57    { { 1, 1, { 1 } },             { 0, 1, { 1 } },    0, 0 },
58
59    { { 0, 1, { 8 } },             { 0, 1, { 4 } },    0, 0 },
60
61    { { 0, 2, { 0, 3 } },          { 0, 1, { 3 } }, 1000, 1 },
62  };
63
64  mpf_t  x, y;
65  int got, got_swapped;
66  int i;
67  mp_trace_base = 16;
68
69  for (i = 0; i < numberof (data); i++)
70    {
71      PTR(x) = (mp_ptr) data[i].x.d;
72      SIZ(x) = data[i].x.size;
73      EXP(x) = data[i].x.exp;
74      PREC(x) = numberof (data[i].x.d);
75      MPF_CHECK_FORMAT (x);
76
77      PTR(y) = (mp_ptr) data[i].y.d;
78      SIZ(y) = data[i].y.size;
79      EXP(y) = data[i].y.exp;
80      PREC(y) = numberof (data[i].y.d);
81      MPF_CHECK_FORMAT (y);
82
83      got         = mpf_eq (x, y, data[i].bits);
84      got_swapped = mpf_eq (y, x, data[i].bits);
85
86      if (got != got_swapped || got != data[i].want)
87	{
88	  printf ("check_data() wrong result at data[%d]\n", i);
89	  mpf_trace ("x   ", x);
90	  mpf_trace ("y   ", y);
91	  printf ("got         %d\n", got);
92	  printf ("got_swapped %d\n", got_swapped);
93	  printf ("want        %d\n", data[i].want);
94	  abort ();
95        }
96    }
97}
98
99void
100check_random (long reps)
101{
102  unsigned long test;
103  gmp_randstate_ptr rands = RANDS;
104  mpf_t a, b, x;
105  mpz_t ds;
106  int hibits, lshift1, lshift2;
107  int xtra;
108
109#define HIBITS 10
110#define LSHIFT1 10
111#define LSHIFT2 10
112
113  mpf_set_default_prec ((1 << HIBITS) + (1 << LSHIFT1) + (1 << LSHIFT2));
114
115  mpz_init (ds);
116  mpf_inits (a, b, x, NULL);
117
118  for (test = 0; test < reps; test++)
119    {
120      mpz_urandomb (ds, rands, HIBITS);
121      hibits = mpz_get_ui (ds) + 1;
122      mpz_urandomb (ds, rands, hibits);
123      mpz_setbit (ds, hibits  - 1);	/* make sure msb is set */
124      mpf_set_z (a, ds);
125      mpf_set_z (b, ds);
126
127      mpz_urandomb (ds, rands, LSHIFT1);
128      lshift1 = mpz_get_ui (ds);
129      mpf_mul_2exp (a, a, lshift1 + 1);
130      mpf_mul_2exp (b, b, lshift1 + 1);
131      mpf_add_ui (a, a, 1);	/* make a one-bit difference */
132
133      mpz_urandomb (ds, rands, LSHIFT2);
134      lshift2 = mpz_get_ui (ds);
135      mpf_mul_2exp (a, a, lshift2);
136      mpf_mul_2exp (b, b, lshift2);
137      mpz_urandomb (ds, rands, lshift2);
138      mpf_set_z (x, ds);
139      mpf_add (a, a, x);
140      mpf_add (b, b, x);
141
142      insert_random_low_zero_limbs (a, rands);
143      insert_random_low_zero_limbs (b, rands);
144
145      if (mpf_eq (a, b, lshift1 + hibits) == 0 ||
146	  mpf_eq (b, a, lshift1 + hibits) == 0)
147	{
148	  dump_abort (a, b, lshift1 + hibits, lshift1, lshift2, hibits, 1, test);
149	}
150      for (xtra = 1; xtra < 100; xtra++)
151	if (mpf_eq (a, b, lshift1 + hibits + xtra) != 0 ||
152	    mpf_eq (b, a, lshift1 + hibits + xtra) != 0)
153	  {
154	    dump_abort (a, b, lshift1 + hibits + xtra, lshift1, lshift2, hibits, 0, test);
155	  }
156    }
157
158  mpf_clears (a, b, x, NULL);
159  mpz_clear (ds);
160}
161
162void
163insert_random_low_zero_limbs (mpf_t x, gmp_randstate_ptr rands)
164{
165  mp_size_t max = PREC(x) - SIZ(x);
166  mp_size_t s;
167  mpz_t ds; mpz_init (ds);
168  mpz_urandomb (ds, rands, 32);
169  s = mpz_get_ui (ds) % (max + 1);
170  MPN_COPY_DECR (PTR(x) + s, PTR(x), SIZ(x));
171  MPN_ZERO (PTR(x), s);
172  SIZ(x) += s;
173  mpz_clear (ds);
174}
175
176void
177dump_abort (mpf_t a, mpf_t b, int cmp_prec, int lshift1, int lshift2, int hibits, int want, long test)
178{
179  printf ("ERROR in test %ld\n", test);
180  printf ("want %d got %d from mpf_eq\n", want, 1-want);
181  printf ("cmp_prec = %d\n", cmp_prec);
182  printf ("lshift1 = %d\n", lshift1);
183  printf ("lshift2 = %d\n", lshift2);
184  printf ("hibits = %d\n", hibits);
185  hexdump (a); puts ("");
186  hexdump (b); puts ("");
187  abort ();
188}
189
190void
191hexdump (mpf_t x)
192{
193  mp_size_t i;
194  for (i = ABSIZ(x) - 1; i >= 0; i--)
195    {
196      gmp_printf ("%0*MX", SZ, PTR(x)[i]);
197      if (i != 0)
198	printf (" ");
199    }
200}
201
202int
203main (int argc, char *argv[])
204{
205  long reps = 10000;
206
207  if (argc == 2)
208    reps = strtol (argv[1], 0, 0);
209
210  tests_start ();
211
212  check_data ();
213  check_random (reps);
214
215  tests_end ();
216  exit (0);
217}
218