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

« back to all changes in this revision

Viewing changes to src/gmp/mpq/get_d.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2007-04-09 11:51:51 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20070409115151-ql8cr0kalzx1jmla
Tags: 0.9i-20070324-2
Upload to unstable. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* double mpq_get_d (mpq_t src) -- Return the double approximation to SRC.
 
1
/* double mpq_get_d (mpq_t src) -- mpq to double, rounding towards zero.
2
2
 
3
 
Copyright 1995, 1996, 2001, 2002 Free Software Foundation, Inc.
 
3
Copyright 1995, 1996, 2001, 2002, 2003, 2004, 2005 Free Software Foundation,
 
4
Inc.
4
5
 
5
6
This file is part of the GNU MP Library.
6
7
 
16
17
 
17
18
You should have received a copy of the GNU Lesser General Public License
18
19
along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
19
 
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20
 
MA 02111-1307, USA. */
 
20
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
21
MA 02110-1301, USA. */
21
22
 
 
23
#include <stdio.h>  /* for NULL */
22
24
#include "gmp.h"
23
25
#include "gmp-impl.h"
24
26
#include "longlong.h"
25
27
 
26
 
/* Algorithm:
27
 
   1. Develop >= n bits of src.num / src.den, where n is the number of bits
28
 
      in a double.  This (partial) division will use all bits from the
29
 
      denominator.
30
 
   2. Use the remainder to determine how to round the result.
31
 
   3. Assign the integral result to a temporary double.
32
 
   4. Scale the temporary double, and return the result.
33
 
 
34
 
   An alternative algorithm, that would be faster:
 
28
 
 
29
/* All that's needed is to get the high 53 bits of the quotient num/den,
 
30
   rounded towards zero.  More than 53 bits is fine, any excess is ignored
 
31
   by mpn_get_d.
 
32
 
 
33
   N_QLIMBS is how many quotient limbs we need to satisfy the mantissa of a
 
34
   double, assuming the highest of those limbs is non-zero.  The target
 
35
   qsize for mpn_tdiv_qr is then 1 more than this, since that function may
 
36
   give a zero in the high limb (and non-zero in the second highest).
 
37
 
 
38
   The use of 8*sizeof(double) in N_QLIMBS is an overestimate of the
 
39
   mantissa bits, but it gets the same result as the true value (53 or 48 or
 
40
   whatever) when rounded up to a multiple of GMP_NUMB_BITS, for non-nails.
 
41
 
 
42
   Enhancements:
 
43
 
 
44
   Use the true mantissa size in the N_QLIMBS formala, to save a divide step
 
45
   in nails.
 
46
 
 
47
   Examine the high limbs of num and den to see if the highest 1 bit of the
 
48
   quotient will fall high enough that just N_QLIMBS-1 limbs is enough to
 
49
   get the necessary bits, thereby saving a division step.
 
50
 
 
51
   Bit shift either num or den to arrange for the above condition on the
 
52
   high 1 bit of the quotient, to save a division step always.  A shift to
 
53
   save a division step is definitely worthwhile with mpn_tdiv_qr, though we
 
54
   may want to reassess this on big num/den when a quotient-only division
 
55
   exists.
 
56
 
 
57
   Maybe we could estimate the final exponent using nsize-dsize (and
 
58
   possibly the high limbs of num and den), so as to detect overflow and
 
59
   return infinity or zero quickly.  Overflow is never very helpful to an
 
60
   application, and can therefore probably be regarded as abnormal, but we
 
61
   may still like to optimize it if the conditions are easy.  (This would
 
62
   only be for float formats we know, unknown formats are not important and
 
63
   can be left to mpn_get_d.)
 
64
 
 
65
   Future:
 
66
 
 
67
   If/when mpn_tdiv_qr supports its qxn parameter we can use that instead of
 
68
   padding n with zeros in temporary space.
 
69
 
 
70
   If/when a quotient-only division exists it can be used here immediately.
 
71
   remp is only to satisfy mpn_tdiv_qr, the remainder is not used.
 
72
 
 
73
   Alternatives:
 
74
 
 
75
   An alternative algorithm, that may be faster:
35
76
   0. Let n be somewhat larger than the number of significant bits in a double.
36
77
   1. Extract the most significant n bits of the denominator, and an equal
37
78
      number of bits from the numerator.
42
83
      we are done.  If they are different, repeat the algorithm from step 1,
43
84
      but first let n = n * 2.
44
85
   4. If we end up using all bits from the numerator and denominator, fall
45
 
      back to the first algorithm above.
 
86
      back to a plain division.
46
87
   5. Just to make life harder, The computation of a + 1 and b + 1 above
47
88
      might give carry-out...  Needs special handling.  It might work to
48
89
      subtract 1 in both cases instead.
49
 
*/
 
90
 
 
91
   Not certain if this approach would be faster than a quotient-only
 
92
   division.  Presumably such optimizations are the sort of thing we would
 
93
   like to have helping everywhere that uses a quotient-only division. */
50
94
 
51
95
double
52
96
mpq_get_d (const MP_RAT *src)
53
97
{
54
 
  mp_ptr np, dp;
55
 
  mp_ptr rp;
 
98
  double res;
 
99
  mp_srcptr np, dp;
 
100
  mp_ptr remp, tp;
56
101
  mp_size_t nsize = src->_mp_num._mp_size;
57
102
  mp_size_t dsize = src->_mp_den._mp_size;
58
 
  mp_size_t qsize, rsize;
59
 
  mp_size_t sign_quotient = nsize ^ dsize;
60
 
  mp_limb_t qlimb;
 
103
  mp_size_t qsize, prospective_qsize, zeros, chop, tsize;
 
104
  mp_size_t sign_quotient = nsize;
 
105
  long exp;
61
106
#define N_QLIMBS (1 + (sizeof (double) + BYTES_PER_MP_LIMB-1) / BYTES_PER_MP_LIMB)
62
107
  mp_limb_t qarr[N_QLIMBS + 1];
63
108
  mp_ptr qp = qarr;
64
 
  TMP_DECL (marker);
65
 
 
66
 
  if (nsize == 0)
 
109
  TMP_DECL;
 
110
 
 
111
  ASSERT (dsize > 0);    /* canonical src */
 
112
 
 
113
  /* mpn_get_d below requires a non-zero operand */
 
114
  if (UNLIKELY (nsize == 0))
67
115
    return 0.0;
68
116
 
69
 
  TMP_MARK (marker);
 
117
  TMP_MARK;
70
118
  nsize = ABS (nsize);
71
119
  dsize = ABS (dsize);
72
120
  np = src->_mp_num._mp_d;
73
121
  dp = src->_mp_den._mp_d;
74
122
 
75
 
  rsize = dsize + N_QLIMBS;
76
 
  rp = (mp_ptr) TMP_ALLOC ((rsize + 1) * BYTES_PER_MP_LIMB);
77
 
 
78
 
  /* Normalize the denominator, i.e. make its most significant bit set by
79
 
     shifting it NORMALIZATION_STEPS bits to the left.  Also shift the
80
 
     numerator the same number of steps (to keep the quotient the same!).  */
81
 
  if ((dp[dsize - 1] & GMP_NUMB_HIGHBIT) == 0)
 
123
  prospective_qsize = nsize - dsize + 1;   /* from using given n,d */
 
124
  qsize = N_QLIMBS + 1;                    /* desired qsize */
 
125
 
 
126
  zeros = qsize - prospective_qsize;       /* padding n to get qsize */
 
127
  exp = (long) -zeros * GMP_NUMB_BITS;     /* relative to low of qp */
 
128
 
 
129
  chop = MAX (-zeros, 0);                  /* negative zeros means shorten n */
 
130
  np += chop;
 
131
  nsize -= chop;
 
132
  zeros += chop;                           /* now zeros >= 0 */
 
133
 
 
134
  tsize = nsize + zeros;                   /* size for possible copy of n */
 
135
 
 
136
  if (WANT_TMP_DEBUG)
82
137
    {
83
 
      mp_ptr tp;
84
 
      mp_limb_t nlimb;
85
 
      unsigned normalization_steps;
86
 
 
87
 
      count_leading_zeros (normalization_steps, dp[dsize - 1]);
88
 
      normalization_steps -= GMP_NAIL_BITS;
89
 
 
90
 
      /* Shift up the denominator setting the most significant bit of
91
 
         the most significant limb.  Use temporary storage not to clobber
92
 
         the original contents of the denominator.  */
93
 
      tp = (mp_ptr) TMP_ALLOC (dsize * BYTES_PER_MP_LIMB);
94
 
      mpn_lshift (tp, dp, dsize, normalization_steps);
95
 
      dp = tp;
96
 
 
97
 
      if (rsize > nsize)
98
 
        {
99
 
          MPN_ZERO (rp, rsize - nsize);
100
 
          nlimb = mpn_lshift (rp + (rsize - nsize),
101
 
                              np, nsize, normalization_steps);
102
 
        }
103
 
      else
104
 
        {
105
 
          nlimb = mpn_lshift (rp, np + (nsize - rsize),
106
 
                              rsize, normalization_steps);
107
 
        }
108
 
      if (nlimb != 0)
109
 
        {
110
 
          rp[rsize] = nlimb;
111
 
          rsize++;
112
 
        }
 
138
      /* separate blocks, for malloc debugging */
 
139
      remp = TMP_ALLOC_LIMBS (dsize);
 
140
      tp = (zeros > 0 ? TMP_ALLOC_LIMBS (tsize) : NULL);
113
141
    }
114
142
  else
115
143
    {
116
 
      if (rsize > nsize)
117
 
        {
118
 
          MPN_ZERO (rp, rsize - nsize);
119
 
          MPN_COPY (rp + (rsize - nsize), np, nsize);
120
 
        }
121
 
      else
122
 
        {
123
 
          MPN_COPY (rp, np + (nsize - rsize), rsize);
124
 
        }
 
144
      /* one block with conditionalized size, for efficiency */
 
145
      remp = TMP_ALLOC_LIMBS (dsize + (zeros > 0 ? tsize : 0));
 
146
      tp = remp + dsize;
125
147
    }
126
148
 
127
 
  qlimb = mpn_divmod (qp, rp, rsize, dp, dsize);
128
 
  qsize = rsize - dsize;
129
 
  if (qlimb)
 
149
  /* zero extend n into temporary space, if necessary */
 
150
  if (zeros > 0)
130
151
    {
131
 
      qp[qsize] = qlimb;
132
 
      qsize++;
 
152
      MPN_ZERO (tp, zeros);
 
153
      MPN_COPY (tp+zeros, np, nsize);
 
154
      np = tp;
 
155
      nsize = tsize;
133
156
    }
134
157
 
135
 
  {
136
 
    double res;
137
 
    mp_size_t i;
138
 
    mp_size_t scale = nsize - dsize - N_QLIMBS;
139
 
 
140
 
#if defined (__vax__)
141
 
    /* Ignore excess quotient limbs.  This is necessary on a vax
142
 
       with its small double exponent, since we'd otherwise get
143
 
       exponent overflow while forming RES.  */
144
 
    if (qsize > N_QLIMBS)
145
 
      {
146
 
        qp += qsize - N_QLIMBS;
147
 
        scale += qsize - N_QLIMBS;
148
 
        qsize = N_QLIMBS;
149
 
      }
150
 
#endif
151
 
 
152
 
    res = qp[qsize - 1];
153
 
    for (i = qsize - 2; i >= 0; i--)
154
 
      res = res * MP_BASE_AS_DOUBLE + qp[i];
155
 
 
156
 
    res = __gmp_scale2 (res, GMP_NUMB_BITS * scale);
157
 
 
158
 
    TMP_FREE (marker);
159
 
    return sign_quotient >= 0 ? res : -res;
160
 
  }
 
158
  ASSERT (qsize == nsize - dsize + 1);
 
159
  mpn_tdiv_qr (qp, remp, (mp_size_t) 0, np, nsize, dp, dsize);
 
160
 
 
161
  /* strip possible zero high limb */
 
162
  qsize -= (qp[qsize-1] == 0);
 
163
 
 
164
  res = mpn_get_d (qp, qsize, sign_quotient, exp);
 
165
  TMP_FREE;
 
166
  return res;
161
167
}