beta-0.89.2
[luatex.git] / source / libs / gmp / gmp-src / mpf / get_str.c
blob682819daaabbd0160b7af705adf13ad441a72013
1 /* mpf_get_str (digit_ptr, exp, base, n_digits, a) -- Convert the floating
2 point number A to a base BASE number and store N_DIGITS raw digits at
3 DIGIT_PTR, and the base BASE exponent in the word pointed to by EXP. For
4 example, the number 3.1416 would be returned as "31416" in DIGIT_PTR and
5 1 in EXP.
7 Copyright 1993-1997, 2000-2003, 2005, 2006, 2011, 2015 Free Software
8 Foundation, Inc.
10 This file is part of the GNU MP Library.
12 The GNU MP Library is free software; you can redistribute it and/or modify
13 it under the terms of either:
15 * the GNU Lesser General Public License as published by the Free
16 Software Foundation; either version 3 of the License, or (at your
17 option) any later version.
21 * the GNU General Public License as published by the Free Software
22 Foundation; either version 2 of the License, or (at your option) any
23 later version.
25 or both in parallel, as here.
27 The GNU MP Library is distributed in the hope that it will be useful, but
28 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30 for more details.
32 You should have received copies of the GNU General Public License and the
33 GNU Lesser General Public License along with the GNU MP Library. If not,
34 see https://www.gnu.org/licenses/. */
36 #include <stdlib.h> /* for NULL */
37 #include "gmp.h"
38 #include "gmp-impl.h"
39 #include "longlong.h" /* for count_leading_zeros */
41 /* Could use some more work.
43 1. Allocation is excessive. Try to combine areas. Perhaps use result
44 string area for temp limb space?
45 2. We generate up to two limbs of extra digits. This is because we don't
46 check the exact number of bits in the input operand, and from that
47 compute an accurate exponent (variable e in the code). It would be
48 cleaner and probably somewhat faster to change this.
51 /* Compute base^exp and return the most significant prec limbs in rp[].
52 Put the count of omitted low limbs in *ign.
53 Return the actual size (which might be less than prec).
54 Allocation of rp[] and the temporary tp[] should be 2*prec+2 limbs. */
55 static mp_size_t
56 mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
57 mp_limb_t base, unsigned long exp,
58 mp_size_t prec, mp_ptr tp)
60 mp_size_t ign; /* counts number of ignored low limbs in r */
61 mp_size_t off; /* keeps track of offset where value starts */
62 mp_ptr passed_rp = rp;
63 mp_size_t rn;
64 int cnt;
65 int i;
67 if (exp == 0)
69 rp[0] = 1;
70 *ignp = 0;
71 return 1;
74 rp[0] = base;
75 rn = 1;
76 off = 0;
77 ign = 0;
78 count_leading_zeros (cnt, exp);
79 for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
81 mpn_sqr (tp, rp + off, rn);
82 rn = 2 * rn;
83 rn -= tp[rn - 1] == 0;
84 ign <<= 1;
86 off = 0;
87 if (rn > prec)
89 ign += rn - prec;
90 off = rn - prec;
91 rn = prec;
93 MP_PTR_SWAP (rp, tp);
95 if (((exp >> i) & 1) != 0)
97 mp_limb_t cy;
98 cy = mpn_mul_1 (rp, rp + off, rn, base);
99 rp[rn] = cy;
100 rn += cy != 0;
101 off = 0;
105 if (rn > prec)
107 ASSERT (rn == prec + 1);
109 ign += rn - prec;
110 rp += rn - prec;
111 rn = prec;
114 /* With somewhat less than 50% probability, we can skip this copy. */
115 if (passed_rp != rp + off)
116 MPN_COPY_INCR (passed_rp, rp + off, rn);
117 *ignp = ign;
118 return rn;
121 char *
122 mpf_get_str (char *dbuf, mp_exp_t *exp, int base, size_t n_digits, mpf_srcptr u)
124 mp_exp_t ue;
125 mp_size_t n_limbs_needed;
126 size_t max_digits;
127 mp_ptr up, pp, tp;
128 mp_size_t un, pn, tn;
129 unsigned char *tstr;
130 mp_exp_t exp_in_base;
131 size_t n_digits_computed;
132 mp_size_t i;
133 const char *num_to_text;
134 size_t alloc_size = 0;
135 char *dp;
136 TMP_DECL;
138 up = PTR(u);
139 un = ABSIZ(u);
140 ue = EXP(u);
142 if (base >= 0)
144 num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
145 if (base <= 1)
146 base = 10;
147 else if (base > 36)
149 num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
150 if (base > 62)
151 return NULL;
154 else
156 base = -base;
157 if (base <= 1)
158 base = 10;
159 else if (base > 36)
160 return NULL;
161 num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
164 MPF_SIGNIFICANT_DIGITS (max_digits, base, PREC(u));
165 if (n_digits == 0 || n_digits > max_digits)
166 n_digits = max_digits;
168 if (dbuf == 0)
170 /* We didn't get a string from the user. Allocate one (and return
171 a pointer to it) with space for `-' and terminating null. */
172 alloc_size = n_digits + 2;
173 dbuf = (char *) (*__gmp_allocate_func) (n_digits + 2);
176 if (un == 0)
178 *exp = 0;
179 *dbuf = 0;
180 n_digits = 0;
181 goto done;
184 TMP_MARK;
186 /* Allocate temporary digit space. We can't put digits directly in the user
187 area, since we generate more digits than requested. (We allocate
188 2 * GMP_LIMB_BITS extra bytes because of the digit block nature of the
189 conversion.) */
190 tstr = (unsigned char *) TMP_ALLOC (n_digits + 2 * GMP_LIMB_BITS + 3);
192 LIMBS_PER_DIGIT_IN_BASE (n_limbs_needed, n_digits, base);
194 if (un > n_limbs_needed)
196 up += un - n_limbs_needed;
197 un = n_limbs_needed;
200 TMP_ALLOC_LIMBS_2 (pp, 2 * n_limbs_needed + 4,
201 tp, 2 * n_limbs_needed + 4);
203 if (ue <= n_limbs_needed)
205 /* We need to multiply number by base^n to get an n_digits integer part. */
206 mp_size_t n_more_limbs_needed, ign, off;
207 unsigned long e;
209 n_more_limbs_needed = n_limbs_needed - ue;
210 DIGITS_IN_BASE_PER_LIMB (e, n_more_limbs_needed, base);
212 pn = mpn_pow_1_highpart (pp, &ign, (mp_limb_t) base, e, n_limbs_needed + 1, tp);
213 if (un > pn)
214 mpn_mul (tp, up, un, pp, pn); /* FIXME: mpn_mul_highpart */
215 else
216 mpn_mul (tp, pp, pn, up, un); /* FIXME: mpn_mul_highpart */
217 tn = un + pn;
218 tn -= tp[tn - 1] == 0;
219 off = un - ue - ign;
220 if (off < 0)
222 MPN_COPY_DECR (tp - off, tp, tn);
223 MPN_ZERO (tp, -off);
224 tn -= off;
225 off = 0;
227 n_digits_computed = mpn_get_str (tstr, base, tp + off, tn - off);
229 exp_in_base = n_digits_computed - e;
231 else
233 /* We need to divide number by base^n to get an n_digits integer part. */
234 mp_size_t n_less_limbs_needed, ign, off, xn;
235 unsigned long e;
236 mp_ptr dummyp, xp;
238 n_less_limbs_needed = ue - n_limbs_needed;
239 DIGITS_IN_BASE_PER_LIMB (e, n_less_limbs_needed, base);
241 pn = mpn_pow_1_highpart (pp, &ign, (mp_limb_t) base, e, n_limbs_needed + 1, tp);
243 xn = n_limbs_needed + (n_less_limbs_needed-ign);
244 xp = TMP_ALLOC_LIMBS (xn);
245 off = xn - un;
246 MPN_ZERO (xp, off);
247 MPN_COPY (xp + off, up, un);
249 dummyp = TMP_ALLOC_LIMBS (pn);
250 mpn_tdiv_qr (tp, dummyp, (mp_size_t) 0, xp, xn, pp, pn);
251 tn = xn - pn + 1;
252 tn -= tp[tn - 1] == 0;
253 n_digits_computed = mpn_get_str (tstr, base, tp, tn);
255 exp_in_base = n_digits_computed + e;
258 /* We should normally have computed too many digits. Round the result
259 at the point indicated by n_digits. */
260 if (n_digits_computed > n_digits)
262 size_t i;
263 /* Round the result. */
264 if (tstr[n_digits] * 2 >= base)
266 n_digits_computed = n_digits;
267 for (i = n_digits - 1;; i--)
269 unsigned int x;
270 x = ++(tstr[i]);
271 if (x != base)
272 break;
273 n_digits_computed--;
274 if (i == 0)
276 /* We had something like `bbbbbbb...bd', where 2*d >= base
277 and `b' denotes digit with significance base - 1.
278 This rounds up to `1', increasing the exponent. */
279 tstr[0] = 1;
280 n_digits_computed = 1;
281 exp_in_base++;
282 break;
288 /* We might have fewer digits than requested as a result of rounding above,
289 (i.e. 0.999999 => 1.0) or because we have a number that simply doesn't
290 need many digits in this base (e.g., 0.125 in base 10). */
291 if (n_digits > n_digits_computed)
292 n_digits = n_digits_computed;
294 /* Remove trailing 0. There can be many zeros. */
295 while (n_digits != 0 && tstr[n_digits - 1] == 0)
296 n_digits--;
298 dp = dbuf + (SIZ(u) < 0);
300 /* Translate to ASCII and copy to result string. */
301 for (i = 0; i < n_digits; i++)
302 dp[i] = num_to_text[tstr[i]];
303 dp[n_digits] = 0;
305 *exp = exp_in_base;
307 if (SIZ(u) < 0)
309 dbuf[0] = '-';
310 n_digits++;
313 TMP_FREE;
315 done:
316 /* If the string was alloced then resize it down to the actual space
317 required. */
318 if (alloc_size != 0)
320 __GMP_REALLOCATE_FUNC_MAYBE_TYPE (dbuf, alloc_size, n_digits + 1, char);
323 return dbuf;