mpz_combit

Niels Möller nisse at lysator.liu.se
Tue Oct 30 10:00:04 CET 2012


nisse at lysator.liu.se (Niels Möller) writes:

> I've tried rewriting mpz_combit. Two reasons: 1. To reduce overhead int
> he common case. 2. I just realized that the common case, for both
> positive and negative numbers, is to complement the corresponding bit
> of  the absolute value.

Any comments on this code?

Regards,
/Niels

> Code below (with some additional comments).
>
>  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;
>
> The above case is an optimization for the common case. If deleted, it
> should still be handled correctly by the common-case code later on.
>
>    /* 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 && 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 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) -= dp[dsize];
>          }
>        else
>          {
>            /* We toggle a zero bit, subtract from the absolute value. */
>            MPN_DECR_U (dp + limb_index, dsize - limb_index, bit);
>            MPN_NORMALIZE (dp, dsize);
>            ASSERT (dsize > 0);
>            SIZ(d) = -dsize;
>          }
>      }
>    else
>      {
>        /* Simple case: Toggle the bit in the absolute value. */
>        dsize = ABS(dsize);
>        if (limb_index < dsize)
>          {
>            dp[limb_index] ^= bit;
>  
>            /* Can happen only when limb_index = dsize - 1. Avoid SIZ(d)
>               bookkeeping in the common case. */
>            if (dp[dsize-1] == 0)
>              {
>                dsize--;
>                MPN_NORMALIZE (dp, dsize);
>                SIZ (d) = SIZ (d) >= 0 ? dsize : -dsize;
>              }
>
> Here, MPN_NORMALIZE could be called unconditionally. I write it this way
> in order to avoid having to check the sign of SIZ (d) in the common
> case. Not sure if that optimization is worth the two extra lines of code.
>
>          }
>        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;
>          }
>      }
>  }
>
> Another reflection: I think it would make sense to have mpz_combit
> return the value of the bit in question. It might also make sense to
> have setbit and clrbit return the previous value of the bit (and in that
> case, for consistency combit should probably return the *previous* value
> of the bit, not the new value). That would be an interface change, of
> course.
>
> Regards,
> /Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.


More information about the gmp-devel mailing list