github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpn/generic/dcpi1_div_qr.c (about)

     1  /* mpn_dcpi1_div_qr_n -- recursive divide-and-conquer division for arbitrary
     2     size operands.
     3  
     4     Contributed to the GNU project by Torbjorn Granlund.
     5  
     6     THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
     7     SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
     8     GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
     9  
    10  Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
    11  
    12  This file is part of the GNU MP Library.
    13  
    14  The GNU MP Library is free software; you can redistribute it and/or modify
    15  it under the terms of either:
    16  
    17    * the GNU Lesser General Public License as published by the Free
    18      Software Foundation; either version 3 of the License, or (at your
    19      option) any later version.
    20  
    21  or
    22  
    23    * the GNU General Public License as published by the Free Software
    24      Foundation; either version 2 of the License, or (at your option) any
    25      later version.
    26  
    27  or both in parallel, as here.
    28  
    29  The GNU MP Library is distributed in the hope that it will be useful, but
    30  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    31  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    32  for more details.
    33  
    34  You should have received copies of the GNU General Public License and the
    35  GNU Lesser General Public License along with the GNU MP Library.  If not,
    36  see https://www.gnu.org/licenses/.  */
    37  
    38  #include "gmp.h"
    39  #include "gmp-impl.h"
    40  #include "longlong.h"
    41  
    42  
    43  mp_limb_t
    44  mpn_dcpi1_div_qr_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
    45  		    gmp_pi1_t *dinv, mp_ptr tp)
    46  {
    47    mp_size_t lo, hi;
    48    mp_limb_t cy, qh, ql;
    49  
    50    lo = n >> 1;			/* floor(n/2) */
    51    hi = n - lo;			/* ceil(n/2) */
    52  
    53    if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
    54      qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
    55    else
    56      qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
    57  
    58    mpn_mul (tp, qp + lo, hi, dp, lo);
    59  
    60    cy = mpn_sub_n (np + lo, np + lo, tp, n);
    61    if (qh != 0)
    62      cy += mpn_sub_n (np + n, np + n, dp, lo);
    63  
    64    while (cy != 0)
    65      {
    66        qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
    67        cy -= mpn_add_n (np + lo, np + lo, dp, n);
    68      }
    69  
    70    if (BELOW_THRESHOLD (lo, DC_DIV_QR_THRESHOLD))
    71      ql = mpn_sbpi1_div_qr (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
    72    else
    73      ql = mpn_dcpi1_div_qr_n (qp, np + hi, dp + hi, lo, dinv, tp);
    74  
    75    mpn_mul (tp, dp, hi, qp, lo);
    76  
    77    cy = mpn_sub_n (np, np, tp, n);
    78    if (ql != 0)
    79      cy += mpn_sub_n (np + lo, np + lo, dp, hi);
    80  
    81    while (cy != 0)
    82      {
    83        mpn_sub_1 (qp, qp, lo, 1);
    84        cy -= mpn_add_n (np, np, dp, n);
    85      }
    86  
    87    return qh;
    88  }
    89  
    90  mp_limb_t
    91  mpn_dcpi1_div_qr (mp_ptr qp,
    92  		  mp_ptr np, mp_size_t nn,
    93  		  mp_srcptr dp, mp_size_t dn,
    94  		  gmp_pi1_t *dinv)
    95  {
    96    mp_size_t qn;
    97    mp_limb_t qh, cy;
    98    mp_ptr tp;
    99    TMP_DECL;
   100  
   101    TMP_MARK;
   102  
   103    ASSERT (dn >= 6);		/* to adhere to mpn_sbpi1_div_qr's limits */
   104    ASSERT (nn - dn >= 3);	/* to adhere to mpn_sbpi1_div_qr's limits */
   105    ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
   106  
   107    tp = TMP_ALLOC_LIMBS (dn);
   108  
   109    qn = nn - dn;
   110    qp += qn;
   111    np += nn;
   112    dp += dn;
   113  
   114    if (qn > dn)
   115      {
   116        /* Reduce qn mod dn without division, optimizing small operations.  */
   117        do
   118  	qn -= dn;
   119        while (qn > dn);
   120  
   121        qp -= qn;			/* point at low limb of next quotient block */
   122        np -= qn;			/* point in the middle of partial remainder */
   123  
   124        /* Perform the typically smaller block first.  */
   125        if (qn == 1)
   126  	{
   127  	  mp_limb_t q, n2, n1, n0, d1, d0;
   128  
   129  	  /* Handle qh up front, for simplicity. */
   130  	  qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
   131  	  if (qh)
   132  	    ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn));
   133  
   134  	  /* A single iteration of schoolbook: One 3/2 division,
   135  	     followed by the bignum update and adjustment. */
   136  	  n2 = np[0];
   137  	  n1 = np[-1];
   138  	  n0 = np[-2];
   139  	  d1 = dp[-1];
   140  	  d0 = dp[-2];
   141  
   142  	  ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
   143  
   144  	  if (UNLIKELY (n2 == d1) && n1 == d0)
   145  	    {
   146  	      q = GMP_NUMB_MASK;
   147  	      cy = mpn_submul_1 (np - dn, dp - dn, dn, q);
   148  	      ASSERT (cy == n2);
   149  	    }
   150  	  else
   151  	    {
   152  	      udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
   153  
   154  	      if (dn > 2)
   155  		{
   156  		  mp_limb_t cy, cy1;
   157  		  cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
   158  
   159  		  cy1 = n0 < cy;
   160  		  n0 = (n0 - cy) & GMP_NUMB_MASK;
   161  		  cy = n1 < cy1;
   162  		  n1 = (n1 - cy1) & GMP_NUMB_MASK;
   163  		  np[-2] = n0;
   164  
   165  		  if (UNLIKELY (cy != 0))
   166  		    {
   167  		      n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
   168  		      qh -= (q == 0);
   169  		      q = (q - 1) & GMP_NUMB_MASK;
   170  		    }
   171  		}
   172  	      else
   173  		np[-2] = n0;
   174  
   175  	      np[-1] = n1;
   176  	    }
   177  	  qp[0] = q;
   178  	}
   179        else
   180  	{
   181  	  /* Do a 2qn / qn division */
   182  	  if (qn == 2)
   183  	    qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2); /* FIXME: obsolete function. Use 5/3 division? */
   184  	  else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
   185  	    qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
   186  	  else
   187  	    qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
   188  
   189  	  if (qn != dn)
   190  	    {
   191  	      if (qn > dn - qn)
   192  		mpn_mul (tp, qp, qn, dp - dn, dn - qn);
   193  	      else
   194  		mpn_mul (tp, dp - dn, dn - qn, qp, qn);
   195  
   196  	      cy = mpn_sub_n (np - dn, np - dn, tp, dn);
   197  	      if (qh != 0)
   198  		cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
   199  
   200  	      while (cy != 0)
   201  		{
   202  		  qh -= mpn_sub_1 (qp, qp, qn, 1);
   203  		  cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
   204  		}
   205  	    }
   206  	}
   207  
   208        qn = nn - dn - qn;
   209        do
   210  	{
   211  	  qp -= dn;
   212  	  np -= dn;
   213  	  mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
   214  	  qn -= dn;
   215  	}
   216        while (qn > 0);
   217      }
   218    else
   219      {
   220        qp -= qn;			/* point at low limb of next quotient block */
   221        np -= qn;			/* point in the middle of partial remainder */
   222  
   223        if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
   224  	qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
   225        else
   226  	qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
   227  
   228        if (qn != dn)
   229  	{
   230  	  if (qn > dn - qn)
   231  	    mpn_mul (tp, qp, qn, dp - dn, dn - qn);
   232  	  else
   233  	    mpn_mul (tp, dp - dn, dn - qn, qp, qn);
   234  
   235  	  cy = mpn_sub_n (np - dn, np - dn, tp, dn);
   236  	  if (qh != 0)
   237  	    cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
   238  
   239  	  while (cy != 0)
   240  	    {
   241  	      qh -= mpn_sub_1 (qp, qp, qn, 1);
   242  	      cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
   243  	    }
   244  	}
   245      }
   246  
   247    TMP_FREE;
   248    return qh;
   249  }