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

数学计算

开发平台:

Unix_Linux

  1. /* mpn_mu_div_q.
  2.    Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
  3.    THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
  4.    SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
  5.    GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
  6. Copyright 2005, 2006, 2007, 2009, 2010 Free Software 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. /*
  19.    The idea of the algorithm used herein is to compute a smaller inverted value
  20.    than used in the standard Barrett algorithm, and thus save time in the
  21.    Newton iterations, and pay just a small price when using the inverted value
  22.    for developing quotient bits.  This algorithm was presented at ICMS 2006.
  23. */
  24. /*
  25.   Things to work on:
  26.   1. This is a rudimentary implementation of mpn_mu_div_q.  The algorithm is
  27.      probably close to optimal, except when mpn_mu_divappr_q fails.
  28.      An alternative which could be considered for much simpler code for the
  29.      complex qn>=dn arm would be to allocate a temporary nn+1 limb buffer, then
  30.      simply call mpn_mu_divappr_q.  Such a temporary allocation is
  31.      unfortunately very large.
  32.   2. We used to fall back to mpn_mu_div_qr when we detect a possible
  33.      mpn_mu_divappr_q rounding problem, now we multiply and compare.
  34.      Unfortunately, since mpn_mu_divappr_q does not return the partial
  35.      remainder, this also doesn't become optimal.  A mpn_mu_divappr_qr could
  36.      solve that.
  37.   3. The allocations done here should be made from the scratch area, which
  38.      then would need to be amended.
  39. */
  40. #include <stdlib.h> /* for NULL */
  41. #include "gmp.h"
  42. #include "gmp-impl.h"
  43. mp_limb_t
  44. mpn_mu_div_q (mp_ptr qp,
  45.       mp_srcptr np, mp_size_t nn,
  46.       mp_srcptr dp, mp_size_t dn,
  47.       mp_ptr scratch)
  48. {
  49.   mp_ptr tp, rp, ip, this_ip;
  50.   mp_size_t qn, in, this_in;
  51.   mp_limb_t cy, qh;
  52.   TMP_DECL;
  53.   TMP_MARK;
  54.   qn = nn - dn;
  55.   tp = TMP_BALLOC_LIMBS (qn + 1);
  56.   if (qn >= dn) /* nn >= 2*dn + 1 */
  57.     {
  58.       /* Find max inverse size needed by the two preinv calls.  FIXME: This is
  59.  not optimal, it underestimates the invariance.  */
  60.       if (dn != qn)
  61. {
  62.   mp_size_t in1, in2;
  63.   in1 = mpn_mu_div_qr_choose_in (qn - dn, dn, 0);
  64.   in2 = mpn_mu_divappr_q_choose_in (dn + 1, dn, 0);
  65.   in = MAX (in1, in2);
  66. }
  67.       else
  68. {
  69.   in = mpn_mu_divappr_q_choose_in (dn + 1, dn, 0);
  70. }
  71.       ip = TMP_BALLOC_LIMBS (in + 1);
  72.       if (dn == in)
  73. {
  74.   MPN_COPY (scratch + 1, dp, in);
  75.   scratch[0] = 1;
  76.   mpn_invertappr (ip, scratch, in + 1, NULL);
  77.   MPN_COPY_INCR (ip, ip + 1, in);
  78. }
  79.       else
  80. {
  81.   cy = mpn_add_1 (scratch, dp + dn - (in + 1), in + 1, 1);
  82.   if (UNLIKELY (cy != 0))
  83.     MPN_ZERO (ip, in);
  84.   else
  85.     {
  86.       mpn_invertappr (ip, scratch, in + 1, NULL);
  87.       MPN_COPY_INCR (ip, ip + 1, in);
  88.     }
  89. }
  90.        /* |_______________________|   dividend
  91.  |________|   divisor  */
  92.       rp = TMP_BALLOC_LIMBS (2 * dn + 1);
  93.       this_in = mpn_mu_div_qr_choose_in (qn - dn, dn, 0);
  94.       this_ip = ip + in - this_in;
  95.       qh = mpn_preinv_mu_div_qr (tp + dn + 1, rp + dn + 1, np + dn, qn, dp, dn,
  96.  this_ip, this_in, scratch);
  97.       MPN_COPY (rp + 1, np, dn);
  98.       rp[0] = 0;
  99.       this_in = mpn_mu_divappr_q_choose_in (dn + 1, dn, 0);
  100.       this_ip = ip + in - this_in;
  101.       cy = mpn_preinv_mu_divappr_q (tp, rp, 2 * dn + 1, dp, dn,
  102.     this_ip, this_in, scratch);
  103.       if (UNLIKELY (cy != 0))
  104. {
  105.   /* Since the partial remainder fed to mpn_preinv_mu_divappr_q was
  106.      canonically reduced, replace the returned value of B^(qn-dn)+eps
  107.      by the largest possible value.  */
  108.   mp_size_t i;
  109.   for (i = 0; i < dn + 1; i++)
  110.     tp[i] = GMP_NUMB_MAX;
  111. }
  112.       /* The max error of mpn_mu_divappr_q is +4.  If the low quotient limb is
  113.  greater than the max error, we cannot trust the quotient.  */
  114.       if (tp[0] > 4)
  115. {
  116.   MPN_COPY (qp, tp + 1, qn);
  117. }
  118.       else
  119. {
  120.   mp_limb_t cy;
  121.   mp_ptr pp;
  122.   /* FIXME: can we use already allocated space? */
  123.   pp = TMP_BALLOC_LIMBS (nn);
  124.   mpn_mul (pp, tp + 1, qn, dp, dn);
  125.   cy = (qh != 0) ? mpn_add_n (pp + qn, pp + qn, dp, dn) : 0;
  126.   if (cy || mpn_cmp (pp, np, nn) > 0) /* At most is wrong by one, no cycle. */
  127.     qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
  128.   else /* Same as above */
  129.     MPN_COPY (qp, tp + 1, qn);
  130. }
  131.     }
  132.   else
  133.     {
  134.        /* |_______________________|   dividend
  135.  |________________|   divisor  */
  136.       /* FIXME: When nn = 2dn-1, qn becomes dn-1, and the numerator size passed
  137.  here becomes 2dn, i.e., more than nn.  This shouldn't hurt, since only
  138.  the most significant dn-1 limbs will actually be read, but it is not
  139.  pretty.  */
  140.       qh = mpn_mu_divappr_q (tp, np + nn - (2 * qn + 2), 2 * qn + 2,
  141.      dp + dn - (qn + 1), qn + 1, scratch);
  142.       /* The max error of mpn_mu_divappr_q is +4, but we get an additional
  143.          error from the divisor truncation.  */
  144.       if (tp[0] > 6)
  145. {
  146.   MPN_COPY (qp, tp + 1, qn);
  147. }
  148.       else
  149. {
  150.   mp_limb_t cy;
  151.   /* FIXME: a shorter product should be enough; we may use already
  152.      allocated space... */
  153.   rp = TMP_BALLOC_LIMBS (nn);
  154.   mpn_mul (rp, dp, dn, tp + 1, qn);
  155.   cy = (qh != 0) ? mpn_add_n (rp + qn, rp + qn, dp, dn) : 0;
  156.   if (cy || mpn_cmp (rp, np, nn) > 0) /* At most is wrong by one, no cycle. */
  157.     qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
  158.   else /* Same as above */
  159.     MPN_COPY (qp, tp + 1, qn);
  160. }
  161.     }
  162.   TMP_FREE;
  163.   return qh;
  164. }
  165. mp_size_t
  166. mpn_mu_div_q_itch (mp_size_t nn, mp_size_t dn, int mua_k)
  167. {
  168.   mp_size_t qn, itch1, itch2;
  169.   qn = nn - dn;
  170.   if (qn >= dn)
  171.     {
  172.       itch1 = mpn_mu_div_qr_itch (qn, dn, mua_k);
  173.       itch2 = mpn_mu_divappr_q_itch (2 * dn + 1, dn, mua_k);
  174.       return MAX (itch1, itch2);
  175.     }
  176.   else
  177.     {
  178.       itch1 = mpn_mu_divappr_q_itch (2 * qn + 2, qn + 1, mua_k);
  179.       return itch1;
  180.     }
  181. }