-2

What is the most efficient way calculate the parity bit (if the number of active bits are odd or even) in a byte array? I have though about iterating through all the bits and summing up the active bits, but that would be very impractical purely based on the number of iterations required on larger byte arrays/files.

Daniel Valland
  • 1,057
  • 4
  • 21
  • 45
  • 4
    You could have a lookup table for the parity of a byte to avoid the iteration over the bits. However, one bit of parity for an entire byte array is unlikely to be of much use if the intention is error-detection. – Andrew Morton Aug 09 '14 at 22:08

3 Answers3

1

For your convenience (and my curiosity), I have done some timing tests with a parity lookup table compared to the other two methods suggested so far:

Module Module1

    Dim rand As New Random

    Dim parityLookup(255) As Integer

    Sub SetUpParityLookup()
        ' setBitsCount data from http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer

        Dim setBitsCount = {
        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
    }
        For i = 0 To 255
            parityLookup(i) = setBitsCount(i) And 1
        Next

    End Sub

    ' Method using lookup table
    Function ParityOfArray(a() As Byte) As Integer
        Dim parity As Integer = 0 ' use an Integer because they are faster
        For i = 0 To a.Length - 1
            parity = parity Xor parityLookup(a(i))
        Next

        Return parity

    End Function

    ' Method by Alireza
    Function ComputeParity(bytes() As Byte) As Byte
        Dim parity As Boolean = False
        For i As Integer = 0 To bytes.Length - 1
            Dim b As Byte = bytes(i)
            While b <> 0
                parity = Not parity
                b = CByte(b And (b - 1))
            End While
        Next
        Return Convert.ToByte(parity)
    End Function

    ' Method by dbasnett
    Function CountBits(byteArray As Byte()) As Integer
        Dim rv As Integer = 0
        For Each b As Byte In byteArray
            Dim count As Integer = b
            count = ((count >> 1) And &H55) + (count And &H55)
            count = ((count >> 2) And &H33) + (count And &H33)
            count = ((count >> 4) And &HF) + (count And &HF)
            rv += count
        Next
        Return rv
    End Function

    Sub FillWithRandomBytes(ByRef a() As Byte)
        rand.NextBytes(a)
    End Sub

    Sub Main()
        SetUpParityLookup()

        Dim nBytes = 10000
        Dim a(nBytes - 1) As Byte
        FillWithRandomBytes(a)

        Dim p As Integer

        Dim sw As New Stopwatch

        sw.Start()
        p = ParityOfArray(a)
        sw.Stop()

        Console.WriteLine("ParityOfArray - Parity: {0} Time: {1}", p, sw.ElapsedTicks)

        sw.Restart()
        p = ComputeParity(a)
        sw.Stop()

        Console.WriteLine("ComputeParity - Parity: {0} Time: {1}", p, sw.ElapsedTicks)

        sw.Restart()
        p = CountBits(a)
        sw.Stop()

        ' Note that the value returned from CountBits should be And-ed with 1.
        Console.WriteLine("CountBits     - Parity: {0} Time: {1}", p And 1, sw.ElapsedTicks)

        Console.ReadLine()

    End Sub

End Module

Typical ouput:

ParityOfArray - Parity: 0 Time: 386
ComputeParity - Parity: 0 Time: 1014
CountBits     - Parity: 0 Time: 695
Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
  • I made a minor change to my code, but it might make a slight difference. – dbasnett Aug 09 '14 at 23:23
  • @dbasnett It might, but I couldn't detect a significant difference, certainly not enough to be faster than a lookup table. – Andrew Morton Aug 09 '14 at 23:29
  • I agree with that, a lookup will be faster than actually counting the one bits. The lookup should give the OP what they are after. FWIW I added a loop to your test code and the timings are significantly different when the code executes more than once. All of the times drop by about 300. – dbasnett Aug 09 '14 at 23:34
  • @dbasnett I tested with a loop of 20 iterations around the test code and with varying (large) sizes of the test data, and based on using a new array of test data in each iteration I suspect that the speed-up seen in iterations after the first is due to the processor automatically speeding up, rather than than promoting the data to a cache closer to the processor. Of course, I could be wrong. – Andrew Morton Aug 09 '14 at 23:58
0

An efficient way to do this is to use the x & (x - 1) operation in a loop, until x becomes zero. This way you will loop only by the number of bits set to 1.

In VB.NET for a byte array:

Function ComputeParity(bytes() As Byte) As Byte
    Dim parity As Boolean = False
    For i As Integer = 0 To bytes.Length - 1
        Dim b As Byte = bytes(i)
        While b <> 0
            parity = Not parity
            b = b And (b - 1)
        End While
    Next
    Return Convert.ToByte(parity)
End Function
Alireza
  • 4,976
  • 1
  • 23
  • 36
0

Here is a function that counts bits.

Private Function CountBits(byteArray As Byte()) As Integer
    Dim rv As Integer = 0
    For x As Integer = 0 To byteArray.Length - 1
        Dim b As Byte = byteArray(x)
        Dim count As Integer = b
        count = ((count >> 1) And &H55) + (count And &H55)
        count = ((count >> 2) And &H33) + (count And &H33)
        count = ((count >> 4) And &HF) + (count And &HF)
        rv += count
    Next
    Return rv
End Function

Note: this code came from a collection of bit twiddling hacks I found some years ago. I converted it to VB.

dbasnett
  • 11,334
  • 2
  • 25
  • 33