Blame mpn/generic/get_str.c

Packit 5c3484
/* mpn_get_str -- Convert {UP,USIZE} to a base BASE string in STR.
Packit 5c3484
Packit 5c3484
   Contributed to the GNU project by Torbjorn Granlund.
Packit 5c3484
Packit 5c3484
   THE FUNCTIONS IN THIS FILE, EXCEPT mpn_get_str, ARE INTERNAL WITH A MUTABLE
Packit 5c3484
   INTERFACE.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN
Packit 5c3484
   FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE
Packit 5c3484
   GNU MP RELEASE.
Packit 5c3484
Packit 5c3484
Copyright 1991-1994, 1996, 2000-2002, 2004, 2006-2008, 2011, 2012 Free Software
Packit 5c3484
Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
/* Conversion of U {up,un} to a string in base b.  Internally, we convert to
Packit 5c3484
   base B = b^m, the largest power of b that fits a limb.  Basic algorithms:
Packit 5c3484
Packit 5c3484
  A) Divide U repeatedly by B, generating a quotient and remainder, until the
Packit 5c3484
     quotient becomes zero.  The remainders hold the converted digits.  Digits
Packit 5c3484
     come out from right to left.  (Used in mpn_sb_get_str.)
Packit 5c3484
Packit 5c3484
  B) Divide U by b^g, for g such that 1/b <= U/b^g < 1, generating a fraction.
Packit 5c3484
     Then develop digits by multiplying the fraction repeatedly by b.  Digits
Packit 5c3484
     come out from left to right.  (Currently not used herein, except for in
Packit 5c3484
     code for converting single limbs to individual digits.)
Packit 5c3484
Packit 5c3484
  C) Compute B^1, B^2, B^4, ..., B^s, for s such that B^s is just above
Packit 5c3484
     sqrt(U).  Then divide U by B^s, generating quotient and remainder.
Packit 5c3484
     Recursively convert the quotient, then the remainder, using the
Packit 5c3484
     precomputed powers.  Digits come out from left to right.  (Used in
Packit 5c3484
     mpn_dc_get_str.)
Packit 5c3484
Packit 5c3484
  When using algorithm C, algorithm B might be suitable for basecase code,
Packit 5c3484
  since the required b^g power will be readily accessible.
Packit 5c3484
Packit 5c3484
  Optimization ideas:
Packit 5c3484
  1. The recursive function of (C) could use less temporary memory.  The powtab
Packit 5c3484
     allocation could be trimmed with some computation, and the tmp area could
Packit 5c3484
     be reduced, or perhaps eliminated if up is reused for both quotient and
Packit 5c3484
     remainder (it is currently used just for remainder).
Packit 5c3484
  2. Store the powers of (C) in normalized form, with the normalization count.
Packit 5c3484
     Quotients will usually need to be left-shifted before each divide, and
Packit 5c3484
     remainders will either need to be left-shifted of right-shifted.
Packit 5c3484
  3. In the code for developing digits from a single limb, we could avoid using
Packit 5c3484
     a full umul_ppmm except for the first (or first few) digits, provided base
Packit 5c3484
     is even.  Subsequent digits can be developed using plain multiplication.
Packit 5c3484
     (This saves on register-starved machines (read x86) and on all machines
Packit 5c3484
     that generate the upper product half using a separate instruction (alpha,
Packit 5c3484
     powerpc, IA-64) or lacks such support altogether (sparc64, hppa64).
Packit 5c3484
  4. Separate mpn_dc_get_str basecase code from code for small conversions. The
Packit 5c3484
     former code will have the exact right power readily available in the
Packit 5c3484
     powtab parameter for dividing the current number into a fraction.  Convert
Packit 5c3484
     that using algorithm B.
Packit 5c3484
  5. Completely avoid division.  Compute the inverses of the powers now in
Packit 5c3484
     powtab instead of the actual powers.
Packit 5c3484
  6. Decrease powtab allocation for even bases.  E.g. for base 10 we could save
Packit 5c3484
     about 30% (1-log(5)/log(10)).
Packit 5c3484
Packit 5c3484
  Basic structure of (C):
Packit 5c3484
    mpn_get_str:
Packit 5c3484
      if POW2_P (n)
Packit 5c3484
	...
Packit 5c3484
      else
Packit 5c3484
	if (un < GET_STR_PRECOMPUTE_THRESHOLD)
Packit 5c3484
	  mpn_sb_get_str (str, base, up, un);
Packit 5c3484
	else
Packit 5c3484
	  precompute_power_tables
Packit 5c3484
	  mpn_dc_get_str
Packit 5c3484
Packit 5c3484
    mpn_dc_get_str:
Packit 5c3484
	mpn_tdiv_qr
Packit 5c3484
	if (qn < GET_STR_DC_THRESHOLD)
Packit 5c3484
	  mpn_sb_get_str
Packit 5c3484
	else
Packit 5c3484
	  mpn_dc_get_str
Packit 5c3484
	if (rn < GET_STR_DC_THRESHOLD)
Packit 5c3484
	  mpn_sb_get_str
Packit 5c3484
	else
Packit 5c3484
	  mpn_dc_get_str
Packit 5c3484
Packit 5c3484
Packit 5c3484
  The reason for the two threshold values is the cost of
Packit 5c3484
  precompute_power_tables.  GET_STR_PRECOMPUTE_THRESHOLD will be considerably
Packit 5c3484
  larger than GET_STR_PRECOMPUTE_THRESHOLD.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The x86s and m68020 have a quotient and remainder "div" instruction and
Packit 5c3484
   gcc recognises an adjacent "/" and "%" can be combined using that.
Packit 5c3484
   Elsewhere "/" and "%" are either separate instructions, or separate
Packit 5c3484
   libgcc calls (which unfortunately gcc as of version 3.0 doesn't combine).
Packit 5c3484
   A multiply and subtract should be faster than a "%" in those cases.  */
Packit 5c3484
#if HAVE_HOST_CPU_FAMILY_x86            \
Packit 5c3484
  || HAVE_HOST_CPU_m68020               \
Packit 5c3484
  || HAVE_HOST_CPU_m68030               \
Packit 5c3484
  || HAVE_HOST_CPU_m68040               \
Packit 5c3484
  || HAVE_HOST_CPU_m68060               \
Packit 5c3484
  || HAVE_HOST_CPU_m68360 /* CPU32 */
Packit 5c3484
#define udiv_qrnd_unnorm(q,r,n,d)       \
Packit 5c3484
  do {                                  \
Packit 5c3484
    mp_limb_t  __q = (n) / (d);         \
Packit 5c3484
    mp_limb_t  __r = (n) % (d);         \
Packit 5c3484
    (q) = __q;                          \
Packit 5c3484
    (r) = __r;                          \
Packit 5c3484
  } while (0)
Packit 5c3484
#else
Packit 5c3484
#define udiv_qrnd_unnorm(q,r,n,d)       \
Packit 5c3484
  do {                                  \
Packit 5c3484
    mp_limb_t  __q = (n) / (d);         \
Packit 5c3484
    mp_limb_t  __r = (n) - __q*(d);     \
Packit 5c3484
    (q) = __q;                          \
Packit 5c3484
    (r) = __r;                          \
Packit 5c3484
  } while (0)
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484

Packit 5c3484
/* Convert {up,un} to a string in base base, and put the result in str.
Packit 5c3484
   Generate len characters, possibly padding with zeros to the left.  If len is
Packit 5c3484
   zero, generate as many characters as required.  Return a pointer immediately
Packit 5c3484
   after the last digit of the result string.  Complexity is O(un^2); intended
Packit 5c3484
   for small conversions.  */
Packit 5c3484
static unsigned char *
Packit 5c3484
mpn_sb_get_str (unsigned char *str, size_t len,
Packit 5c3484
		mp_ptr up, mp_size_t un, int base)
Packit 5c3484
{
Packit 5c3484
  mp_limb_t rl, ul;
Packit 5c3484
  unsigned char *s;
Packit 5c3484
  size_t l;
Packit 5c3484
  /* Allocate memory for largest possible string, given that we only get here
Packit 5c3484
     for operands with un < GET_STR_PRECOMPUTE_THRESHOLD and that the smallest
Packit 5c3484
     base is 3.  7/11 is an approximation to 1/log2(3).  */
Packit 5c3484
#if TUNE_PROGRAM_BUILD
Packit 5c3484
#define BUF_ALLOC (GET_STR_THRESHOLD_LIMIT * GMP_LIMB_BITS * 7 / 11)
Packit 5c3484
#else
Packit 5c3484
#define BUF_ALLOC (GET_STR_PRECOMPUTE_THRESHOLD * GMP_LIMB_BITS * 7 / 11)
Packit 5c3484
#endif
Packit 5c3484
  unsigned char buf[BUF_ALLOC];
Packit 5c3484
#if TUNE_PROGRAM_BUILD
Packit 5c3484
  mp_limb_t rp[GET_STR_THRESHOLD_LIMIT];
Packit 5c3484
#else
Packit 5c3484
  mp_limb_t rp[GET_STR_PRECOMPUTE_THRESHOLD];
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
  if (base == 10)
Packit 5c3484
    {
Packit 5c3484
      /* Special case code for base==10 so that the compiler has a chance to
Packit 5c3484
	 optimize things.  */
Packit 5c3484
Packit 5c3484
      MPN_COPY (rp + 1, up, un);
Packit 5c3484
Packit 5c3484
      s = buf + BUF_ALLOC;
Packit 5c3484
      while (un > 1)
Packit 5c3484
	{
Packit 5c3484
	  int i;
Packit 5c3484
	  mp_limb_t frac, digit;
Packit 5c3484
	  MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
Packit 5c3484
					 MP_BASES_BIG_BASE_10,
Packit 5c3484
					 MP_BASES_BIG_BASE_INVERTED_10,
Packit 5c3484
					 MP_BASES_NORMALIZATION_STEPS_10);
Packit 5c3484
	  un -= rp[un] == 0;
Packit 5c3484
	  frac = (rp[0] + 1) << GMP_NAIL_BITS;
Packit 5c3484
	  s -= MP_BASES_CHARS_PER_LIMB_10;
Packit 5c3484
#if HAVE_HOST_CPU_FAMILY_x86
Packit 5c3484
	  /* The code below turns out to be a bit slower for x86 using gcc.
Packit 5c3484
	     Use plain code.  */
Packit 5c3484
	  i = MP_BASES_CHARS_PER_LIMB_10;
Packit 5c3484
	  do
Packit 5c3484
	    {
Packit 5c3484
	      umul_ppmm (digit, frac, frac, 10);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	    }
Packit 5c3484
	  while (--i);
Packit 5c3484
#else
Packit 5c3484
	  /* Use the fact that 10 in binary is 1010, with the lowest bit 0.
Packit 5c3484
	     After a few umul_ppmm, we will have accumulated enough low zeros
Packit 5c3484
	     to use a plain multiply.  */
Packit 5c3484
	  if (MP_BASES_NORMALIZATION_STEPS_10 == 0)
Packit 5c3484
	    {
Packit 5c3484
	      umul_ppmm (digit, frac, frac, 10);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	    }
Packit 5c3484
	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 1)
Packit 5c3484
	    {
Packit 5c3484
	      umul_ppmm (digit, frac, frac, 10);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	    }
Packit 5c3484
	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 2)
Packit 5c3484
	    {
Packit 5c3484
	      umul_ppmm (digit, frac, frac, 10);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	    }
Packit 5c3484
	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 3)
Packit 5c3484
	    {
Packit 5c3484
	      umul_ppmm (digit, frac, frac, 10);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	    }
Packit 5c3484
	  i = (MP_BASES_CHARS_PER_LIMB_10 - ((MP_BASES_NORMALIZATION_STEPS_10 < 4)
Packit 5c3484
					     ? (4-MP_BASES_NORMALIZATION_STEPS_10)
Packit 5c3484
					     : 0));
Packit 5c3484
	  frac = (frac + 0xf) >> 4;
Packit 5c3484
	  do
Packit 5c3484
	    {
Packit 5c3484
	      frac *= 10;
Packit 5c3484
	      digit = frac >> (GMP_LIMB_BITS - 4);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	      frac &= (~(mp_limb_t) 0) >> 4;
Packit 5c3484
	    }
Packit 5c3484
	  while (--i);
Packit 5c3484
#endif
Packit 5c3484
	  s -= MP_BASES_CHARS_PER_LIMB_10;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      ul = rp[1];
Packit 5c3484
      while (ul != 0)
Packit 5c3484
	{
Packit 5c3484
	  udiv_qrnd_unnorm (ul, rl, ul, 10);
Packit 5c3484
	  *--s = rl;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  else /* not base 10 */
Packit 5c3484
    {
Packit 5c3484
      unsigned chars_per_limb;
Packit 5c3484
      mp_limb_t big_base, big_base_inverted;
Packit 5c3484
      unsigned normalization_steps;
Packit 5c3484
Packit 5c3484
      chars_per_limb = mp_bases[base].chars_per_limb;
Packit 5c3484
      big_base = mp_bases[base].big_base;
Packit 5c3484
      big_base_inverted = mp_bases[base].big_base_inverted;
Packit 5c3484
      count_leading_zeros (normalization_steps, big_base);
Packit 5c3484
Packit 5c3484
      MPN_COPY (rp + 1, up, un);
Packit 5c3484
Packit 5c3484
      s = buf + BUF_ALLOC;
Packit 5c3484
      while (un > 1)
Packit 5c3484
	{
Packit 5c3484
	  int i;
Packit 5c3484
	  mp_limb_t frac;
Packit 5c3484
	  MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
Packit 5c3484
					 big_base, big_base_inverted,
Packit 5c3484
					 normalization_steps);
Packit 5c3484
	  un -= rp[un] == 0;
Packit 5c3484
	  frac = (rp[0] + 1) << GMP_NAIL_BITS;
Packit 5c3484
	  s -= chars_per_limb;
Packit 5c3484
	  i = chars_per_limb;
Packit 5c3484
	  do
Packit 5c3484
	    {
Packit 5c3484
	      mp_limb_t digit;
Packit 5c3484
	      umul_ppmm (digit, frac, frac, base);
Packit 5c3484
	      *s++ = digit;
Packit 5c3484
	    }
Packit 5c3484
	  while (--i);
Packit 5c3484
	  s -= chars_per_limb;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      ul = rp[1];
Packit 5c3484
      while (ul != 0)
Packit 5c3484
	{
Packit 5c3484
	  udiv_qrnd_unnorm (ul, rl, ul, base);
Packit 5c3484
	  *--s = rl;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  l = buf + BUF_ALLOC - s;
Packit 5c3484
  while (l < len)
Packit 5c3484
    {
Packit 5c3484
      *str++ = 0;
Packit 5c3484
      len--;
Packit 5c3484
    }
Packit 5c3484
  while (l != 0)
Packit 5c3484
    {
Packit 5c3484
      *str++ = *s++;
Packit 5c3484
      l--;
Packit 5c3484
    }
Packit 5c3484
  return str;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484

Packit 5c3484
/* Convert {UP,UN} to a string with a base as represented in POWTAB, and put
Packit 5c3484
   the string in STR.  Generate LEN characters, possibly padding with zeros to
Packit 5c3484
   the left.  If LEN is zero, generate as many characters as required.
Packit 5c3484
   Return a pointer immediately after the last digit of the result string.
Packit 5c3484
   This uses divide-and-conquer and is intended for large conversions.  */
Packit 5c3484
static unsigned char *
Packit 5c3484
mpn_dc_get_str (unsigned char *str, size_t len,
Packit 5c3484
		mp_ptr up, mp_size_t un,
Packit 5c3484
		const powers_t *powtab, mp_ptr tmp)
Packit 5c3484
{
Packit 5c3484
  if (BELOW_THRESHOLD (un, GET_STR_DC_THRESHOLD))
Packit 5c3484
    {
Packit 5c3484
      if (un != 0)
Packit 5c3484
	str = mpn_sb_get_str (str, len, up, un, powtab->base);
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  while (len != 0)
Packit 5c3484
	    {
Packit 5c3484
	      *str++ = 0;
Packit 5c3484
	      len--;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      mp_ptr pwp, qp, rp;
Packit 5c3484
      mp_size_t pwn, qn;
Packit 5c3484
      mp_size_t sn;
Packit 5c3484
Packit 5c3484
      pwp = powtab->p;
Packit 5c3484
      pwn = powtab->n;
Packit 5c3484
      sn = powtab->shift;
Packit 5c3484
Packit 5c3484
      if (un < pwn + sn || (un == pwn + sn && mpn_cmp (up + sn, pwp, un - sn) < 0))
Packit 5c3484
	{
Packit 5c3484
	  str = mpn_dc_get_str (str, len, up, un, powtab - 1, tmp);
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  qp = tmp;		/* (un - pwn + 1) limbs for qp */
Packit 5c3484
	  rp = up;		/* pwn limbs for rp; overwrite up area */
Packit 5c3484
Packit 5c3484
	  mpn_tdiv_qr (qp, rp + sn, 0L, up + sn, un - sn, pwp, pwn);
Packit 5c3484
	  qn = un - sn - pwn; qn += qp[qn] != 0;		/* quotient size */
Packit 5c3484
Packit 5c3484
	  ASSERT (qn < pwn + sn || (qn == pwn + sn && mpn_cmp (qp + sn, pwp, pwn) < 0));
Packit 5c3484
Packit 5c3484
	  if (len != 0)
Packit 5c3484
	    len = len - powtab->digits_in_base;
Packit 5c3484
Packit 5c3484
	  str = mpn_dc_get_str (str, len, qp, qn, powtab - 1, tmp + qn);
Packit 5c3484
	  str = mpn_dc_get_str (str, powtab->digits_in_base, rp, pwn + sn, powtab - 1, tmp);
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  return str;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484

Packit 5c3484
/* There are no leading zeros on the digits generated at str, but that's not
Packit 5c3484
   currently a documented feature.  The current mpz_out_str and mpz_get_str
Packit 5c3484
   rely on it.  */
Packit 5c3484
Packit 5c3484
size_t
Packit 5c3484
mpn_get_str (unsigned char *str, int base, mp_ptr up, mp_size_t un)
Packit 5c3484
{
Packit 5c3484
  mp_ptr powtab_mem, powtab_mem_ptr;
Packit 5c3484
  mp_limb_t big_base;
Packit 5c3484
  size_t digits_in_base;
Packit 5c3484
  powers_t powtab[GMP_LIMB_BITS];
Packit 5c3484
  int pi;
Packit 5c3484
  mp_size_t n;
Packit 5c3484
  mp_ptr p, t;
Packit 5c3484
  size_t out_len;
Packit 5c3484
  mp_ptr tmp;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  /* Special case zero, as the code below doesn't handle it.  */
Packit 5c3484
  if (un == 0)
Packit 5c3484
    {
Packit 5c3484
      str[0] = 0;
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (POW2_P (base))
Packit 5c3484
    {
Packit 5c3484
      /* The base is a power of 2.  Convert from most significant end.  */
Packit 5c3484
      mp_limb_t n1, n0;
Packit 5c3484
      int bits_per_digit = mp_bases[base].big_base;
Packit 5c3484
      int cnt;
Packit 5c3484
      int bit_pos;
Packit 5c3484
      mp_size_t i;
Packit 5c3484
      unsigned char *s = str;
Packit 5c3484
      mp_bitcnt_t bits;
Packit 5c3484
Packit 5c3484
      n1 = up[un - 1];
Packit 5c3484
      count_leading_zeros (cnt, n1);
Packit 5c3484
Packit 5c3484
      /* BIT_POS should be R when input ends in least significant nibble,
Packit 5c3484
	 R + bits_per_digit * n when input ends in nth least significant
Packit 5c3484
	 nibble. */
Packit 5c3484
Packit 5c3484
      bits = (mp_bitcnt_t) GMP_NUMB_BITS * un - cnt + GMP_NAIL_BITS;
Packit 5c3484
      cnt = bits % bits_per_digit;
Packit 5c3484
      if (cnt != 0)
Packit 5c3484
	bits += bits_per_digit - cnt;
Packit 5c3484
      bit_pos = bits - (mp_bitcnt_t) (un - 1) * GMP_NUMB_BITS;
Packit 5c3484
Packit 5c3484
      /* Fast loop for bit output.  */
Packit 5c3484
      i = un - 1;
Packit 5c3484
      for (;;)
Packit 5c3484
	{
Packit 5c3484
	  bit_pos -= bits_per_digit;
Packit 5c3484
	  while (bit_pos >= 0)
Packit 5c3484
	    {
Packit 5c3484
	      *s++ = (n1 >> bit_pos) & ((1 << bits_per_digit) - 1);
Packit 5c3484
	      bit_pos -= bits_per_digit;
Packit 5c3484
	    }
Packit 5c3484
	  i--;
Packit 5c3484
	  if (i < 0)
Packit 5c3484
	    break;
Packit 5c3484
	  n0 = (n1 << -bit_pos) & ((1 << bits_per_digit) - 1);
Packit 5c3484
	  n1 = up[i];
Packit 5c3484
	  bit_pos += GMP_NUMB_BITS;
Packit 5c3484
	  *s++ = n0 | (n1 >> bit_pos);
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      return s - str;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  /* General case.  The base is not a power of 2.  */
Packit 5c3484
Packit 5c3484
  if (BELOW_THRESHOLD (un, GET_STR_PRECOMPUTE_THRESHOLD))
Packit 5c3484
    return mpn_sb_get_str (str, (size_t) 0, up, un, base) - str;
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
Packit 5c3484
  /* Allocate one large block for the powers of big_base.  */
Packit 5c3484
  powtab_mem = TMP_BALLOC_LIMBS (mpn_dc_get_str_powtab_alloc (un));
Packit 5c3484
  powtab_mem_ptr = powtab_mem;
Packit 5c3484
Packit 5c3484
  /* Compute a table of powers, were the largest power is >= sqrt(U).  */
Packit 5c3484
Packit 5c3484
  big_base = mp_bases[base].big_base;
Packit 5c3484
  digits_in_base = mp_bases[base].chars_per_limb;
Packit 5c3484
Packit 5c3484
  {
Packit 5c3484
    mp_size_t n_pows, xn, pn, exptab[GMP_LIMB_BITS], bexp;
Packit 5c3484
    mp_limb_t cy;
Packit 5c3484
    mp_size_t shift;
Packit 5c3484
    size_t ndig;
Packit 5c3484
Packit 5c3484
    DIGITS_IN_BASE_PER_LIMB (ndig, un, base);
Packit 5c3484
    xn = 1 + ndig / mp_bases[base].chars_per_limb; /* FIXME: scalar integer division */
Packit 5c3484
Packit 5c3484
    n_pows = 0;
Packit 5c3484
    for (pn = xn; pn != 1; pn = (pn + 1) >> 1)
Packit 5c3484
      {
Packit 5c3484
	exptab[n_pows] = pn;
Packit 5c3484
	n_pows++;
Packit 5c3484
      }
Packit 5c3484
    exptab[n_pows] = 1;
Packit 5c3484
Packit 5c3484
    powtab[0].p = &big_base;
Packit 5c3484
    powtab[0].n = 1;
Packit 5c3484
    powtab[0].digits_in_base = digits_in_base;
Packit 5c3484
    powtab[0].base = base;
Packit 5c3484
    powtab[0].shift = 0;
Packit 5c3484
Packit 5c3484
    powtab[1].p = powtab_mem_ptr;  powtab_mem_ptr += 2;
Packit 5c3484
    powtab[1].p[0] = big_base;
Packit 5c3484
    powtab[1].n = 1;
Packit 5c3484
    powtab[1].digits_in_base = digits_in_base;
Packit 5c3484
    powtab[1].base = base;
Packit 5c3484
    powtab[1].shift = 0;
Packit 5c3484
Packit 5c3484
    n = 1;
Packit 5c3484
    p = &big_base;
Packit 5c3484
    bexp = 1;
Packit 5c3484
    shift = 0;
Packit 5c3484
    for (pi = 2; pi < n_pows; pi++)
Packit 5c3484
      {
Packit 5c3484
	t = powtab_mem_ptr;
Packit 5c3484
	powtab_mem_ptr += 2 * n + 2;
Packit 5c3484
Packit 5c3484
	ASSERT_ALWAYS (powtab_mem_ptr < powtab_mem + mpn_dc_get_str_powtab_alloc (un));
Packit 5c3484
Packit 5c3484
	mpn_sqr (t, p, n);
Packit 5c3484
Packit 5c3484
	digits_in_base *= 2;
Packit 5c3484
	n *= 2;  n -= t[n - 1] == 0;
Packit 5c3484
	bexp *= 2;
Packit 5c3484
Packit 5c3484
	if (bexp + 1 < exptab[n_pows - pi])
Packit 5c3484
	  {
Packit 5c3484
	    digits_in_base += mp_bases[base].chars_per_limb;
Packit 5c3484
	    cy = mpn_mul_1 (t, t, n, big_base);
Packit 5c3484
	    t[n] = cy;
Packit 5c3484
	    n += cy != 0;
Packit 5c3484
	    bexp += 1;
Packit 5c3484
	  }
Packit 5c3484
	shift *= 2;
Packit 5c3484
	/* Strip low zero limbs.  */
Packit 5c3484
	while (t[0] == 0)
Packit 5c3484
	  {
Packit 5c3484
	    t++;
Packit 5c3484
	    n--;
Packit 5c3484
	    shift++;
Packit 5c3484
	  }
Packit 5c3484
	p = t;
Packit 5c3484
	powtab[pi].p = p;
Packit 5c3484
	powtab[pi].n = n;
Packit 5c3484
	powtab[pi].digits_in_base = digits_in_base;
Packit 5c3484
	powtab[pi].base = base;
Packit 5c3484
	powtab[pi].shift = shift;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
    for (pi = 1; pi < n_pows; pi++)
Packit 5c3484
      {
Packit 5c3484
	t = powtab[pi].p;
Packit 5c3484
	n = powtab[pi].n;
Packit 5c3484
	cy = mpn_mul_1 (t, t, n, big_base);
Packit 5c3484
	t[n] = cy;
Packit 5c3484
	n += cy != 0;
Packit 5c3484
	if (t[0] == 0)
Packit 5c3484
	  {
Packit 5c3484
	    powtab[pi].p = t + 1;
Packit 5c3484
	    n--;
Packit 5c3484
	    powtab[pi].shift++;
Packit 5c3484
	  }
Packit 5c3484
	powtab[pi].n = n;
Packit 5c3484
	powtab[pi].digits_in_base += mp_bases[base].chars_per_limb;
Packit 5c3484
      }
Packit 5c3484
Packit 5c3484
#if 0
Packit 5c3484
    { int i;
Packit 5c3484
      printf ("Computed table values for base=%d, un=%d, xn=%d:\n", base, un, xn);
Packit 5c3484
      for (i = 0; i < n_pows; i++)
Packit 5c3484
	printf ("%2d: %10ld %10ld %11ld %ld\n", i, exptab[n_pows-i], powtab[i].n, powtab[i].digits_in_base, powtab[i].shift);
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  }
Packit 5c3484
Packit 5c3484
  /* Using our precomputed powers, now in powtab[], convert our number.  */
Packit 5c3484
  tmp = TMP_BALLOC_LIMBS (mpn_dc_get_str_itch (un));
Packit 5c3484
  out_len = mpn_dc_get_str (str, 0, up, un, powtab + (pi - 1), tmp) - str;
Packit 5c3484
  TMP_FREE;
Packit 5c3484
Packit 5c3484
  return out_len;
Packit 5c3484
}