beta-0.89.2
[luatex.git] / source / libs / gmp / gmp-src / mpq / get_d.c
blobf206cdbc004cacb23f4c371d5d8dbea1809b2e9c
1 /* double mpq_get_d (mpq_t src) -- mpq to double, rounding towards zero.
3 Copyright 1995, 1996, 2001-2005 Free Software Foundation, Inc.
5 This file is part of the GNU MP Library.
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of either:
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
16 * the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any
18 later version.
20 or both in parallel, as here.
22 The GNU MP Library is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 for more details.
27 You should have received copies of the GNU General Public License and the
28 GNU Lesser General Public License along with the GNU MP Library. If not,
29 see https://www.gnu.org/licenses/. */
31 #include <stdio.h> /* for NULL */
32 #include "gmp.h"
33 #include "gmp-impl.h"
34 #include "longlong.h"
37 /* All that's needed is to get the high 53 bits of the quotient num/den,
38 rounded towards zero. More than 53 bits is fine, any excess is ignored
39 by mpn_get_d.
41 N_QLIMBS is how many quotient limbs we need to satisfy the mantissa of a
42 double, assuming the highest of those limbs is non-zero. The target
43 qsize for mpn_tdiv_qr is then 1 more than this, since that function may
44 give a zero in the high limb (and non-zero in the second highest).
46 The use of 8*sizeof(double) in N_QLIMBS is an overestimate of the
47 mantissa bits, but it gets the same result as the true value (53 or 48 or
48 whatever) when rounded up to a multiple of GMP_NUMB_BITS, for non-nails.
50 Enhancements:
52 Use the true mantissa size in the N_QLIMBS formula, to save a divide step
53 in nails.
55 Examine the high limbs of num and den to see if the highest 1 bit of the
56 quotient will fall high enough that just N_QLIMBS-1 limbs is enough to
57 get the necessary bits, thereby saving a division step.
59 Bit shift either num or den to arrange for the above condition on the
60 high 1 bit of the quotient, to save a division step always. A shift to
61 save a division step is definitely worthwhile with mpn_tdiv_qr, though we
62 may want to reassess this on big num/den when a quotient-only division
63 exists.
65 Maybe we could estimate the final exponent using nsize-dsize (and
66 possibly the high limbs of num and den), so as to detect overflow and
67 return infinity or zero quickly. Overflow is never very helpful to an
68 application, and can therefore probably be regarded as abnormal, but we
69 may still like to optimize it if the conditions are easy. (This would
70 only be for float formats we know, unknown formats are not important and
71 can be left to mpn_get_d.)
73 Future:
75 If/when mpn_tdiv_qr supports its qxn parameter we can use that instead of
76 padding n with zeros in temporary space.
78 If/when a quotient-only division exists it can be used here immediately.
79 remp is only to satisfy mpn_tdiv_qr, the remainder is not used.
81 Alternatives:
83 An alternative algorithm, that may be faster:
84 0. Let n be somewhat larger than the number of significant bits in a double.
85 1. Extract the most significant n bits of the denominator, and an equal
86 number of bits from the numerator.
87 2. Interpret the extracted numbers as integers, call them a and b
88 respectively, and develop n bits of the fractions ((a + 1) / b) and
89 (a / (b + 1)) using mpn_divrem.
90 3. If the computed values are identical UP TO THE POSITION WE CARE ABOUT,
91 we are done. If they are different, repeat the algorithm from step 1,
92 but first let n = n * 2.
93 4. If we end up using all bits from the numerator and denominator, fall
94 back to a plain division.
95 5. Just to make life harder, The computation of a + 1 and b + 1 above
96 might give carry-out... Needs special handling. It might work to
97 subtract 1 in both cases instead.
99 Not certain if this approach would be faster than a quotient-only
100 division. Presumably such optimizations are the sort of thing we would
101 like to have helping everywhere that uses a quotient-only division. */
103 double
104 mpq_get_d (mpq_srcptr src)
106 double res;
107 mp_srcptr np, dp;
108 mp_ptr remp, tp;
109 mp_size_t nsize = SIZ(NUM(src));
110 mp_size_t dsize = SIZ(DEN(src));
111 mp_size_t qsize, prospective_qsize, zeros, chop, tsize;
112 mp_size_t sign_quotient = nsize;
113 long exp;
114 #define N_QLIMBS (1 + (sizeof (double) + GMP_LIMB_BYTES-1) / GMP_LIMB_BYTES)
115 mp_limb_t qarr[N_QLIMBS + 1];
116 mp_ptr qp = qarr;
117 TMP_DECL;
119 ASSERT (dsize > 0); /* canonical src */
121 /* mpn_get_d below requires a non-zero operand */
122 if (UNLIKELY (nsize == 0))
123 return 0.0;
125 TMP_MARK;
126 nsize = ABS (nsize);
127 dsize = ABS (dsize);
128 np = PTR(NUM(src));
129 dp = PTR(DEN(src));
131 prospective_qsize = nsize - dsize + 1; /* from using given n,d */
132 qsize = N_QLIMBS + 1; /* desired qsize */
134 zeros = qsize - prospective_qsize; /* padding n to get qsize */
135 exp = (long) -zeros * GMP_NUMB_BITS; /* relative to low of qp */
137 chop = MAX (-zeros, 0); /* negative zeros means shorten n */
138 np += chop;
139 nsize -= chop;
140 zeros += chop; /* now zeros >= 0 */
142 tsize = nsize + zeros; /* size for possible copy of n */
144 if (WANT_TMP_DEBUG)
146 /* separate blocks, for malloc debugging */
147 remp = TMP_ALLOC_LIMBS (dsize);
148 tp = (zeros > 0 ? TMP_ALLOC_LIMBS (tsize) : NULL);
150 else
152 /* one block with conditionalized size, for efficiency */
153 remp = TMP_ALLOC_LIMBS (dsize + (zeros > 0 ? tsize : 0));
154 tp = remp + dsize;
157 /* zero extend n into temporary space, if necessary */
158 if (zeros > 0)
160 MPN_ZERO (tp, zeros);
161 MPN_COPY (tp+zeros, np, nsize);
162 np = tp;
163 nsize = tsize;
166 ASSERT (qsize == nsize - dsize + 1);
167 mpn_tdiv_qr (qp, remp, (mp_size_t) 0, np, nsize, dp, dsize);
169 /* strip possible zero high limb */
170 qsize -= (qp[qsize-1] == 0);
172 res = mpn_get_d (qp, qsize, sign_quotient, exp);
173 TMP_FREE;
174 return res;