1 /* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base) --
2    Convert a STR_LEN long base BASE byte string pointed to by STR to a limb
3    vector pointed to by RES_PTR.  Return the number of limbs in RES_PTR.
4 
5    Contributed to the GNU project by Torbjorn Granlund.
6 
7    THE FUNCTIONS IN THIS FILE, EXCEPT mpn_set_str, ARE INTERNAL WITH A MUTABLE
8    INTERFACE.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN
9    FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE
10    GNU MP RELEASE.
11 
12 Copyright 1991-1994, 1996, 2000-2002, 2004, 2006-2008, 2012, 2013 Free
13 Software Foundation, Inc.
14 
15 This file is part of the GNU MP Library.
16 
17 The GNU MP Library is free software; you can redistribute it and/or modify
18 it under the terms of either:
19 
20   * the GNU Lesser General Public License as published by the Free
21     Software Foundation; either version 3 of the License, or (at your
22     option) any later version.
23 
24 or
25 
26   * the GNU General Public License as published by the Free Software
27     Foundation; either version 2 of the License, or (at your option) any
28     later version.
29 
30 or both in parallel, as here.
31 
32 The GNU MP Library is distributed in the hope that it will be useful, but
33 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
34 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
35 for more details.
36 
37 You should have received copies of the GNU General Public License and the
38 GNU Lesser General Public License along with the GNU MP Library.  If not,
39 see https://www.gnu.org/licenses/.  */
40 
41 
42 /* TODO:
43 
44       Perhaps do not compute the highest power?
45       Instead, multiply twice by the 2nd highest power:
46 
47 	       _______
48 	      |_______|  hp
49 	      |_______|  pow
50        _______________
51       |_______________|  final result
52 
53 
54 	       _______
55 	      |_______|  hp
56 		  |___|  pow[-1]
57 	   ___________
58 	  |___________|  intermediate result
59 		  |___|  pow[-1]
60        _______________
61       |_______________|  final result
62 
63       Generalizing that idea, perhaps we should make powtab contain successive
64       cubes, not squares.
65 */
66 
67 #include "gmp.h"
68 #include "gmp-impl.h"
69 #include "longlong.h"
70 
71 mp_size_t
mpn_set_str(mp_ptr rp,const unsigned char * str,size_t str_len,int base)72 mpn_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
73 {
74   if (POW2_P (base))
75     {
76       /* The base is a power of 2.  Read the input string from least to most
77 	 significant character/digit.  */
78 
79       const unsigned char *s;
80       int next_bitpos;
81       mp_limb_t res_digit;
82       mp_size_t size;
83       int bits_per_indigit = mp_bases[base].big_base;
84 
85       size = 0;
86       res_digit = 0;
87       next_bitpos = 0;
88 
89       for (s = str + str_len - 1; s >= str; s--)
90 	{
91 	  int inp_digit = *s;
92 
93 	  res_digit |= ((mp_limb_t) inp_digit << next_bitpos) & GMP_NUMB_MASK;
94 	  next_bitpos += bits_per_indigit;
95 	  if (next_bitpos >= GMP_NUMB_BITS)
96 	    {
97 	      rp[size++] = res_digit;
98 	      next_bitpos -= GMP_NUMB_BITS;
99 	      res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
100 	    }
101 	}
102 
103       if (res_digit != 0)
104 	rp[size++] = res_digit;
105       return size;
106     }
107 
108   if (BELOW_THRESHOLD (str_len, SET_STR_PRECOMPUTE_THRESHOLD))
109     return mpn_bc_set_str (rp, str, str_len, base);
110   else
111     {
112       mp_ptr powtab_mem, tp;
113       powers_t powtab[GMP_LIMB_BITS];
114       int chars_per_limb;
115       mp_size_t size;
116       mp_size_t un;
117       TMP_DECL;
118 
119       TMP_MARK;
120 
121       chars_per_limb = mp_bases[base].chars_per_limb;
122 
123       un = str_len / chars_per_limb + 1;
124 
125       /* Allocate one large block for the powers of big_base.  */
126       powtab_mem = TMP_BALLOC_LIMBS (mpn_dc_set_str_powtab_alloc (un));
127 
128       mpn_set_str_compute_powtab (powtab, powtab_mem, un, base);
129 
130       tp = TMP_BALLOC_LIMBS (mpn_dc_set_str_itch (un));
131       size = mpn_dc_set_str (rp, str, str_len, powtab, tp);
132 
133       TMP_FREE;
134       return size;
135     }
136 }
137 
138 void
mpn_set_str_compute_powtab(powers_t * powtab,mp_ptr powtab_mem,mp_size_t un,int base)139 mpn_set_str_compute_powtab (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un, int base)
140 {
141   mp_ptr powtab_mem_ptr;
142   long i, pi;
143   mp_size_t n;
144   mp_ptr p, t;
145   mp_limb_t big_base;
146   int chars_per_limb;
147   size_t digits_in_base;
148   mp_size_t shift;
149 
150   powtab_mem_ptr = powtab_mem;
151 
152   chars_per_limb = mp_bases[base].chars_per_limb;
153   big_base = mp_bases[base].big_base;
154 
155   p = powtab_mem_ptr;
156   powtab_mem_ptr += 1;
157 
158   digits_in_base = chars_per_limb;
159 
160   p[0] = big_base;
161   n = 1;
162 
163   count_leading_zeros (i, un - 1);
164   i = GMP_LIMB_BITS - 1 - i;
165 
166   powtab[i].p = p;
167   powtab[i].n = n;
168   powtab[i].digits_in_base = digits_in_base;
169   powtab[i].base = base;
170   powtab[i].shift = 0;
171 
172   shift = 0;
173   for (pi = i - 1; pi >= 0; pi--)
174     {
175       t = powtab_mem_ptr;
176       powtab_mem_ptr += 2 * n;
177 
178       ASSERT_ALWAYS (powtab_mem_ptr < powtab_mem + mpn_dc_set_str_powtab_alloc (un));
179 
180       mpn_sqr (t, p, n);
181       n = 2 * n - 1; n += t[n] != 0;
182       digits_in_base *= 2;
183 #if 1
184       if ((((un - 1) >> pi) & 2) == 0)
185 	{
186 	  mpn_divexact_1 (t, t, n, big_base);
187 	  n -= t[n - 1] == 0;
188 	  digits_in_base -= chars_per_limb;
189 	}
190 #else
191       if (CLEVER_CONDITION_1 ())
192 	{
193 	  /* perform adjustment operation of previous */
194 	  cy = mpn_mul_1 (p, p, n, big_base);
195 	}
196       if (CLEVER_CONDITION_2 ())
197 	{
198 	  /* perform adjustment operation of new */
199 	  cy = mpn_mul_1 (t, t, n, big_base);
200 	}
201 #endif
202       shift *= 2;
203       /* Strip low zero limbs, but be careful to keep the result divisible by
204 	 big_base.  */
205       while (t[0] == 0 && (t[1] & ((big_base & -big_base) - 1)) == 0)
206 	{
207 	  t++;
208 	  n--;
209 	  shift++;
210 	}
211       p = t;
212       powtab[pi].p = p;
213       powtab[pi].n = n;
214       powtab[pi].digits_in_base = digits_in_base;
215       powtab[pi].base = base;
216       powtab[pi].shift = shift;
217     }
218 }
219 
220 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)221 mpn_dc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len,
222 		const powers_t *powtab, mp_ptr tp)
223 {
224   size_t len_lo, len_hi;
225   mp_limb_t cy;
226   mp_size_t ln, hn, n, sn;
227 
228   len_lo = powtab->digits_in_base;
229 
230   if (str_len <= len_lo)
231     {
232       if (BELOW_THRESHOLD (str_len, SET_STR_DC_THRESHOLD))
233 	return mpn_bc_set_str (rp, str, str_len, powtab->base);
234       else
235 	return mpn_dc_set_str (rp, str, str_len, powtab + 1, tp);
236     }
237 
238   len_hi = str_len - len_lo;
239   ASSERT (len_lo >= len_hi);
240 
241   if (BELOW_THRESHOLD (len_hi, SET_STR_DC_THRESHOLD))
242     hn = mpn_bc_set_str (tp, str, len_hi, powtab->base);
243   else
244     hn = mpn_dc_set_str (tp, str, len_hi, powtab + 1, rp);
245 
246   sn = powtab->shift;
247 
248   if (hn == 0)
249     {
250       /* Zero +1 limb here, to avoid reading an allocated but uninitialised
251 	 limb in mpn_incr_u below.  */
252       MPN_ZERO (rp, powtab->n + sn + 1);
253     }
254   else
255     {
256       if (powtab->n > hn)
257 	mpn_mul (rp + sn, powtab->p, powtab->n, tp, hn);
258       else
259 	mpn_mul (rp + sn, tp, hn, powtab->p, powtab->n);
260       MPN_ZERO (rp, sn);
261     }
262 
263   str = str + str_len - len_lo;
264   if (BELOW_THRESHOLD (len_lo, SET_STR_DC_THRESHOLD))
265     ln = mpn_bc_set_str (tp, str, len_lo, powtab->base);
266   else
267     ln = mpn_dc_set_str (tp, str, len_lo, powtab + 1, tp + powtab->n + sn + 1);
268 
269   if (ln != 0)
270     {
271       cy = mpn_add_n (rp, rp, tp, ln);
272       mpn_incr_u (rp + ln, cy);
273     }
274   n = hn + powtab->n + sn;
275   return n - (rp[n - 1] == 0);
276 }
277 
278 mp_size_t
mpn_bc_set_str(mp_ptr rp,const unsigned char * str,size_t str_len,int base)279 mpn_bc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
280 {
281   mp_size_t size;
282   size_t i;
283   long j;
284   mp_limb_t cy_limb;
285 
286   mp_limb_t big_base;
287   int chars_per_limb;
288   mp_limb_t res_digit;
289 
290   ASSERT (base >= 2);
291   ASSERT (base < numberof (mp_bases));
292   ASSERT (str_len >= 1);
293 
294   big_base = mp_bases[base].big_base;
295   chars_per_limb = mp_bases[base].chars_per_limb;
296 
297   size = 0;
298   for (i = chars_per_limb; i < str_len; i += chars_per_limb)
299     {
300       res_digit = *str++;
301       if (base == 10)
302 	{ /* This is a common case.
303 	     Help the compiler to avoid multiplication.  */
304 	  for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
305 	    res_digit = res_digit * 10 + *str++;
306 	}
307       else
308 	{
309 	  for (j = chars_per_limb - 1; j != 0; j--)
310 	    res_digit = res_digit * base + *str++;
311 	}
312 
313       if (size == 0)
314 	{
315 	  if (res_digit != 0)
316 	    {
317 	      rp[0] = res_digit;
318 	      size = 1;
319 	    }
320 	}
321       else
322 	{
323 #if HAVE_NATIVE_mpn_mul_1c
324 	  cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
325 #else
326 	  cy_limb = mpn_mul_1 (rp, rp, size, big_base);
327 	  cy_limb += mpn_add_1 (rp, rp, size, res_digit);
328 #endif
329 	  if (cy_limb != 0)
330 	    rp[size++] = cy_limb;
331 	}
332     }
333 
334   big_base = base;
335   res_digit = *str++;
336   if (base == 10)
337     { /* This is a common case.
338 	 Help the compiler to avoid multiplication.  */
339       for (j = str_len - (i - MP_BASES_CHARS_PER_LIMB_10) - 1; j > 0; j--)
340 	{
341 	  res_digit = res_digit * 10 + *str++;
342 	  big_base *= 10;
343 	}
344     }
345   else
346     {
347       for (j = str_len - (i - chars_per_limb) - 1; j > 0; j--)
348 	{
349 	  res_digit = res_digit * base + *str++;
350 	  big_base *= base;
351 	}
352     }
353 
354   if (size == 0)
355     {
356       if (res_digit != 0)
357 	{
358 	  rp[0] = res_digit;
359 	  size = 1;
360 	}
361     }
362   else
363     {
364 #if HAVE_NATIVE_mpn_mul_1c
365       cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
366 #else
367       cy_limb = mpn_mul_1 (rp, rp, size, big_base);
368       cy_limb += mpn_add_1 (rp, rp, size, res_digit);
369 #endif
370       if (cy_limb != 0)
371 	rp[size++] = cy_limb;
372     }
373   return size;
374 }
375