[BACK]Return to set_str.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / mpn / generic

Diff for /OpenXM_contrib/gmp/mpn/generic/Attic/set_str.c between version 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2000/09/09 14:12:27 version 1.1.1.3, 2003/08/25 16:06:20
Line 1 
Line 1 
 /* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base)  /* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base) --
    -- Convert a STR_LEN long base BASE byte string pointed to by STR to a     Convert a STR_LEN long base BASE byte string pointed to by STR to a limb
    limb vector pointed to by RES_PTR.  Return the number of limbs in     vector pointed to by RES_PTR.  Return the number of limbs in RES_PTR.
    RES_PTR.  
   
 Copyright (C) 1991, 1992, 1993, 1994, 1996, 2000 Free Software Foundation,  Copyright 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002 Free Software
 Inc.  Foundation, Inc.
   
 This file is part of the GNU MP Library.  This file is part of the GNU MP Library.
   
 The GNU MP Library is free software; you can redistribute it and/or modify  The GNU MP Library is free software; you can redistribute it and/or modify it
 it under the terms of the GNU Lesser General Public License as published by  under the terms of the GNU Library General Public License as published by the
 the Free Software Foundation; either version 2.1 of the License, or (at your  Free Software Foundation; either version 2 of the License, or (at your option)
 option) any later version.  any later version.
   
 The GNU MP Library is distributed in the hope that it will be useful, but  The GNU MP Library is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License
 License for more details.  for more details.
   
 You should have received a copy of the GNU Lesser General Public License  You should have received a copy of the GNU Library General Public License along
 along with the GNU MP Library; see the file COPYING.LIB.  If not, write to  with the GNU MP Library; see the file COPYING.LIB.  If not, write to the Free
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 MA 02111-1307, USA. */  USA. */
   
 #include "gmp.h"  #include "gmp.h"
 #include "gmp-impl.h"  #include "gmp-impl.h"
   
 mp_size_t  static mp_size_t convert_blocks __GMP_PROTO ((mp_ptr, const unsigned char *, size_t, int));
 #if __STDC__  
 mpn_set_str (mp_ptr xp, const unsigned char *str, size_t str_len, int base)  /* When to switch to sub-quadratic code.  This counts characters/digits in
 #else     the input string, not limbs as most other *_THRESHOLD.  */
 mpn_set_str (xp, str, str_len, base)  #ifndef SET_STR_THRESHOLD
      mp_ptr xp;  #define SET_STR_THRESHOLD 4000
      const unsigned char *str;  
      size_t str_len;  
      int base;  
 #endif  #endif
   
   /* Don't define this to anything but 1 for now.  In order to make other values
      work well, either the convert_blocks function should be generazed to handle
      larger blocks than chars_per_limb, or the basecase code should be broken out
      of the main function.  Also note that this must be a power of 2.  */
   #ifndef SET_STR_BLOCK_SIZE
   #define SET_STR_BLOCK_SIZE 1    /* Must be a power of 2. */
   #endif
   
   
   /* This check interferes with expression based values of SET_STR_THRESHOLD
      used for tuning and measuring.
   #if SET_STR_BLOCK_SIZE >= SET_STR_THRESHOLD
   These values are silly.
   The sub-quadratic code would recurse to itself.
   #endif
   */
   
   mp_size_t
   mpn_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
 {  {
   mp_size_t size;    mp_size_t size;
   mp_limb_t big_base;    mp_limb_t big_base;
   int indigits_per_limb;    int chars_per_limb;
   mp_limb_t res_digit;    mp_limb_t res_digit;
   
     ASSERT (base >= 2);
     ASSERT (base < numberof (__mp_bases));
     ASSERT (str_len >= 1);
   
   big_base = __mp_bases[base].big_base;    big_base = __mp_bases[base].big_base;
   indigits_per_limb = __mp_bases[base].chars_per_limb;    chars_per_limb = __mp_bases[base].chars_per_limb;
   
 /*   size = str_len / indigits_per_limb + 1;  */  
   
   size = 0;    size = 0;
   
   if ((base & (base - 1)) == 0)    if (POW2_P (base))
     {      {
       /* The base is a power of 2.  Read the input string from        /* The base is a power of 2.  Read the input string from least to most
          least to most significant character/digit.  */           significant character/digit.  */
   
       const unsigned char *s;        const unsigned char *s;
       int next_bitpos;        int next_bitpos;
Line 65  mpn_set_str (xp, str, str_len, base)
Line 83  mpn_set_str (xp, str, str_len, base)
         {          {
           int inp_digit = *s;            int inp_digit = *s;
   
           res_digit |= (mp_limb_t) inp_digit << next_bitpos;            res_digit |= ((mp_limb_t) inp_digit << next_bitpos) & GMP_NUMB_MASK;
           next_bitpos += bits_per_indigit;            next_bitpos += bits_per_indigit;
           if (next_bitpos >= BITS_PER_MP_LIMB)            if (next_bitpos >= GMP_NUMB_BITS)
             {              {
               xp[size++] = res_digit;                rp[size++] = res_digit;
               next_bitpos -= BITS_PER_MP_LIMB;                next_bitpos -= GMP_NUMB_BITS;
               res_digit = inp_digit >> (bits_per_indigit - next_bitpos);                res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
             }              }
         }          }
   
       if (res_digit != 0)        if (res_digit != 0)
         xp[size++] = res_digit;          rp[size++] = res_digit;
         return size;
     }      }
   else    else
     {      {
       /* General case.  The base is not a power of 2.  */        /* General case.  The base is not a power of 2.  */
   
       size_t i;        if (str_len < SET_STR_THRESHOLD)
       int j;  
       mp_limb_t cy_limb;  
   
       for (i = indigits_per_limb; i < str_len; i += indigits_per_limb)  
         {          {
             size_t i;
             int j;
             mp_limb_t cy_limb;
   
             for (i = chars_per_limb; i < str_len; i += chars_per_limb)
               {
                 res_digit = *str++;
                 if (base == 10)
                   { /* This is a common case.
                        Help the compiler to avoid multiplication.  */
                     for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
                       res_digit = res_digit * 10 + *str++;
                   }
                 else
                   {
                     for (j = chars_per_limb - 1; j != 0; j--)
                       res_digit = res_digit * base + *str++;
                   }
   
                 if (size == 0)
                   {
                     if (res_digit != 0)
                       {
                         rp[0] = res_digit;
                         size = 1;
                       }
                   }
                 else
                   {
   #if HAVE_NATIVE_mpn_mul_1c
                     cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
   #else
                     cy_limb = mpn_mul_1 (rp, rp, size, big_base);
                     cy_limb += mpn_add_1 (rp, rp, size, res_digit);
   #endif
                     if (cy_limb != 0)
                       rp[size++] = cy_limb;
                   }
               }
   
             big_base = base;
           res_digit = *str++;            res_digit = *str++;
           if (base == 10)            if (base == 10)
             { /* This is a common case.              { /* This is a common case.
                  Help the compiler to avoid multiplication.  */                   Help the compiler to avoid multiplication.  */
               for (j = 1; j < indigits_per_limb; j++)                for (j = str_len - (i - MP_BASES_CHARS_PER_LIMB_10) - 1; j > 0; j--)
                 res_digit = res_digit * 10 + *str++;                  {
                     res_digit = res_digit * 10 + *str++;
                     big_base *= 10;
                   }
             }              }
           else            else
             {              {
               for (j = 1; j < indigits_per_limb; j++)                for (j = str_len - (i - chars_per_limb) - 1; j > 0; j--)
                 res_digit = res_digit * base + *str++;                  {
                     res_digit = res_digit * base + *str++;
                     big_base *= base;
                   }
             }              }
   
           if (size == 0)            if (size == 0)
             {              {
               if (res_digit != 0)                if (res_digit != 0)
                 {                  {
                   xp[0] = res_digit;                    rp[0] = res_digit;
                   size = 1;                    size = 1;
                 }                  }
             }              }
           else            else
             {              {
               cy_limb = mpn_mul_1 (xp, xp, size, big_base);  #if HAVE_NATIVE_mpn_mul_1c
               cy_limb += mpn_add_1 (xp, xp, size, res_digit);                cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
   #else
                 cy_limb = mpn_mul_1 (rp, rp, size, big_base);
                 cy_limb += mpn_add_1 (rp, rp, size, res_digit);
   #endif
               if (cy_limb != 0)                if (cy_limb != 0)
                 xp[size++] = cy_limb;                  rp[size++] = cy_limb;
             }              }
             return size;
         }          }
         else
           {
             /* Sub-quadratic code.  */
   
       big_base = base;            mp_ptr dp;
       res_digit = *str++;            mp_size_t dsize;
       if (base == 10)            mp_ptr xp, tp;
         { /* This is a common case.            mp_size_t step;
              Help the compiler to avoid multiplication.  */            mp_size_t i;
           for (j = 1; j < str_len - (i - indigits_per_limb); j++)            size_t alloc;
             mp_size_t n;
             mp_ptr pow_mem;
   
             alloc = (str_len + chars_per_limb - 1) / chars_per_limb;
             alloc = 2 * alloc;
             dp = __GMP_ALLOCATE_FUNC_LIMBS (alloc);
   
   #if SET_STR_BLOCK_SIZE == 1
             dsize = convert_blocks (dp, str, str_len, base);
   #else
             {
               const unsigned char *s;
               mp_ptr ddp = dp;
   
               s = str + str_len;
               while (s - str >  SET_STR_BLOCK_SIZE * chars_per_limb)
                 {
                   s -= SET_STR_BLOCK_SIZE * chars_per_limb;
                   mpn_set_str (ddp, s, SET_STR_BLOCK_SIZE * chars_per_limb, base);
                   ddp += SET_STR_BLOCK_SIZE;
                 }
               ddp += mpn_set_str (ddp, str, s - str, base);
               dsize = ddp - dp;
             }
   #endif
   
             /* Allocate space for powers of big_base.  Could trim this in two
                ways:
                1. Only really need 2^ceil(log2(dsize)) bits for the largest
                   power.
                2. Only the variable to get the largest power need that much
                   memory.  The other variable needs half as much.  Need just
                   figure out which of xp and tp will hold the last one.
                Net space savings would be in the range 1/4 to 5/8 of current
                allocation, depending on how close to the next power of 2 that
                dsize is.  */
             pow_mem = __GMP_ALLOCATE_FUNC_LIMBS (2 * alloc);
             xp = pow_mem;
             tp = pow_mem + alloc;
   
             xp[0] = big_base;
             n = 1;
             step = 1;
   #if SET_STR_BLOCK_SIZE != 1
             for (i = SET_STR_BLOCK_SIZE; i > 1; i >>= 1)
             {              {
               res_digit = res_digit * 10 + *str++;                mpn_sqr_n (tp, xp, n);
               big_base *= 10;                n = 2 * n;
                 n -= tp[n - 1] == 0;
   
                 step = 2 * step;
                 MP_PTR_SWAP (tp, xp);
             }              }
         }  #endif
       else  
         {            /* Multiply every second limb block, each `step' limbs large by the
           for (j = 1; j < str_len - (i - indigits_per_limb); j++)               base power currently in xp[], then add this to the adjacent block.
                We thereby convert from dsize blocks in base big_base, to dsize/2
                blocks in base big_base^2, then to dsize/4 blocks in base
                big_base^4, etc, etc.  */
   
             if (step < dsize)
             {              {
               res_digit = res_digit * base + *str++;                for (;;)
               big_base *= base;                  {
                     for (i = 0; i < dsize - step; i += 2 * step)
                       {
                         mp_ptr bp = dp + i;
                         mp_size_t m = dsize - i - step;
                         mp_size_t hi;
                         if (n >= m)
                           {
                             mpn_mul (tp, xp, n, bp + step, m);
                             mpn_add (bp, tp, n + m, bp, n);
                             hi = i + n + m;
                             dsize = hi;
                             dsize -= dp[dsize - 1] == 0;
                           }
                         else
                           {
                             mpn_mul_n (tp, xp, bp + step, n);
                             mpn_add (bp, tp, n + n, bp, n);
                           }
                       }
   
                     step = 2 * step;
                     if (! (step < dsize))
                       break;
   
                     mpn_sqr_n (tp, xp, n);
                     n = 2 * n;
                     n -= tp[n - 1] == 0;
                     MP_PTR_SWAP (tp, xp);
                   }
             }              }
   
             MPN_NORMALIZE (dp, dsize);
             MPN_COPY (rp, dp, dsize);
             __GMP_FREE_FUNC_LIMBS (pow_mem, 2 * alloc);
             __GMP_FREE_FUNC_LIMBS (dp, alloc);
             return dsize;
         }          }
       }
   }
   
       if (size == 0)  static mp_size_t
   convert_blocks (mp_ptr dp, const unsigned char *str, size_t str_len, int base)
   {
     int chars_per_limb;
     mp_size_t i;
     int j;
     int ds;
     mp_size_t dsize;
     mp_limb_t res_digit;
   
     chars_per_limb = __mp_bases[base].chars_per_limb;
   
     dsize = str_len / chars_per_limb;
     ds = str_len % chars_per_limb;
   
     if (ds != 0)
       {
         res_digit = *str++;
         for (j = ds - 1; j != 0; j--)
           res_digit = res_digit * base + *str++;
         dp[dsize] = res_digit;
       }
   
     if (base == 10)
       {
         for (i = dsize - 1; i >= 0; i--)
         {          {
           if (res_digit != 0)            res_digit = *str++;
             {            for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
               xp[0] = res_digit;              res_digit = res_digit * 10 + *str++;
               size = 1;            dp[i] = res_digit;
             }  
         }          }
       else      }
     else
       {
         for (i = dsize - 1; i >= 0; i--)
         {          {
           cy_limb = mpn_mul_1 (xp, xp, size, big_base);            res_digit = *str++;
           cy_limb += mpn_add_1 (xp, xp, size, res_digit);            for (j = chars_per_limb - 1; j != 0; j--)
           if (cy_limb != 0)              res_digit = res_digit * base + *str++;
             xp[size++] = cy_limb;            dp[i] = res_digit;
         }          }
     }      }
   
   return size;    return dsize + (ds != 0);
 }  }

Legend:
Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>