diff options
Diffstat (limited to 'vendor/gmp-6.3.0/mpz/combit.c')
-rw-r--r-- | vendor/gmp-6.3.0/mpz/combit.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/vendor/gmp-6.3.0/mpz/combit.c b/vendor/gmp-6.3.0/mpz/combit.c new file mode 100644 index 0000000..0a29875 --- /dev/null +++ b/vendor/gmp-6.3.0/mpz/combit.c @@ -0,0 +1,103 @@ +/* mpz_combit -- complement a specified bit. + +Copyright 2002, 2003, 2012, 2015 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 either: + + * 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. + +or + + * the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any + later version. + +or both in parallel, as here. + +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 General Public License +for more details. + +You should have received copies of the GNU General Public License and the +GNU Lesser General Public License along with the GNU MP Library. If not, +see https://www.gnu.org/licenses/. */ + +#include "gmp-impl.h" + +void +mpz_combit (mpz_ptr d, mp_bitcnt_t bit_index) +{ + mp_size_t dsize = SIZ(d); + mp_ptr dp = PTR(d); + + mp_size_t limb_index = bit_index / GMP_NUMB_BITS; + mp_limb_t bit = (CNST_LIMB (1) << (bit_index % GMP_NUMB_BITS)); + + /* Check for the most common case: Positive input, no realloc or + normalization needed. */ + if (limb_index + 1 < dsize) + dp[limb_index] ^= bit; + + /* Check for the hairy case. d < 0, and we have all zero bits to the + right of the bit to toggle. */ + else if (limb_index < -dsize + && (limb_index == 0 || mpn_zero_p (dp, limb_index)) + && (dp[limb_index] & (bit - 1)) == 0) + { + ASSERT (dsize < 0); + dsize = -dsize; + + if (dp[limb_index] & bit) + { + /* We toggle the least significant one bit. Corresponds to + an add, with potential carry propagation, on the absolute + value. */ + dp = MPZ_REALLOC (d, 1 + dsize); + dp[dsize] = 0; + MPN_INCR_U (dp + limb_index, 1 + dsize - limb_index, bit); + SIZ(d) = - dsize - dp[dsize]; + } + else + { + /* We toggle a zero bit, subtract from the absolute value. */ + MPN_DECR_U (dp + limb_index, dsize - limb_index, bit); + /* The absolute value shrinked by at most one bit. */ + dsize -= dp[dsize - 1] == 0; + ASSERT (dsize > 0 && dp[dsize - 1] != 0); + SIZ (d) = -dsize; + } + } + else + { + /* Simple case: Toggle the bit in the absolute value. */ + dsize = ABS(dsize); + if (limb_index < dsize) + { + mp_limb_t dlimb; + dlimb = dp[limb_index] ^ bit; + dp[limb_index] = dlimb; + + /* Can happen only when limb_index = dsize - 1. Avoid SIZ(d) + bookkeeping in the common case. */ + if (UNLIKELY ((dlimb == 0) + limb_index == dsize)) /* dsize == limb_index + 1 */ + { + /* high limb became zero, must normalize */ + MPN_NORMALIZE (dp, limb_index); + SIZ (d) = SIZ (d) >= 0 ? limb_index : -limb_index; + } + } + else + { + dp = MPZ_REALLOC (d, limb_index + 1); + MPN_ZERO(dp + dsize, limb_index - dsize); + dp[limb_index++] = bit; + SIZ(d) = SIZ(d) >= 0 ? limb_index : -limb_index; + } + } +} |