186d7f5d3SJohn Marino /* mpn_get_str -- Convert {UP,USIZE} to a base BASE string in STR.
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino Contributed to the GNU project by Torbjorn Granlund.
486d7f5d3SJohn Marino
586d7f5d3SJohn Marino THE FUNCTIONS IN THIS FILE, EXCEPT mpn_get_str, ARE INTERNAL WITH A MUTABLE
686d7f5d3SJohn Marino INTERFACE. IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES. IN
786d7f5d3SJohn Marino FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE
886d7f5d3SJohn Marino GNU MP RELEASE.
986d7f5d3SJohn Marino
1086d7f5d3SJohn Marino Copyright 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002, 2004, 2006, 2007,
1186d7f5d3SJohn Marino 2008 Free Software Foundation, Inc.
1286d7f5d3SJohn Marino
1386d7f5d3SJohn Marino This file is part of the GNU MP Library.
1486d7f5d3SJohn Marino
1586d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
1686d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1786d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
1886d7f5d3SJohn Marino option) any later version.
1986d7f5d3SJohn Marino
2086d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
2186d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2286d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
2386d7f5d3SJohn Marino License for more details.
2486d7f5d3SJohn Marino
2586d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
2686d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
2786d7f5d3SJohn Marino
2886d7f5d3SJohn Marino #include "gmp.h"
2986d7f5d3SJohn Marino #include "gmp-impl.h"
3086d7f5d3SJohn Marino #include "longlong.h"
3186d7f5d3SJohn Marino
3286d7f5d3SJohn Marino /* Conversion of U {up,un} to a string in base b. Internally, we convert to
3386d7f5d3SJohn Marino base B = b^m, the largest power of b that fits a limb. Basic algorithms:
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino A) Divide U repeatedly by B, generating a quotient and remainder, until the
3686d7f5d3SJohn Marino quotient becomes zero. The remainders hold the converted digits. Digits
3786d7f5d3SJohn Marino come out from right to left. (Used in mpn_sb_get_str.)
3886d7f5d3SJohn Marino
3986d7f5d3SJohn Marino B) Divide U by b^g, for g such that 1/b <= U/b^g < 1, generating a fraction.
4086d7f5d3SJohn Marino Then develop digits by multiplying the fraction repeatedly by b. Digits
4186d7f5d3SJohn Marino come out from left to right. (Currently not used herein, except for in
4286d7f5d3SJohn Marino code for converting single limbs to individual digits.)
4386d7f5d3SJohn Marino
4486d7f5d3SJohn Marino C) Compute B^1, B^2, B^4, ..., B^s, for s such that B^s is just above
4586d7f5d3SJohn Marino sqrt(U). Then divide U by B^s, generating quotient and remainder.
4686d7f5d3SJohn Marino Recursively convert the quotient, then the remainder, using the
4786d7f5d3SJohn Marino precomputed powers. Digits come out from left to right. (Used in
4886d7f5d3SJohn Marino mpn_dc_get_str.)
4986d7f5d3SJohn Marino
5086d7f5d3SJohn Marino When using algorithm C, algorithm B might be suitable for basecase code,
5186d7f5d3SJohn Marino since the required b^g power will be readily accessible.
5286d7f5d3SJohn Marino
5386d7f5d3SJohn Marino Optimization ideas:
5486d7f5d3SJohn Marino 1. The recursive function of (C) could use less temporary memory. The powtab
5586d7f5d3SJohn Marino allocation could be trimmed with some computation, and the tmp area could
5686d7f5d3SJohn Marino be reduced, or perhaps eliminated if up is reused for both quotient and
5786d7f5d3SJohn Marino remainder (it is currently used just for remainder).
5886d7f5d3SJohn Marino 2. Store the powers of (C) in normalized form, with the normalization count.
5986d7f5d3SJohn Marino Quotients will usually need to be left-shifted before each divide, and
6086d7f5d3SJohn Marino remainders will either need to be left-shifted of right-shifted.
6186d7f5d3SJohn Marino 3. In the code for developing digits from a single limb, we could avoid using
6286d7f5d3SJohn Marino a full umul_ppmm except for the first (or first few) digits, provided base
6386d7f5d3SJohn Marino is even. Subsequent digits can be developed using plain multiplication.
6486d7f5d3SJohn Marino (This saves on register-starved machines (read x86) and on all machines
6586d7f5d3SJohn Marino that generate the upper product half using a separate instruction (alpha,
6686d7f5d3SJohn Marino powerpc, IA-64) or lacks such support altogether (sparc64, hppa64).
6786d7f5d3SJohn Marino 4. Separate mpn_dc_get_str basecase code from code for small conversions. The
6886d7f5d3SJohn Marino former code will have the exact right power readily available in the
6986d7f5d3SJohn Marino powtab parameter for dividing the current number into a fraction. Convert
7086d7f5d3SJohn Marino that using algorithm B.
7186d7f5d3SJohn Marino 5. Completely avoid division. Compute the inverses of the powers now in
7286d7f5d3SJohn Marino powtab instead of the actual powers.
7386d7f5d3SJohn Marino 6. Decrease powtab allocation for even bases. E.g. for base 10 we could save
7486d7f5d3SJohn Marino about 30% (1-log(5)/log(10)).
7586d7f5d3SJohn Marino
7686d7f5d3SJohn Marino Basic structure of (C):
7786d7f5d3SJohn Marino mpn_get_str:
7886d7f5d3SJohn Marino if POW2_P (n)
7986d7f5d3SJohn Marino ...
8086d7f5d3SJohn Marino else
8186d7f5d3SJohn Marino if (un < GET_STR_PRECOMPUTE_THRESHOLD)
8286d7f5d3SJohn Marino mpn_sb_get_str (str, base, up, un);
8386d7f5d3SJohn Marino else
8486d7f5d3SJohn Marino precompute_power_tables
8586d7f5d3SJohn Marino mpn_dc_get_str
8686d7f5d3SJohn Marino
8786d7f5d3SJohn Marino mpn_dc_get_str:
8886d7f5d3SJohn Marino mpn_tdiv_qr
8986d7f5d3SJohn Marino if (qn < GET_STR_DC_THRESHOLD)
9086d7f5d3SJohn Marino mpn_sb_get_str
9186d7f5d3SJohn Marino else
9286d7f5d3SJohn Marino mpn_dc_get_str
9386d7f5d3SJohn Marino if (rn < GET_STR_DC_THRESHOLD)
9486d7f5d3SJohn Marino mpn_sb_get_str
9586d7f5d3SJohn Marino else
9686d7f5d3SJohn Marino mpn_dc_get_str
9786d7f5d3SJohn Marino
9886d7f5d3SJohn Marino
9986d7f5d3SJohn Marino The reason for the two threshold values is the cost of
10086d7f5d3SJohn Marino precompute_power_tables. GET_STR_PRECOMPUTE_THRESHOLD will be considerably
10186d7f5d3SJohn Marino larger than GET_STR_PRECOMPUTE_THRESHOLD. */
10286d7f5d3SJohn Marino
10386d7f5d3SJohn Marino
10486d7f5d3SJohn Marino /* The x86s and m68020 have a quotient and remainder "div" instruction and
10586d7f5d3SJohn Marino gcc recognises an adjacent "/" and "%" can be combined using that.
10686d7f5d3SJohn Marino Elsewhere "/" and "%" are either separate instructions, or separate
10786d7f5d3SJohn Marino libgcc calls (which unfortunately gcc as of version 3.0 doesn't combine).
10886d7f5d3SJohn Marino A multiply and subtract should be faster than a "%" in those cases. */
10986d7f5d3SJohn Marino #if HAVE_HOST_CPU_FAMILY_x86 \
11086d7f5d3SJohn Marino || HAVE_HOST_CPU_m68020 \
11186d7f5d3SJohn Marino || HAVE_HOST_CPU_m68030 \
11286d7f5d3SJohn Marino || HAVE_HOST_CPU_m68040 \
11386d7f5d3SJohn Marino || HAVE_HOST_CPU_m68060 \
11486d7f5d3SJohn Marino || HAVE_HOST_CPU_m68360 /* CPU32 */
11586d7f5d3SJohn Marino #define udiv_qrnd_unnorm(q,r,n,d) \
11686d7f5d3SJohn Marino do { \
11786d7f5d3SJohn Marino mp_limb_t __q = (n) / (d); \
11886d7f5d3SJohn Marino mp_limb_t __r = (n) % (d); \
11986d7f5d3SJohn Marino (q) = __q; \
12086d7f5d3SJohn Marino (r) = __r; \
12186d7f5d3SJohn Marino } while (0)
12286d7f5d3SJohn Marino #else
12386d7f5d3SJohn Marino #define udiv_qrnd_unnorm(q,r,n,d) \
12486d7f5d3SJohn Marino do { \
12586d7f5d3SJohn Marino mp_limb_t __q = (n) / (d); \
12686d7f5d3SJohn Marino mp_limb_t __r = (n) - __q*(d); \
12786d7f5d3SJohn Marino (q) = __q; \
12886d7f5d3SJohn Marino (r) = __r; \
12986d7f5d3SJohn Marino } while (0)
13086d7f5d3SJohn Marino #endif
13186d7f5d3SJohn Marino
13286d7f5d3SJohn Marino
13386d7f5d3SJohn Marino /* Convert {up,un} to a string in base base, and put the result in str.
13486d7f5d3SJohn Marino Generate len characters, possibly padding with zeros to the left. If len is
13586d7f5d3SJohn Marino zero, generate as many characters as required. Return a pointer immediately
13686d7f5d3SJohn Marino after the last digit of the result string. Complexity is O(un^2); intended
13786d7f5d3SJohn Marino for small conversions. */
13886d7f5d3SJohn Marino static unsigned char *
mpn_sb_get_str(unsigned char * str,size_t len,mp_ptr up,mp_size_t un,int base)13986d7f5d3SJohn Marino mpn_sb_get_str (unsigned char *str, size_t len,
14086d7f5d3SJohn Marino mp_ptr up, mp_size_t un, int base)
14186d7f5d3SJohn Marino {
14286d7f5d3SJohn Marino mp_limb_t rl, ul;
14386d7f5d3SJohn Marino unsigned char *s;
14486d7f5d3SJohn Marino size_t l;
14586d7f5d3SJohn Marino /* Allocate memory for largest possible string, given that we only get here
14686d7f5d3SJohn Marino for operands with un < GET_STR_PRECOMPUTE_THRESHOLD and that the smallest
14786d7f5d3SJohn Marino base is 3. 7/11 is an approximation to 1/log2(3). */
14886d7f5d3SJohn Marino #if TUNE_PROGRAM_BUILD
14986d7f5d3SJohn Marino #define BUF_ALLOC (GET_STR_THRESHOLD_LIMIT * GMP_LIMB_BITS * 7 / 11)
15086d7f5d3SJohn Marino #else
15186d7f5d3SJohn Marino #define BUF_ALLOC (GET_STR_PRECOMPUTE_THRESHOLD * GMP_LIMB_BITS * 7 / 11)
15286d7f5d3SJohn Marino #endif
15386d7f5d3SJohn Marino unsigned char buf[BUF_ALLOC];
15486d7f5d3SJohn Marino #if TUNE_PROGRAM_BUILD
15586d7f5d3SJohn Marino mp_limb_t rp[GET_STR_THRESHOLD_LIMIT];
15686d7f5d3SJohn Marino #else
15786d7f5d3SJohn Marino mp_limb_t rp[GET_STR_PRECOMPUTE_THRESHOLD];
15886d7f5d3SJohn Marino #endif
15986d7f5d3SJohn Marino
16086d7f5d3SJohn Marino if (base == 10)
16186d7f5d3SJohn Marino {
16286d7f5d3SJohn Marino /* Special case code for base==10 so that the compiler has a chance to
16386d7f5d3SJohn Marino optimize things. */
16486d7f5d3SJohn Marino
16586d7f5d3SJohn Marino MPN_COPY (rp + 1, up, un);
16686d7f5d3SJohn Marino
16786d7f5d3SJohn Marino s = buf + BUF_ALLOC;
16886d7f5d3SJohn Marino while (un > 1)
16986d7f5d3SJohn Marino {
17086d7f5d3SJohn Marino int i;
17186d7f5d3SJohn Marino mp_limb_t frac, digit;
17286d7f5d3SJohn Marino MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
17386d7f5d3SJohn Marino MP_BASES_BIG_BASE_10,
17486d7f5d3SJohn Marino MP_BASES_BIG_BASE_INVERTED_10,
17586d7f5d3SJohn Marino MP_BASES_NORMALIZATION_STEPS_10);
17686d7f5d3SJohn Marino un -= rp[un] == 0;
17786d7f5d3SJohn Marino frac = (rp[0] + 1) << GMP_NAIL_BITS;
17886d7f5d3SJohn Marino s -= MP_BASES_CHARS_PER_LIMB_10;
17986d7f5d3SJohn Marino #if HAVE_HOST_CPU_FAMILY_x86
18086d7f5d3SJohn Marino /* The code below turns out to be a bit slower for x86 using gcc.
18186d7f5d3SJohn Marino Use plain code. */
18286d7f5d3SJohn Marino i = MP_BASES_CHARS_PER_LIMB_10;
18386d7f5d3SJohn Marino do
18486d7f5d3SJohn Marino {
18586d7f5d3SJohn Marino umul_ppmm (digit, frac, frac, 10);
18686d7f5d3SJohn Marino *s++ = digit;
18786d7f5d3SJohn Marino }
18886d7f5d3SJohn Marino while (--i);
18986d7f5d3SJohn Marino #else
19086d7f5d3SJohn Marino /* Use the fact that 10 in binary is 1010, with the lowest bit 0.
19186d7f5d3SJohn Marino After a few umul_ppmm, we will have accumulated enough low zeros
19286d7f5d3SJohn Marino to use a plain multiply. */
19386d7f5d3SJohn Marino if (MP_BASES_NORMALIZATION_STEPS_10 == 0)
19486d7f5d3SJohn Marino {
19586d7f5d3SJohn Marino umul_ppmm (digit, frac, frac, 10);
19686d7f5d3SJohn Marino *s++ = digit;
19786d7f5d3SJohn Marino }
19886d7f5d3SJohn Marino if (MP_BASES_NORMALIZATION_STEPS_10 <= 1)
19986d7f5d3SJohn Marino {
20086d7f5d3SJohn Marino umul_ppmm (digit, frac, frac, 10);
20186d7f5d3SJohn Marino *s++ = digit;
20286d7f5d3SJohn Marino }
20386d7f5d3SJohn Marino if (MP_BASES_NORMALIZATION_STEPS_10 <= 2)
20486d7f5d3SJohn Marino {
20586d7f5d3SJohn Marino umul_ppmm (digit, frac, frac, 10);
20686d7f5d3SJohn Marino *s++ = digit;
20786d7f5d3SJohn Marino }
20886d7f5d3SJohn Marino if (MP_BASES_NORMALIZATION_STEPS_10 <= 3)
20986d7f5d3SJohn Marino {
21086d7f5d3SJohn Marino umul_ppmm (digit, frac, frac, 10);
21186d7f5d3SJohn Marino *s++ = digit;
21286d7f5d3SJohn Marino }
21386d7f5d3SJohn Marino i = (MP_BASES_CHARS_PER_LIMB_10 - ((MP_BASES_NORMALIZATION_STEPS_10 < 4)
21486d7f5d3SJohn Marino ? (4-MP_BASES_NORMALIZATION_STEPS_10)
21586d7f5d3SJohn Marino : 0));
21686d7f5d3SJohn Marino frac = (frac + 0xf) >> 4;
21786d7f5d3SJohn Marino do
21886d7f5d3SJohn Marino {
21986d7f5d3SJohn Marino frac *= 10;
22086d7f5d3SJohn Marino digit = frac >> (GMP_LIMB_BITS - 4);
22186d7f5d3SJohn Marino *s++ = digit;
22286d7f5d3SJohn Marino frac &= (~(mp_limb_t) 0) >> 4;
22386d7f5d3SJohn Marino }
22486d7f5d3SJohn Marino while (--i);
22586d7f5d3SJohn Marino #endif
22686d7f5d3SJohn Marino s -= MP_BASES_CHARS_PER_LIMB_10;
22786d7f5d3SJohn Marino }
22886d7f5d3SJohn Marino
22986d7f5d3SJohn Marino ul = rp[1];
23086d7f5d3SJohn Marino while (ul != 0)
23186d7f5d3SJohn Marino {
23286d7f5d3SJohn Marino udiv_qrnd_unnorm (ul, rl, ul, 10);
23386d7f5d3SJohn Marino *--s = rl;
23486d7f5d3SJohn Marino }
23586d7f5d3SJohn Marino }
23686d7f5d3SJohn Marino else /* not base 10 */
23786d7f5d3SJohn Marino {
23886d7f5d3SJohn Marino unsigned chars_per_limb;
23986d7f5d3SJohn Marino mp_limb_t big_base, big_base_inverted;
24086d7f5d3SJohn Marino unsigned normalization_steps;
24186d7f5d3SJohn Marino
24286d7f5d3SJohn Marino chars_per_limb = mp_bases[base].chars_per_limb;
24386d7f5d3SJohn Marino big_base = mp_bases[base].big_base;
24486d7f5d3SJohn Marino big_base_inverted = mp_bases[base].big_base_inverted;
24586d7f5d3SJohn Marino count_leading_zeros (normalization_steps, big_base);
24686d7f5d3SJohn Marino
24786d7f5d3SJohn Marino MPN_COPY (rp + 1, up, un);
24886d7f5d3SJohn Marino
24986d7f5d3SJohn Marino s = buf + BUF_ALLOC;
25086d7f5d3SJohn Marino while (un > 1)
25186d7f5d3SJohn Marino {
25286d7f5d3SJohn Marino int i;
25386d7f5d3SJohn Marino mp_limb_t frac;
25486d7f5d3SJohn Marino MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
25586d7f5d3SJohn Marino big_base, big_base_inverted,
25686d7f5d3SJohn Marino normalization_steps);
25786d7f5d3SJohn Marino un -= rp[un] == 0;
25886d7f5d3SJohn Marino frac = (rp[0] + 1) << GMP_NAIL_BITS;
25986d7f5d3SJohn Marino s -= chars_per_limb;
26086d7f5d3SJohn Marino i = chars_per_limb;
26186d7f5d3SJohn Marino do
26286d7f5d3SJohn Marino {
26386d7f5d3SJohn Marino mp_limb_t digit;
26486d7f5d3SJohn Marino umul_ppmm (digit, frac, frac, base);
26586d7f5d3SJohn Marino *s++ = digit;
26686d7f5d3SJohn Marino }
26786d7f5d3SJohn Marino while (--i);
26886d7f5d3SJohn Marino s -= chars_per_limb;
26986d7f5d3SJohn Marino }
27086d7f5d3SJohn Marino
27186d7f5d3SJohn Marino ul = rp[1];
27286d7f5d3SJohn Marino while (ul != 0)
27386d7f5d3SJohn Marino {
27486d7f5d3SJohn Marino udiv_qrnd_unnorm (ul, rl, ul, base);
27586d7f5d3SJohn Marino *--s = rl;
27686d7f5d3SJohn Marino }
27786d7f5d3SJohn Marino }
27886d7f5d3SJohn Marino
27986d7f5d3SJohn Marino l = buf + BUF_ALLOC - s;
28086d7f5d3SJohn Marino while (l < len)
28186d7f5d3SJohn Marino {
28286d7f5d3SJohn Marino *str++ = 0;
28386d7f5d3SJohn Marino len--;
28486d7f5d3SJohn Marino }
28586d7f5d3SJohn Marino while (l != 0)
28686d7f5d3SJohn Marino {
28786d7f5d3SJohn Marino *str++ = *s++;
28886d7f5d3SJohn Marino l--;
28986d7f5d3SJohn Marino }
29086d7f5d3SJohn Marino return str;
29186d7f5d3SJohn Marino }
29286d7f5d3SJohn Marino
29386d7f5d3SJohn Marino
29486d7f5d3SJohn Marino /* Convert {UP,UN} to a string with a base as represented in POWTAB, and put
29586d7f5d3SJohn Marino the string in STR. Generate LEN characters, possibly padding with zeros to
29686d7f5d3SJohn Marino the left. If LEN is zero, generate as many characters as required.
29786d7f5d3SJohn Marino Return a pointer immediately after the last digit of the result string.
29886d7f5d3SJohn Marino This uses divide-and-conquer and is intended for large conversions. */
29986d7f5d3SJohn Marino static unsigned char *
mpn_dc_get_str(unsigned char * str,size_t len,mp_ptr up,mp_size_t un,const powers_t * powtab,mp_ptr tmp)30086d7f5d3SJohn Marino mpn_dc_get_str (unsigned char *str, size_t len,
30186d7f5d3SJohn Marino mp_ptr up, mp_size_t un,
30286d7f5d3SJohn Marino const powers_t *powtab, mp_ptr tmp)
30386d7f5d3SJohn Marino {
30486d7f5d3SJohn Marino if (BELOW_THRESHOLD (un, GET_STR_DC_THRESHOLD))
30586d7f5d3SJohn Marino {
30686d7f5d3SJohn Marino if (un != 0)
30786d7f5d3SJohn Marino str = mpn_sb_get_str (str, len, up, un, powtab->base);
30886d7f5d3SJohn Marino else
30986d7f5d3SJohn Marino {
31086d7f5d3SJohn Marino while (len != 0)
31186d7f5d3SJohn Marino {
31286d7f5d3SJohn Marino *str++ = 0;
31386d7f5d3SJohn Marino len--;
31486d7f5d3SJohn Marino }
31586d7f5d3SJohn Marino }
31686d7f5d3SJohn Marino }
31786d7f5d3SJohn Marino else
31886d7f5d3SJohn Marino {
31986d7f5d3SJohn Marino mp_ptr pwp, qp, rp;
32086d7f5d3SJohn Marino mp_size_t pwn, qn;
32186d7f5d3SJohn Marino mp_size_t sn;
32286d7f5d3SJohn Marino
32386d7f5d3SJohn Marino pwp = powtab->p;
32486d7f5d3SJohn Marino pwn = powtab->n;
32586d7f5d3SJohn Marino sn = powtab->shift;
32686d7f5d3SJohn Marino
32786d7f5d3SJohn Marino if (un < pwn + sn || (un == pwn + sn && mpn_cmp (up + sn, pwp, un - sn) < 0))
32886d7f5d3SJohn Marino {
32986d7f5d3SJohn Marino str = mpn_dc_get_str (str, len, up, un, powtab - 1, tmp);
33086d7f5d3SJohn Marino }
33186d7f5d3SJohn Marino else
33286d7f5d3SJohn Marino {
33386d7f5d3SJohn Marino qp = tmp; /* (un - pwn + 1) limbs for qp */
33486d7f5d3SJohn Marino rp = up; /* pwn limbs for rp; overwrite up area */
33586d7f5d3SJohn Marino
33686d7f5d3SJohn Marino mpn_tdiv_qr (qp, rp + sn, 0L, up + sn, un - sn, pwp, pwn);
33786d7f5d3SJohn Marino qn = un - sn - pwn; qn += qp[qn] != 0; /* quotient size */
33886d7f5d3SJohn Marino
33986d7f5d3SJohn Marino ASSERT (qn < pwn + sn || (qn == pwn + sn && mpn_cmp (qp + sn, pwp, pwn) < 0));
34086d7f5d3SJohn Marino
34186d7f5d3SJohn Marino if (len != 0)
34286d7f5d3SJohn Marino len = len - powtab->digits_in_base;
34386d7f5d3SJohn Marino
34486d7f5d3SJohn Marino str = mpn_dc_get_str (str, len, qp, qn, powtab - 1, tmp + qn);
34586d7f5d3SJohn Marino str = mpn_dc_get_str (str, powtab->digits_in_base, rp, pwn + sn, powtab - 1, tmp);
34686d7f5d3SJohn Marino }
34786d7f5d3SJohn Marino }
34886d7f5d3SJohn Marino return str;
34986d7f5d3SJohn Marino }
35086d7f5d3SJohn Marino
35186d7f5d3SJohn Marino
35286d7f5d3SJohn Marino /* There are no leading zeros on the digits generated at str, but that's not
35386d7f5d3SJohn Marino currently a documented feature. */
35486d7f5d3SJohn Marino
35586d7f5d3SJohn Marino size_t
mpn_get_str(unsigned char * str,int base,mp_ptr up,mp_size_t un)35686d7f5d3SJohn Marino mpn_get_str (unsigned char *str, int base, mp_ptr up, mp_size_t un)
35786d7f5d3SJohn Marino {
35886d7f5d3SJohn Marino mp_ptr powtab_mem, powtab_mem_ptr;
35986d7f5d3SJohn Marino mp_limb_t big_base;
36086d7f5d3SJohn Marino size_t digits_in_base;
36186d7f5d3SJohn Marino powers_t powtab[GMP_LIMB_BITS];
36286d7f5d3SJohn Marino int pi;
36386d7f5d3SJohn Marino mp_size_t n;
36486d7f5d3SJohn Marino mp_ptr p, t;
36586d7f5d3SJohn Marino size_t out_len;
36686d7f5d3SJohn Marino mp_ptr tmp;
36786d7f5d3SJohn Marino TMP_DECL;
36886d7f5d3SJohn Marino
36986d7f5d3SJohn Marino /* Special case zero, as the code below doesn't handle it. */
37086d7f5d3SJohn Marino if (un == 0)
37186d7f5d3SJohn Marino {
37286d7f5d3SJohn Marino str[0] = 0;
37386d7f5d3SJohn Marino return 1;
37486d7f5d3SJohn Marino }
37586d7f5d3SJohn Marino
37686d7f5d3SJohn Marino if (POW2_P (base))
37786d7f5d3SJohn Marino {
37886d7f5d3SJohn Marino /* The base is a power of 2. Convert from most significant end. */
37986d7f5d3SJohn Marino mp_limb_t n1, n0;
38086d7f5d3SJohn Marino int bits_per_digit = mp_bases[base].big_base;
38186d7f5d3SJohn Marino int cnt;
38286d7f5d3SJohn Marino int bit_pos;
38386d7f5d3SJohn Marino mp_size_t i;
38486d7f5d3SJohn Marino unsigned char *s = str;
38586d7f5d3SJohn Marino mp_bitcnt_t bits;
38686d7f5d3SJohn Marino
38786d7f5d3SJohn Marino n1 = up[un - 1];
38886d7f5d3SJohn Marino count_leading_zeros (cnt, n1);
38986d7f5d3SJohn Marino
39086d7f5d3SJohn Marino /* BIT_POS should be R when input ends in least significant nibble,
39186d7f5d3SJohn Marino R + bits_per_digit * n when input ends in nth least significant
39286d7f5d3SJohn Marino nibble. */
39386d7f5d3SJohn Marino
39486d7f5d3SJohn Marino bits = (mp_bitcnt_t) GMP_NUMB_BITS * un - cnt + GMP_NAIL_BITS;
39586d7f5d3SJohn Marino cnt = bits % bits_per_digit;
39686d7f5d3SJohn Marino if (cnt != 0)
39786d7f5d3SJohn Marino bits += bits_per_digit - cnt;
39886d7f5d3SJohn Marino bit_pos = bits - (mp_bitcnt_t) (un - 1) * GMP_NUMB_BITS;
39986d7f5d3SJohn Marino
40086d7f5d3SJohn Marino /* Fast loop for bit output. */
40186d7f5d3SJohn Marino i = un - 1;
40286d7f5d3SJohn Marino for (;;)
40386d7f5d3SJohn Marino {
40486d7f5d3SJohn Marino bit_pos -= bits_per_digit;
40586d7f5d3SJohn Marino while (bit_pos >= 0)
40686d7f5d3SJohn Marino {
40786d7f5d3SJohn Marino *s++ = (n1 >> bit_pos) & ((1 << bits_per_digit) - 1);
40886d7f5d3SJohn Marino bit_pos -= bits_per_digit;
40986d7f5d3SJohn Marino }
41086d7f5d3SJohn Marino i--;
41186d7f5d3SJohn Marino if (i < 0)
41286d7f5d3SJohn Marino break;
41386d7f5d3SJohn Marino n0 = (n1 << -bit_pos) & ((1 << bits_per_digit) - 1);
41486d7f5d3SJohn Marino n1 = up[i];
41586d7f5d3SJohn Marino bit_pos += GMP_NUMB_BITS;
41686d7f5d3SJohn Marino *s++ = n0 | (n1 >> bit_pos);
41786d7f5d3SJohn Marino }
41886d7f5d3SJohn Marino
41986d7f5d3SJohn Marino return s - str;
42086d7f5d3SJohn Marino }
42186d7f5d3SJohn Marino
42286d7f5d3SJohn Marino /* General case. The base is not a power of 2. */
42386d7f5d3SJohn Marino
42486d7f5d3SJohn Marino if (BELOW_THRESHOLD (un, GET_STR_PRECOMPUTE_THRESHOLD))
42586d7f5d3SJohn Marino return mpn_sb_get_str (str, (size_t) 0, up, un, base) - str;
42686d7f5d3SJohn Marino
42786d7f5d3SJohn Marino TMP_MARK;
42886d7f5d3SJohn Marino
42986d7f5d3SJohn Marino /* Allocate one large block for the powers of big_base. */
43086d7f5d3SJohn Marino powtab_mem = TMP_BALLOC_LIMBS (mpn_dc_get_str_powtab_alloc (un));
43186d7f5d3SJohn Marino powtab_mem_ptr = powtab_mem;
43286d7f5d3SJohn Marino
43386d7f5d3SJohn Marino /* Compute a table of powers, were the largest power is >= sqrt(U). */
43486d7f5d3SJohn Marino
43586d7f5d3SJohn Marino big_base = mp_bases[base].big_base;
43686d7f5d3SJohn Marino digits_in_base = mp_bases[base].chars_per_limb;
43786d7f5d3SJohn Marino
43886d7f5d3SJohn Marino {
43986d7f5d3SJohn Marino mp_size_t n_pows, xn, pn, exptab[GMP_LIMB_BITS], bexp;
44086d7f5d3SJohn Marino mp_limb_t cy;
44186d7f5d3SJohn Marino mp_size_t shift;
44286d7f5d3SJohn Marino
44386d7f5d3SJohn Marino n_pows = 0;
44486d7f5d3SJohn Marino xn = 1 + un*(mp_bases[base].chars_per_bit_exactly*GMP_NUMB_BITS)/mp_bases[base].chars_per_limb;
44586d7f5d3SJohn Marino for (pn = xn; pn != 1; pn = (pn + 1) >> 1)
44686d7f5d3SJohn Marino {
44786d7f5d3SJohn Marino exptab[n_pows] = pn;
44886d7f5d3SJohn Marino n_pows++;
44986d7f5d3SJohn Marino }
45086d7f5d3SJohn Marino exptab[n_pows] = 1;
45186d7f5d3SJohn Marino
45286d7f5d3SJohn Marino powtab[0].p = &big_base;
45386d7f5d3SJohn Marino powtab[0].n = 1;
45486d7f5d3SJohn Marino powtab[0].digits_in_base = digits_in_base;
45586d7f5d3SJohn Marino powtab[0].base = base;
45686d7f5d3SJohn Marino powtab[0].shift = 0;
45786d7f5d3SJohn Marino
45886d7f5d3SJohn Marino powtab[1].p = powtab_mem_ptr; powtab_mem_ptr += 2;
45986d7f5d3SJohn Marino powtab[1].p[0] = big_base;
46086d7f5d3SJohn Marino powtab[1].n = 1;
46186d7f5d3SJohn Marino powtab[1].digits_in_base = digits_in_base;
46286d7f5d3SJohn Marino powtab[1].base = base;
46386d7f5d3SJohn Marino powtab[1].shift = 0;
46486d7f5d3SJohn Marino
46586d7f5d3SJohn Marino n = 1;
46686d7f5d3SJohn Marino p = &big_base;
46786d7f5d3SJohn Marino bexp = 1;
46886d7f5d3SJohn Marino shift = 0;
46986d7f5d3SJohn Marino for (pi = 2; pi < n_pows; pi++)
47086d7f5d3SJohn Marino {
47186d7f5d3SJohn Marino t = powtab_mem_ptr;
47286d7f5d3SJohn Marino powtab_mem_ptr += 2 * n + 2;
47386d7f5d3SJohn Marino
47486d7f5d3SJohn Marino ASSERT_ALWAYS (powtab_mem_ptr < powtab_mem + mpn_dc_get_str_powtab_alloc (un));
47586d7f5d3SJohn Marino
47686d7f5d3SJohn Marino mpn_sqr (t, p, n);
47786d7f5d3SJohn Marino
47886d7f5d3SJohn Marino digits_in_base *= 2;
47986d7f5d3SJohn Marino n *= 2; n -= t[n - 1] == 0;
48086d7f5d3SJohn Marino bexp *= 2;
48186d7f5d3SJohn Marino
48286d7f5d3SJohn Marino if (bexp + 1 < exptab[n_pows - pi])
48386d7f5d3SJohn Marino {
48486d7f5d3SJohn Marino digits_in_base += mp_bases[base].chars_per_limb;
48586d7f5d3SJohn Marino cy = mpn_mul_1 (t, t, n, big_base);
48686d7f5d3SJohn Marino t[n] = cy;
48786d7f5d3SJohn Marino n += cy != 0;
48886d7f5d3SJohn Marino bexp += 1;
48986d7f5d3SJohn Marino }
49086d7f5d3SJohn Marino shift *= 2;
49186d7f5d3SJohn Marino /* Strip low zero limbs. */
49286d7f5d3SJohn Marino while (t[0] == 0)
49386d7f5d3SJohn Marino {
49486d7f5d3SJohn Marino t++;
49586d7f5d3SJohn Marino n--;
49686d7f5d3SJohn Marino shift++;
49786d7f5d3SJohn Marino }
49886d7f5d3SJohn Marino p = t;
49986d7f5d3SJohn Marino powtab[pi].p = p;
50086d7f5d3SJohn Marino powtab[pi].n = n;
50186d7f5d3SJohn Marino powtab[pi].digits_in_base = digits_in_base;
50286d7f5d3SJohn Marino powtab[pi].base = base;
50386d7f5d3SJohn Marino powtab[pi].shift = shift;
50486d7f5d3SJohn Marino }
50586d7f5d3SJohn Marino
50686d7f5d3SJohn Marino for (pi = 1; pi < n_pows; pi++)
50786d7f5d3SJohn Marino {
50886d7f5d3SJohn Marino t = powtab[pi].p;
50986d7f5d3SJohn Marino n = powtab[pi].n;
51086d7f5d3SJohn Marino cy = mpn_mul_1 (t, t, n, big_base);
51186d7f5d3SJohn Marino t[n] = cy;
51286d7f5d3SJohn Marino n += cy != 0;
51386d7f5d3SJohn Marino if (t[0] == 0)
51486d7f5d3SJohn Marino {
51586d7f5d3SJohn Marino powtab[pi].p = t + 1;
51686d7f5d3SJohn Marino n--;
51786d7f5d3SJohn Marino powtab[pi].shift++;
51886d7f5d3SJohn Marino }
51986d7f5d3SJohn Marino powtab[pi].n = n;
52086d7f5d3SJohn Marino powtab[pi].digits_in_base += mp_bases[base].chars_per_limb;
52186d7f5d3SJohn Marino }
52286d7f5d3SJohn Marino
52386d7f5d3SJohn Marino #if 0
52486d7f5d3SJohn Marino { int i;
52586d7f5d3SJohn Marino printf ("Computed table values for base=%d, un=%d, xn=%d:\n", base, un, xn);
52686d7f5d3SJohn Marino for (i = 0; i < n_pows; i++)
52786d7f5d3SJohn Marino printf ("%2d: %10ld %10ld %11ld %ld\n", i, exptab[n_pows-i], powtab[i].n, powtab[i].digits_in_base, powtab[i].shift);
52886d7f5d3SJohn Marino }
52986d7f5d3SJohn Marino #endif
53086d7f5d3SJohn Marino }
53186d7f5d3SJohn Marino
53286d7f5d3SJohn Marino /* Using our precomputed powers, now in powtab[], convert our number. */
53386d7f5d3SJohn Marino tmp = TMP_BALLOC_LIMBS (mpn_dc_get_str_itch (un));
53486d7f5d3SJohn Marino out_len = mpn_dc_get_str (str, 0, up, un, powtab - 1 + pi, tmp) - str;
53586d7f5d3SJohn Marino TMP_FREE;
53686d7f5d3SJohn Marino
53786d7f5d3SJohn Marino return out_len;
53886d7f5d3SJohn Marino }
539