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

数学计算

开发平台:

Unix_Linux

  1. /* hgcd2.c
  2.    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
  3.    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
  4.    GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
  5. Copyright 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2008 Free Software
  6. Foundation, Inc.
  7. This file is part of the GNU MP Library.
  8. The GNU MP Library is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU Lesser General Public License as published by
  10. the Free Software Foundation; either version 3 of the License, or (at your
  11. option) any later version.
  12. The GNU MP Library is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  14. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  15. License for more details.
  16. You should have received a copy of the GNU Lesser General Public License
  17. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  18. #include "gmp.h"
  19. #include "gmp-impl.h"
  20. #include "longlong.h"
  21. #if GMP_NAIL_BITS == 0
  22. /* Copied from the old mpn/generic/gcdext.c, and modified slightly to return
  23.    the remainder. */
  24. /* Single-limb division optimized for small quotients. */
  25. static inline mp_limb_t
  26. div1 (mp_ptr rp,
  27.       mp_limb_t n0,
  28.       mp_limb_t d0)
  29. {
  30.   mp_limb_t q = 0;
  31.   if ((mp_limb_signed_t) n0 < 0)
  32.     {
  33.       int cnt;
  34.       for (cnt = 1; (mp_limb_signed_t) d0 >= 0; cnt++)
  35. {
  36.   d0 = d0 << 1;
  37. }
  38.       q = 0;
  39.       while (cnt)
  40. {
  41.   q <<= 1;
  42.   if (n0 >= d0)
  43.     {
  44.       n0 = n0 - d0;
  45.       q |= 1;
  46.     }
  47.   d0 = d0 >> 1;
  48.   cnt--;
  49. }
  50.     }
  51.   else
  52.     {
  53.       int cnt;
  54.       for (cnt = 0; n0 >= d0; cnt++)
  55. {
  56.   d0 = d0 << 1;
  57. }
  58.       q = 0;
  59.       while (cnt)
  60. {
  61.   d0 = d0 >> 1;
  62.   q <<= 1;
  63.   if (n0 >= d0)
  64.     {
  65.       n0 = n0 - d0;
  66.       q |= 1;
  67.     }
  68.   cnt--;
  69. }
  70.     }
  71.   *rp = n0;
  72.   return q;
  73. }
  74. /* Two-limb division optimized for small quotients.  */
  75. static inline mp_limb_t
  76. div2 (mp_ptr rp,
  77.       mp_limb_t nh, mp_limb_t nl,
  78.       mp_limb_t dh, mp_limb_t dl)
  79. {
  80.   mp_limb_t q = 0;
  81.   if ((mp_limb_signed_t) nh < 0)
  82.     {
  83.       int cnt;
  84.       for (cnt = 1; (mp_limb_signed_t) dh >= 0; cnt++)
  85. {
  86.   dh = (dh << 1) | (dl >> (GMP_LIMB_BITS - 1));
  87.   dl = dl << 1;
  88. }
  89.       while (cnt)
  90. {
  91.   q <<= 1;
  92.   if (nh > dh || (nh == dh && nl >= dl))
  93.     {
  94.       sub_ddmmss (nh, nl, nh, nl, dh, dl);
  95.       q |= 1;
  96.     }
  97.   dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
  98.   dh = dh >> 1;
  99.   cnt--;
  100. }
  101.     }
  102.   else
  103.     {
  104.       int cnt;
  105.       for (cnt = 0; nh > dh || (nh == dh && nl >= dl); cnt++)
  106. {
  107.   dh = (dh << 1) | (dl >> (GMP_LIMB_BITS - 1));
  108.   dl = dl << 1;
  109. }
  110.       while (cnt)
  111. {
  112.   dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
  113.   dh = dh >> 1;
  114.   q <<= 1;
  115.   if (nh > dh || (nh == dh && nl >= dl))
  116.     {
  117.       sub_ddmmss (nh, nl, nh, nl, dh, dl);
  118.       q |= 1;
  119.     }
  120.   cnt--;
  121. }
  122.     }
  123.   rp[0] = nl;
  124.   rp[1] = nh;
  125.   return q;
  126. }
  127. #if 0
  128. /* This div2 uses less branches, but it seems to nevertheless be
  129.    slightly slower than the above code. */
  130. static inline mp_limb_t
  131. div2 (mp_ptr rp,
  132.       mp_limb_t nh, mp_limb_t nl,
  133.       mp_limb_t dh, mp_limb_t dl)
  134. {
  135.   mp_limb_t q = 0;
  136.   int ncnt;
  137.   int dcnt;
  138.   count_leading_zeros (ncnt, nh);
  139.   count_leading_zeros (dcnt, dh);
  140.   dcnt -= ncnt;
  141.   dh = (dh << dcnt) + (-(dcnt > 0) & (dl >> (GMP_LIMB_BITS - dcnt)));
  142.   dl <<= dcnt;
  143.   do
  144.     {
  145.       mp_limb_t bit;
  146.       q <<= 1;
  147.       if (UNLIKELY (nh == dh))
  148. bit = (nl >= dl);
  149.       else
  150. bit = (nh > dh);
  151.       q |= bit;
  152.       sub_ddmmss (nh, nl, nh, nl, (-bit) & dh, (-bit) & dl);
  153.       dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
  154.       dh = dh >> 1;
  155.     }
  156.   while (dcnt--);
  157.   rp[0] = nl;
  158.   rp[1] = nh;
  159.   return q;
  160. }
  161. #endif
  162. #else /* GMP_NAIL_BITS != 0 */
  163. /* Check all functions for nail support. */
  164. /* hgcd2 should be defined to take inputs including nail bits, and
  165.    produce a matrix with elements also including nail bits. This is
  166.    necessary, for the matrix elements to be useful with mpn_mul_1,
  167.    mpn_addmul_1 and friends. */
  168. #error Not implemented
  169. #endif /* GMP_NAIL_BITS != 0 */
  170. /* Reduces a,b until |a-b| (almost) fits in one limb + 1 bit. Constructs
  171.    matrix M. Returns 1 if we make progress, i.e. can perform at least
  172.    one subtraction. Otherwise returns zero.. */
  173. /* FIXME: Possible optimizations:
  174.    The div2 function starts with checking the most significant bit of
  175.    the numerator. We can maintained normalized operands here, call
  176.    hgcd with normalized operands only, which should make the code
  177.    simpler and possibly faster.
  178.    Experiment with table lookups on the most significant bits.
  179.    This function is also a candidate for assembler implementation.
  180. */
  181. int
  182. mpn_hgcd2 (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
  183.    struct hgcd_matrix1 *M)
  184. {
  185.   mp_limb_t u00, u01, u10, u11;
  186.   if (ah < 2 || bh < 2)
  187.     return 0;
  188.   if (ah > bh || (ah == bh && al > bl))
  189.     {
  190.       sub_ddmmss (ah, al, ah, al, bh, bl);
  191.       if (ah < 2)
  192. return 0;
  193.       u00 = u01 = u11 = 1;
  194.       u10 = 0;
  195.     }
  196.   else
  197.     {
  198.       sub_ddmmss (bh, bl, bh, bl, ah, al);
  199.       if (bh < 2)
  200. return 0;
  201.       u00 = u10 = u11 = 1;
  202.       u01 = 0;
  203.     }
  204.   if (ah < bh)
  205.     goto subtract_a;
  206.   for (;;)
  207.     {
  208.       ASSERT (ah >= bh);
  209.       if (ah == bh)
  210. goto done;
  211.       if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
  212. {
  213.   ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
  214.   bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
  215.   break;
  216. }
  217.       /* Subtract a -= q b, and multiply M from the right by (1 q ; 0
  218.  1), affecting the second column of M. */
  219.       ASSERT (ah > bh);
  220.       sub_ddmmss (ah, al, ah, al, bh, bl);
  221.       if (ah < 2)
  222. goto done;
  223.       if (ah <= bh)
  224. {
  225.   /* Use q = 1 */
  226.   u01 += u00;
  227.   u11 += u10;
  228. }
  229.       else
  230. {
  231.   mp_limb_t r[2];
  232.   mp_limb_t q = div2 (r, ah, al, bh, bl);
  233.   al = r[0]; ah = r[1];
  234.   if (ah < 2)
  235.     {
  236.       /* A is too small, but q is correct. */
  237.       u01 += q * u00;
  238.       u11 += q * u10;
  239.       goto done;
  240.     }
  241.   q++;
  242.   u01 += q * u00;
  243.   u11 += q * u10;
  244. }
  245.     subtract_a:
  246.       ASSERT (bh >= ah);
  247.       if (ah == bh)
  248. goto done;
  249.       if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
  250. {
  251.   ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
  252.   bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
  253.   goto subtract_a1;
  254. }
  255.       /* Subtract b -= q a, and multiply M from the right by (1 0 ; q
  256.  1), affecting the first column of M. */
  257.       sub_ddmmss (bh, bl, bh, bl, ah, al);
  258.       if (bh < 2)
  259. goto done;
  260.       if (bh <= ah)
  261. {
  262.   /* Use q = 1 */
  263.   u00 += u01;
  264.   u10 += u11;
  265. }
  266.       else
  267. {
  268.   mp_limb_t r[2];
  269.   mp_limb_t q = div2 (r, bh, bl, ah, al);
  270.   bl = r[0]; bh = r[1];
  271.   if (bh < 2)
  272.     {
  273.       /* B is too small, but q is correct. */
  274.       u00 += q * u01;
  275.       u10 += q * u11;
  276.       goto done;
  277.     }
  278.   q++;
  279.   u00 += q * u01;
  280.   u10 += q * u11;
  281. }
  282.     }
  283.   /* NOTE: Since we discard the least significant half limb, we don't
  284.      get a truly maximal M (corresponding to |a - b| <
  285.      2^{GMP_LIMB_BITS +1}). */
  286.   /* Single precision loop */
  287.   for (;;)
  288.     {
  289.       ASSERT (ah >= bh);
  290.       if (ah == bh)
  291. break;
  292.       ah -= bh;
  293.       if (ah < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
  294. break;
  295.       if (ah <= bh)
  296. {
  297.   /* Use q = 1 */
  298.   u01 += u00;
  299.   u11 += u10;
  300. }
  301.       else
  302. {
  303.   mp_limb_t r;
  304.   mp_limb_t q = div1 (&r, ah, bh);
  305.   ah = r;
  306.   if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
  307.     {
  308.       /* A is too small, but q is correct. */
  309.       u01 += q * u00;
  310.       u11 += q * u10;
  311.       break;
  312.     }
  313.   q++;
  314.   u01 += q * u00;
  315.   u11 += q * u10;
  316. }
  317.     subtract_a1:
  318.       ASSERT (bh >= ah);
  319.       if (ah == bh)
  320. break;
  321.       bh -= ah;
  322.       if (bh < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
  323. break;
  324.       if (bh <= ah)
  325. {
  326.   /* Use q = 1 */
  327.   u00 += u01;
  328.   u10 += u11;
  329. }
  330.       else
  331. {
  332.   mp_limb_t r;
  333.   mp_limb_t q = div1 (&r, bh, ah);
  334.   bh = r;
  335.   if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
  336.     {
  337.       /* B is too small, but q is correct. */
  338.       u00 += q * u01;
  339.       u10 += q * u11;
  340.       break;
  341.     }
  342.   q++;
  343.   u00 += q * u01;
  344.   u10 += q * u11;
  345. }
  346.     }
  347.  done:
  348.   M->u[0][0] = u00; M->u[0][1] = u01;
  349.   M->u[1][0] = u10; M->u[1][1] = u11;
  350.   return 1;
  351. }
  352. /* Sets (r;b) = (a;b) M, with M = (u00, u01; u10, u11). Vector must
  353.  * have space for n + 1 limbs. Uses three buffers to avoid a copy*/
  354. mp_size_t
  355. mpn_hgcd_mul_matrix1_vector (const struct hgcd_matrix1 *M,
  356.      mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
  357. {
  358.   mp_limb_t ah, bh;
  359.   /* Compute (r,b) <-- (u00 a + u10 b, u01 a + u11 b) as
  360.      r  = u00 * a
  361.      r += u10 * b
  362.      b *= u11
  363.      b += u01 * a
  364.   */
  365. #if HAVE_NATIVE_mpn_addaddmul_1msb0
  366.   ah = mpn_addaddmul_1msb0 (rp, ap, bp, n, M->u[0][0], M->u[1][0]);
  367.   bh = mpn_addaddmul_1msb0 (bp, bp, ap, n, M->u[1][1], M->u[0][1]);
  368. #else
  369.   ah =     mpn_mul_1 (rp, ap, n, M->u[0][0]);
  370.   ah += mpn_addmul_1 (rp, bp, n, M->u[1][0]);
  371.   bh =     mpn_mul_1 (bp, bp, n, M->u[1][1]);
  372.   bh += mpn_addmul_1 (bp, ap, n, M->u[0][1]);
  373. #endif
  374.   rp[n] = ah;
  375.   bp[n] = bh;
  376.   n += (ah | bh) > 0;
  377.   return n;
  378. }
  379. /* Sets (r;b) = M^{-1}(a;b), with M^{-1} = (u11, -u01; -u10, u00) from
  380.    the left. Uses three buffers, to avoid a copy. */
  381. mp_size_t
  382. mpn_hgcd_mul_matrix1_inverse_vector (const struct hgcd_matrix1 *M,
  383.      mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
  384. {
  385.   mp_limb_t h0, h1;
  386.   /* Compute (r;b) <-- (u11 a - u01 b; -u10 a + u00 b) as
  387.      r  = u11 * a
  388.      r -= u01 * b
  389.      b *= u00
  390.      b -= u10 * a
  391.   */
  392.   h0 =    mpn_mul_1 (rp, ap, n, M->u[1][1]);
  393.   h1 = mpn_submul_1 (rp, bp, n, M->u[0][1]);
  394.   ASSERT (h0 == h1);
  395.   h0 =    mpn_mul_1 (bp, bp, n, M->u[0][0]);
  396.   h1 = mpn_submul_1 (bp, ap, n, M->u[1][0]);
  397.   ASSERT (h0 == h1);
  398.   n -= (rp[n-1] | bp[n-1]) == 0;
  399.   return n;
  400. }