refmpf.c revision 1.1.1.1 1 1.1 mrg /* Reference floating point routines.
2 1.1 mrg
3 1.1 mrg Copyright 1996, 2001, 2004, 2005 Free Software Foundation, Inc.
4 1.1 mrg
5 1.1 mrg This file is part of the GNU MP Library.
6 1.1 mrg
7 1.1 mrg The GNU MP Library is free software; you can redistribute it and/or modify
8 1.1 mrg it under the terms of the GNU Lesser General Public License as published by
9 1.1 mrg the Free Software Foundation; either version 3 of the License, or (at your
10 1.1 mrg option) any later version.
11 1.1 mrg
12 1.1 mrg The GNU MP Library is distributed in the hope that it will be useful, but
13 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 1.1 mrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 1.1 mrg License for more details.
16 1.1 mrg
17 1.1 mrg You should have received a copy of the GNU Lesser General Public License
18 1.1 mrg along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
19 1.1 mrg
20 1.1 mrg #include <stdio.h>
21 1.1 mrg #include <stdlib.h>
22 1.1 mrg
23 1.1 mrg #include "gmp.h"
24 1.1 mrg #include "gmp-impl.h"
25 1.1 mrg #include "tests.h"
26 1.1 mrg
27 1.1 mrg
28 1.1 mrg void
29 1.1 mrg refmpf_add (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
30 1.1 mrg {
31 1.1 mrg mp_size_t hi, lo, size;
32 1.1 mrg mp_ptr ut, vt, wt;
33 1.1 mrg int neg;
34 1.1 mrg mp_exp_t exp;
35 1.1 mrg mp_limb_t cy;
36 1.1 mrg TMP_DECL;
37 1.1 mrg
38 1.1 mrg TMP_MARK;
39 1.1 mrg
40 1.1 mrg if (SIZ (u) == 0)
41 1.1 mrg {
42 1.1 mrg size = ABSIZ (v);
43 1.1 mrg wt = TMP_ALLOC_LIMBS (size + 1);
44 1.1 mrg MPN_COPY (wt, PTR (v), size);
45 1.1 mrg exp = EXP (v);
46 1.1 mrg neg = SIZ (v) < 0;
47 1.1 mrg goto done;
48 1.1 mrg }
49 1.1 mrg if (SIZ (v) == 0)
50 1.1 mrg {
51 1.1 mrg size = ABSIZ (u);
52 1.1 mrg wt = TMP_ALLOC_LIMBS (size + 1);
53 1.1 mrg MPN_COPY (wt, PTR (u), size);
54 1.1 mrg exp = EXP (u);
55 1.1 mrg neg = SIZ (u) < 0;
56 1.1 mrg goto done;
57 1.1 mrg }
58 1.1 mrg if ((SIZ (u) ^ SIZ (v)) < 0)
59 1.1 mrg {
60 1.1 mrg mpf_t tmp;
61 1.1 mrg SIZ (tmp) = -SIZ (v);
62 1.1 mrg EXP (tmp) = EXP (v);
63 1.1 mrg PTR (tmp) = PTR (v);
64 1.1 mrg refmpf_sub (w, u, tmp);
65 1.1 mrg return;
66 1.1 mrg }
67 1.1 mrg neg = SIZ (u) < 0;
68 1.1 mrg
69 1.1 mrg /* Compute the significance of the hi and lo end of the result. */
70 1.1 mrg hi = MAX (EXP (u), EXP (v));
71 1.1 mrg lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
72 1.1 mrg size = hi - lo;
73 1.1 mrg ut = TMP_ALLOC_LIMBS (size + 1);
74 1.1 mrg vt = TMP_ALLOC_LIMBS (size + 1);
75 1.1 mrg wt = TMP_ALLOC_LIMBS (size + 1);
76 1.1 mrg MPN_ZERO (ut, size);
77 1.1 mrg MPN_ZERO (vt, size);
78 1.1 mrg {int off;
79 1.1 mrg off = size + (EXP (u) - hi) - ABSIZ (u);
80 1.1 mrg MPN_COPY (ut + off, PTR (u), ABSIZ (u));
81 1.1 mrg off = size + (EXP (v) - hi) - ABSIZ (v);
82 1.1 mrg MPN_COPY (vt + off, PTR (v), ABSIZ (v));
83 1.1 mrg }
84 1.1 mrg
85 1.1 mrg cy = mpn_add_n (wt, ut, vt, size);
86 1.1 mrg wt[size] = cy;
87 1.1 mrg size += cy;
88 1.1 mrg exp = hi + cy;
89 1.1 mrg
90 1.1 mrg done:
91 1.1 mrg if (size > PREC (w))
92 1.1 mrg {
93 1.1 mrg wt += size - PREC (w);
94 1.1 mrg size = PREC (w);
95 1.1 mrg }
96 1.1 mrg MPN_COPY (PTR (w), wt, size);
97 1.1 mrg SIZ (w) = neg == 0 ? size : -size;
98 1.1 mrg EXP (w) = exp;
99 1.1 mrg TMP_FREE;
100 1.1 mrg }
101 1.1 mrg
102 1.1 mrg
103 1.1 mrg /* Add 1 "unit in last place" (ie. in the least significant limb) to f.
104 1.1 mrg f cannot be zero, since that has no well-defined "last place".
105 1.1 mrg
106 1.1 mrg This routine is designed for use in cases where we pay close attention to
107 1.1 mrg the size of the data value and are using that (and the exponent) to
108 1.1 mrg indicate the accurate part of a result, or similar. For this reason, if
109 1.1 mrg there's a carry out we don't store 1 and adjust the exponent, we just
110 1.1 mrg leave 100..00. We don't even adjust if there's a carry out of prec+1
111 1.1 mrg limbs, but instead give up in that case (which we intend shouldn't arise
112 1.1 mrg in normal circumstances). */
113 1.1 mrg
114 1.1 mrg void
115 1.1 mrg refmpf_add_ulp (mpf_ptr f)
116 1.1 mrg {
117 1.1 mrg mp_ptr fp = PTR(f);
118 1.1 mrg mp_size_t fsize = SIZ(f);
119 1.1 mrg mp_size_t abs_fsize = ABSIZ(f);
120 1.1 mrg mp_limb_t c;
121 1.1 mrg
122 1.1 mrg if (fsize == 0)
123 1.1 mrg {
124 1.1 mrg printf ("Oops, refmpf_add_ulp called with f==0\n");
125 1.1 mrg abort ();
126 1.1 mrg }
127 1.1 mrg
128 1.1 mrg c = refmpn_add_1 (fp, fp, abs_fsize, CNST_LIMB(1));
129 1.1 mrg if (c != 0)
130 1.1 mrg {
131 1.1 mrg if (abs_fsize >= PREC(f) + 1)
132 1.1 mrg {
133 1.1 mrg printf ("Oops, refmpf_add_ulp carried out of prec+1 limbs\n");
134 1.1 mrg abort ();
135 1.1 mrg }
136 1.1 mrg
137 1.1 mrg fp[abs_fsize] = c;
138 1.1 mrg abs_fsize++;
139 1.1 mrg SIZ(f) = (fsize > 0 ? abs_fsize : - abs_fsize);
140 1.1 mrg EXP(f)++;
141 1.1 mrg }
142 1.1 mrg }
143 1.1 mrg
144 1.1 mrg /* Fill f with size limbs of the given value, setup as an integer. */
145 1.1 mrg void
146 1.1 mrg refmpf_fill (mpf_ptr f, mp_size_t size, mp_limb_t value)
147 1.1 mrg {
148 1.1 mrg ASSERT (size >= 0);
149 1.1 mrg size = MIN (PREC(f) + 1, size);
150 1.1 mrg SIZ(f) = size;
151 1.1 mrg EXP(f) = size;
152 1.1 mrg refmpn_fill (PTR(f), size, value);
153 1.1 mrg }
154 1.1 mrg
155 1.1 mrg /* Strip high zero limbs from the f data, adjusting exponent accordingly. */
156 1.1 mrg void
157 1.1 mrg refmpf_normalize (mpf_ptr f)
158 1.1 mrg {
159 1.1 mrg while (SIZ(f) != 0 && PTR(f)[ABSIZ(f)-1] == 0)
160 1.1 mrg {
161 1.1 mrg SIZ(f) = (SIZ(f) >= 0 ? SIZ(f)-1 : SIZ(f)+1);
162 1.1 mrg EXP(f) --;
163 1.1 mrg }
164 1.1 mrg if (SIZ(f) == 0)
165 1.1 mrg EXP(f) = 0;
166 1.1 mrg }
167 1.1 mrg
168 1.1 mrg /* refmpf_set_overlap sets up dst as a copy of src, but with PREC(dst)
169 1.1 mrg unchanged, in preparation for an overlap test.
170 1.1 mrg
171 1.1 mrg The full value of src is copied, and the space at PTR(dst) is extended as
172 1.1 mrg necessary. The way PREC(dst) is unchanged is as per an mpf_set_prec_raw.
173 1.1 mrg The return value is the new PTR(dst) space precision, in bits, ready for
174 1.1 mrg a restoring mpf_set_prec_raw before mpf_clear. */
175 1.1 mrg
176 1.1 mrg unsigned long
177 1.1 mrg refmpf_set_overlap (mpf_ptr dst, mpf_srcptr src)
178 1.1 mrg {
179 1.1 mrg mp_size_t dprec = PREC(dst);
180 1.1 mrg mp_size_t ssize = ABSIZ(src);
181 1.1 mrg unsigned long ret;
182 1.1 mrg
183 1.1 mrg refmpf_set_prec_limbs (dst, (unsigned long) MAX (dprec, ssize));
184 1.1 mrg mpf_set (dst, src);
185 1.1 mrg
186 1.1 mrg ret = mpf_get_prec (dst);
187 1.1 mrg PREC(dst) = dprec;
188 1.1 mrg return ret;
189 1.1 mrg }
190 1.1 mrg
191 1.1 mrg /* Like mpf_set_prec, but taking a precision in limbs.
192 1.1 mrg PREC(f) ends up as the given "prec" value. */
193 1.1 mrg void
194 1.1 mrg refmpf_set_prec_limbs (mpf_ptr f, unsigned long prec)
195 1.1 mrg {
196 1.1 mrg mpf_set_prec (f, __GMPF_PREC_TO_BITS (prec));
197 1.1 mrg }
198 1.1 mrg
199 1.1 mrg
200 1.1 mrg void
201 1.1 mrg refmpf_sub (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
202 1.1 mrg {
203 1.1 mrg mp_size_t hi, lo, size;
204 1.1 mrg mp_ptr ut, vt, wt;
205 1.1 mrg int neg;
206 1.1 mrg mp_exp_t exp;
207 1.1 mrg TMP_DECL;
208 1.1 mrg
209 1.1 mrg TMP_MARK;
210 1.1 mrg
211 1.1 mrg if (SIZ (u) == 0)
212 1.1 mrg {
213 1.1 mrg size = ABSIZ (v);
214 1.1 mrg wt = TMP_ALLOC_LIMBS (size + 1);
215 1.1 mrg MPN_COPY (wt, PTR (v), size);
216 1.1 mrg exp = EXP (v);
217 1.1 mrg neg = SIZ (v) > 0;
218 1.1 mrg goto done;
219 1.1 mrg }
220 1.1 mrg if (SIZ (v) == 0)
221 1.1 mrg {
222 1.1 mrg size = ABSIZ (u);
223 1.1 mrg wt = TMP_ALLOC_LIMBS (size + 1);
224 1.1 mrg MPN_COPY (wt, PTR (u), size);
225 1.1 mrg exp = EXP (u);
226 1.1 mrg neg = SIZ (u) < 0;
227 1.1 mrg goto done;
228 1.1 mrg }
229 1.1 mrg if ((SIZ (u) ^ SIZ (v)) < 0)
230 1.1 mrg {
231 1.1 mrg mpf_t tmp;
232 1.1 mrg SIZ (tmp) = -SIZ (v);
233 1.1 mrg EXP (tmp) = EXP (v);
234 1.1 mrg PTR (tmp) = PTR (v);
235 1.1 mrg refmpf_add (w, u, tmp);
236 1.1 mrg if (SIZ (u) < 0)
237 1.1 mrg mpf_neg (w, w);
238 1.1 mrg return;
239 1.1 mrg }
240 1.1 mrg neg = SIZ (u) < 0;
241 1.1 mrg
242 1.1 mrg /* Compute the significance of the hi and lo end of the result. */
243 1.1 mrg hi = MAX (EXP (u), EXP (v));
244 1.1 mrg lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
245 1.1 mrg size = hi - lo;
246 1.1 mrg ut = TMP_ALLOC_LIMBS (size + 1);
247 1.1 mrg vt = TMP_ALLOC_LIMBS (size + 1);
248 1.1 mrg wt = TMP_ALLOC_LIMBS (size + 1);
249 1.1 mrg MPN_ZERO (ut, size);
250 1.1 mrg MPN_ZERO (vt, size);
251 1.1 mrg {int off;
252 1.1 mrg off = size + (EXP (u) - hi) - ABSIZ (u);
253 1.1 mrg MPN_COPY (ut + off, PTR (u), ABSIZ (u));
254 1.1 mrg off = size + (EXP (v) - hi) - ABSIZ (v);
255 1.1 mrg MPN_COPY (vt + off, PTR (v), ABSIZ (v));
256 1.1 mrg }
257 1.1 mrg
258 1.1 mrg if (mpn_cmp (ut, vt, size) >= 0)
259 1.1 mrg mpn_sub_n (wt, ut, vt, size);
260 1.1 mrg else
261 1.1 mrg {
262 1.1 mrg mpn_sub_n (wt, vt, ut, size);
263 1.1 mrg neg ^= 1;
264 1.1 mrg }
265 1.1 mrg exp = hi;
266 1.1 mrg while (size != 0 && wt[size - 1] == 0)
267 1.1 mrg {
268 1.1 mrg size--;
269 1.1 mrg exp--;
270 1.1 mrg }
271 1.1 mrg
272 1.1 mrg done:
273 1.1 mrg if (size > PREC (w))
274 1.1 mrg {
275 1.1 mrg wt += size - PREC (w);
276 1.1 mrg size = PREC (w);
277 1.1 mrg }
278 1.1 mrg MPN_COPY (PTR (w), wt, size);
279 1.1 mrg SIZ (w) = neg == 0 ? size : -size;
280 1.1 mrg EXP (w) = exp;
281 1.1 mrg TMP_FREE;
282 1.1 mrg }
283 1.1 mrg
284 1.1 mrg
285 1.1 mrg /* Validate got by comparing to want. Return 1 if good, 0 if bad.
286 1.1 mrg
287 1.1 mrg The data in got is compared to that in want, up to either PREC(got) limbs
288 1.1 mrg or the size of got, whichever is bigger. Clearly we always demand
289 1.1 mrg PREC(got) of accuracy, but we go further and say that if got is bigger
290 1.1 mrg then any extra must be correct too.
291 1.1 mrg
292 1.1 mrg want needs to have enough data to allow this comparison. The size in
293 1.1 mrg want doesn't have to be that big though, if it's smaller then further low
294 1.1 mrg limbs are taken to be zero.
295 1.1 mrg
296 1.1 mrg This validation approach is designed to allow some flexibility in exactly
297 1.1 mrg how much data is generated by an mpf function, ie. either prec or prec+1
298 1.1 mrg limbs. We don't try to make a reference function that emulates that same
299 1.1 mrg size decision, instead the idea is for a validation function to generate
300 1.1 mrg at least as much data as the real function, then compare. */
301 1.1 mrg
302 1.1 mrg int
303 1.1 mrg refmpf_validate (const char *name, mpf_srcptr got, mpf_srcptr want)
304 1.1 mrg {
305 1.1 mrg int bad = 0;
306 1.1 mrg mp_size_t gsize, wsize, cmpsize, i;
307 1.1 mrg mp_srcptr gp, wp;
308 1.1 mrg mp_limb_t glimb, wlimb;
309 1.1 mrg
310 1.1 mrg MPF_CHECK_FORMAT (got);
311 1.1 mrg
312 1.1 mrg if (EXP (got) != EXP (want))
313 1.1 mrg {
314 1.1 mrg printf ("%s: wrong exponent\n", name);
315 1.1 mrg bad = 1;
316 1.1 mrg }
317 1.1 mrg
318 1.1 mrg gsize = SIZ (got);
319 1.1 mrg wsize = SIZ (want);
320 1.1 mrg if ((gsize < 0 && wsize > 0) || (gsize > 0 && wsize < 0))
321 1.1 mrg {
322 1.1 mrg printf ("%s: wrong sign\n", name);
323 1.1 mrg bad = 1;
324 1.1 mrg }
325 1.1 mrg
326 1.1 mrg gsize = ABS (gsize);
327 1.1 mrg wsize = ABS (wsize);
328 1.1 mrg
329 1.1 mrg /* most significant limb of respective data */
330 1.1 mrg gp = PTR (got) + gsize - 1;
331 1.1 mrg wp = PTR (want) + wsize - 1;
332 1.1 mrg
333 1.1 mrg /* compare limb data */
334 1.1 mrg cmpsize = MAX (PREC (got), gsize);
335 1.1 mrg for (i = 0; i < cmpsize; i++)
336 1.1 mrg {
337 1.1 mrg glimb = (i < gsize ? gp[-i] : 0);
338 1.1 mrg wlimb = (i < wsize ? wp[-i] : 0);
339 1.1 mrg
340 1.1 mrg if (glimb != wlimb)
341 1.1 mrg {
342 1.1 mrg printf ("%s: wrong data starting at index %ld from top\n",
343 1.1 mrg name, (long) i);
344 1.1 mrg bad = 1;
345 1.1 mrg break;
346 1.1 mrg }
347 1.1 mrg }
348 1.1 mrg
349 1.1 mrg if (bad)
350 1.1 mrg {
351 1.1 mrg printf (" prec %d\n", PREC(got));
352 1.1 mrg printf (" exp got %ld\n", (long) EXP(got));
353 1.1 mrg printf (" exp want %ld\n", (long) EXP(want));
354 1.1 mrg printf (" size got %d\n", SIZ(got));
355 1.1 mrg printf (" size want %d\n", SIZ(want));
356 1.1 mrg printf (" limbs (high to low)\n");
357 1.1 mrg printf (" got ");
358 1.1 mrg for (i = ABSIZ(got)-1; i >= 0; i--)
359 1.1 mrg {
360 1.1 mrg gmp_printf ("%MX", PTR(got)[i]);
361 1.1 mrg if (i != 0)
362 1.1 mrg printf (",");
363 1.1 mrg }
364 1.1 mrg printf ("\n");
365 1.1 mrg printf (" want ");
366 1.1 mrg for (i = ABSIZ(want)-1; i >= 0; i--)
367 1.1 mrg {
368 1.1 mrg gmp_printf ("%MX", PTR(want)[i]);
369 1.1 mrg if (i != 0)
370 1.1 mrg printf (",");
371 1.1 mrg }
372 1.1 mrg printf ("\n");
373 1.1 mrg return 0;
374 1.1 mrg }
375 1.1 mrg
376 1.1 mrg return 1;
377 1.1 mrg }
378 1.1 mrg
379 1.1 mrg
380 1.1 mrg int
381 1.1 mrg refmpf_validate_division (const char *name, mpf_srcptr got,
382 1.1 mrg mpf_srcptr n, mpf_srcptr d)
383 1.1 mrg {
384 1.1 mrg mp_size_t nsize, dsize, sign, prec, qsize, tsize;
385 1.1 mrg mp_srcptr np, dp;
386 1.1 mrg mp_ptr tp, qp, rp;
387 1.1 mrg mpf_t want;
388 1.1 mrg int ret;
389 1.1 mrg
390 1.1 mrg nsize = SIZ (n);
391 1.1 mrg dsize = SIZ (d);
392 1.1 mrg ASSERT_ALWAYS (dsize != 0);
393 1.1 mrg
394 1.1 mrg sign = nsize ^ dsize;
395 1.1 mrg nsize = ABS (nsize);
396 1.1 mrg dsize = ABS (dsize);
397 1.1 mrg
398 1.1 mrg np = PTR (n);
399 1.1 mrg dp = PTR (d);
400 1.1 mrg prec = PREC (got);
401 1.1 mrg
402 1.1 mrg EXP (want) = EXP (n) - EXP (d) + 1;
403 1.1 mrg
404 1.1 mrg qsize = prec + 2; /* at least prec+1 limbs, after high zero */
405 1.1 mrg tsize = qsize + dsize - 1; /* dividend size to give desired qsize */
406 1.1 mrg
407 1.1 mrg /* dividend n, extended or truncated */
408 1.1 mrg tp = refmpn_malloc_limbs (tsize);
409 1.1 mrg refmpn_copy_extend (tp, tsize, np, nsize);
410 1.1 mrg
411 1.1 mrg qp = refmpn_malloc_limbs (qsize);
412 1.1 mrg rp = refmpn_malloc_limbs (dsize); /* remainder, unused */
413 1.1 mrg
414 1.1 mrg ASSERT_ALWAYS (qsize == tsize - dsize + 1);
415 1.1 mrg refmpn_tdiv_qr (qp, rp, (mp_size_t) 0, tp, tsize, dp, dsize);
416 1.1 mrg
417 1.1 mrg PTR (want) = qp;
418 1.1 mrg SIZ (want) = (sign >= 0 ? qsize : -qsize);
419 1.1 mrg refmpf_normalize (want);
420 1.1 mrg
421 1.1 mrg ret = refmpf_validate (name, got, want);
422 1.1 mrg
423 1.1 mrg free (tp);
424 1.1 mrg free (qp);
425 1.1 mrg free (rp);
426 1.1 mrg
427 1.1 mrg return ret;
428 1.1 mrg }
429