Blame mpn/generic/set_str.c

Packit 5c3484
/* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base) --
Packit 5c3484
   Convert a STR_LEN long base BASE byte string pointed to by STR to a limb
Packit 5c3484
   vector pointed to by RES_PTR.  Return the number of limbs in RES_PTR.
Packit 5c3484
Packit 5c3484
   Contributed to the GNU project by Torbjorn Granlund.
Packit 5c3484
Packit 5c3484
   THE FUNCTIONS IN THIS FILE, EXCEPT mpn_set_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, 2012, 2013 Free
Packit 5c3484
Software 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
Packit 5c3484
/* TODO:
Packit 5c3484
Packit 5c3484
      Perhaps do not compute the highest power?
Packit 5c3484
      Instead, multiply twice by the 2nd highest power:
Packit 5c3484
Packit 5c3484
	       _______
Packit 5c3484
	      |_______|  hp
Packit 5c3484
	      |_______|  pow
Packit 5c3484
       _______________
Packit 5c3484
      |_______________|  final result
Packit 5c3484
Packit 5c3484
Packit 5c3484
	       _______
Packit 5c3484
	      |_______|  hp
Packit 5c3484
		  |___|  pow[-1]
Packit 5c3484
	   ___________
Packit 5c3484
	  |___________|  intermediate result
Packit 5c3484
		  |___|  pow[-1]
Packit 5c3484
       _______________
Packit 5c3484
      |_______________|  final result
Packit 5c3484
Packit 5c3484
      Generalizing that idea, perhaps we should make powtab contain successive
Packit 5c3484
      cubes, not squares.
Packit 5c3484
*/
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
mp_size_t
Packit 5c3484
mpn_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
Packit 5c3484
{
Packit 5c3484
  if (POW2_P (base))
Packit 5c3484
    {
Packit 5c3484
      /* The base is a power of 2.  Read the input string from least to most
Packit 5c3484
	 significant character/digit.  */
Packit 5c3484
Packit 5c3484
      const unsigned char *s;
Packit 5c3484
      int next_bitpos;
Packit 5c3484
      mp_limb_t res_digit;
Packit 5c3484
      mp_size_t size;
Packit 5c3484
      int bits_per_indigit = mp_bases[base].big_base;
Packit 5c3484
Packit 5c3484
      size = 0;
Packit 5c3484
      res_digit = 0;
Packit 5c3484
      next_bitpos = 0;
Packit 5c3484
Packit 5c3484
      for (s = str + str_len - 1; s >= str; s--)
Packit 5c3484
	{
Packit 5c3484
	  int inp_digit = *s;
Packit 5c3484
Packit 5c3484
	  res_digit |= ((mp_limb_t) inp_digit << next_bitpos) & GMP_NUMB_MASK;
Packit 5c3484
	  next_bitpos += bits_per_indigit;
Packit 5c3484
	  if (next_bitpos >= GMP_NUMB_BITS)
Packit 5c3484
	    {
Packit 5c3484
	      rp[size++] = res_digit;
Packit 5c3484
	      next_bitpos -= GMP_NUMB_BITS;
Packit 5c3484
	      res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (res_digit != 0)
Packit 5c3484
	rp[size++] = res_digit;
Packit 5c3484
      return size;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (BELOW_THRESHOLD (str_len, SET_STR_PRECOMPUTE_THRESHOLD))
Packit 5c3484
    return mpn_bc_set_str (rp, str, str_len, base);
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      mp_ptr powtab_mem, tp;
Packit 5c3484
      powers_t powtab[GMP_LIMB_BITS];
Packit 5c3484
      int chars_per_limb;
Packit 5c3484
      mp_size_t size;
Packit 5c3484
      mp_size_t un;
Packit 5c3484
      TMP_DECL;
Packit 5c3484
Packit 5c3484
      TMP_MARK;
Packit 5c3484
Packit 5c3484
      chars_per_limb = mp_bases[base].chars_per_limb;
Packit 5c3484
Packit 5c3484
      un = str_len / chars_per_limb + 1;
Packit 5c3484
Packit 5c3484
      /* Allocate one large block for the powers of big_base.  */
Packit 5c3484
      powtab_mem = TMP_BALLOC_LIMBS (mpn_dc_set_str_powtab_alloc (un));
Packit 5c3484
Packit 5c3484
      mpn_set_str_compute_powtab (powtab, powtab_mem, un, base);
Packit 5c3484
Packit 5c3484
      tp = TMP_BALLOC_LIMBS (mpn_dc_set_str_itch (un));
Packit 5c3484
      size = mpn_dc_set_str (rp, str, str_len, powtab, tp);
Packit 5c3484
Packit 5c3484
      TMP_FREE;
Packit 5c3484
      return size;
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
mpn_set_str_compute_powtab (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un, int base)
Packit 5c3484
{
Packit 5c3484
  mp_ptr powtab_mem_ptr;
Packit 5c3484
  long i, pi;
Packit 5c3484
  mp_size_t n;
Packit 5c3484
  mp_ptr p, t;
Packit 5c3484
  mp_limb_t big_base;
Packit 5c3484
  int chars_per_limb;
Packit 5c3484
  size_t digits_in_base;
Packit 5c3484
  mp_size_t shift;
Packit 5c3484
Packit 5c3484
  powtab_mem_ptr = powtab_mem;
Packit 5c3484
Packit 5c3484
  chars_per_limb = mp_bases[base].chars_per_limb;
Packit 5c3484
  big_base = mp_bases[base].big_base;
Packit 5c3484
Packit 5c3484
  p = powtab_mem_ptr;
Packit 5c3484
  powtab_mem_ptr += 1;
Packit 5c3484
Packit 5c3484
  digits_in_base = chars_per_limb;
Packit 5c3484
Packit 5c3484
  p[0] = big_base;
Packit 5c3484
  n = 1;
Packit 5c3484
Packit 5c3484
  count_leading_zeros (i, un - 1);
Packit 5c3484
  i = GMP_LIMB_BITS - 1 - i;
Packit 5c3484
Packit 5c3484
  powtab[i].p = p;
Packit 5c3484
  powtab[i].n = n;
Packit 5c3484
  powtab[i].digits_in_base = digits_in_base;
Packit 5c3484
  powtab[i].base = base;
Packit 5c3484
  powtab[i].shift = 0;
Packit 5c3484
Packit 5c3484
  shift = 0;
Packit 5c3484
  for (pi = i - 1; pi >= 0; pi--)
Packit 5c3484
    {
Packit 5c3484
      t = powtab_mem_ptr;
Packit 5c3484
      powtab_mem_ptr += 2 * n;
Packit 5c3484
Packit 5c3484
      ASSERT_ALWAYS (powtab_mem_ptr < powtab_mem + mpn_dc_set_str_powtab_alloc (un));
Packit 5c3484
Packit 5c3484
      mpn_sqr (t, p, n);
Packit 5c3484
      n = 2 * n - 1; n += t[n] != 0;
Packit 5c3484
      digits_in_base *= 2;
Packit 5c3484
#if 1
Packit 5c3484
      if ((((un - 1) >> pi) & 2) == 0)
Packit 5c3484
	{
Packit 5c3484
	  mpn_divexact_1 (t, t, n, big_base);
Packit 5c3484
	  n -= t[n - 1] == 0;
Packit 5c3484
	  digits_in_base -= chars_per_limb;
Packit 5c3484
	}
Packit 5c3484
#else
Packit 5c3484
      if (CLEVER_CONDITION_1 ())
Packit 5c3484
	{
Packit 5c3484
	  /* perform adjustment operation of previous */
Packit 5c3484
	  cy = mpn_mul_1 (p, p, n, big_base);
Packit 5c3484
	}
Packit 5c3484
      if (CLEVER_CONDITION_2 ())
Packit 5c3484
	{
Packit 5c3484
	  /* perform adjustment operation of new */
Packit 5c3484
	  cy = mpn_mul_1 (t, t, n, big_base);
Packit 5c3484
	}
Packit 5c3484
#endif
Packit 5c3484
      shift *= 2;
Packit 5c3484
      /* Strip low zero limbs, but be careful to keep the result divisible by
Packit 5c3484
	 big_base.  */
Packit 5c3484
      while (t[0] == 0 && (t[1] & ((big_base & -big_base) - 1)) == 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
Packit 5c3484
mp_size_t
Packit 5c3484
mpn_dc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len,
Packit 5c3484
		const powers_t *powtab, mp_ptr tp)
Packit 5c3484
{
Packit 5c3484
  size_t len_lo, len_hi;
Packit 5c3484
  mp_limb_t cy;
Packit 5c3484
  mp_size_t ln, hn, n, sn;
Packit 5c3484
Packit 5c3484
  len_lo = powtab->digits_in_base;
Packit 5c3484
Packit 5c3484
  if (str_len <= len_lo)
Packit 5c3484
    {
Packit 5c3484
      if (BELOW_THRESHOLD (str_len, SET_STR_DC_THRESHOLD))
Packit 5c3484
	return mpn_bc_set_str (rp, str, str_len, powtab->base);
Packit 5c3484
      else
Packit 5c3484
	return mpn_dc_set_str (rp, str, str_len, powtab + 1, tp);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  len_hi = str_len - len_lo;
Packit 5c3484
  ASSERT (len_lo >= len_hi);
Packit 5c3484
Packit 5c3484
  if (BELOW_THRESHOLD (len_hi, SET_STR_DC_THRESHOLD))
Packit 5c3484
    hn = mpn_bc_set_str (tp, str, len_hi, powtab->base);
Packit 5c3484
  else
Packit 5c3484
    hn = mpn_dc_set_str (tp, str, len_hi, powtab + 1, rp);
Packit 5c3484
Packit 5c3484
  sn = powtab->shift;
Packit 5c3484
Packit 5c3484
  if (hn == 0)
Packit 5c3484
    {
Packit 5c3484
      /* Zero +1 limb here, to avoid reading an allocated but uninitialised
Packit 5c3484
	 limb in mpn_incr_u below.  */
Packit 5c3484
      MPN_ZERO (rp, powtab->n + sn + 1);
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      if (powtab->n > hn)
Packit 5c3484
	mpn_mul (rp + sn, powtab->p, powtab->n, tp, hn);
Packit 5c3484
      else
Packit 5c3484
	mpn_mul (rp + sn, tp, hn, powtab->p, powtab->n);
Packit 5c3484
      MPN_ZERO (rp, sn);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  str = str + str_len - len_lo;
Packit 5c3484
  if (BELOW_THRESHOLD (len_lo, SET_STR_DC_THRESHOLD))
Packit 5c3484
    ln = mpn_bc_set_str (tp, str, len_lo, powtab->base);
Packit 5c3484
  else
Packit 5c3484
    ln = mpn_dc_set_str (tp, str, len_lo, powtab + 1, tp + powtab->n + sn + 1);
Packit 5c3484
Packit 5c3484
  if (ln != 0)
Packit 5c3484
    {
Packit 5c3484
      cy = mpn_add_n (rp, rp, tp, ln);
Packit 5c3484
      mpn_incr_u (rp + ln, cy);
Packit 5c3484
    }
Packit 5c3484
  n = hn + powtab->n + sn;
Packit 5c3484
  return n - (rp[n - 1] == 0);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
mp_size_t
Packit 5c3484
mpn_bc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
Packit 5c3484
{
Packit 5c3484
  mp_size_t size;
Packit 5c3484
  size_t i;
Packit 5c3484
  long j;
Packit 5c3484
  mp_limb_t cy_limb;
Packit 5c3484
Packit 5c3484
  mp_limb_t big_base;
Packit 5c3484
  int chars_per_limb;
Packit 5c3484
  mp_limb_t res_digit;
Packit 5c3484
Packit 5c3484
  ASSERT (base >= 2);
Packit 5c3484
  ASSERT (base < numberof (mp_bases));
Packit 5c3484
  ASSERT (str_len >= 1);
Packit 5c3484
Packit 5c3484
  big_base = mp_bases[base].big_base;
Packit 5c3484
  chars_per_limb = mp_bases[base].chars_per_limb;
Packit 5c3484
Packit 5c3484
  size = 0;
Packit 5c3484
  for (i = chars_per_limb; i < str_len; i += chars_per_limb)
Packit 5c3484
    {
Packit 5c3484
      res_digit = *str++;
Packit 5c3484
      if (base == 10)
Packit 5c3484
	{ /* This is a common case.
Packit 5c3484
	     Help the compiler to avoid multiplication.  */
Packit 5c3484
	  for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
Packit 5c3484
	    res_digit = res_digit * 10 + *str++;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
	  for (j = chars_per_limb - 1; j != 0; j--)
Packit 5c3484
	    res_digit = res_digit * base + *str++;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (size == 0)
Packit 5c3484
	{
Packit 5c3484
	  if (res_digit != 0)
Packit 5c3484
	    {
Packit 5c3484
	      rp[0] = res_digit;
Packit 5c3484
	      size = 1;
Packit 5c3484
	    }
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	{
Packit 5c3484
#if HAVE_NATIVE_mpn_mul_1c
Packit 5c3484
	  cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
Packit 5c3484
#else
Packit 5c3484
	  cy_limb = mpn_mul_1 (rp, rp, size, big_base);
Packit 5c3484
	  cy_limb += mpn_add_1 (rp, rp, size, res_digit);
Packit 5c3484
#endif
Packit 5c3484
	  if (cy_limb != 0)
Packit 5c3484
	    rp[size++] = cy_limb;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  big_base = base;
Packit 5c3484
  res_digit = *str++;
Packit 5c3484
  if (base == 10)
Packit 5c3484
    { /* This is a common case.
Packit 5c3484
	 Help the compiler to avoid multiplication.  */
Packit 5c3484
      for (j = str_len - (i - MP_BASES_CHARS_PER_LIMB_10) - 1; j > 0; j--)
Packit 5c3484
	{
Packit 5c3484
	  res_digit = res_digit * 10 + *str++;
Packit 5c3484
	  big_base *= 10;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      for (j = str_len - (i - chars_per_limb) - 1; j > 0; j--)
Packit 5c3484
	{
Packit 5c3484
	  res_digit = res_digit * base + *str++;
Packit 5c3484
	  big_base *= base;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  if (size == 0)
Packit 5c3484
    {
Packit 5c3484
      if (res_digit != 0)
Packit 5c3484
	{
Packit 5c3484
	  rp[0] = res_digit;
Packit 5c3484
	  size = 1;
Packit 5c3484
	}
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
#if HAVE_NATIVE_mpn_mul_1c
Packit 5c3484
      cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
Packit 5c3484
#else
Packit 5c3484
      cy_limb = mpn_mul_1 (rp, rp, size, big_base);
Packit 5c3484
      cy_limb += mpn_add_1 (rp, rp, size, res_digit);
Packit 5c3484
#endif
Packit 5c3484
      if (cy_limb != 0)
Packit 5c3484
	rp[size++] = cy_limb;
Packit 5c3484
    }
Packit 5c3484
  return size;
Packit 5c3484
}