(root)/
gmp-6.3.0/
mpf/
ui_sub.c
       1  /* mpf_ui_sub -- Subtract a float from an unsigned long int.
       2  
       3  Copyright 1993-1996, 2001, 2002, 2005, 2014 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library.
       6  
       7  The GNU MP Library is free software; you can redistribute it and/or modify
       8  it under the terms of either:
       9  
      10    * the GNU Lesser General Public License as published by the Free
      11      Software Foundation; either version 3 of the License, or (at your
      12      option) any later version.
      13  
      14  or
      15  
      16    * the GNU General Public License as published by the Free Software
      17      Foundation; either version 2 of the License, or (at your option) any
      18      later version.
      19  
      20  or both in parallel, as here.
      21  
      22  The GNU MP Library is distributed in the hope that it will be useful, but
      23  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      24  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      25  for more details.
      26  
      27  You should have received copies of the GNU General Public License and the
      28  GNU Lesser General Public License along with the GNU MP Library.  If not,
      29  see https://www.gnu.org/licenses/.  */
      30  
      31  #include "gmp-impl.h"
      32  
      33  void
      34  mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
      35  {
      36  #if 1
      37    __mpf_struct uu;
      38    mp_limb_t ul;
      39  
      40    if (u == 0)
      41      {
      42        mpf_neg (r, v);
      43        return;
      44      }
      45  
      46    ul = u;
      47    uu._mp_size = 1;
      48    uu._mp_d = &ul;
      49    uu._mp_exp = 1;
      50    mpf_sub (r, &uu, v);
      51  
      52  #else
      53    mp_srcptr up, vp;
      54    mp_ptr rp, tp;
      55    mp_size_t usize, vsize, rsize;
      56    mp_size_t prec;
      57    mp_exp_t uexp;
      58    mp_size_t ediff;
      59    int negate;
      60    mp_limb_t ulimb;
      61    TMP_DECL;
      62  
      63    vsize = v->_mp_size;
      64  
      65    /* Handle special cases that don't work in generic code below.  */
      66    if (u == 0)
      67      {
      68        mpf_neg (r, v);
      69        return;
      70      }
      71    if (vsize == 0)
      72      {
      73        mpf_set_ui (r, u);
      74        return;
      75      }
      76  
      77    /* If signs of U and V are different, perform addition.  */
      78    if (vsize < 0)
      79      {
      80        __mpf_struct v_negated;
      81        v_negated._mp_size = -vsize;
      82        v_negated._mp_exp = v->_mp_exp;
      83        v_negated._mp_d = v->_mp_d;
      84        mpf_add_ui (r, &v_negated, u);
      85        return;
      86      }
      87  
      88    /* Signs are now known to be the same.  */
      89    ASSERT (vsize > 0);
      90    ulimb = u;
      91    /* Make U be the operand with the largest exponent.  */
      92    negate = 1 < v->_mp_exp;
      93    prec = r->_mp_prec + negate;
      94    rp = r->_mp_d;
      95    if (negate)
      96      {
      97        usize = vsize;
      98        vsize = 1;
      99        up = v->_mp_d;
     100        vp = &ulimb;
     101        uexp = v->_mp_exp;
     102        ediff = uexp - 1;
     103  
     104        /* If U extends beyond PREC, ignore the part that does.  */
     105        if (usize > prec)
     106  	{
     107  	  up += usize - prec;
     108  	  usize = prec;
     109  	}
     110        ASSERT (ediff > 0);
     111      }
     112    else
     113      {
     114        vp = v->_mp_d;
     115        ediff = 1 - v->_mp_exp;
     116    /* Ignore leading limbs in U and V that are equal.  Doing
     117       this helps increase the precision of the result.  */
     118        if (ediff == 0 && ulimb == vp[vsize - 1])
     119  	{
     120  	  usize = 0;
     121  	  vsize--;
     122  	  uexp = 0;
     123  	  /* Note that V might now have leading zero limbs.
     124  	     In that case we have to adjust uexp.  */
     125  	  for (;;)
     126  	    {
     127  	      if (vsize == 0) {
     128  		rsize = 0;
     129  		uexp = 0;
     130  		goto done;
     131  	      }
     132  	      if ( vp[vsize - 1] != 0)
     133  		break;
     134  	      vsize--, uexp--;
     135  	    }
     136  	}
     137        else
     138  	{
     139  	  usize = 1;
     140  	  uexp = 1;
     141  	  up = &ulimb;
     142  	}
     143        ASSERT (usize <= prec);
     144      }
     145  
     146    if (ediff >= prec)
     147      {
     148        /* V completely cancelled.  */
     149        if (rp != up)
     150  	MPN_COPY (rp, up, usize);
     151        rsize = usize;
     152      }
     153    else
     154      {
     155    /* If V extends beyond PREC, ignore the part that does.
     156       Note that this can make vsize neither zero nor negative.  */
     157    if (vsize + ediff > prec)
     158      {
     159        vp += vsize + ediff - prec;
     160        vsize = prec - ediff;
     161      }
     162  
     163        /* Locate the least significant non-zero limb in (the needed
     164  	 parts of) U and V, to simplify the code below.  */
     165        ASSERT (vsize > 0);
     166        for (;;)
     167  	{
     168  	  if (vp[0] != 0)
     169  	    break;
     170  	  vp++, vsize--;
     171  	  if (vsize == 0)
     172  	    {
     173  	      MPN_COPY (rp, up, usize);
     174  	      rsize = usize;
     175  	      goto done;
     176  	    }
     177  	}
     178        for (;;)
     179  	{
     180  	  if (usize == 0)
     181  	    {
     182  	      MPN_COPY (rp, vp, vsize);
     183  	      rsize = vsize;
     184  	      negate ^= 1;
     185  	      goto done;
     186  	    }
     187  	  if (up[0] != 0)
     188  	    break;
     189  	  up++, usize--;
     190  	}
     191  
     192        ASSERT (usize > 0 && vsize > 0);
     193        TMP_MARK;
     194  
     195        tp = TMP_ALLOC_LIMBS (prec);
     196  
     197        /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
     198        /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
     199  
     200        if (usize > ediff)
     201  	{
     202  	  /* U and V partially overlaps.  */
     203  	  if (ediff == 0)
     204  	    {
     205  	      ASSERT (usize == 1 && vsize >= 1 && ulimb == *up); /* usize is 1>ediff, vsize >= 1 */
     206  	      if (1 < vsize)
     207  		{
     208  		  /* u        */
     209  		  /* vvvvvvv  */
     210  		  rsize = vsize;
     211  		  vsize -= 1;
     212  		  /* mpn_cmp (up, vp + vsize - usize, usize) > 0 */
     213  		  if (ulimb > vp[vsize])
     214  		    {
     215  		      tp[vsize] = ulimb - vp[vsize] - 1;
     216  		      ASSERT_CARRY (mpn_neg (tp, vp, vsize));
     217  		    }
     218  		  else
     219  		    {
     220  		      /* vvvvvvv  */  /* Swap U and V. */
     221  		      /* u        */
     222  		      MPN_COPY (tp, vp, vsize);
     223  		      tp[vsize] = vp[vsize] - ulimb;
     224  		      negate = 1;
     225  		    }
     226  		}
     227  	      else /* vsize == usize == 1 */
     228  		{
     229  		  /* u     */
     230  		  /* v     */
     231  		  rsize = 1;
     232  		  negate = ulimb < vp[0];
     233  		  tp[0] = negate ? vp[0] - ulimb: ulimb - vp[0];
     234  		}
     235  	    }
     236  	  else
     237  	    {
     238  	      ASSERT (vsize + ediff <= usize);
     239  	      ASSERT (vsize == 1 && usize >= 2 && ulimb == *vp);
     240  		{
     241  		  /* uuuu     */
     242  		  /*   v      */
     243  		  mp_size_t size;
     244  		  size = usize - ediff - 1;
     245  		  MPN_COPY (tp, up, size);
     246  		  ASSERT_NOCARRY (mpn_sub_1 (tp + size, up + size, usize - size, ulimb));
     247  		  rsize = usize;
     248  		}
     249  		/* Other cases are not possible */
     250  		/* uuuu     */
     251  		/*   vvvvv  */
     252  	    }
     253  	}
     254        else
     255  	{
     256  	  /* uuuu     */
     257  	  /*      vv  */
     258  	  mp_size_t size, i;
     259  	  ASSERT_CARRY (mpn_neg (tp, vp, vsize));
     260  	  rsize = vsize + ediff;
     261  	  size = rsize - usize;
     262  	  for (i = vsize; i < size; i++)
     263  	    tp[i] = GMP_NUMB_MAX;
     264  	  ASSERT_NOCARRY (mpn_sub_1 (tp + size, up, usize, CNST_LIMB (1)));
     265  	}
     266  
     267        /* Full normalize.  Optimize later.  */
     268        while (rsize != 0 && tp[rsize - 1] == 0)
     269  	{
     270  	  rsize--;
     271  	  uexp--;
     272  	}
     273        MPN_COPY (rp, tp, rsize);
     274        TMP_FREE;
     275      }
     276  
     277   done:
     278    r->_mp_size = negate ? -rsize : rsize;
     279    r->_mp_exp = uexp;
     280  #endif
     281  }