1/* mpz_combit -- complement a specified bit.
2
3Copyright 2002, 2003 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20#include "gmp.h"
21#include "gmp-impl.h"
22
23void
24mpz_combit (mpz_ptr d, mp_bitcnt_t bit_index)
25{
26  mp_size_t dsize = ABSIZ(d);
27  mp_ptr dp = LIMBS(d);
28
29  mp_size_t limb_index = bit_index / GMP_NUMB_BITS;
30  mp_limb_t bit = ((mp_limb_t) 1 << (bit_index % GMP_NUMB_BITS));
31
32  if (limb_index >= dsize)
33    {
34      MPZ_REALLOC(d, limb_index + 1);
35      dp = LIMBS(d);
36
37      MPN_ZERO(dp + dsize, limb_index + 1 - dsize);
38      dsize = limb_index + 1;
39    }
40
41  if (SIZ(d) >= 0)
42    {
43      dp[limb_index] ^= bit;
44      MPN_NORMALIZE (dp, dsize);
45      SIZ(d) = dsize;
46    }
47  else
48    {
49      mp_limb_t x = -dp[limb_index];
50      mp_size_t i;
51
52      /* non-zero limb below us means ones-complement */
53      for (i = limb_index-1; i >= 0; i--)
54	if (dp[i] != 0)
55	  {
56	    x--;  /* change twos comp to ones comp */
57	    break;
58	  }
59
60      if (x & bit)
61	{
62	  mp_limb_t  c;
63
64	  /* Clearing the bit increases the magitude. We might need a carry. */
65	  MPZ_REALLOC(d, dsize + 1);
66	  dp = LIMBS(d);
67
68	  __GMPN_ADD_1 (c, dp+limb_index, dp+limb_index,
69			dsize - limb_index, bit);
70	  dp[dsize] = c;
71	  dsize += c;
72	}
73      else
74	/* Setting the bit decreases the magnitude */
75	mpn_sub_1(dp+limb_index, dp+limb_index, dsize + limb_index, bit);
76
77      MPN_NORMALIZE (dp, dsize);
78      SIZ(d) = -dsize;
79    }
80}
81