xref: /dflybsd-src/contrib/gmp/mpf/sub.c (revision d365564473a20a528d07c59cad8ee2f4bea5546f)
14b6a78b7SSimon Schubert /* mpf_sub -- Subtract two floats.
24b6a78b7SSimon Schubert 
3*d2d4b659SJohn Marino Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2011 Free
44b6a78b7SSimon Schubert Software Foundation, Inc.
54b6a78b7SSimon Schubert 
64b6a78b7SSimon Schubert This file is part of the GNU MP Library.
74b6a78b7SSimon Schubert 
84b6a78b7SSimon Schubert The GNU MP Library is free software; you can redistribute it and/or modify
94b6a78b7SSimon Schubert it under the terms of the GNU Lesser General Public License as published by
104b6a78b7SSimon Schubert the Free Software Foundation; either version 3 of the License, or (at your
114b6a78b7SSimon Schubert option) any later version.
124b6a78b7SSimon Schubert 
134b6a78b7SSimon Schubert The GNU MP Library is distributed in the hope that it will be useful, but
144b6a78b7SSimon Schubert WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
154b6a78b7SSimon Schubert or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
164b6a78b7SSimon Schubert License for more details.
174b6a78b7SSimon Schubert 
184b6a78b7SSimon Schubert You should have received a copy of the GNU Lesser General Public License
194b6a78b7SSimon Schubert along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
204b6a78b7SSimon Schubert 
214b6a78b7SSimon Schubert #include "gmp.h"
224b6a78b7SSimon Schubert #include "gmp-impl.h"
234b6a78b7SSimon Schubert 
244b6a78b7SSimon Schubert void
mpf_sub(mpf_ptr r,mpf_srcptr u,mpf_srcptr v)254b6a78b7SSimon Schubert mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
264b6a78b7SSimon Schubert {
274b6a78b7SSimon Schubert   mp_srcptr up, vp;
284b6a78b7SSimon Schubert   mp_ptr rp, tp;
294b6a78b7SSimon Schubert   mp_size_t usize, vsize, rsize;
304b6a78b7SSimon Schubert   mp_size_t prec;
314b6a78b7SSimon Schubert   mp_exp_t exp;
324b6a78b7SSimon Schubert   mp_size_t ediff;
334b6a78b7SSimon Schubert   int negate;
344b6a78b7SSimon Schubert   TMP_DECL;
354b6a78b7SSimon Schubert 
364b6a78b7SSimon Schubert   usize = u->_mp_size;
374b6a78b7SSimon Schubert   vsize = v->_mp_size;
384b6a78b7SSimon Schubert 
394b6a78b7SSimon Schubert   /* Handle special cases that don't work in generic code below.  */
404b6a78b7SSimon Schubert   if (usize == 0)
414b6a78b7SSimon Schubert     {
424b6a78b7SSimon Schubert       mpf_neg (r, v);
434b6a78b7SSimon Schubert       return;
444b6a78b7SSimon Schubert     }
454b6a78b7SSimon Schubert   if (vsize == 0)
464b6a78b7SSimon Schubert     {
474b6a78b7SSimon Schubert       if (r != u)
484b6a78b7SSimon Schubert         mpf_set (r, u);
494b6a78b7SSimon Schubert       return;
504b6a78b7SSimon Schubert     }
514b6a78b7SSimon Schubert 
524b6a78b7SSimon Schubert   /* If signs of U and V are different, perform addition.  */
534b6a78b7SSimon Schubert   if ((usize ^ vsize) < 0)
544b6a78b7SSimon Schubert     {
554b6a78b7SSimon Schubert       __mpf_struct v_negated;
564b6a78b7SSimon Schubert       v_negated._mp_size = -vsize;
574b6a78b7SSimon Schubert       v_negated._mp_exp = v->_mp_exp;
584b6a78b7SSimon Schubert       v_negated._mp_d = v->_mp_d;
594b6a78b7SSimon Schubert       mpf_add (r, u, &v_negated);
604b6a78b7SSimon Schubert       return;
614b6a78b7SSimon Schubert     }
624b6a78b7SSimon Schubert 
634b6a78b7SSimon Schubert   TMP_MARK;
644b6a78b7SSimon Schubert 
654b6a78b7SSimon Schubert   /* Signs are now known to be the same.  */
664b6a78b7SSimon Schubert   negate = usize < 0;
674b6a78b7SSimon Schubert 
684b6a78b7SSimon Schubert   /* Make U be the operand with the largest exponent.  */
694b6a78b7SSimon Schubert   if (u->_mp_exp < v->_mp_exp)
704b6a78b7SSimon Schubert     {
714b6a78b7SSimon Schubert       mpf_srcptr t;
724b6a78b7SSimon Schubert       t = u; u = v; v = t;
734b6a78b7SSimon Schubert       negate ^= 1;
744b6a78b7SSimon Schubert       usize = u->_mp_size;
754b6a78b7SSimon Schubert       vsize = v->_mp_size;
764b6a78b7SSimon Schubert     }
774b6a78b7SSimon Schubert 
784b6a78b7SSimon Schubert   usize = ABS (usize);
794b6a78b7SSimon Schubert   vsize = ABS (vsize);
804b6a78b7SSimon Schubert   up = u->_mp_d;
814b6a78b7SSimon Schubert   vp = v->_mp_d;
824b6a78b7SSimon Schubert   rp = r->_mp_d;
834b6a78b7SSimon Schubert   prec = r->_mp_prec + 1;
844b6a78b7SSimon Schubert   exp = u->_mp_exp;
854b6a78b7SSimon Schubert   ediff = u->_mp_exp - v->_mp_exp;
864b6a78b7SSimon Schubert 
874b6a78b7SSimon Schubert   /* If ediff is 0 or 1, we might have a situation where the operands are
884b6a78b7SSimon Schubert      extremely close.  We need to scan the operands from the most significant
894b6a78b7SSimon Schubert      end ignore the initial parts that are equal.  */
904b6a78b7SSimon Schubert   if (ediff <= 1)
914b6a78b7SSimon Schubert     {
924b6a78b7SSimon Schubert       if (ediff == 0)
934b6a78b7SSimon Schubert 	{
944b6a78b7SSimon Schubert 	  /* Skip leading limbs in U and V that are equal.  */
954b6a78b7SSimon Schubert 	  if (up[usize - 1] == vp[vsize - 1])
964b6a78b7SSimon Schubert 	    {
974b6a78b7SSimon Schubert 	      /* This loop normally exits immediately.  Optimize for that.  */
984b6a78b7SSimon Schubert 	      do
994b6a78b7SSimon Schubert 		{
1004b6a78b7SSimon Schubert 		  usize--;
1014b6a78b7SSimon Schubert 		  vsize--;
1024b6a78b7SSimon Schubert 		  exp--;
1034b6a78b7SSimon Schubert 
1044b6a78b7SSimon Schubert 		  if (usize == 0)
1054b6a78b7SSimon Schubert 		    {
1064b6a78b7SSimon Schubert                       /* u cancels high limbs of v, result is rest of v */
1074b6a78b7SSimon Schubert 		      negate ^= 1;
1084b6a78b7SSimon Schubert                     cancellation:
1094b6a78b7SSimon Schubert                       /* strip high zeros before truncating to prec */
1104b6a78b7SSimon Schubert                       while (vsize != 0 && vp[vsize - 1] == 0)
1114b6a78b7SSimon Schubert                         {
1124b6a78b7SSimon Schubert                           vsize--;
1134b6a78b7SSimon Schubert                           exp--;
1144b6a78b7SSimon Schubert                         }
1154b6a78b7SSimon Schubert 		      if (vsize > prec)
1164b6a78b7SSimon Schubert 			{
1174b6a78b7SSimon Schubert 			  vp += vsize - prec;
1184b6a78b7SSimon Schubert 			  vsize = prec;
1194b6a78b7SSimon Schubert 			}
1204b6a78b7SSimon Schubert                       MPN_COPY_INCR (rp, vp, vsize);
1214b6a78b7SSimon Schubert                       rsize = vsize;
1224b6a78b7SSimon Schubert                       goto done;
1234b6a78b7SSimon Schubert 		    }
1244b6a78b7SSimon Schubert 		  if (vsize == 0)
1254b6a78b7SSimon Schubert 		    {
1264b6a78b7SSimon Schubert                       vp = up;
1274b6a78b7SSimon Schubert                       vsize = usize;
1284b6a78b7SSimon Schubert                       goto cancellation;
1294b6a78b7SSimon Schubert 		    }
1304b6a78b7SSimon Schubert 		}
1314b6a78b7SSimon Schubert 	      while (up[usize - 1] == vp[vsize - 1]);
1324b6a78b7SSimon Schubert 	    }
1334b6a78b7SSimon Schubert 
1344b6a78b7SSimon Schubert 	  if (up[usize - 1] < vp[vsize - 1])
1354b6a78b7SSimon Schubert 	    {
1364b6a78b7SSimon Schubert 	      /* For simplicity, swap U and V.  Note that since the loop above
1374b6a78b7SSimon Schubert 		 wouldn't have exited unless up[usize - 1] and vp[vsize - 1]
1384b6a78b7SSimon Schubert 		 were non-equal, this if-statement catches all cases where U
1394b6a78b7SSimon Schubert 		 is smaller than V.  */
1404b6a78b7SSimon Schubert 	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
1414b6a78b7SSimon Schubert 	      negate ^= 1;
1424b6a78b7SSimon Schubert 	      /* negating ediff not necessary since it is 0.  */
1434b6a78b7SSimon Schubert 	    }
1444b6a78b7SSimon Schubert 
1454b6a78b7SSimon Schubert 	  /* Check for
1464b6a78b7SSimon Schubert 	     x+1 00000000 ...
1474b6a78b7SSimon Schubert 	      x  ffffffff ... */
1484b6a78b7SSimon Schubert 	  if (up[usize - 1] != vp[vsize - 1] + 1)
1494b6a78b7SSimon Schubert 	    goto general_case;
1504b6a78b7SSimon Schubert 	  usize--;
1514b6a78b7SSimon Schubert 	  vsize--;
1524b6a78b7SSimon Schubert 	  exp--;
1534b6a78b7SSimon Schubert 	}
1544b6a78b7SSimon Schubert       else /* ediff == 1 */
1554b6a78b7SSimon Schubert 	{
1564b6a78b7SSimon Schubert 	  /* Check for
1574b6a78b7SSimon Schubert 	     1 00000000 ...
1584b6a78b7SSimon Schubert 	     0 ffffffff ... */
1594b6a78b7SSimon Schubert 
1604b6a78b7SSimon Schubert 	  if (up[usize - 1] != 1 || vp[vsize - 1] != GMP_NUMB_MAX
1614b6a78b7SSimon Schubert 	      || (usize >= 2 && up[usize - 2] != 0))
1624b6a78b7SSimon Schubert 	    goto general_case;
1634b6a78b7SSimon Schubert 
1644b6a78b7SSimon Schubert 	  usize--;
1654b6a78b7SSimon Schubert 	  exp--;
1664b6a78b7SSimon Schubert 	}
1674b6a78b7SSimon Schubert 
1684b6a78b7SSimon Schubert       /* Skip sequences of 00000000/ffffffff */
1694b6a78b7SSimon Schubert       while (vsize != 0 && usize != 0 && up[usize - 1] == 0
1704b6a78b7SSimon Schubert 	     && vp[vsize - 1] == GMP_NUMB_MAX)
1714b6a78b7SSimon Schubert 	{
1724b6a78b7SSimon Schubert 	  usize--;
1734b6a78b7SSimon Schubert 	  vsize--;
1744b6a78b7SSimon Schubert 	  exp--;
1754b6a78b7SSimon Schubert 	}
1764b6a78b7SSimon Schubert 
1774b6a78b7SSimon Schubert       if (usize == 0)
1784b6a78b7SSimon Schubert 	{
1794b6a78b7SSimon Schubert 	  while (vsize != 0 && vp[vsize - 1] == GMP_NUMB_MAX)
1804b6a78b7SSimon Schubert 	    {
1814b6a78b7SSimon Schubert 	      vsize--;
1824b6a78b7SSimon Schubert 	      exp--;
1834b6a78b7SSimon Schubert 	    }
1844b6a78b7SSimon Schubert 	}
1854b6a78b7SSimon Schubert 
1864b6a78b7SSimon Schubert       if (usize > prec - 1)
1874b6a78b7SSimon Schubert 	{
1884b6a78b7SSimon Schubert 	  up += usize - (prec - 1);
1894b6a78b7SSimon Schubert 	  usize = prec - 1;
1904b6a78b7SSimon Schubert 	}
1914b6a78b7SSimon Schubert       if (vsize > prec - 1)
1924b6a78b7SSimon Schubert 	{
1934b6a78b7SSimon Schubert 	  vp += vsize - (prec - 1);
1944b6a78b7SSimon Schubert 	  vsize = prec - 1;
1954b6a78b7SSimon Schubert 	}
1964b6a78b7SSimon Schubert 
19754028e53SJohn Marino       tp = TMP_ALLOC_LIMBS (prec);
1984b6a78b7SSimon Schubert       {
1994b6a78b7SSimon Schubert 	mp_limb_t cy_limb;
2004b6a78b7SSimon Schubert 	if (vsize == 0)
2014b6a78b7SSimon Schubert 	  {
2024b6a78b7SSimon Schubert 	    mp_size_t size, i;
2034b6a78b7SSimon Schubert 	    size = usize;
2044b6a78b7SSimon Schubert 	    for (i = 0; i < size; i++)
2054b6a78b7SSimon Schubert 	      tp[i] = up[i];
2064b6a78b7SSimon Schubert 	    tp[size] = 1;
2074b6a78b7SSimon Schubert 	    rsize = size + 1;
2084b6a78b7SSimon Schubert 	    exp++;
2094b6a78b7SSimon Schubert 	    goto normalize;
2104b6a78b7SSimon Schubert 	  }
2114b6a78b7SSimon Schubert 	if (usize == 0)
2124b6a78b7SSimon Schubert 	  {
2134b6a78b7SSimon Schubert 	    mp_size_t size, i;
2144b6a78b7SSimon Schubert 	    size = vsize;
2154b6a78b7SSimon Schubert 	    for (i = 0; i < size; i++)
2164b6a78b7SSimon Schubert 	      tp[i] = ~vp[i] & GMP_NUMB_MASK;
2174b6a78b7SSimon Schubert 	    cy_limb = 1 - mpn_add_1 (tp, tp, vsize, (mp_limb_t) 1);
2184b6a78b7SSimon Schubert 	    rsize = vsize;
2194b6a78b7SSimon Schubert 	    if (cy_limb == 0)
2204b6a78b7SSimon Schubert 	      {
2214b6a78b7SSimon Schubert 		tp[rsize] = 1;
2224b6a78b7SSimon Schubert 		rsize++;
2234b6a78b7SSimon Schubert 		exp++;
2244b6a78b7SSimon Schubert 	      }
2254b6a78b7SSimon Schubert 	    goto normalize;
2264b6a78b7SSimon Schubert 	  }
2274b6a78b7SSimon Schubert 	if (usize >= vsize)
2284b6a78b7SSimon Schubert 	  {
2294b6a78b7SSimon Schubert 	    /* uuuu     */
2304b6a78b7SSimon Schubert 	    /* vv       */
2314b6a78b7SSimon Schubert 	    mp_size_t size;
2324b6a78b7SSimon Schubert 	    size = usize - vsize;
2334b6a78b7SSimon Schubert 	    MPN_COPY (tp, up, size);
2344b6a78b7SSimon Schubert 	    cy_limb = mpn_sub_n (tp + size, up + size, vp, vsize);
2354b6a78b7SSimon Schubert 	    rsize = usize;
2364b6a78b7SSimon Schubert 	  }
2374b6a78b7SSimon Schubert 	else /* (usize < vsize) */
2384b6a78b7SSimon Schubert 	  {
2394b6a78b7SSimon Schubert 	    /* uuuu     */
2404b6a78b7SSimon Schubert 	    /* vvvvvvv  */
2414b6a78b7SSimon Schubert 	    mp_size_t size, i;
2424b6a78b7SSimon Schubert 	    size = vsize - usize;
2434b6a78b7SSimon Schubert 	    for (i = 0; i < size; i++)
2444b6a78b7SSimon Schubert 	      tp[i] = ~vp[i] & GMP_NUMB_MASK;
2454b6a78b7SSimon Schubert 	    cy_limb = mpn_sub_n (tp + size, up, vp + size, usize);
2464b6a78b7SSimon Schubert 	    cy_limb+= mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
2474b6a78b7SSimon Schubert 	    cy_limb-= mpn_add_1 (tp, tp, vsize, (mp_limb_t) 1);
2484b6a78b7SSimon Schubert 	    rsize = vsize;
2494b6a78b7SSimon Schubert 	  }
2504b6a78b7SSimon Schubert 	if (cy_limb == 0)
2514b6a78b7SSimon Schubert 	  {
2524b6a78b7SSimon Schubert 	    tp[rsize] = 1;
2534b6a78b7SSimon Schubert 	    rsize++;
2544b6a78b7SSimon Schubert 	    exp++;
2554b6a78b7SSimon Schubert 	  }
2564b6a78b7SSimon Schubert 	goto normalize;
2574b6a78b7SSimon Schubert       }
2584b6a78b7SSimon Schubert     }
2594b6a78b7SSimon Schubert 
2604b6a78b7SSimon Schubert general_case:
2614b6a78b7SSimon Schubert   /* If U extends beyond PREC, ignore the part that does.  */
2624b6a78b7SSimon Schubert   if (usize > prec)
2634b6a78b7SSimon Schubert     {
2644b6a78b7SSimon Schubert       up += usize - prec;
2654b6a78b7SSimon Schubert       usize = prec;
2664b6a78b7SSimon Schubert     }
2674b6a78b7SSimon Schubert 
2684b6a78b7SSimon Schubert   /* If V extends beyond PREC, ignore the part that does.
2694b6a78b7SSimon Schubert      Note that this may make vsize negative.  */
2704b6a78b7SSimon Schubert   if (vsize + ediff > prec)
2714b6a78b7SSimon Schubert     {
2724b6a78b7SSimon Schubert       vp += vsize + ediff - prec;
2734b6a78b7SSimon Schubert       vsize = prec - ediff;
2744b6a78b7SSimon Schubert     }
2754b6a78b7SSimon Schubert 
2764b6a78b7SSimon Schubert   if (ediff >= prec)
2774b6a78b7SSimon Schubert     {
2784b6a78b7SSimon Schubert       /* V completely cancelled.  */
279*d2d4b659SJohn Marino       if (rp != up)
2804b6a78b7SSimon Schubert 	MPN_COPY (rp, up, usize);
2814b6a78b7SSimon Schubert       rsize = usize;
2824b6a78b7SSimon Schubert     }
2834b6a78b7SSimon Schubert   else
2844b6a78b7SSimon Schubert     {
285*d2d4b659SJohn Marino       /* Allocate temp space for the result.  Allocate
286*d2d4b659SJohn Marino 	 just vsize + ediff later???  */
287*d2d4b659SJohn Marino       tp = TMP_ALLOC_LIMBS (prec);
288*d2d4b659SJohn Marino 
2894b6a78b7SSimon Schubert       /* Locate the least significant non-zero limb in (the needed
2904b6a78b7SSimon Schubert 	 parts of) U and V, to simplify the code below.  */
2914b6a78b7SSimon Schubert       for (;;)
2924b6a78b7SSimon Schubert 	{
2934b6a78b7SSimon Schubert 	  if (vsize == 0)
2944b6a78b7SSimon Schubert 	    {
2954b6a78b7SSimon Schubert 	      MPN_COPY (rp, up, usize);
2964b6a78b7SSimon Schubert 	      rsize = usize;
2974b6a78b7SSimon Schubert 	      goto done;
2984b6a78b7SSimon Schubert 	    }
2994b6a78b7SSimon Schubert 	  if (vp[0] != 0)
3004b6a78b7SSimon Schubert 	    break;
3014b6a78b7SSimon Schubert 	  vp++, vsize--;
3024b6a78b7SSimon Schubert 	}
3034b6a78b7SSimon Schubert       for (;;)
3044b6a78b7SSimon Schubert 	{
3054b6a78b7SSimon Schubert 	  if (usize == 0)
3064b6a78b7SSimon Schubert 	    {
3074b6a78b7SSimon Schubert 	      MPN_COPY (rp, vp, vsize);
3084b6a78b7SSimon Schubert 	      rsize = vsize;
3094b6a78b7SSimon Schubert 	      negate ^= 1;
3104b6a78b7SSimon Schubert 	      goto done;
3114b6a78b7SSimon Schubert 	    }
3124b6a78b7SSimon Schubert 	  if (up[0] != 0)
3134b6a78b7SSimon Schubert 	    break;
3144b6a78b7SSimon Schubert 	  up++, usize--;
3154b6a78b7SSimon Schubert 	}
3164b6a78b7SSimon Schubert 
3174b6a78b7SSimon Schubert       /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
3184b6a78b7SSimon Schubert       /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
3194b6a78b7SSimon Schubert 
3204b6a78b7SSimon Schubert       if (usize > ediff)
3214b6a78b7SSimon Schubert 	{
3224b6a78b7SSimon Schubert 	  /* U and V partially overlaps.  */
3234b6a78b7SSimon Schubert 	  if (ediff == 0)
3244b6a78b7SSimon Schubert 	    {
3254b6a78b7SSimon Schubert 	      /* Have to compare the leading limbs of u and v
3264b6a78b7SSimon Schubert 		 to determine whether to compute u - v or v - u.  */
3274b6a78b7SSimon Schubert 	      if (usize >= vsize)
3284b6a78b7SSimon Schubert 		{
3294b6a78b7SSimon Schubert 		  /* uuuu     */
3304b6a78b7SSimon Schubert 		  /* vv       */
3314b6a78b7SSimon Schubert 		  mp_size_t size;
3324b6a78b7SSimon Schubert 		  size = usize - vsize;
3334b6a78b7SSimon Schubert 		  MPN_COPY (tp, up, size);
3344b6a78b7SSimon Schubert 		  mpn_sub_n (tp + size, up + size, vp, vsize);
3354b6a78b7SSimon Schubert 		  rsize = usize;
3364b6a78b7SSimon Schubert 		}
3374b6a78b7SSimon Schubert 	      else /* (usize < vsize) */
3384b6a78b7SSimon Schubert 		{
3394b6a78b7SSimon Schubert 		  /* uuuu     */
3404b6a78b7SSimon Schubert 		  /* vvvvvvv  */
3414b6a78b7SSimon Schubert 		  mp_size_t size, i;
3424b6a78b7SSimon Schubert 		  size = vsize - usize;
3434b6a78b7SSimon Schubert 		  tp[0] = -vp[0] & GMP_NUMB_MASK;
3444b6a78b7SSimon Schubert 		  for (i = 1; i < size; i++)
3454b6a78b7SSimon Schubert 		    tp[i] = ~vp[i] & GMP_NUMB_MASK;
3464b6a78b7SSimon Schubert 		  mpn_sub_n (tp + size, up, vp + size, usize);
3474b6a78b7SSimon Schubert 		  mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
3484b6a78b7SSimon Schubert 		  rsize = vsize;
3494b6a78b7SSimon Schubert 		}
3504b6a78b7SSimon Schubert 	    }
3514b6a78b7SSimon Schubert 	  else
3524b6a78b7SSimon Schubert 	    {
3534b6a78b7SSimon Schubert 	      if (vsize + ediff <= usize)
3544b6a78b7SSimon Schubert 		{
3554b6a78b7SSimon Schubert 		  /* uuuu     */
3564b6a78b7SSimon Schubert 		  /*   v      */
3574b6a78b7SSimon Schubert 		  mp_size_t size;
3584b6a78b7SSimon Schubert 		  size = usize - ediff - vsize;
3594b6a78b7SSimon Schubert 		  MPN_COPY (tp, up, size);
3604b6a78b7SSimon Schubert 		  mpn_sub (tp + size, up + size, usize - size, vp, vsize);
3614b6a78b7SSimon Schubert 		  rsize = usize;
3624b6a78b7SSimon Schubert 		}
3634b6a78b7SSimon Schubert 	      else
3644b6a78b7SSimon Schubert 		{
3654b6a78b7SSimon Schubert 		  /* uuuu     */
3664b6a78b7SSimon Schubert 		  /*   vvvvv  */
3674b6a78b7SSimon Schubert 		  mp_size_t size, i;
3684b6a78b7SSimon Schubert 		  size = vsize + ediff - usize;
3694b6a78b7SSimon Schubert 		  tp[0] = -vp[0] & GMP_NUMB_MASK;
3704b6a78b7SSimon Schubert 		  for (i = 1; i < size; i++)
3714b6a78b7SSimon Schubert 		    tp[i] = ~vp[i] & GMP_NUMB_MASK;
3724b6a78b7SSimon Schubert 		  mpn_sub (tp + size, up, usize, vp + size, usize - ediff);
3734b6a78b7SSimon Schubert 		  mpn_sub_1 (tp + size, tp + size, usize, (mp_limb_t) 1);
3744b6a78b7SSimon Schubert 		  rsize = vsize + ediff;
3754b6a78b7SSimon Schubert 		}
3764b6a78b7SSimon Schubert 	    }
3774b6a78b7SSimon Schubert 	}
3784b6a78b7SSimon Schubert       else
3794b6a78b7SSimon Schubert 	{
3804b6a78b7SSimon Schubert 	  /* uuuu     */
3814b6a78b7SSimon Schubert 	  /*      vv  */
3824b6a78b7SSimon Schubert 	  mp_size_t size, i;
3834b6a78b7SSimon Schubert 	  size = vsize + ediff - usize;
3844b6a78b7SSimon Schubert 	  tp[0] = -vp[0] & GMP_NUMB_MASK;
3854b6a78b7SSimon Schubert 	  for (i = 1; i < vsize; i++)
3864b6a78b7SSimon Schubert 	    tp[i] = ~vp[i] & GMP_NUMB_MASK;
3874b6a78b7SSimon Schubert 	  for (i = vsize; i < size; i++)
3884b6a78b7SSimon Schubert 	    tp[i] = GMP_NUMB_MAX;
3894b6a78b7SSimon Schubert 	  mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1);
3904b6a78b7SSimon Schubert 	  rsize = size + usize;
3914b6a78b7SSimon Schubert 	}
3924b6a78b7SSimon Schubert 
3934b6a78b7SSimon Schubert     normalize:
3944b6a78b7SSimon Schubert       /* Full normalize.  Optimize later.  */
3954b6a78b7SSimon Schubert       while (rsize != 0 && tp[rsize - 1] == 0)
3964b6a78b7SSimon Schubert 	{
3974b6a78b7SSimon Schubert 	  rsize--;
3984b6a78b7SSimon Schubert 	  exp--;
3994b6a78b7SSimon Schubert 	}
4004b6a78b7SSimon Schubert       MPN_COPY (rp, tp, rsize);
4014b6a78b7SSimon Schubert     }
4024b6a78b7SSimon Schubert 
4034b6a78b7SSimon Schubert  done:
4044b6a78b7SSimon Schubert   r->_mp_size = negate ? -rsize : rsize;
4054b6a78b7SSimon Schubert   if (rsize == 0)
4064b6a78b7SSimon Schubert     exp = 0;
4074b6a78b7SSimon Schubert   r->_mp_exp = exp;
4084b6a78b7SSimon Schubert   TMP_FREE;
4094b6a78b7SSimon Schubert }
410