github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/mpf/sub.c (about)

     1  /* mpf_sub -- Subtract two floats.
     2  
     3  Copyright 1993-1996, 1999-2002, 2004, 2005, 2011, 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.h"
    32  #include "gmp-impl.h"
    33  
    34  void
    35  mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
    36  {
    37    mp_srcptr up, vp;
    38    mp_ptr rp, tp;
    39    mp_size_t usize, vsize, rsize;
    40    mp_size_t prec;
    41    mp_exp_t exp;
    42    mp_size_t ediff;
    43    int negate;
    44    TMP_DECL;
    45  
    46    usize = SIZ (u);
    47    vsize = SIZ (v);
    48  
    49    /* Handle special cases that don't work in generic code below.  */
    50    if (usize == 0)
    51      {
    52        mpf_neg (r, v);
    53        return;
    54      }
    55    if (vsize == 0)
    56      {
    57        if (r != u)
    58          mpf_set (r, u);
    59        return;
    60      }
    61  
    62    /* If signs of U and V are different, perform addition.  */
    63    if ((usize ^ vsize) < 0)
    64      {
    65        __mpf_struct v_negated;
    66        v_negated._mp_size = -vsize;
    67        v_negated._mp_exp = EXP (v);
    68        v_negated._mp_d = PTR (v);
    69        mpf_add (r, u, &v_negated);
    70        return;
    71      }
    72  
    73    TMP_MARK;
    74  
    75    /* Signs are now known to be the same.  */
    76    negate = usize < 0;
    77  
    78    /* Make U be the operand with the largest exponent.  */
    79    if (EXP (u) < EXP (v))
    80      {
    81        mpf_srcptr t;
    82        t = u; u = v; v = t;
    83        negate ^= 1;
    84        usize = SIZ (u);
    85        vsize = SIZ (v);
    86      }
    87  
    88    usize = ABS (usize);
    89    vsize = ABS (vsize);
    90    up = PTR (u);
    91    vp = PTR (v);
    92    rp = PTR (r);
    93    prec = PREC (r) + 1;
    94    exp = EXP (u);
    95    ediff = exp - EXP (v);
    96  
    97    /* If ediff is 0 or 1, we might have a situation where the operands are
    98       extremely close.  We need to scan the operands from the most significant
    99       end ignore the initial parts that are equal.  */
   100    if (ediff <= 1)
   101      {
   102        if (ediff == 0)
   103  	{
   104  	  /* Skip leading limbs in U and V that are equal.  */
   105  	      /* This loop normally exits immediately.  Optimize for that.  */
   106  	      while (up[usize - 1] == vp[vsize - 1])
   107  		{
   108  		  usize--;
   109  		  vsize--;
   110  		  exp--;
   111  
   112  		  if (usize == 0)
   113  		    {
   114                        /* u cancels high limbs of v, result is rest of v */
   115  		      negate ^= 1;
   116                      cancellation:
   117                        /* strip high zeros before truncating to prec */
   118                        while (vsize != 0 && vp[vsize - 1] == 0)
   119                          {
   120                            vsize--;
   121                            exp--;
   122                          }
   123  		      if (vsize > prec)
   124  			{
   125  			  vp += vsize - prec;
   126  			  vsize = prec;
   127  			}
   128                        MPN_COPY_INCR (rp, vp, vsize);
   129                        rsize = vsize;
   130                        goto done;
   131  		    }
   132  		  if (vsize == 0)
   133  		    {
   134                        vp = up;
   135                        vsize = usize;
   136                        goto cancellation;
   137  		    }
   138  		}
   139  
   140  	  if (up[usize - 1] < vp[vsize - 1])
   141  	    {
   142  	      /* For simplicity, swap U and V.  Note that since the loop above
   143  		 wouldn't have exited unless up[usize - 1] and vp[vsize - 1]
   144  		 were non-equal, this if-statement catches all cases where U
   145  		 is smaller than V.  */
   146  	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
   147  	      negate ^= 1;
   148  	      /* negating ediff not necessary since it is 0.  */
   149  	    }
   150  
   151  	  /* Check for
   152  	     x+1 00000000 ...
   153  	      x  ffffffff ... */
   154  	  if (up[usize - 1] != vp[vsize - 1] + 1)
   155  	    goto general_case;
   156  	  usize--;
   157  	  vsize--;
   158  	  exp--;
   159  	}
   160        else /* ediff == 1 */
   161  	{
   162  	  /* Check for
   163  	     1 00000000 ...
   164  	     0 ffffffff ... */
   165  
   166  	  if (up[usize - 1] != 1 || vp[vsize - 1] != GMP_NUMB_MAX
   167  	      || (usize >= 2 && up[usize - 2] != 0))
   168  	    goto general_case;
   169  
   170  	  usize--;
   171  	  exp--;
   172  	}
   173  
   174        /* Skip sequences of 00000000/ffffffff */
   175        while (vsize != 0 && usize != 0 && up[usize - 1] == 0
   176  	     && vp[vsize - 1] == GMP_NUMB_MAX)
   177  	{
   178  	  usize--;
   179  	  vsize--;
   180  	  exp--;
   181  	}
   182  
   183        if (usize == 0)
   184  	{
   185  	  while (vsize != 0 && vp[vsize - 1] == GMP_NUMB_MAX)
   186  	    {
   187  	      vsize--;
   188  	      exp--;
   189  	    }
   190  	}
   191        else if (usize > prec - 1)
   192  	{
   193  	  up += usize - (prec - 1);
   194  	  usize = prec - 1;
   195  	}
   196        if (vsize > prec - 1)
   197  	{
   198  	  vp += vsize - (prec - 1);
   199  	  vsize = prec - 1;
   200  	}
   201  
   202        tp = TMP_ALLOC_LIMBS (prec);
   203        {
   204  	mp_limb_t cy_limb;
   205  	if (vsize == 0)
   206  	  {
   207  	    MPN_COPY (tp, up, usize);
   208  	    tp[usize] = 1;
   209  	    rsize = usize + 1;
   210  	    exp++;
   211  	    goto normalized;
   212  	  }
   213  	if (usize == 0)
   214  	  {
   215  	    cy_limb = mpn_neg (tp, vp, vsize);
   216  	    rsize = vsize;
   217  	  }
   218  	else if (usize >= vsize)
   219  	  {
   220  	    /* uuuu     */
   221  	    /* vv       */
   222  	    mp_size_t size;
   223  	    size = usize - vsize;
   224  	    MPN_COPY (tp, up, size);
   225  	    cy_limb = mpn_sub_n (tp + size, up + size, vp, vsize);
   226  	    rsize = usize;
   227  	  }
   228  	else /* (usize < vsize) */
   229  	  {
   230  	    /* uuuu     */
   231  	    /* vvvvvvv  */
   232  	    mp_size_t size;
   233  	    size = vsize - usize;
   234  	    cy_limb = mpn_neg (tp, vp, size);
   235  	    cy_limb = mpn_sub_nc (tp + size, up, vp + size, usize, cy_limb);
   236  	    rsize = vsize;
   237  	  }
   238  	if (cy_limb == 0)
   239  	  {
   240  	    tp[rsize] = 1;
   241  	    rsize++;
   242  	    exp++;
   243  	    goto normalized;
   244  	  }
   245  	goto normalize;
   246        }
   247      }
   248  
   249  general_case:
   250    /* If U extends beyond PREC, ignore the part that does.  */
   251    if (usize > prec)
   252      {
   253        up += usize - prec;
   254        usize = prec;
   255      }
   256  
   257    /* If V extends beyond PREC, ignore the part that does.
   258       Note that this may make vsize negative.  */
   259    if (vsize + ediff > prec)
   260      {
   261        vp += vsize + ediff - prec;
   262        vsize = prec - ediff;
   263      }
   264  
   265    if (ediff >= prec)
   266      {
   267        /* V completely cancelled.  */
   268        if (rp != up)
   269  	MPN_COPY (rp, up, usize);
   270        rsize = usize;
   271      }
   272    else
   273      {
   274        /* Allocate temp space for the result.  Allocate
   275  	 just vsize + ediff later???  */
   276        tp = TMP_ALLOC_LIMBS (prec);
   277  
   278        /* Locate the least significant non-zero limb in (the needed
   279  	 parts of) U and V, to simplify the code below.  */
   280        for (;;)
   281  	{
   282  	  if (vsize == 0)
   283  	    {
   284  	      MPN_COPY (rp, up, usize);
   285  	      rsize = usize;
   286  	      goto done;
   287  	    }
   288  	  if (vp[0] != 0)
   289  	    break;
   290  	  vp++, vsize--;
   291  	}
   292        for (;;)
   293  	{
   294  	  if (usize == 0)
   295  	    {
   296  	      MPN_COPY (rp, vp, vsize);
   297  	      rsize = vsize;
   298  	      negate ^= 1;
   299  	      goto done;
   300  	    }
   301  	  if (up[0] != 0)
   302  	    break;
   303  	  up++, usize--;
   304  	}
   305  
   306        /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
   307        /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
   308  
   309        if (usize > ediff)
   310  	{
   311  	  /* U and V partially overlaps.  */
   312  	  if (ediff == 0)
   313  	    {
   314  	      /* Have to compare the leading limbs of u and v
   315  		 to determine whether to compute u - v or v - u.  */
   316  	      if (usize >= vsize)
   317  		{
   318  		  /* uuuu     */
   319  		  /* vv       */
   320  		  mp_size_t size;
   321  		  size = usize - vsize;
   322  		  MPN_COPY (tp, up, size);
   323  		  mpn_sub_n (tp + size, up + size, vp, vsize);
   324  		  rsize = usize;
   325  		}
   326  	      else /* (usize < vsize) */
   327  		{
   328  		  /* uuuu     */
   329  		  /* vvvvvvv  */
   330  		  mp_size_t size;
   331  		  size = vsize - usize;
   332  		  ASSERT_CARRY (mpn_neg (tp, vp, size));
   333  		  mpn_sub_nc (tp + size, up, vp + size, usize, CNST_LIMB (1));
   334  		  rsize = vsize;
   335  		}
   336  	    }
   337  	  else
   338  	    {
   339  	      if (vsize + ediff <= usize)
   340  		{
   341  		  /* uuuu     */
   342  		  /*   v      */
   343  		  mp_size_t size;
   344  		  size = usize - ediff - vsize;
   345  		  MPN_COPY (tp, up, size);
   346  		  mpn_sub (tp + size, up + size, usize - size, vp, vsize);
   347  		  rsize = usize;
   348  		}
   349  	      else
   350  		{
   351  		  /* uuuu     */
   352  		  /*   vvvvv  */
   353  		  mp_size_t size;
   354  		  rsize = vsize + ediff;
   355  		  size = rsize - usize;
   356  		  ASSERT_CARRY (mpn_neg (tp, vp, size));
   357  		  mpn_sub (tp + size, up, usize, vp + size, usize - ediff);
   358  		  /* Should we use sub_nc then sub_1? */
   359  		  MPN_DECR_U (tp + size, usize, CNST_LIMB (1));
   360  		}
   361  	    }
   362  	}
   363        else
   364  	{
   365  	  /* uuuu     */
   366  	  /*      vv  */
   367  	  mp_size_t size, i;
   368  	  size = vsize + ediff - usize;
   369  	  ASSERT_CARRY (mpn_neg (tp, vp, vsize));
   370  	  for (i = vsize; i < size; i++)
   371  	    tp[i] = GMP_NUMB_MAX;
   372  	  mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1);
   373  	  rsize = size + usize;
   374  	}
   375  
   376      normalize:
   377        /* Full normalize.  Optimize later.  */
   378        while (rsize != 0 && tp[rsize - 1] == 0)
   379  	{
   380  	  rsize--;
   381  	  exp--;
   382  	}
   383      normalized:
   384        MPN_COPY (rp, tp, rsize);
   385      }
   386  
   387   done:
   388    TMP_FREE;
   389    if (rsize == 0) {
   390      SIZ (r) = 0;
   391      EXP (r) = 0;
   392    } else {
   393      SIZ (r) = negate ? -rsize : rsize;
   394      EXP (r) = exp;
   395    }
   396  }