186d7f5d3SJohn Marino /* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base) --
286d7f5d3SJohn Marino Convert a STR_LEN long base BASE byte string pointed to by STR to a limb
386d7f5d3SJohn Marino vector pointed to by RES_PTR. Return the number of limbs in RES_PTR.
486d7f5d3SJohn Marino
586d7f5d3SJohn Marino Contributed to the GNU project by Torbjorn Granlund.
686d7f5d3SJohn Marino
786d7f5d3SJohn Marino THE FUNCTIONS IN THIS FILE, EXCEPT mpn_set_str, ARE INTERNAL WITH A MUTABLE
886d7f5d3SJohn Marino INTERFACE. IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES. IN
986d7f5d3SJohn Marino FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE
1086d7f5d3SJohn Marino GNU MP RELEASE.
1186d7f5d3SJohn Marino
1286d7f5d3SJohn Marino Copyright 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002, 2004, 2006, 2007,
1386d7f5d3SJohn Marino 2008 Free Software Foundation, Inc.
1486d7f5d3SJohn Marino
1586d7f5d3SJohn Marino This file is part of the GNU MP Library.
1686d7f5d3SJohn Marino
1786d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
1886d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
1986d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
2086d7f5d3SJohn Marino option) any later version.
2186d7f5d3SJohn Marino
2286d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
2386d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2486d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
2586d7f5d3SJohn Marino License for more details.
2686d7f5d3SJohn Marino
2786d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
2886d7f5d3SJohn Marino along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
2986d7f5d3SJohn Marino
3086d7f5d3SJohn Marino
3186d7f5d3SJohn Marino /* TODO:
3286d7f5d3SJohn Marino
3386d7f5d3SJohn Marino Perhaps do not compute the highest power?
3486d7f5d3SJohn Marino Instead, multiply twice by the 2nd highest power:
3586d7f5d3SJohn Marino
3686d7f5d3SJohn Marino _______
3786d7f5d3SJohn Marino |_______| hp
3886d7f5d3SJohn Marino |_______| pow
3986d7f5d3SJohn Marino _______________
4086d7f5d3SJohn Marino |_______________| final result
4186d7f5d3SJohn Marino
4286d7f5d3SJohn Marino
4386d7f5d3SJohn Marino _______
4486d7f5d3SJohn Marino |_______| hp
4586d7f5d3SJohn Marino |___| pow[-1]
4686d7f5d3SJohn Marino ___________
4786d7f5d3SJohn Marino |___________| intermediate result
4886d7f5d3SJohn Marino |___| pow[-1]
4986d7f5d3SJohn Marino _______________
5086d7f5d3SJohn Marino |_______________| final result
5186d7f5d3SJohn Marino
5286d7f5d3SJohn Marino Generalizing that idea, perhaps we should make powtab contain successive
5386d7f5d3SJohn Marino cubes, not squares.
5486d7f5d3SJohn Marino */
5586d7f5d3SJohn Marino
5686d7f5d3SJohn Marino #include "gmp.h"
5786d7f5d3SJohn Marino #include "gmp-impl.h"
5886d7f5d3SJohn Marino #include "longlong.h"
5986d7f5d3SJohn Marino
6086d7f5d3SJohn Marino mp_size_t
mpn_set_str(mp_ptr rp,const unsigned char * str,size_t str_len,int base)6186d7f5d3SJohn Marino mpn_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
6286d7f5d3SJohn Marino {
6386d7f5d3SJohn Marino if (POW2_P (base))
6486d7f5d3SJohn Marino {
6586d7f5d3SJohn Marino /* The base is a power of 2. Read the input string from least to most
6686d7f5d3SJohn Marino significant character/digit. */
6786d7f5d3SJohn Marino
6886d7f5d3SJohn Marino const unsigned char *s;
6986d7f5d3SJohn Marino int next_bitpos;
7086d7f5d3SJohn Marino mp_limb_t res_digit;
7186d7f5d3SJohn Marino mp_size_t size;
7286d7f5d3SJohn Marino int bits_per_indigit = mp_bases[base].big_base;
7386d7f5d3SJohn Marino
7486d7f5d3SJohn Marino size = 0;
7586d7f5d3SJohn Marino res_digit = 0;
7686d7f5d3SJohn Marino next_bitpos = 0;
7786d7f5d3SJohn Marino
7886d7f5d3SJohn Marino for (s = str + str_len - 1; s >= str; s--)
7986d7f5d3SJohn Marino {
8086d7f5d3SJohn Marino int inp_digit = *s;
8186d7f5d3SJohn Marino
8286d7f5d3SJohn Marino res_digit |= ((mp_limb_t) inp_digit << next_bitpos) & GMP_NUMB_MASK;
8386d7f5d3SJohn Marino next_bitpos += bits_per_indigit;
8486d7f5d3SJohn Marino if (next_bitpos >= GMP_NUMB_BITS)
8586d7f5d3SJohn Marino {
8686d7f5d3SJohn Marino rp[size++] = res_digit;
8786d7f5d3SJohn Marino next_bitpos -= GMP_NUMB_BITS;
8886d7f5d3SJohn Marino res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
8986d7f5d3SJohn Marino }
9086d7f5d3SJohn Marino }
9186d7f5d3SJohn Marino
9286d7f5d3SJohn Marino if (res_digit != 0)
9386d7f5d3SJohn Marino rp[size++] = res_digit;
9486d7f5d3SJohn Marino return size;
9586d7f5d3SJohn Marino }
9686d7f5d3SJohn Marino
9786d7f5d3SJohn Marino if (BELOW_THRESHOLD (str_len, SET_STR_PRECOMPUTE_THRESHOLD))
9886d7f5d3SJohn Marino return mpn_bc_set_str (rp, str, str_len, base);
9986d7f5d3SJohn Marino else
10086d7f5d3SJohn Marino {
10186d7f5d3SJohn Marino mp_ptr powtab_mem, tp;
10286d7f5d3SJohn Marino powers_t powtab[GMP_LIMB_BITS];
10386d7f5d3SJohn Marino int chars_per_limb;
10486d7f5d3SJohn Marino mp_size_t size;
10586d7f5d3SJohn Marino mp_size_t un;
10686d7f5d3SJohn Marino TMP_DECL;
10786d7f5d3SJohn Marino
10886d7f5d3SJohn Marino TMP_MARK;
10986d7f5d3SJohn Marino
11086d7f5d3SJohn Marino chars_per_limb = mp_bases[base].chars_per_limb;
11186d7f5d3SJohn Marino
11286d7f5d3SJohn Marino un = str_len / chars_per_limb + 1;
11386d7f5d3SJohn Marino
11486d7f5d3SJohn Marino /* Allocate one large block for the powers of big_base. */
11586d7f5d3SJohn Marino powtab_mem = TMP_BALLOC_LIMBS (mpn_dc_set_str_powtab_alloc (un));
11686d7f5d3SJohn Marino
11786d7f5d3SJohn Marino mpn_set_str_compute_powtab (powtab, powtab_mem, un, base);
11886d7f5d3SJohn Marino
11986d7f5d3SJohn Marino tp = TMP_BALLOC_LIMBS (mpn_dc_set_str_itch (un));
12086d7f5d3SJohn Marino size = mpn_dc_set_str (rp, str, str_len, powtab, tp);
12186d7f5d3SJohn Marino
12286d7f5d3SJohn Marino TMP_FREE;
12386d7f5d3SJohn Marino return size;
12486d7f5d3SJohn Marino }
12586d7f5d3SJohn Marino }
12686d7f5d3SJohn Marino
12786d7f5d3SJohn Marino void
mpn_set_str_compute_powtab(powers_t * powtab,mp_ptr powtab_mem,mp_size_t un,int base)12886d7f5d3SJohn Marino mpn_set_str_compute_powtab (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un, int base)
12986d7f5d3SJohn Marino {
13086d7f5d3SJohn Marino mp_ptr powtab_mem_ptr;
13186d7f5d3SJohn Marino long i, pi;
13286d7f5d3SJohn Marino mp_size_t n;
13386d7f5d3SJohn Marino mp_ptr p, t;
13486d7f5d3SJohn Marino unsigned normalization_steps;
13586d7f5d3SJohn Marino mp_limb_t big_base, big_base_inverted;
13686d7f5d3SJohn Marino int chars_per_limb;
13786d7f5d3SJohn Marino size_t digits_in_base;
13886d7f5d3SJohn Marino mp_size_t shift;
13986d7f5d3SJohn Marino
14086d7f5d3SJohn Marino powtab_mem_ptr = powtab_mem;
14186d7f5d3SJohn Marino
14286d7f5d3SJohn Marino chars_per_limb = mp_bases[base].chars_per_limb;
14386d7f5d3SJohn Marino big_base = mp_bases[base].big_base;
14486d7f5d3SJohn Marino big_base_inverted = mp_bases[base].big_base_inverted;
14586d7f5d3SJohn Marino count_leading_zeros (normalization_steps, big_base);
14686d7f5d3SJohn Marino
14786d7f5d3SJohn Marino p = powtab_mem_ptr;
14886d7f5d3SJohn Marino powtab_mem_ptr += 1;
14986d7f5d3SJohn Marino
15086d7f5d3SJohn Marino digits_in_base = chars_per_limb;
15186d7f5d3SJohn Marino
15286d7f5d3SJohn Marino p[0] = big_base;
15386d7f5d3SJohn Marino n = 1;
15486d7f5d3SJohn Marino
15586d7f5d3SJohn Marino count_leading_zeros (i, un - 1);
15686d7f5d3SJohn Marino i = GMP_LIMB_BITS - 1 - i;
15786d7f5d3SJohn Marino
15886d7f5d3SJohn Marino powtab[i].p = p;
15986d7f5d3SJohn Marino powtab[i].n = n;
16086d7f5d3SJohn Marino powtab[i].digits_in_base = digits_in_base;
16186d7f5d3SJohn Marino powtab[i].base = base;
16286d7f5d3SJohn Marino powtab[i].shift = 0;
16386d7f5d3SJohn Marino
16486d7f5d3SJohn Marino shift = 0;
16586d7f5d3SJohn Marino for (pi = i - 1; pi >= 0; pi--)
16686d7f5d3SJohn Marino {
16786d7f5d3SJohn Marino t = powtab_mem_ptr;
16886d7f5d3SJohn Marino powtab_mem_ptr += 2 * n;
16986d7f5d3SJohn Marino
17086d7f5d3SJohn Marino ASSERT_ALWAYS (powtab_mem_ptr < powtab_mem + mpn_dc_set_str_powtab_alloc (un));
17186d7f5d3SJohn Marino
17286d7f5d3SJohn Marino mpn_sqr (t, p, n);
17386d7f5d3SJohn Marino n = 2 * n - 1; n += t[n] != 0;
17486d7f5d3SJohn Marino digits_in_base *= 2;
17586d7f5d3SJohn Marino #if 1
17686d7f5d3SJohn Marino if ((((un - 1) >> pi) & 2) == 0)
17786d7f5d3SJohn Marino {
17886d7f5d3SJohn Marino mpn_divexact_1 (t, t, n, big_base);
17986d7f5d3SJohn Marino n -= t[n - 1] == 0;
18086d7f5d3SJohn Marino digits_in_base -= chars_per_limb;
18186d7f5d3SJohn Marino }
18286d7f5d3SJohn Marino #else
18386d7f5d3SJohn Marino if (CLEVER_CONDITION_1 ())
18486d7f5d3SJohn Marino {
18586d7f5d3SJohn Marino /* perform adjustment operation of previous */
18686d7f5d3SJohn Marino cy = mpn_mul_1 (p, p, n, big_base);
18786d7f5d3SJohn Marino }
18886d7f5d3SJohn Marino if (CLEVER_CONDITION_2 ())
18986d7f5d3SJohn Marino {
19086d7f5d3SJohn Marino /* perform adjustment operation of new */
19186d7f5d3SJohn Marino cy = mpn_mul_1 (t, t, n, big_base);
19286d7f5d3SJohn Marino }
19386d7f5d3SJohn Marino #endif
19486d7f5d3SJohn Marino shift *= 2;
19586d7f5d3SJohn Marino /* Strip low zero limbs, but be careful to keep the result divisible by
19686d7f5d3SJohn Marino big_base. */
19786d7f5d3SJohn Marino while (t[0] == 0 && (t[1] & ((big_base & -big_base) - 1)) == 0)
19886d7f5d3SJohn Marino {
19986d7f5d3SJohn Marino t++;
20086d7f5d3SJohn Marino n--;
20186d7f5d3SJohn Marino shift++;
20286d7f5d3SJohn Marino }
20386d7f5d3SJohn Marino p = t;
20486d7f5d3SJohn Marino powtab[pi].p = p;
20586d7f5d3SJohn Marino powtab[pi].n = n;
20686d7f5d3SJohn Marino powtab[pi].digits_in_base = digits_in_base;
20786d7f5d3SJohn Marino powtab[pi].base = base;
20886d7f5d3SJohn Marino powtab[pi].shift = shift;
20986d7f5d3SJohn Marino }
21086d7f5d3SJohn Marino }
21186d7f5d3SJohn Marino
21286d7f5d3SJohn Marino mp_size_t
mpn_dc_set_str(mp_ptr rp,const unsigned char * str,size_t str_len,const powers_t * powtab,mp_ptr tp)21386d7f5d3SJohn Marino mpn_dc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len,
21486d7f5d3SJohn Marino const powers_t *powtab, mp_ptr tp)
21586d7f5d3SJohn Marino {
21686d7f5d3SJohn Marino size_t len_lo, len_hi;
21786d7f5d3SJohn Marino mp_limb_t cy;
21886d7f5d3SJohn Marino mp_size_t ln, hn, n, sn;
21986d7f5d3SJohn Marino
22086d7f5d3SJohn Marino len_lo = powtab->digits_in_base;
22186d7f5d3SJohn Marino
22286d7f5d3SJohn Marino if (str_len <= len_lo)
22386d7f5d3SJohn Marino {
22486d7f5d3SJohn Marino if (BELOW_THRESHOLD (str_len, SET_STR_DC_THRESHOLD))
22586d7f5d3SJohn Marino return mpn_bc_set_str (rp, str, str_len, powtab->base);
22686d7f5d3SJohn Marino else
22786d7f5d3SJohn Marino return mpn_dc_set_str (rp, str, str_len, powtab + 1, tp);
22886d7f5d3SJohn Marino }
22986d7f5d3SJohn Marino
23086d7f5d3SJohn Marino len_hi = str_len - len_lo;
23186d7f5d3SJohn Marino ASSERT (len_lo >= len_hi);
23286d7f5d3SJohn Marino
23386d7f5d3SJohn Marino if (BELOW_THRESHOLD (len_hi, SET_STR_DC_THRESHOLD))
23486d7f5d3SJohn Marino hn = mpn_bc_set_str (tp, str, len_hi, powtab->base);
23586d7f5d3SJohn Marino else
23686d7f5d3SJohn Marino hn = mpn_dc_set_str (tp, str, len_hi, powtab + 1, rp);
23786d7f5d3SJohn Marino
23886d7f5d3SJohn Marino sn = powtab->shift;
23986d7f5d3SJohn Marino
24086d7f5d3SJohn Marino if (hn == 0)
24186d7f5d3SJohn Marino {
24286d7f5d3SJohn Marino MPN_ZERO (rp, powtab->n + sn);
24386d7f5d3SJohn Marino }
24486d7f5d3SJohn Marino else
24586d7f5d3SJohn Marino {
24686d7f5d3SJohn Marino if (powtab->n > hn)
24786d7f5d3SJohn Marino mpn_mul (rp + sn, powtab->p, powtab->n, tp, hn);
24886d7f5d3SJohn Marino else
24986d7f5d3SJohn Marino mpn_mul (rp + sn, tp, hn, powtab->p, powtab->n);
25086d7f5d3SJohn Marino MPN_ZERO (rp, sn);
25186d7f5d3SJohn Marino }
25286d7f5d3SJohn Marino
25386d7f5d3SJohn Marino str = str + str_len - len_lo;
25486d7f5d3SJohn Marino if (BELOW_THRESHOLD (len_lo, SET_STR_DC_THRESHOLD))
25586d7f5d3SJohn Marino ln = mpn_bc_set_str (tp, str, len_lo, powtab->base);
25686d7f5d3SJohn Marino else
25786d7f5d3SJohn Marino ln = mpn_dc_set_str (tp, str, len_lo, powtab + 1, tp + powtab->n + sn + 1);
25886d7f5d3SJohn Marino
25986d7f5d3SJohn Marino if (ln != 0)
26086d7f5d3SJohn Marino {
26186d7f5d3SJohn Marino cy = mpn_add_n (rp, rp, tp, ln);
26286d7f5d3SJohn Marino mpn_incr_u (rp + ln, cy);
26386d7f5d3SJohn Marino }
26486d7f5d3SJohn Marino n = hn + powtab->n + sn;
26586d7f5d3SJohn Marino return n - (rp[n - 1] == 0);
26686d7f5d3SJohn Marino }
26786d7f5d3SJohn Marino
26886d7f5d3SJohn Marino mp_size_t
mpn_bc_set_str(mp_ptr rp,const unsigned char * str,size_t str_len,int base)26986d7f5d3SJohn Marino mpn_bc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
27086d7f5d3SJohn Marino {
27186d7f5d3SJohn Marino mp_size_t size;
27286d7f5d3SJohn Marino size_t i;
27386d7f5d3SJohn Marino long j;
27486d7f5d3SJohn Marino mp_limb_t cy_limb;
27586d7f5d3SJohn Marino
27686d7f5d3SJohn Marino mp_limb_t big_base;
27786d7f5d3SJohn Marino int chars_per_limb;
27886d7f5d3SJohn Marino mp_limb_t res_digit;
27986d7f5d3SJohn Marino
28086d7f5d3SJohn Marino ASSERT (base >= 2);
28186d7f5d3SJohn Marino ASSERT (base < numberof (mp_bases));
28286d7f5d3SJohn Marino ASSERT (str_len >= 1);
28386d7f5d3SJohn Marino
28486d7f5d3SJohn Marino big_base = mp_bases[base].big_base;
28586d7f5d3SJohn Marino chars_per_limb = mp_bases[base].chars_per_limb;
28686d7f5d3SJohn Marino
28786d7f5d3SJohn Marino size = 0;
28886d7f5d3SJohn Marino for (i = chars_per_limb; i < str_len; i += chars_per_limb)
28986d7f5d3SJohn Marino {
29086d7f5d3SJohn Marino res_digit = *str++;
29186d7f5d3SJohn Marino if (base == 10)
29286d7f5d3SJohn Marino { /* This is a common case.
29386d7f5d3SJohn Marino Help the compiler to avoid multiplication. */
29486d7f5d3SJohn Marino for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
29586d7f5d3SJohn Marino res_digit = res_digit * 10 + *str++;
29686d7f5d3SJohn Marino }
29786d7f5d3SJohn Marino else
29886d7f5d3SJohn Marino {
29986d7f5d3SJohn Marino for (j = chars_per_limb - 1; j != 0; j--)
30086d7f5d3SJohn Marino res_digit = res_digit * base + *str++;
30186d7f5d3SJohn Marino }
30286d7f5d3SJohn Marino
30386d7f5d3SJohn Marino if (size == 0)
30486d7f5d3SJohn Marino {
30586d7f5d3SJohn Marino if (res_digit != 0)
30686d7f5d3SJohn Marino {
30786d7f5d3SJohn Marino rp[0] = res_digit;
30886d7f5d3SJohn Marino size = 1;
30986d7f5d3SJohn Marino }
31086d7f5d3SJohn Marino }
31186d7f5d3SJohn Marino else
31286d7f5d3SJohn Marino {
31386d7f5d3SJohn Marino #if HAVE_NATIVE_mpn_mul_1c
31486d7f5d3SJohn Marino cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
31586d7f5d3SJohn Marino #else
31686d7f5d3SJohn Marino cy_limb = mpn_mul_1 (rp, rp, size, big_base);
31786d7f5d3SJohn Marino cy_limb += mpn_add_1 (rp, rp, size, res_digit);
31886d7f5d3SJohn Marino #endif
31986d7f5d3SJohn Marino if (cy_limb != 0)
32086d7f5d3SJohn Marino rp[size++] = cy_limb;
32186d7f5d3SJohn Marino }
32286d7f5d3SJohn Marino }
32386d7f5d3SJohn Marino
32486d7f5d3SJohn Marino big_base = base;
32586d7f5d3SJohn Marino res_digit = *str++;
32686d7f5d3SJohn Marino if (base == 10)
32786d7f5d3SJohn Marino { /* This is a common case.
32886d7f5d3SJohn Marino Help the compiler to avoid multiplication. */
32986d7f5d3SJohn Marino for (j = str_len - (i - MP_BASES_CHARS_PER_LIMB_10) - 1; j > 0; j--)
33086d7f5d3SJohn Marino {
33186d7f5d3SJohn Marino res_digit = res_digit * 10 + *str++;
33286d7f5d3SJohn Marino big_base *= 10;
33386d7f5d3SJohn Marino }
33486d7f5d3SJohn Marino }
33586d7f5d3SJohn Marino else
33686d7f5d3SJohn Marino {
33786d7f5d3SJohn Marino for (j = str_len - (i - chars_per_limb) - 1; j > 0; j--)
33886d7f5d3SJohn Marino {
33986d7f5d3SJohn Marino res_digit = res_digit * base + *str++;
34086d7f5d3SJohn Marino big_base *= base;
34186d7f5d3SJohn Marino }
34286d7f5d3SJohn Marino }
34386d7f5d3SJohn Marino
34486d7f5d3SJohn Marino if (size == 0)
34586d7f5d3SJohn Marino {
34686d7f5d3SJohn Marino if (res_digit != 0)
34786d7f5d3SJohn Marino {
34886d7f5d3SJohn Marino rp[0] = res_digit;
34986d7f5d3SJohn Marino size = 1;
35086d7f5d3SJohn Marino }
35186d7f5d3SJohn Marino }
35286d7f5d3SJohn Marino else
35386d7f5d3SJohn Marino {
35486d7f5d3SJohn Marino #if HAVE_NATIVE_mpn_mul_1c
35586d7f5d3SJohn Marino cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
35686d7f5d3SJohn Marino #else
35786d7f5d3SJohn Marino cy_limb = mpn_mul_1 (rp, rp, size, big_base);
35886d7f5d3SJohn Marino cy_limb += mpn_add_1 (rp, rp, size, res_digit);
35986d7f5d3SJohn Marino #endif
36086d7f5d3SJohn Marino if (cy_limb != 0)
36186d7f5d3SJohn Marino rp[size++] = cy_limb;
36286d7f5d3SJohn Marino }
36386d7f5d3SJohn Marino return size;
36486d7f5d3SJohn Marino }
365