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