divrem_1.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:7k
源码类别:

数学计算

开发平台:

Unix_Linux

  1. /* UltraSparc 64 mpn_divrem_1 -- mpn by limb division.
  2. Copyright 1991, 1993, 1994, 1996, 1998, 1999, 2000, 2001, 2003 Free Software
  3. Foundation, Inc.
  4. This file is part of the GNU MP Library.
  5. The GNU MP Library is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or (at your
  8. option) any later version.
  9. The GNU MP Library is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  12. License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  15. #include "gmp.h"
  16. #include "gmp-impl.h"
  17. #include "longlong.h"
  18. #include "mpn/sparc64/sparc64.h"
  19. /*                   64-bit divisor       32-bit divisor
  20.                        cycles/limb          cycles/limb
  21.                         (approx)             (approx)
  22.                    integer  fraction    integer  fraction
  23.    Ultrasparc 2i:    160      160          122      96
  24. */
  25. /* 32-bit divisors are treated in special case code.  This requires 4 mulx
  26.    per limb instead of 8 in the general case.
  27.    For big endian systems we need HALF_ENDIAN_ADJ included in the src[i]
  28.    addressing, to get the two halves of each limb read in the correct order.
  29.    This is kept in an adj variable.  Doing that measures about 4 c/l faster
  30.    than just writing HALF_ENDIAN_ADJ(i) in the integer loop.  The latter
  31.    shouldn't be 6 cycles worth of work, but perhaps it doesn't schedule well
  32.    (on gcc 3.2.1 at least).  The fraction loop doesn't seem affected, but we
  33.    still use a variable since that ought to work out best.  */
  34. mp_limb_t
  35. mpn_divrem_1 (mp_ptr qp_limbptr, mp_size_t xsize_limbs,
  36.               mp_srcptr ap_limbptr, mp_size_t size_limbs, mp_limb_t d_limb)
  37. {
  38.   mp_size_t  total_size_limbs;
  39.   mp_size_t  i;
  40.   ASSERT (xsize_limbs >= 0);
  41.   ASSERT (size_limbs >= 0);
  42.   ASSERT (d_limb != 0);
  43.   /* FIXME: What's the correct overlap rule when xsize!=0? */
  44.   ASSERT (MPN_SAME_OR_SEPARATE_P (qp_limbptr + xsize_limbs,
  45.                                   ap_limbptr, size_limbs));
  46.   total_size_limbs = size_limbs + xsize_limbs;
  47.   if (UNLIKELY (total_size_limbs == 0))
  48.     return 0;
  49.   /* udivx is good for total_size==1, and no need to bother checking
  50.      limb<divisor, since if that's likely the caller should check */
  51.   if (UNLIKELY (total_size_limbs == 1))
  52.     {
  53.       mp_limb_t  a, q;
  54.       a = (LIKELY (size_limbs != 0) ? ap_limbptr[0] : 0);
  55.       q = a / d_limb;
  56.       qp_limbptr[0] = q;
  57.       return a - q*d_limb;
  58.     }
  59.   if (d_limb <= CNST_LIMB(0xFFFFFFFF))
  60.     {
  61.       mp_size_t  size, xsize, total_size, adj;
  62.       unsigned   *qp, n1, n0, q, r, nshift, norm_rmask;
  63.       mp_limb_t  dinv_limb;
  64.       const unsigned *ap;
  65.       int        norm, norm_rshift;
  66.       size = 2 * size_limbs;
  67.       xsize = 2 * xsize_limbs;
  68.       total_size = size + xsize;
  69.       ap = (unsigned *) ap_limbptr;
  70.       qp = (unsigned *) qp_limbptr;
  71.       qp += xsize;
  72.       r = 0;        /* initial remainder */
  73.       if (LIKELY (size != 0))
  74.         {
  75.           n1 = ap[size-1 + HALF_ENDIAN_ADJ(1)];
  76.           /* If the length of the source is uniformly distributed, then
  77.              there's a 50% chance of the high 32-bits being zero, which we
  78.              can skip.  */
  79.           if (n1 == 0)
  80.             {
  81.               n1 = ap[size-2 + HALF_ENDIAN_ADJ(0)];
  82.               total_size--;
  83.               size--;
  84.               ASSERT (size > 0);  /* because always even */
  85.               qp[size + HALF_ENDIAN_ADJ(1)] = 0;
  86.             }
  87.           /* Skip a division if high < divisor (high quotient 0).  Testing
  88.              here before before normalizing will still skip as often as
  89.              possible.  */
  90.           if (n1 < d_limb)
  91.             {
  92.               r = n1;
  93.               size--;
  94.               qp[size + HALF_ENDIAN_ADJ(size)] = 0;
  95.               total_size--;
  96.               if (total_size == 0)
  97.                 return r;
  98.             }
  99.         }
  100.       count_leading_zeros_32 (norm, d_limb);
  101.       norm -= 32;
  102.       d_limb <<= norm;
  103.       r <<= norm;
  104.       norm_rshift = 32 - norm;
  105.       norm_rmask = (norm == 0 ? 0 : 0xFFFFFFFF);
  106.       invert_half_limb (dinv_limb, d_limb);
  107.       if (LIKELY (size != 0))
  108.         {
  109.           i = size - 1;
  110.           adj = HALF_ENDIAN_ADJ (i);
  111.           n1 = ap[i + adj];
  112.           adj = -adj;
  113.           r |= ((n1 >> norm_rshift) & norm_rmask);
  114.           for ( ; i > 0; i--)
  115.             {
  116.               n0 = ap[i-1 + adj];
  117.               adj = -adj;
  118.               nshift = (n1 << norm) | ((n0 >> norm_rshift) & norm_rmask);
  119.               udiv_qrnnd_half_preinv (q, r, r, nshift, d_limb, dinv_limb);
  120.               qp[i + adj] = q;
  121.               n1 = n0;
  122.             }
  123.           nshift = n1 << norm;
  124.           udiv_qrnnd_half_preinv (q, r, r, nshift, d_limb, dinv_limb);
  125.           qp[0 + HALF_ENDIAN_ADJ(0)] = q;
  126.         }
  127.       qp -= xsize;
  128.       adj = HALF_ENDIAN_ADJ (0);
  129.       for (i = xsize-1; i >= 0; i--)
  130.         {
  131.           udiv_qrnnd_half_preinv (q, r, r, 0, d_limb, dinv_limb);
  132.           adj = -adj;
  133.           qp[i + adj] = q;
  134.         }
  135.       return r >> norm;
  136.     }
  137.   else
  138.     {
  139.       mp_srcptr  ap;
  140.       mp_ptr     qp;
  141.       mp_size_t  size, xsize, total_size;
  142.       mp_limb_t  d, n1, n0, q, r, dinv, nshift, norm_rmask;
  143.       int        norm, norm_rshift;
  144.       ap = ap_limbptr;
  145.       qp = qp_limbptr;
  146.       size = size_limbs;
  147.       xsize = xsize_limbs;
  148.       total_size = total_size_limbs;
  149.       d = d_limb;
  150.       qp += total_size;   /* above high limb */
  151.       r = 0;              /* initial remainder */
  152.       if (LIKELY (size != 0))
  153.         {
  154.           /* Skip a division if high < divisor (high quotient 0).  Testing
  155.              here before before normalizing will still skip as often as
  156.              possible.  */
  157.           n1 = ap[size-1];
  158.           if (n1 < d)
  159.             {
  160.               r = n1;
  161.               *--qp = 0;
  162.               total_size--;
  163.               if (total_size == 0)
  164.                 return r;
  165.               size--;
  166.             }
  167.         }
  168.       count_leading_zeros (norm, d);
  169.       d <<= norm;
  170.       r <<= norm;
  171.       norm_rshift = GMP_LIMB_BITS - norm;
  172.       norm_rmask = (norm == 0 ? 0 : ~CNST_LIMB(0));
  173.       invert_limb (dinv, d);
  174.       if (LIKELY (size != 0))
  175.         {
  176.           n1 = ap[size-1];
  177.           r |= ((n1 >> norm_rshift) & norm_rmask);
  178.           for (i = size-2; i >= 0; i--)
  179.             {
  180.               n0 = ap[i];
  181.               nshift = (n1 << norm) | ((n0 >> norm_rshift) & norm_rmask);
  182.               udiv_qrnnd_preinv (q, r, r, nshift, d, dinv);
  183.               *--qp = q;
  184.               n1 = n0;
  185.             }
  186.           nshift = n1 << norm;
  187.           udiv_qrnnd_preinv (q, r, r, nshift, d, dinv);
  188.           *--qp = q;
  189.         }
  190.       for (i = 0; i < xsize; i++)
  191.         {
  192.           udiv_qrnnd_preinv (q, r, r, CNST_LIMB(0), d, dinv);
  193.           *--qp = q;
  194.         }
  195.       return r >> norm;
  196.     }
  197. }