xref: /netbsd-src/external/lgpl3/gmp/dist/tests/mpf/t-sub.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /* Test mpf_sub.
2 
3 Copyright 1996, 2001, 2004 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 #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 
111 void
112 check_data (void)
113 {
114   static const struct {
115     struct {
116       int        exp, size;
117       mp_limb_t  d[10];
118     } x, y, want;
119 
120   } data[] = {
121     { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
122 
123     /* f - f == 0, various sizes.
124        These exercise a past problem (gmp 4.1.3 and earlier) where the
125        result exponent was not zeroed on a zero result like this.  */
126     { { 0, 0 }, { 0, 0 }, { 0, 0 } },
127     { { 99, 1, { 1 } },             { 99, 1, { 1 } },             { 0, 0 } },
128     { { 99, 2, { 123, 456 } },      { 99, 2, { 123, 456 } },      { 0, 0 } },
129     { { 99, 3, { 123, 456, 789 } }, { 99, 3, { 123, 456, 789 } }, { 0, 0 } },
130 
131     /* High limbs cancel, leaving just the low limbs of the longer operand.
132        This exercises a past problem (gmp 4.1.3 and earlier) where high zero
133        limbs on the remainder were not stripped before truncating to the
134        destination, causing loss of precision.  */
135     { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
136     { { 123, 3, { 8, 0, 9 } },          { 123, 1, { 9 } }, { 121, 1, { 8 } } },
137     { { 123, 4, { 8, 0, 0, 9 } },       { 123, 1, { 9 } }, { 120, 1, { 8 } } },
138     { { 123, 5, { 8, 0, 0, 0, 9 } },    { 123, 1, { 9 } }, { 119, 1, { 8 } } },
139     { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 1, { 9 } }, { 118, 1, { 8 } } },
140 
141   };
142 
143   mpf_t  x, y, got, want;
144   int  i, swap;
145 
146   mp_trace_base = 16;
147   mpf_init (got);
148 
149   for (i = 0; i < numberof (data); i++)
150     {
151       for (swap = 0; swap <= 1; swap++)
152         {
153           PTR(x) = (mp_ptr) data[i].x.d;
154           SIZ(x) = data[i].x.size;
155           EXP(x) = data[i].x.exp;
156           PREC(x) = numberof (data[i].x.d);
157           MPF_CHECK_FORMAT (x);
158 
159           PTR(y) = (mp_ptr) data[i].y.d;
160           SIZ(y) = data[i].y.size;
161           EXP(y) = data[i].y.exp;
162           PREC(y) = numberof (data[i].y.d);
163           MPF_CHECK_FORMAT (y);
164 
165           PTR(want) = (mp_ptr) data[i].want.d;
166           SIZ(want) = data[i].want.size;
167           EXP(want) = data[i].want.exp;
168           PREC(want) = numberof (data[i].want.d);
169           MPF_CHECK_FORMAT (want);
170 
171           if (swap)
172             {
173               mpf_swap (x, y);
174               SIZ(want) = - SIZ(want);
175             }
176 
177           mpf_sub (got, x, y);
178 /*           MPF_CHECK_FORMAT (got); */
179 
180           if (mpf_cmp (got, want) != 0)
181             {
182               printf ("check_data() wrong reault at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
183               mpf_trace ("x   ", x);
184               mpf_trace ("y   ", y);
185               mpf_trace ("got ", got);
186               mpf_trace ("want", want);
187               abort ();
188             }
189         }
190     }
191 
192   mpf_clear (got);
193 }
194 
195 
196 int
197 main (int argc, char **argv)
198 {
199   tests_start ();
200 
201   check_data ();
202   check_rand (argc, argv);
203 
204   tests_end ();
205   exit (0);
206 }
207