/* mpz_ui_sub -- Subtract an unsigned one-word integer and an mpz_t.

Copyright 2002, 2004 Free Software Foundation, Inc.

This file is part of the GNU MP Library.

The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

The GNU MP Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public License
along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */

#include "gmp.h"
#include "gmp-impl.h"

void
mpz_ui_sub (mpz_ptr w, unsigned long int uval, mpz_srcptr v)
{
  mp_ptr vp, wp;
  mp_size_t vn, wn;
  mp_limb_t cy;

#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
  if (uval > GMP_NUMB_MAX)
    {
      mpz_t u;
      mp_limb_t ul[2];
      PTR(u) = ul;
      ul[0] = uval & GMP_NUMB_MASK;
      ul[1] = uval >> GMP_NUMB_BITS;
      SIZ(u) = 2;
      mpz_sub (w, u, v);
      return;
    }
#endif

  vp = PTR(v);
  vn = SIZ(v);

  wp = PTR(w);

  if (vn > 1)
    {
      wp = MPZ_REALLOC (w, vn);
      vp = PTR(v);
      mpn_sub_1 (wp, vp, vn, (mp_limb_t) uval);
      wn = -(vn - (wp[vn - 1] == 0));
    }
  else if (vn == 1)
    {
      if (uval >= vp[0])
	{
	  wp[0] = uval - vp[0];
	  wn = wp[0] != 0;
	}
      else
	{
	  wp[0] = vp[0] - uval;
	  wn = -1;
	}
    }
  else if (vn == 0)
    {
      wp[0] = uval;
      wn = uval != 0;
    }
  else /* (vn < 0) */
    {
      vn = -vn;
      wp = MPZ_REALLOC (w, vn + 1);
      vp = PTR(v);
      cy = mpn_add_1 (wp, vp, vn, (mp_limb_t) uval);
      wp[vn] = cy;
      wn = vn + (cy != 0);
    }

  SIZ(w) = wn;
}
