Efficient Bit addressing in Python.

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Hendrik van Rooyen

    Efficient Bit addressing in Python.


    Is there a canonical way to address the bits in a structure
    like an array or string or struct?

    Or alternatively, is there a good way to combine eight
    ints that represent bits into one of the bytes in some
    array or string or whatever?

    It seems to me that there is a dilemma here :

    if you can write:

    bit3 = 1

    Then you have to jump through hoops to get
    bit0 through bit7 into some byte that you can send
    to an i/o routine.

    On the other hand, if you keep the bits "in" the
    byte, then you can write:

    byte[3] = '\x7e'

    but you have to jump through hoops to get at
    the individual bits.

    Is there a "best" way?

    It would be nice to be able to write:

    if io.byte2.bit3:
    do_something()

    if io.byte2 == alarm_value:
    do_something_el se()

    where:

    io.byte2 & 8 "is" io.byte2.bit3

    Is this possible?

    - Hendrik

  • George Sakkis

    #2
    Re: Efficient Bit addressing in Python.

    On Oct 9, 6:30 pm, "Hendrik van Rooyen" <m...@microcorp .co.zawrote:
    Is there a canonical way to address the bits in a structure
    like an array or string or struct?
    I don't know of a canonical way (bit hacking is not really common in
    Python) but pehaps BitPacket [1] comes close to what you're after.

    George

    [1] http://hacks-galore.org/aleix/BitPacket/

    Comment

    • Mensanator

      #3
      Re: Efficient Bit addressing in Python.

      On Oct 9, 5:30 pm, "Hendrik van Rooyen" <m...@microcorp .co.zawrote:
      Is there a canonical way to address the bits in a structure
      like an array or string or struct?
      >
      Or alternatively, is there a good way to combine eight
      ints that represent bits into one of the bytes in some
      array or string or whatever?
      >
      It seems to me that there is a dilemma here :
      >
      if you can write:
      >
      bit3 = 1
      >
      Then you have to jump through hoops to get
      bit0 through bit7 into some byte that you can send
      to an i/o routine.
      >
      On the other hand, if you keep the bits "in" the
      byte, then you can write:
      >
      byte[3] = '\x7e'
      >
      but you have to jump through hoops to get at
      the individual bits.
      >
      Is there a "best" way?
      >
      It would be nice to be able to write:
      >
      if io.byte2.bit3:
         do_something()
      >
      if io.byte2 == alarm_value:
        do_something_el se()
      >
      where:
      >
       io.byte2 & 8   "is"  io.byte2.bit3
      >
      Is this possible?
      >
      - Hendrik
      I use the gmpy module for all my bit related work and
      have been very satisfied with the results.

      Examples of functions pertinent to bit operations:

      digits(...)
      digits(x[,base]): returns Python string representing x in the
      given base (2 to 36, default 10 if omitted or 0); leading '-'
      present if x<0, but no leading '+' if x>=0. x must be an mpz,
      or else gets coerced into one.

      getbit(...)
      getbit(x,n): returns 0 or 1, the bit-value of bit n of x;
      n must be an ordinary Python int, >=0; x is an mpz, or else
      gets coerced to one.

      hamdist(...)
      hamdist(x,y): returns the Hamming distance (number of bit-
      positions
      where the bits differ) between x and y. x and y must be mpz,
      or else
      get coerced to mpz.

      lowbits(...)
      lowbits(x,n): returns the n lowest bits of x; n must be an
      ordinary Python int, >0; x must be an mpz, or else gets
      coerced to one.

      numdigits(...)
      numdigits(x[,base]): returns length of string representing x
      in
      the given base (2 to 36, default 10 if omitted or 0); the
      value
      returned may sometimes be 1 more than necessary; no provision
      for any 'sign' characte, nor leading '0' or '0x' decoration,
      is made in the returned length. x must be an mpz, or else
      gets
      coerced into one.

      popcount(...)
      popcount(x): returns the number of 1-bits set in x; note that
      this is 'infinite' if x<0, and in that case, -1 is returned.
      x must be an mpz, or else gets coerced to one.

      scan0(...)
      scan0(x, n=0): returns the bit-index of the first 0-bit of x
      (that
      is at least n); n must be an ordinary Python int, >=0. If no
      more
      0-bits are in x at or above bit-index n (which can only happen
      for
      x<0, notionally extended with infinite 1-bits), None is
      returned.
      x must be an mpz, or else gets coerced to one.

      scan1(...)
      scan1(x, n=0): returns the bit-index of the first 1-bit of x
      (that
      is at least n); n must be an ordinary Python int, >=0. If no
      more
      1-bits are in x at or above bit-index n (which can only happen
      for
      x>=0, notionally extended with infinite 0-bits), None is
      returned.
      x must be an mpz, or else gets coerced to one.

      setbit(...)
      setbit(x,n,v=1) : returns a copy of the value of x, with bit n
      set
      to value v; n must be an ordinary Python int, >=0; v, 0 or !
      =0;
      x must be an mpz, or else gets coerced to one.

      Comment

      • Ross Ridge

        #4
        Re: Efficient Bit addressing in Python.

        Hendrik van Rooyen <mail@microcorp .co.zawrote:
        >Is there a canonical way to address the bits in a structure
        >like an array or string or struct?
        >
        >Or alternatively, is there a good way to combine eight
        >ints that represent bits into one of the bytes in some
        >array or string or whatever?
        This is the code I use to convert large bit arrays to byte strings and
        back:

        import string
        import binascii
        import array

        _tr_16 = string.maketran s("0123456789ab cdef",
        "\x00\x01\x02\x 03"
        "\x10\x11\x12\x 13"
        "\x20\x21\x22\x 23"
        "\x30\x31\x32\x 33")
        _tr_4 = string.maketran s("0123",
        "\x00\x01"
        "\x10\x11")
        _tr_2 = string.maketran s("01", "\x00\x01")

        def string_to_bit_a rray(s):
        """Convert a string to an array containing a sequence of bits."""
        s = binascii.hexlif y(s).translate( _tr_16)
        s = binascii.hexlif y(s).translate( _tr_4)
        s = binascii.hexlif y(s).translate( _tr_2)
        a = array.array('B' , s)
        return a

        _tr_rev_2 = string.maketran s("\x00\x01", "01")
        _tr_rev_4 = string.maketran s("\x00\x01"
        "\x10\x11",
        "0123")
        _tr_rev_16 = string.maketran s("\x00\x01\x02 \x03"
        "\x10\x11\x12\x 13"
        "\x20\x21\x22\x 23"
        "\x30\x31\x32\x 33",
        "0123456789abcd ef")
        def bit_array_to_st ring(a):
        """Convert an array containing a sequence of bits to a string."""
        remainder = len(a) % 8
        if remainder != 0:
        a.fromlist([0] * (8 - remainder))
        s = a.tostring()
        s = binascii.unhexl ify(s.translate (_tr_rev_2))
        s = binascii.unhexl ify(s.translate (_tr_rev_4))
        return binascii.unhexl ify(s.translate (_tr_rev_16))

        I don't think you can do anything faster with standard modules, although
        it might not be effecient if you're only working with a single byte.

        Ross Ridge

        --
        l/ // Ross Ridge -- The Great HTMU
        [oo][oo] rridge@csclub.u waterloo.ca
        -()-/()/ http://www.csclub.uwaterloo.ca/~rridge/
        db //

        Comment

        • Aaron \Castironpi\ Brady

          #5
          Re: Efficient Bit addressing in Python.

          On Oct 9, 5:30 pm, "Hendrik van Rooyen" <m...@microcorp .co.zawrote:
          Is there a canonical way to address the bits in a structure
          like an array or string or struct?
          >
          Or alternatively, is there a good way to combine eight
          ints that represent bits into one of the bytes in some
          array or string or whatever?
          >
          It seems to me that there is a dilemma here :
          >
          if you can write:
          >
          bit3 = 1
          >
          Then you have to jump through hoops to get
          bit0 through bit7 into some byte that you can send
          to an i/o routine.
          >
          On the other hand, if you keep the bits "in" the
          byte, then you can write:
          >
          byte[3] = '\x7e'
          >
          but you have to jump through hoops to get at
          the individual bits.
          >
          Is there a "best" way?
          >
          It would be nice to be able to write:
          >
          if io.byte2.bit3:
             do_something()
          >
          if io.byte2 == alarm_value:
            do_something_el se()
          >
          where:
          >
           io.byte2 & 8   "is"  io.byte2.bit3
          >
          Is this possible?
          >
          - Hendrik
          This is tolerable. If you've got a better 'clear' operation than
          'xor', you're welcome to it.

          class BitSet:
          def __init__( self, value ):
          self.value= value
          def __setitem__( self, index, value ):
          if value:
          self.value= self.value| (1<< index)
          elif self[ index ]:
          self.value= self.value^ (1<< index)
          def __getitem__( self, index ):
          return self.value& (1<< index )
          def __repr__( self ):
          return repr( self.value )

          if __name__== '__main__':
          b= BitSet( 15 )
          print b
          b[0]= 0
          print b
          b[0]= 1
          print b
          b[4]= 1
          print b
          b[4]= 0
          print b

          /Output:
          15
          14
          15
          31
          15

          Comment

          • Aaron \Castironpi\ Brady

            #6
            Re: Efficient Bit addressing in Python.

            On Oct 10, 10:37 pm, "Aaron \"Castironpi \" Brady"
            <castiro...@gma il.comwrote:
            On Oct 9, 5:30 pm, "Hendrik van Rooyen" <m...@microcorp .co.zawrote:
            >
            >
            >
            Is there a canonical way to address the bits in a structure
            like an array or string or struct?
            >
            Or alternatively, is there a good way to combine eight
            ints that represent bits into one of the bytes in some
            array or string or whatever?
            snip
            >
            class BitSet:
                def __init__( self, value ):
                    self.value= value
                def __setitem__( self, index, value ):
                    if value:
                        self.value= self.value| (1<< index)
                    elif self[ index ]:
                        self.value= self.value^ (1<< index)
                def __getitem__( self, index ):
                    return self.value& (1<< index )
            snip

            This could read:

            def __getitem__( self, index ):
            return 1 if self.value& (1<< index ) else 0

            Or you could shift self.value, and mask with unity.

            Comment

            Working...