(root)/
gmp-6.3.0/
mpn/
generic/
sbpi1_divappr_q.c
       1  /* mpn_sbpi1_divappr_q -- Schoolbook division using the Möller-Granlund 3/2
       2     division algorithm, returning approximate quotient.  The quotient returned
       3     is either correct, or one too large.
       4  
       5     Contributed to the GNU project by Torbjorn Granlund.
       6  
       7     THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
       8     SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
       9     GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
      10  
      11  Copyright 2007, 2009 Free Software Foundation, Inc.
      12  
      13  This file is part of the GNU MP Library.
      14  
      15  The GNU MP Library is free software; you can redistribute it and/or modify
      16  it under the terms of either:
      17  
      18    * the GNU Lesser General Public License as published by the Free
      19      Software Foundation; either version 3 of the License, or (at your
      20      option) any later version.
      21  
      22  or
      23  
      24    * the GNU General Public License as published by the Free Software
      25      Foundation; either version 2 of the License, or (at your option) any
      26      later version.
      27  
      28  or both in parallel, as here.
      29  
      30  The GNU MP Library is distributed in the hope that it will be useful, but
      31  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      32  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      33  for more details.
      34  
      35  You should have received copies of the GNU General Public License and the
      36  GNU Lesser General Public License along with the GNU MP Library.  If not,
      37  see https://www.gnu.org/licenses/.  */
      38  
      39  
      40  #include "gmp-impl.h"
      41  #include "longlong.h"
      42  
      43  mp_limb_t
      44  mpn_sbpi1_divappr_q (mp_ptr qp,
      45  		     mp_ptr np, mp_size_t nn,
      46  		     mp_srcptr dp, mp_size_t dn,
      47  		     mp_limb_t dinv)
      48  {
      49    mp_limb_t qh;
      50    mp_size_t qn, i;
      51    mp_limb_t n1, n0;
      52    mp_limb_t d1, d0;
      53    mp_limb_t cy, cy1;
      54    mp_limb_t q;
      55    mp_limb_t flag;
      56  
      57    ASSERT (dn > 2);
      58    ASSERT (nn >= dn);
      59    ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
      60  
      61    np += nn;
      62  
      63    qn = nn - dn;
      64    if (qn + 1 < dn)
      65      {
      66        dp += dn - (qn + 1);
      67        dn = qn + 1;
      68      }
      69  
      70    qh = mpn_cmp (np - dn, dp, dn) >= 0;
      71    if (qh != 0)
      72      mpn_sub_n (np - dn, np - dn, dp, dn);
      73  
      74    qp += qn;
      75  
      76    dn -= 2;			/* offset dn by 2 for main division loops,
      77  				   saving two iterations in mpn_submul_1.  */
      78    d1 = dp[dn + 1];
      79    d0 = dp[dn + 0];
      80  
      81    np -= 2;
      82  
      83    n1 = np[1];
      84  
      85    for (i = qn - (dn + 2); i >= 0; i--)
      86      {
      87        np--;
      88        if (UNLIKELY (n1 == d1) && np[1] == d0)
      89  	{
      90  	  q = GMP_NUMB_MASK;
      91  	  mpn_submul_1 (np - dn, dp, dn + 2, q);
      92  	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
      93  	}
      94        else
      95  	{
      96  	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
      97  
      98  	  cy = mpn_submul_1 (np - dn, dp, dn, q);
      99  
     100  	  cy1 = n0 < cy;
     101  	  n0 = (n0 - cy) & GMP_NUMB_MASK;
     102  	  cy = n1 < cy1;
     103  	  n1 -= cy1;
     104  	  np[0] = n0;
     105  
     106  	  if (UNLIKELY (cy != 0))
     107  	    {
     108  	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
     109  	      q--;
     110  	    }
     111  	}
     112  
     113        *--qp = q;
     114      }
     115  
     116    flag = ~CNST_LIMB(0);
     117  
     118    if (dn >= 0)
     119      {
     120        for (i = dn; i > 0; i--)
     121  	{
     122  	  np--;
     123  	  if (UNLIKELY (n1 >= (d1 & flag)))
     124  	    {
     125  	      q = GMP_NUMB_MASK;
     126  	      cy = mpn_submul_1 (np - dn, dp, dn + 2, q);
     127  
     128  	      if (UNLIKELY (n1 != cy))
     129  		{
     130  		  if (n1 < (cy & flag))
     131  		    {
     132  		      q--;
     133  		      mpn_add_n (np - dn, np - dn, dp, dn + 2);
     134  		    }
     135  		  else
     136  		    flag = 0;
     137  		}
     138  	      n1 = np[1];
     139  	    }
     140  	  else
     141  	    {
     142  	      udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
     143  
     144  	      cy = mpn_submul_1 (np - dn, dp, dn, q);
     145  
     146  	      cy1 = n0 < cy;
     147  	      n0 = (n0 - cy) & GMP_NUMB_MASK;
     148  	      cy = n1 < cy1;
     149  	      n1 -= cy1;
     150  	      np[0] = n0;
     151  
     152  	      if (UNLIKELY (cy != 0))
     153  		{
     154  		  n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
     155  		  q--;
     156  		}
     157  	    }
     158  
     159  	  *--qp = q;
     160  
     161  	  /* Truncate operands.  */
     162  	  dn--;
     163  	  dp++;
     164  	}
     165  
     166        np--;
     167        if (UNLIKELY (n1 >= (d1 & flag)))
     168  	{
     169  	  q = GMP_NUMB_MASK;
     170  	  cy = mpn_submul_1 (np, dp, 2, q);
     171  
     172  	  if (UNLIKELY (n1 != cy))
     173  	    {
     174  	      if (n1 < (cy & flag))
     175  		{
     176  		  q--;
     177  		  add_ssaaaa (np[1], np[0], np[1], np[0], dp[1], dp[0]);
     178  		}
     179  	      else
     180  		flag = 0;
     181  	    }
     182  	  n1 = np[1];
     183  	}
     184        else
     185  	{
     186  	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
     187  
     188  	  np[1] = n1;
     189  	  np[0] = n0;
     190  	}
     191  
     192        *--qp = q;
     193      }
     194  
     195    ASSERT_ALWAYS (np[1] == n1);
     196  
     197    return qh;
     198  }