/* mpf_get_str (digit_ptr, exp, base, n_digits, a) -- Convert the floating point number A to a base BASE number and store N_DIGITS raw digits at DIGIT_PTR, and the base BASE exponent in the word pointed to by EXP. For example, the number 3.1416 would be returned as "31416" in DIGIT_PTR and 1 in EXP. Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gmp.h" #include "gmp-impl.h" #include "longlong.h" /* New algorithm for converting fractions (951019): 0. Call the fraction to convert F. 1. Compute [exp * log(2^BITS_PER_MP_LIMB)/log(B)], i.e., [exp * BITS_PER_MP_LIMB * __mp_bases[B].chars_per_bit_exactly]. Exp is the number of limbs between the limb point and the most significant non-zero limb. Call this result n. 2. Compute B^n. 3. F*B^n will now be just below 1, which can be converted easily. (Just multiply by B repeatedly, and see the digits fall out as integers.) We should interrupt the conversion process of F*B^n as soon as the number of digits requested have been generated. New algorithm for converting integers (951019): 0. Call the integer to convert I. 1. Compute [exp * log(2^BITS_PER_MP_LIMB)/log(B)], i.e., [exp BITS_PER_MP_LIMB * __mp_bases[B].chars_per_bit_exactly]. Exp is the number of limbs between the limb point and the least significant non-zero limb. Call this result n. 2. Compute B^n. 3. I/B^n can be converted easily. (Just divide by B repeatedly. In GMP, this is best done by calling mpn_get_str.) Note that converting I/B^n could yield more digits than requested. For efficiency, the variable n above should be set larger in such cases, to kill all undesired digits in the division in step 3. */ char * #if __STDC__ mpf_get_str (char *digit_ptr, mp_exp_t *exp, int base, size_t n_digits, mpf_srcptr u) #else mpf_get_str (digit_ptr, exp, base, n_digits, u) char *digit_ptr; mp_exp_t *exp; int base; size_t n_digits; mpf_srcptr u; #endif { mp_size_t usize; mp_exp_t uexp; unsigned char *str; size_t str_size; char *num_to_text; long i; /* should be size_t */ mp_ptr rp; mp_limb_t big_base; size_t digits_computed_so_far; int dig_per_u; mp_srcptr up; unsigned char *tstr; mp_exp_t exp_in_base; TMP_DECL (marker); TMP_MARK (marker); usize = u->_mp_size; uexp = u->_mp_exp; if (base >= 0) { if (base == 0) base = 10; num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz"; } else { base = -base; num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } /* Don't compute more digits than U can accurately represent. Also, if 0 digits were requested, give *exactly* as many digits as can be accurately represented. */ { size_t max_digits = (((u->_mp_prec - 1) * BITS_PER_MP_LIMB) * __mp_bases[base].chars_per_bit_exactly); if (n_digits == 0 || n_digits > max_digits) n_digits = max_digits; } if (digit_ptr == 0) { /* We didn't get a string from the user. Allocate one (and return a pointer to it) with space for `-' and terminating null. */ digit_ptr = (char *) (*_mp_allocate_func) (n_digits + 2); } if (usize == 0) { *exp = 0; *digit_ptr = 0; return digit_ptr; } str = (unsigned char *) digit_ptr; /* Allocate temporary digit space. We can't put digits directly in the user area, since we almost always generate more digits than requested. */ tstr = (unsigned char *) TMP_ALLOC (n_digits + 3 * BITS_PER_MP_LIMB); if (usize < 0) { *digit_ptr = '-'; str++; usize = -usize; } digits_computed_so_far = 0; if (uexp > usize) { /* The number has just an integral part. */ mp_size_t rsize; mp_size_t exp_in_limbs; mp_size_t msize; mp_ptr tp, xp, mp; int cnt; mp_limb_t cy; mp_size_t start_str; mp_size_t n_limbs; n_limbs = 2 + ((mp_size_t) (n_digits / __mp_bases[base].chars_per_bit_exactly) / BITS_PER_MP_LIMB); /* Compute n such that [u/B^n] contains (somewhat) more than n_digits digits. (We compute less than that only if that is an exact number, i.e., exp is small enough.) */ exp_in_limbs = uexp; if (n_limbs >= exp_in_limbs) { /* The number is so small that we convert the entire number. */ exp_in_base = 0; rp = (mp_ptr) TMP_ALLOC (exp_in_limbs * BYTES_PER_MP_LIMB); MPN_ZERO (rp, exp_in_limbs - usize); MPN_COPY (rp + (exp_in_limbs - usize), u->_mp_d, usize); rsize = exp_in_limbs; } else { exp_in_limbs -= n_limbs; exp_in_base = (((exp_in_limbs * BITS_PER_MP_LIMB - 1)) * __mp_bases[base].chars_per_bit_exactly); rsize = exp_in_limbs + 1; rp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); tp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); rp[0] = base; rsize = 1; count_leading_zeros (cnt, exp_in_base); for (i = BITS_PER_MP_LIMB - cnt - 2; i >= 0; i--) { mpn_mul_n (tp, rp, rp, rsize); rsize = 2 * rsize; rsize -= tp[rsize - 1] == 0; xp = tp; tp = rp; rp = xp; if (((exp_in_base >> i) & 1) != 0) { cy = mpn_mul_1 (rp, rp, rsize, (mp_limb_t) base); rp[rsize] = cy; rsize += cy != 0; } } mp = u->_mp_d; msize = usize; { mp_ptr qp; mp_limb_t qflag; mp_size_t xtra; if (msize < rsize) { mp_ptr tmp = (mp_ptr) TMP_ALLOC ((rsize+1)* BYTES_PER_MP_LIMB); MPN_ZERO (tmp, rsize - msize); MPN_COPY (tmp + rsize - msize, mp, msize); mp = tmp; msize = rsize; } else { mp_ptr tmp = (mp_ptr) TMP_ALLOC ((msize+1)* BYTES_PER_MP_LIMB); MPN_COPY (tmp, mp, msize); mp = tmp; } count_leading_zeros (cnt, rp[rsize - 1]); cy = 0; if (cnt != 0) { mpn_lshift (rp, rp, rsize, cnt); cy = mpn_lshift (mp, mp, msize, cnt); if (cy) mp[msize++] = cy; } { mp_size_t qsize = n_limbs + (cy != 0); qp = (mp_ptr) TMP_ALLOC ((qsize + 1) * BYTES_PER_MP_LIMB); xtra = qsize - (msize - rsize); qflag = mpn_divrem (qp, xtra, mp, msize, rp, rsize); qp[qsize] = qflag; rsize = qsize + qflag; rp = qp; } } } str_size = mpn_get_str (tstr, base, rp, rsize); if (str_size > n_digits + 3 * BITS_PER_MP_LIMB) abort (); start_str = 0; while (tstr[start_str] == 0) start_str++; for (i = start_str; i < str_size; i++) { tstr[digits_computed_so_far++] = tstr[i]; if (digits_computed_so_far > n_digits) break; } exp_in_base = exp_in_base + str_size - start_str; goto finish_up; } exp_in_base = 0; if (uexp > 0) { /* The number has an integral part, convert that first. If there is a fractional part too, it will be handled later. */ mp_size_t start_str; rp = (mp_ptr) TMP_ALLOC (uexp * BYTES_PER_MP_LIMB); up = u->_mp_d + usize - uexp; MPN_COPY (rp, up, uexp); str_size = mpn_get_str (tstr, base, rp, uexp); start_str = 0; while (tstr[start_str] == 0) start_str++; for (i = start_str; i < str_size; i++) { tstr[digits_computed_so_far++] = tstr[i]; if (digits_computed_so_far > n_digits) { exp_in_base = str_size - start_str; goto finish_up; } } exp_in_base = str_size - start_str; /* Modify somewhat and fall out to convert fraction... */ usize -= uexp; uexp = 0; } if (usize <= 0) goto finish_up; /* Convert the fraction. */ { mp_size_t rsize, msize; mp_ptr rp, tp, xp, mp; int cnt; mp_limb_t cy; mp_exp_t nexp; big_base = __mp_bases[base].big_base; dig_per_u = __mp_bases[base].chars_per_limb; /* Hack for correctly (although not efficiently) converting to bases that are powers of 2. If we deem it important, we could handle powers of 2 by shifting and masking (just like mpn_get_str). */ if (big_base < 10) /* logarithm of base when power of two */ { int logbase = big_base; if (dig_per_u * logbase == BITS_PER_MP_LIMB) dig_per_u--; big_base = (mp_limb_t) 1 << (dig_per_u * logbase); /* fall out to general code... */ } #if 0 if (0 && uexp == 0) { rp = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB); up = u->_mp_d; MPN_COPY (rp, up, usize); rsize = usize; nexp = 0; } else {} #endif uexp = -uexp; if (u->_mp_d[usize - 1] == 0) cnt = 0; else count_leading_zeros (cnt, u->_mp_d[usize - 1]); nexp = ((uexp * BITS_PER_MP_LIMB) + cnt) * __mp_bases[base].chars_per_bit_exactly; if (nexp == 0) { rp = (mp_ptr) TMP_ALLOC (usize * BYTES_PER_MP_LIMB); up = u->_mp_d; MPN_COPY (rp, up, usize); rsize = usize; } else { rsize = uexp + 2; rp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); tp = (mp_ptr) TMP_ALLOC (rsize * BYTES_PER_MP_LIMB); rp[0] = base; rsize = 1; count_leading_zeros (cnt, nexp); for (i = BITS_PER_MP_LIMB - cnt - 2; i >= 0; i--) { mpn_mul_n (tp, rp, rp, rsize); rsize = 2 * rsize; rsize -= tp[rsize - 1] == 0; xp = tp; tp = rp; rp = xp; if (((nexp >> i) & 1) != 0) { cy = mpn_mul_1 (rp, rp, rsize, (mp_limb_t) base); rp[rsize] = cy; rsize += cy != 0; } } /* Did our multiplier (base^nexp) cancel with uexp? */ #if 0 if (uexp != rsize) { do { cy = mpn_mul_1 (rp, rp, rsize, big_base); nexp += dig_per_u; } while (cy == 0); rp[rsize++] = cy; } #endif mp = u->_mp_d; msize = usize; tp = (mp_ptr) TMP_ALLOC ((rsize + msize) * BYTES_PER_MP_LIMB); if (rsize > msize) cy = mpn_mul (tp, rp, rsize, mp, msize); else cy = mpn_mul (tp, mp, msize, rp, rsize); rsize += msize; rsize -= cy == 0; rp = tp; /* If we already output digits (for an integral part) pad leading zeros. */ if (digits_computed_so_far != 0) for (i = 0; i < nexp; i++) tstr[digits_computed_so_far++] = 0; } while (digits_computed_so_far <= n_digits) { /* For speed: skip trailing zeroes. */ if (rp[0] == 0) { rp++; rsize--; if (rsize == 0) { n_digits = digits_computed_so_far; break; } } cy = mpn_mul_1 (rp, rp, rsize, big_base); if (digits_computed_so_far == 0 && cy == 0) { abort (); nexp += dig_per_u; continue; } /* Convert N1 from BIG_BASE to a string of digits in BASE using single precision operations. */ { unsigned char *s = tstr + digits_computed_so_far + dig_per_u; for (i = dig_per_u - 1; i >= 0; i--) { *--s = cy % base; cy /= base; } } digits_computed_so_far += dig_per_u; } if (exp_in_base == 0) exp_in_base = -nexp; } finish_up: /* We can have at most one leading 0. Remove it. */ if (tstr[0] == 0) { tstr++; digits_computed_so_far--; exp_in_base--; } /* We should normally have computed too many digits. Round the result at the point indicated by n_digits. */ if (digits_computed_so_far > n_digits) { /* Round the result. */ if (tstr[n_digits] * 2 >= base) { digits_computed_so_far = n_digits; for (i = n_digits - 1; i >= 0; i--) { unsigned int x; x = ++(tstr[i]); if (x < base) goto rounded_ok; digits_computed_so_far--; } tstr[0] = 1; digits_computed_so_far = 1; exp_in_base++; rounded_ok:; } } /* We might have fewer digits than requested as a result of rounding above, (i.e. 0.999999 => 1.0) or because we have a number that simply doesn't need many digits in this base (i.e., 0.125 in base 10). */ if (n_digits > digits_computed_so_far) n_digits = digits_computed_so_far; /* Remove trailing 0. There can be many zeros. */ while (n_digits != 0 && tstr[n_digits - 1] == 0) n_digits--; /* Translate to ascii and null-terminate. */ for (i = 0; i < n_digits; i++) *str++ = num_to_text[tstr[i]]; *str = 0; *exp = exp_in_base; TMP_FREE (marker); return digit_ptr; } #if COPY_THIS_TO_OTHER_PLACES /* Use this expression in lots of places in the library instead of the count_leading_zeros+expression that is used currently. This expression is much more accurate and will save odles of memory. */ rsize = ((mp_size_t) (exp_in_base / __mp_bases[base].chars_per_bit_exactly) + BITS_PER_MP_LIMB) / BITS_PER_MP_LIMB; #endif