~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/gmp/mpfr/sub1.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}