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

数学计算

开发平台:

Unix_Linux

  1. /* mpn_modexact_1c_odd -- mpn by limb exact division style remainder.
  2.    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
  3.    CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
  4.    FUTURE GNU MP RELEASES.
  5. Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
  6. This file is part of the GNU MP Library.
  7. The GNU MP Library is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU Lesser General Public License as published by
  9. the Free Software Foundation; either version 3 of the License, or (at your
  10. option) any later version.
  11. The GNU MP Library is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  14. License for more details.
  15. You should have received a copy of the GNU Lesser General Public License
  16. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  17. #include "gmp.h"
  18. #include "gmp-impl.h"
  19. #include "longlong.h"
  20. /* Calculate an r satisfying
  21.            r*B^k + a - c == q*d
  22.    where B=2^GMP_LIMB_BITS, a is {src,size}, k is either size or size-1
  23.    (the caller won't know which), and q is the quotient (discarded).  d must
  24.    be odd, c can be any limb value.
  25.    If c<d then r will be in the range 0<=r<d, or if c>=d then 0<=r<=d.
  26.    This slightly strange function suits the initial Nx1 reduction for GCDs
  27.    or Jacobi symbols since the factors of 2 in B^k can be ignored, leaving
  28.    -r == a mod d (by passing c=0).  For a GCD the factor of -1 on r can be
  29.    ignored, or for the Jacobi symbol it can be accounted for.  The function
  30.    also suits divisibility and congruence testing since if r=0 (or r=d) is
  31.    obtained then a==c mod d.
  32.    r is a bit like the remainder returned by mpn_divexact_by3c, and is the
  33.    sort of remainder mpn_divexact_1 might return.  Like mpn_divexact_by3c, r
  34.    represents a borrow, since effectively quotient limbs are chosen so that
  35.    subtracting that multiple of d from src at each step will produce a zero
  36.    limb.
  37.    A long calculation can be done piece by piece from low to high by passing
  38.    the return value from one part as the carry parameter to the next part.
  39.    The effective final k becomes anything between size and size-n, if n
  40.    pieces are used.
  41.    A similar sort of routine could be constructed based on adding multiples
  42.    of d at each limb, much like redc in mpz_powm does.  Subtracting however
  43.    has a small advantage that when subtracting to cancel out l there's never
  44.    a borrow into h, whereas using an addition would put a carry into h
  45.    depending whether l==0 or l!=0.
  46.    In terms of efficiency, this function is similar to a mul-by-inverse
  47.    mpn_mod_1.  Both are essentially two multiplies and are best suited to
  48.    CPUs with low latency multipliers (in comparison to a divide instruction
  49.    at least.)  But modexact has a few less supplementary operations, only
  50.    needs low part and high part multiplies, and has fewer working quantities
  51.    (helping CPUs with few registers).
  52.    In the main loop it will be noted that the new carry (call it r) is the
  53.    sum of the high product h and any borrow from l=s-c.  If c<d then we will
  54.    have r<d too, for the following reasons.  Let q=l*inverse be the quotient
  55.    limb, so that q*d = B*h + l, where B=2^GMP_NUMB_BITS.  Now if h=d-1 then
  56.        l = q*d - B*(d-1) <= (B-1)*d - B*(d-1) = B-d
  57.    But if l=s-c produces a borrow when c<d, then l>=B-d+1 and hence will
  58.    never have h=d-1 and so r=h+borrow <= d-1.
  59.    When c>=d, on the other hand, h=d-1 can certainly occur together with a
  60.    borrow, thereby giving only r<=d, as per the function definition above.
  61.    As a design decision it's left to the caller to check for r=d if it might
  62.    be passing c>=d.  Several applications have c<d initially so the extra
  63.    test is often unnecessary, for example the GCDs or a plain divisibility
  64.    d|a test will pass c=0.
  65.    The special case for size==1 is so that it can be assumed c<=d in the
  66.    high<=divisor test at the end.  c<=d is only guaranteed after at least
  67.    one iteration of the main loop.  There's also a decent chance one % is
  68.    faster than a binvert_limb, though that will depend on the processor.
  69.    A CPU specific implementation might want to omit the size==1 code or the
  70.    high<divisor test.  mpn/x86/k6/mode1o.asm for instance finds neither
  71.    useful.  */
  72. mp_limb_t
  73. mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d,
  74.                      mp_limb_t orig_c)
  75. {
  76.   mp_limb_t  s, h, l, inverse, dummy, dmul, ret;
  77.   mp_limb_t  c = orig_c;
  78.   mp_size_t  i;
  79.   ASSERT (size >= 1);
  80.   ASSERT (d & 1);
  81.   ASSERT_MPN (src, size);
  82.   ASSERT_LIMB (d);
  83.   ASSERT_LIMB (c);
  84.   if (size == 1)
  85.     {
  86.       s = src[0];
  87.       if (s > c)
  88. {
  89.   l = s-c;
  90.   h = l % d;
  91.   if (h != 0)
  92.     h = d - h;
  93. }
  94.       else
  95. {
  96.   l = c-s;
  97.   h = l % d;
  98. }
  99.       return h;
  100.     }
  101.   binvert_limb (inverse, d);
  102.   dmul = d << GMP_NAIL_BITS;
  103.   i = 0;
  104.   do
  105.     {
  106.       s = src[i];
  107.       SUBC_LIMB (c, l, s, c);
  108.       l = (l * inverse) & GMP_NUMB_MASK;
  109.       umul_ppmm (h, dummy, l, dmul);
  110.       c += h;
  111.     }
  112.   while (++i < size-1);
  113.   s = src[i];
  114.   if (s <= d)
  115.     {
  116.       /* With high<=d the final step can be a subtract and addback.  If c==0
  117.  then the addback will restore to l>=0.  If c==d then will get l==d
  118.  if s==0, but that's ok per the function definition.  */
  119.       l = c - s;
  120.       if (c < s)
  121. l += d;
  122.       ret = l;
  123.     }
  124.   else
  125.     {
  126.       /* Can't skip a divide, just do the loop code once more. */
  127.       SUBC_LIMB (c, l, s, c);
  128.       l = (l * inverse) & GMP_NUMB_MASK;
  129.       umul_ppmm (h, dummy, l, dmul);
  130.       c += h;
  131.       ret = c;
  132.     }
  133.   ASSERT (orig_c < d ? ret < d : ret <= d);
  134.   return ret;
  135. }
  136. #if 0
  137. /* The following is an alternate form that might shave one cycle on a
  138.    superscalar processor since it takes c+=h off the dependent chain,
  139.    leaving just a low product, high product, and a subtract.
  140.    This is for CPU specific implementations to consider.  A special case for
  141.    high<divisor and/or size==1 can be added if desired.
  142.    Notice that c is only ever 0 or 1, since if s-c produces a borrow then
  143.    x=0xFF..FF and x-h cannot produce a borrow.  The c=(x>s) could become
  144.    c=(x==0xFF..FF) too, if that helped.  */
  145. mp_limb_t
  146. mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d, mp_limb_t h)
  147. {
  148.   mp_limb_t  s, x, y, inverse, dummy, dmul, c1, c2;
  149.   mp_limb_t  c = 0;
  150.   mp_size_t  i;
  151.   ASSERT (size >= 1);
  152.   ASSERT (d & 1);
  153.   binvert_limb (inverse, d);
  154.   dmul = d << GMP_NAIL_BITS;
  155.   for (i = 0; i < size; i++)
  156.     {
  157.       ASSERT (c==0 || c==1);
  158.       s = src[i];
  159.       SUBC_LIMB (c1, x, s, c);
  160.       SUBC_LIMB (c2, y, x, h);
  161.       c = c1 + c2;
  162.       y = (y * inverse) & GMP_NUMB_MASK;
  163.       umul_ppmm (h, dummy, y, dmul);
  164.     }
  165.   h += c;
  166.   return h;
  167. }
  168. #endif