Annotation of OpenXM_contrib/gmp/mpfr/sub1.c, Revision 1.1.1.1
1.1 ohara 1: /* mpfr_sub1 -- internal function to perform a "real" subtraction
2:
3: Copyright 2001 Free Software Foundation.
4: Contributed by the Spaces project, INRIA Lorraine.
5:
6: This file is part of the MPFR Library.
7:
8: The MPFR Library is free software; you can redistribute it and/or modify
9: it under the terms of the GNU Lesser General Public License as published by
10: the Free Software Foundation; either version 2.1 of the License, or (at your
11: option) any later version.
12:
13: The MPFR Library is distributed in the hope that it will be useful, but
14: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16: License for more details.
17:
18: You should have received a copy of the GNU Lesser General Public License
19: along with the MPFR Library; see the file COPYING.LIB. If not, write to
20: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21: MA 02111-1307, USA. */
22:
23: #include "gmp.h"
24: #include "gmp-impl.h"
25: #include "mpfr.h"
26: #include "mpfr-impl.h"
27:
28: /* compute sign(b) * (|b| - |c|), with |b| > |c|, diff_exp = EXP(b) - EXP(c)
29: Returns 0 iff result is exact,
30: a negative value when the result is less than the exact value,
31: a positive value otherwise.
32: */
33:
34: int
35: mpfr_sub1 (mpfr_ptr a, mpfr_srcptr b, mpfr_srcptr c, mp_rnd_t rnd_mode,
36: int sub)
37: {
38: int sign;
39: mp_exp_unsigned_t diff_exp;
40: mp_prec_t cancel, cancel1;
41: mp_size_t cancel2, an, bn, cn, cn0;
42: mp_limb_t *ap, *bp, *cp;
43: mp_limb_t carry, bb, cc, borrow = 0;
44: int inexact = 0, shift_b, shift_c, is_exact = 1, down = 0, add_exp = 0;
45: int sh, k;
46: TMP_DECL(marker);
47:
48: TMP_MARK(marker);
49: ap = MPFR_MANT(a);
50: an = 1 + (MPFR_PREC(a) - 1) / BITS_PER_MP_LIMB;
51:
52: sign = mpfr_cmp2 (b, c, &cancel);
53: if (sign == 0)
54: {
55: if (rnd_mode == GMP_RNDD)
56: MPFR_SET_NEG(a);
57: else
58: MPFR_SET_POS(a);
59: MPFR_SET_ZERO(a);
60: MPFR_RET(0);
61: }
62:
63: /* If subtraction: sign(a) = sign * sign(b) */
64: if (sub && MPFR_SIGN(a) != sign * MPFR_SIGN(b))
65: MPFR_CHANGE_SIGN(a);
66:
67: if (sign < 0) /* swap b and c so that |b| > |c| */
68: {
69: mpfr_srcptr t;
70: t = b; b = c; c = t;
71: }
72:
73: /* If addition: sign(a) = sign of the larger argument in absolute value */
74: if (!sub)
75: MPFR_SET_SAME_SIGN(a, b);
76:
77: diff_exp = (mp_exp_unsigned_t) MPFR_EXP(b) - MPFR_EXP(c);
78:
79: /* reserve a space to store b aligned with the result, i.e. shifted by
80: (-cancel) % BITS_PER_MP_LIMB to the right */
81: bn = 1 + (MPFR_PREC(b) - 1) / BITS_PER_MP_LIMB;
82: shift_b = cancel % BITS_PER_MP_LIMB;
83: if (shift_b)
84: shift_b = BITS_PER_MP_LIMB - shift_b;
85: cancel1 = (cancel + shift_b) / BITS_PER_MP_LIMB;
86: /* the high cancel1 limbs from b should not be taken into account */
87: if (shift_b == 0)
88: bp = MPFR_MANT(b); /* no need of an extra space */
89: else
90: {
91: bp = TMP_ALLOC ((bn + 1) * BYTES_PER_MP_LIMB);
92: bp[0] = mpn_rshift (bp + 1, MPFR_MANT(b), bn++, shift_b);
93: }
94:
95: /* reserve a space to store c aligned with the result, i.e. shifted by
96: (diff_exp-cancel) % BITS_PER_MP_LIMB to the right */
97: cn = 1 + (MPFR_PREC(c) - 1) / BITS_PER_MP_LIMB;
98: shift_c = diff_exp - (cancel % BITS_PER_MP_LIMB);
99: shift_c = (shift_c + BITS_PER_MP_LIMB) % BITS_PER_MP_LIMB;
100: if (shift_c == 0)
101: cp = MPFR_MANT(c);
102: else
103: {
104: cp = TMP_ALLOC ((cn + 1) * BYTES_PER_MP_LIMB);
105: cp[0] = mpn_rshift (cp + 1, MPFR_MANT(c), cn++, shift_c);
106: }
107:
108: #ifdef DEBUG
109: printf("shift_b=%u shift_c=%u\n", shift_b, shift_c);
110: #endif
111:
112: /* ensure ap != bp and ap != cp */
113: if (ap == bp)
114: {
115: bp = (mp_ptr) TMP_ALLOC(bn * BYTES_PER_MP_LIMB);
116: MPN_COPY (bp, ap, bn);
117: /* ap == cp cannot occur since we would have b=c, which is detected
118: in mpfr_add or mpfr_sub */
119: }
120: else if (ap == cp)
121: {
122: cp = (mp_ptr) TMP_ALLOC (cn * BYTES_PER_MP_LIMB);
123: MPN_COPY(cp, ap, cn);
124: }
125:
126: /* here we have shift_c = (diff_exp - cancel) % BITS_PER_MP_LIMB,
127: thus we want cancel2 = ceil((cancel - diff_exp) / BITS_PER_MP_LIMB) */
128:
129: cancel2 = (long int) (cancel - (diff_exp - shift_c)) / BITS_PER_MP_LIMB;
130: /* the high cancel2 limbs from b should not be taken into account */
131: #ifdef DEBUG
132: printf("cancel=%u cancel1=%u cancel2=%d\n", cancel, cancel1, cancel2);
133: #endif
134:
135: /* ap[an-1] ap[0]
136: <----------------+-----------|---->
137: <----------PREC(a)----------><-sh->
138: cancel1
139: limbs bp[bn-cancel1-1]
140: <--...-----><----------------+-----------+----------->
141: cancel2
142: limbs cp[cn-cancel2-1] cancel2 >= 0
143: <--...--><----------------+----------------+---------------->
144: (-cancel2) cancel2 < 0
145: limbs <----------------+---------------->
146: */
147:
148: /* first part: put in ap[0..an-1] the value of high(b) - high(c),
149: where high(b) consists of the high an+cancel1 limbs of b,
150: and high(c) consists of the high an+cancel2 limbs of c.
151: */
152:
153: /* copy high(b) into a */
154: if (an + cancel1 <= bn) /* a: <----------------+-----------|---->
155: b: <-----------------------------------------> */
156: MPN_COPY (ap, bp + bn - (an + cancel1), an);
157: else /* a: <----------------+-----------|---->
158: b: <-------------------------> */
159: if (cancel1 < bn) /* otherwise b does not overlap with a */
160: {
161: MPN_ZERO (ap, an + cancel1 - bn);
162: MPN_COPY (ap + an + cancel1 - bn, bp, bn - cancel1);
163: }
164: else
165: MPN_ZERO (ap, an);
166:
167: #ifdef DEBUG
168: printf("after copying high(b), a="); mpfr_print_binary(a); putchar('\n');
169: #endif
170:
171: /* subtract high(c) */
172: if (an + cancel2 > 0) /* otherwise c does not overlap with a */
173: {
174: mp_limb_t *ap2;
175:
176: if (cancel2 >= 0)
177: {
178: if (an + cancel2 <= cn) /* a: <----------------------------->
179: c: <-----------------------------------------> */
180: mpn_sub_n (ap, ap, cp + cn - (an + cancel2), an);
181: else /* a: <---------------------------->
182: c: <-------------------------> */
183: {
184: ap2 = ap + an + cancel2 - cn;
185: if (cn > cancel2)
186: mpn_sub_n (ap2, ap2, cp, cn - cancel2);
187: }
188: }
189: else /* cancel2 < 0 */
190: {
191: if (an + cancel2 <= cn) /* a: <----------------------------->
192: c: <-----------------------------> */
193: borrow = mpn_sub_n (ap, ap, cp + cn - (an + cancel2), an + cancel2);
194: else /* a: <---------------------------->
195: c: <----------------> */
196: {
197: ap2 = ap + an + cancel2 - cn;
198: borrow = mpn_sub_n (ap2, ap2, cp, cn);
199: }
200: ap2 = ap + an + cancel2;
201: mpn_sub_1 (ap2, ap2, -cancel2, borrow);
202: }
203: }
204:
205: #ifdef DEBUG
206: printf("after subtracting high(c), a="); mpfr_print_binary(a); putchar('\n');
207: #endif
208:
209: /* now perform rounding */
210: sh = an * BITS_PER_MP_LIMB - MPFR_PREC(a); /* last unused bits from a */
211: carry = ap[0] & ((MP_LIMB_T_ONE << sh) - MP_LIMB_T_ONE);
212: ap[0] -= carry;
213:
214: if (rnd_mode == GMP_RNDN)
215: {
216: if (sh)
217: {
218: is_exact = (carry == 0);
219: /* can decide except when carry = 2^(sh-1) [middle]
220: or carry = 0 [truncate, but cannot decide inexact flag] */
221: down = (carry < (MP_LIMB_T_ONE << (sh - 1)));
222: if (carry > (MP_LIMB_T_ONE << (sh - 1)))
223: goto add_one_ulp;
224: else if ((0 < carry) && down)
225: {
226: inexact = -1; /* result if smaller than exact value */
227: goto truncate;
228: }
229: }
230: }
231: else /* directed rounding: set rnd_mode to RNDZ iff towards zero */
232: {
233: if (((rnd_mode == GMP_RNDD) && (MPFR_SIGN(a) > 0)) ||
234: ((rnd_mode == GMP_RNDU) && (MPFR_SIGN(a) < 0)))
235: rnd_mode = GMP_RNDZ;
236:
237: if (carry)
238: {
239: if (rnd_mode == GMP_RNDZ)
240: {
241: inexact = -1;
242: goto truncate;
243: }
244: else /* round away */
245: goto add_one_ulp;
246: }
247: }
248:
249: /* we have to consider the low (bn - (an+cancel1)) limbs from b,
250: and the (cn - (an+cancel2)) limbs from c. */
251: bn -= an + cancel1;
252: cn0 = cn;
253: cn -= (long int) an + cancel2;
254: #ifdef DEBUG
255: printf("last %d bits from a are %lu, bn=%ld, cn=%ld\n", sh, carry, bn, cn);
256: #endif
257:
258: for (k = 0; (bn > 0) || (cn > 0); k = 1)
259: {
260: bb = (bn > 0) ? bp[--bn] : 0;
261: if ((cn > 0) && (cn-- <= cn0))
262: cc = cp[cn];
263: else
264: cc = 0;
265:
266: if (down == 0)
267: down = (bb < cc);
268:
269: if ((rnd_mode == GMP_RNDN) && !k && sh == 0)
270: {
271: mp_limb_t half = GMP_LIMB_HIGHBIT;
272:
273: is_exact = (bb == cc);
274:
275: /* add one ulp if bb > cc + half
276: truncate if cc - half < bb < cc + half
277: sub one ulp if bb < cc - half
278: */
279:
280: if (down)
281: {
282: if (cc >= half)
283: cc -= half;
284: else
285: bb += half;
286: }
287: else /* bb >= cc */
288: {
289: if (cc < half)
290: cc += half;
291: else
292: bb -= half;
293: }
294: }
295:
296: #ifdef DEBUG
297: printf(" bb=%lu cc=%lu down=%d is_exact=%d\n", bb, cc, down, is_exact);
298: #endif
299: if (bb < cc)
300: {
301: if (rnd_mode == GMP_RNDZ)
302: goto sub_one_ulp;
303: else if (rnd_mode != GMP_RNDN) /* round away */
304: {
305: inexact = 1;
306: goto truncate;
307: }
308: else /* round to nearest */
309: {
310: if (is_exact && sh == 0)
311: {
312: inexact = 0;
313: goto truncate;
314: }
315: else if (down && sh == 0)
316: goto sub_one_ulp;
317: else
318: {
319: inexact = (is_exact) ? 1 : -1;
320: goto truncate;
321: }
322: }
323: }
324: else if (bb > cc)
325: {
326: if (rnd_mode == GMP_RNDZ)
327: {
328: inexact = -1;
329: goto truncate;
330: }
331: else if (rnd_mode != GMP_RNDN) /* round away */
332: goto add_one_ulp;
333: else /* round to nearest */
334: {
335: if (is_exact)
336: {
337: inexact = -1;
338: goto truncate;
339: }
340: else if (down)
341: {
342: inexact = 1;
343: goto truncate;
344: }
345: else
346: goto add_one_ulp;
347: }
348: }
349: }
350:
351: if ((rnd_mode == GMP_RNDN) && !is_exact)
352: {
353: /* even rounding rule */
354: if ((ap[0] >> sh) & 1)
355: {
356: if (down) goto sub_one_ulp;
357: else goto add_one_ulp;
358: }
359: else
360: inexact = (down) ? 1 : -1;
361: }
362: else
363: inexact = 0;
364: goto truncate;
365:
366: sub_one_ulp: /* add one unit in last place to a */
367: mpn_sub_1 (ap, ap, an, MP_LIMB_T_ONE << sh);
368: inexact = -1;
369: goto end_of_sub;
370:
371: add_one_ulp: /* add one unit in last place to a */
372: if (mpn_add_1 (ap, ap, an, MP_LIMB_T_ONE << sh)) /* result is a power of 2 */
373: {
374: ap[an-1] = GMP_LIMB_HIGHBIT;
375: add_exp = 1;
376: }
377: inexact = 1; /* result larger than exact value */
378:
379: truncate:
380: if ((ap[an-1] >> (BITS_PER_MP_LIMB - 1)) == 0) /* case 1 - epsilon */
381: {
382: ap[an-1] = GMP_LIMB_HIGHBIT;
383: add_exp = 1;
384: }
385:
386: end_of_sub:
387: /* we have to set MPFR_EXP(a) to MPFR_EXP(b) - cancel + add_exp, taking
388: care of underflows/overflows in that computation, and of the allowed
389: exponent range */
390: if (cancel)
391: {
392: mp_exp_t exp_b;
393:
394: cancel -= add_exp; /* still valid as unsigned long */
395: exp_b = MPFR_EXP(b); /* save it in case a equals b */
396: MPFR_EXP(a) = MPFR_EXP(b) - cancel;
397: if ((MPFR_EXP(a) > exp_b) /* underflow in type mp_exp_t */
398: || (MPFR_EXP(a) < __mpfr_emin))
399: {
400: TMP_FREE(marker);
401: return mpfr_set_underflow (a, rnd_mode, MPFR_SIGN(a));
402: }
403: }
404: else /* cancel = 0: MPFR_EXP(a) <- MPFR_EXP(b) + add_exp */
405: {
406: /* in case cancel = 0, add_exp can still be 1, in case b is just
407: below a power of two, c is very small, prec(a) < prec(b),
408: and rnd=away or nearest */
409: if (add_exp && MPFR_EXP(b) == __mpfr_emax)
410: {
411: TMP_FREE(marker);
412: return mpfr_set_overflow (a, rnd_mode, MPFR_SIGN(a));
413: }
414: MPFR_EXP(a) = MPFR_EXP(b) + add_exp;
415: }
416: TMP_FREE(marker);
417: #ifdef DEBUG
418: printf ("result is a="); mpfr_print_binary(a); putchar('\n');
419: #endif
420: /* check that result is msb-normalized */
421: MPFR_ASSERTN(ap[an-1] > ~ap[an-1]);
422: return inexact * MPFR_SIGN(a);
423: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>