xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpf/t-sub.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* Test mpf_sub.
2 
3 Copyright 1996, 2001, 2004, 2014 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.h"
24 #include "gmp-impl.h"
25 #include "tests.h"
26 
27 #ifndef SIZE
28 #define SIZE 16
29 #endif
30 
31 void
32 check_rand (int argc, char **argv)
33 {
34   mp_size_t size;
35   mp_exp_t exp;
36   int reps = 20000;
37   int i;
38   mpf_t u, v, w, wref;
39   mp_size_t bprec = 100;
40   mpf_t rerr, max_rerr, limit_rerr;
41 
42   if (argc > 1)
43     {
44       reps = strtol (argv[1], 0, 0);
45       if (argc > 2)
46 	bprec = strtol (argv[2], 0, 0);
47     }
48 
49   mpf_set_default_prec (bprec);
50 
51   mpf_init_set_ui (limit_rerr, 1);
52   mpf_div_2exp (limit_rerr, limit_rerr, bprec);
53 #if VERBOSE
54   mpf_dump (limit_rerr);
55 #endif
56   mpf_init (rerr);
57   mpf_init_set_ui (max_rerr, 0);
58 
59   mpf_init (u);
60   mpf_init (v);
61   mpf_init (w);
62   mpf_init (wref);
63   for (i = 0; i < reps; i++)
64     {
65       size = urandom () % (2 * SIZE) - SIZE;
66       exp = urandom () % SIZE;
67       mpf_random2 (u, size, exp);
68 
69       size = urandom () % (2 * SIZE) - SIZE;
70       exp = urandom () % SIZE;
71       mpf_random2 (v, size, exp);
72 
73       if ((urandom () & 1) != 0)
74 	mpf_add_ui (u, v, 1);
75       else if ((urandom () & 1) != 0)
76 	mpf_sub_ui (u, v, 1);
77 
78       mpf_sub (w, u, v);
79       refmpf_sub (wref, u, v);
80 
81       mpf_reldiff (rerr, w, wref);
82       if (mpf_cmp (rerr, max_rerr) > 0)
83 	{
84 	  mpf_set (max_rerr, rerr);
85 #if VERBOSE
86 	  mpf_dump (max_rerr);
87 #endif
88 	  if (mpf_cmp (rerr, limit_rerr) > 0)
89 	    {
90 	      printf ("ERROR after %d tests\n", i);
91 	      printf ("   u = "); mpf_dump (u);
92 	      printf ("   v = "); mpf_dump (v);
93 	      printf ("wref = "); mpf_dump (wref);
94 	      printf ("   w = "); mpf_dump (w);
95 	      abort ();
96 	    }
97 	}
98     }
99 
100   mpf_clear (limit_rerr);
101   mpf_clear (rerr);
102   mpf_clear (max_rerr);
103 
104   mpf_clear (u);
105   mpf_clear (v);
106   mpf_clear (w);
107   mpf_clear (wref);
108 }
109 
110 #define W GMP_NUMB_MAX
111 
112 void
113 check_data (void)
114 {
115   static const struct {
116     struct {
117       int        exp, size;
118       mp_limb_t  d[10];
119     } x, y, want;
120 
121   } data[] = {
122     { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
123     { { 1, 1, { 9 } },                  { 1, 1, { 8 } },   { 1, 1, { 1 } } },
124     { { 1, 1, { 9 } },                 { 1, -1, { 6 } },   { 1, 1, { 15 } } },
125     { { 1, 2, { 8, 9 } },               { 1, 1, { 8 } },   { 1, 2, { 8, 1 } } },
126     { { 2, 2, { 8, 1 } },               { 1, 1, { 9 } },   { 1, 1, { W } } },
127     { { 2, 2, { 9, 8 } },               { 1, 1, { 9 } },   { 2, 1, { 8 } } },
128     { { 2, 1, { 1 } },                  { 1, 1, { 1 } },   { 1, 1, { W } } },
129     { { 2, 1, { 9 } },                  { 1, 1, { W } },   { 2, 2, { 1, 8 } } },
130 
131     { { 1, 2, { W, 8 } },             { 1, 1, { 9 } },   { 0, -1, { 1 } } },
132     { { 1, 2, { W, 7 } },             { 1, 1, { 9 } },   { 1, -2, { 1, 1 } } },
133     { { 1, 2, { 1, 8 } },             { 1, 1, { 9 } },   { 0, -1, { W } } },
134     { { 1, 2, { 1, 7 } },             { 1, 1, { 9 } },   { 1, -2, { W, 1 } } },
135     { { 1, 2, { 0, 8 } },             { 1, 1, { 9 } },   { 1, -1, { 1 } } },
136     { { 2, 3, { 5, 8, 1 } },          { 1, 1, { 9 } },   { 1, 2, { 5, W } } },
137     { { 3, 1, { 1 } },                { 1, 1, { 1 } },   { 2, 2, { W, W } } },
138     { { 1, 6, { W, W, W, W, W, 8 } }, { 1, 1, { 9 } },   { -4, -1, { 1 } } },
139     { { 5, 5, { W-6, W, W, W, W } },  { 6, 1, { 1 } },   { 1, -1, { 7 } } },
140 
141     /* f - f == 0, various sizes.
142        These exercise a past problem (gmp 4.1.3 and earlier) where the
143        result exponent was not zeroed on a zero result like this.  */
144     { { 0, 0 }, { 0, 0 }, { 0, 0 } },
145     { { 99, 3, { 0, 0, 1 } },       { 99, 1, { 1 } },             { 0, 0 } },
146     { { 99, 3, { 0, 123, 456 } },   { 99, 2, { 123, 456 } },      { 0, 0 } },
147     { { 99, 3, { 123, 456, 789 } }, { 99, 3, { 123, 456, 789 } }, { 0, 0 } },
148 
149     /* High limbs cancel, leaving just the low limbs of the longer operand.
150        This exercises a past problem (gmp 4.1.3 and earlier) where high zero
151        limbs on the remainder were not stripped before truncating to the
152        destination, causing loss of precision.  */
153     { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
154     { { 123, 3, { 8, 0, 9 } },          { 123, 1, { 9 } }, { 121, 1, { 8 } } },
155     { { 123, 4, { 8, 0, 0, 9 } },       { 123, 1, { 9 } }, { 120, 1, { 8 } } },
156     { { 123, 5, { 8, 0, 0, 0, 9 } },    { 123, 1, { 9 } }, { 119, 1, { 8 } } },
157     { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 1, { 9 } }, { 118, 1, { 8 } } },
158     /* { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 6, { 9, 0, 0, 0, 0, 8 } }, { 122, 5, { W, W, W, W, W } } }, */
159 
160   };
161 
162   mpf_t  x, y, got, want;
163   int  i, swap, fail;
164 
165   fail = 0;
166   mp_trace_base = 16;
167   mpf_init (got);
168 
169   for (i = 0; i < numberof (data); i++)
170     {
171       for (swap = 0; swap <= 7; swap++)
172         {
173           PTR(x) = (mp_ptr) data[i].x.d;
174           SIZ(x) = data[i].x.size;
175           EXP(x) = data[i].x.exp;
176           PREC(x) = numberof (data[i].x.d);
177           MPF_CHECK_FORMAT (x);
178 
179           PTR(y) = (mp_ptr) data[i].y.d;
180           SIZ(y) = data[i].y.size;
181           EXP(y) = data[i].y.exp;
182           PREC(y) = numberof (data[i].y.d);
183           MPF_CHECK_FORMAT (y);
184 
185           PTR(want) = (mp_ptr) data[i].want.d;
186           SIZ(want) = data[i].want.size;
187           EXP(want) = data[i].want.exp;
188           PREC(want) = numberof (data[i].want.d);
189           MPF_CHECK_FORMAT (want);
190 
191           if (swap & 4)
192             {
193               mpf_swap (want, y);
194             }
195 
196 	  if ((SIZ (x) ^ SIZ (y)) < 0)
197 	    continue; /* It's an addition, not a subtraction (TO BE REMOVED) */
198 
199           if (swap & 1)
200             {
201               mpf_swap (x, y);
202               SIZ(want) = - SIZ(want);
203             }
204 
205           if (swap & 2)
206             {
207               SIZ(want) = - SIZ(want);
208               SIZ(x) = - SIZ(x);
209               SIZ(y) = - SIZ(y);
210             }
211 
212           mpf_sub (got, x, y);
213 /*           MPF_CHECK_FORMAT (got); */
214 
215           if (! refmpf_validate ("mpf_sub", got, want))
216             {
217               printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
218               mpf_trace ("x   ", x);
219               mpf_trace ("y   ", y);
220               mpf_trace ("got ", got);
221               mpf_trace ("want", want);
222 	      fail = 1;
223             }
224 
225 	  if (SIZ (x) == 1 || SIZ (x) == 0 )
226 	    {
227 	      if (SIZ (y)) EXP (y) -= EXP (x) - (mp_exp_t) SIZ (x);
228 	      if (SIZ (want)) EXP (want) -= EXP (x) - (mp_exp_t) SIZ (x);
229 	      EXP (x) = (mp_exp_t) SIZ (x);
230 
231 	      if (mpf_fits_uint_p (x))
232 		{
233 		  mpf_ui_sub (got, mpf_get_ui (x), y);
234 
235 		  if (! refmpf_validate ("mpf_ui_sub", got, want))
236 		    {
237 		      printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
238 		      mpf_trace ("x   ", x);
239 		      mpf_trace ("y   ", y);
240 		      mpf_trace ("got ", got);
241 		      mpf_trace ("want", want);
242 		      fail = 1;
243 		    }
244 		}
245 	    }
246 
247 	  if (SIZ (y) == 1 || SIZ (y) == 0)
248 	    {
249 	      if (SIZ (x)) EXP (x) -= EXP (y) - (mp_exp_t) SIZ (y);
250 	      if (SIZ (want)) EXP (want) -= EXP (y) - (mp_exp_t) SIZ (y);
251 	      EXP (y) = (mp_exp_t) SIZ (y);
252 
253 	      if (mpf_fits_uint_p (x))
254 		{
255 		  mpf_sub_ui (got, x, mpf_get_ui (y));
256 
257 		  if (! refmpf_validate ("mpf_sub_ui", got, want))
258 		    {
259 		      printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
260 		      mpf_trace ("x   ", x);
261 		      mpf_trace ("y   ", y);
262 		      mpf_trace ("got ", got);
263 		      mpf_trace ("want", want);
264 		      fail = 1;
265 		    }
266 		}
267 	    }
268 
269         }
270     }
271 
272   mpf_clear (got);
273   if (fail)
274     abort ();
275 }
276 
277 
278 int
279 main (int argc, char **argv)
280 {
281   tests_start ();
282 
283   check_data ();
284   check_rand (argc, argv);
285 
286   tests_end ();
287   exit (0);
288 }
289