1
votes

I am not sure if I am calculating the parity bit correctly for the the check Parity bit function I wrote. The codeWord is 11 chars long with 4 parity bits and 7 data bits. Does the implementation look good?

void parityCheck(char* codeWord) {
int parity[4] = {0}, i = 0, diffParity[4] = {0}, twoPower = 0, bitSum = 0;

// Stores # of 1's for each parity bit in array.
parity[0] = (codeWord[2] - 48) + (codeWord[4] - 48) + (codeWord[6] - 48) + (codeWord[8] - 48) + (codeWord[10] - 48);
parity[1] = (codeWord[2] - 48) + (codeWord[5] - 48) + (codeWord[6] - 48) + (codeWord[9] - 48) + (codeWord[10] - 48);
parity[2] = (codeWord[4] - 48) + (codeWord[5] - 48) + (codeWord[6] - 48);
parity[3] = (codeWord[8] - 48) + (codeWord[9] - 48) + (codeWord[10] - 48);

// Determines if sum of bits is even or odd, then tests for difference from actual parity bit.
for (i = 0; i < 4; i++) {
    twoPower = (int)pow((double)2, i);

    if (parity[i] % 2 == 0)
            parity[i] = 0;
        else
            parity[i] = 1;

        if ((codeWord[twoPower-1] - 48) != parity[i])
            diffParity[i] = 1;
}

// Calculates the location of the error bit.
for (i = 0; i < 4; i++) {
    twoPower = (int)pow((double)2, i);
    bitSum += diffParity[i]*twoPower;
}



// Inverts bit at location of error.
if (bitSum <= 11 && bitSum > 0) {
    if ((codeWord[bitSum-1] - 48)) 
        codeWord[bitSum-1] = '0';
    else
        codeWord[bitSum-1] = '1';
}
3
Why not use bit-fields?meaning-matters
I'd replace twoPower = (int)pow((double)2, i) with twoPower = 1 << i. This is likely to give a big performance improvement.John Zwinck
@randomname rather than do a codeWord[2] - 48) + (codeWord[4] - 48) + ..., consider codeWord[2] - 48) ^ (codeWord[4] - 48) ^ . Then if (parity[i] % 2 == 0) ... not needed. Further, - 48 s/b -'0'.chux - Reinstate Monica
The 4 lines if-statement "if (parity[i] % 2.." can be replaced with the more efficient parity[i] &= 1;.Jongware
I guess @meaning-matters meant “bit field” in the sense that you treat a single integer as a sequence of bits, using bit shift operations. This is quite portable, see my answer for an example. What is not portable are bit fields as structelements, i.e. using less than a whole adressable byte for a member of a structure.MvG

3 Answers

1
votes

Does the implementation look good?

This very much depends on your measure for “good”. I can confirm that it does get the job done, so at least it is correct. Your code is very verbose, and thus hard to check for correctness. I'd do the following:

int parity_check(int codeWord) {
  int parity = 0, codeWordBit, bitPos;
  for (bitPos = 1; bitPos <= 11; ++bitPos) {
    codeWordBit = ((codeWord >> (bitPos - 1)) & 1);
    parity ^= bitPos*codeWordBit;
  }
  if (parity != 0) {
    if (parity > 11)
      return -1; // multi-bit error!
    codeWord ^= 1 << (parity - 1);
  }
  return codeWord;
}

Instead of a sequence of digit characters, I treat your whole code word as a single integer, which is a lot more efficient.

Looking at the table at Wikipedia, I see that the columns of that table form binary representations of the sequence 1 … 11. Each code word bit affects exactly those parity bits mentioned in that column, so I take the code word bit (which is zero or one), multiply it by the bit pattern of that column to obtain either that pattern or zero, then XOR this with the current parity bit pattern. The effect of this is that a zero code word bit won't change anything, whereas a non-zero code word bit flips all associated parity bits.

Some care has to be taken because the bit pattern is one-based, whereas the bit position using the right shift trick is zero-based. So I have to subtract one, then shift right by that amount, and then extract the least significant digit in order to obtain the codeWordBit.

Using my implementation for reference, I was able to verify (by complete enumeration) that your code works the same.

0
votes

Your code works fine AFAIK as it passed test cases I conjured up. Some simplifications were employed, but the OP functionality not changed. Some classic simplifications were made for easier viewing.

void parityCheck(char* cW) {
  int parity[4] = { 0 }, i = 0, diffParity[4] = { 0 }, twoPower = 0, bitSum = 0;

  // Stores # of 1's for each parity bit in array.
  parity[0] = (cW[2] - '0') + (cW[4] - '0') + (cW[6] - '0') + (cW[8] - '0') + (cW[10] - '0');
  parity[1] = (cW[2] - '0') + (cW[5] - '0') + (cW[6] - '0') + (cW[9] - '0') + (cW[10] - '0');
  parity[2] = (cW[4] - '0') + (cW[5] - '0') + (cW[6] - '0');
  parity[3] = (cW[8] - '0') + (cW[9] - '0') + (cW[10] - '0');

  // Determines if sum of bits is even or odd, then tests for difference from actual parity bit.
  for (i = 0; i < 4; i++) {
    //twoPower = (int) pow((double) 2, i);
    twoPower = 1 << i;
    //if (parity[i] % 2 == 0) parity[i] = 0; else parity[i] = 1;
    parity[i] &= 1;  // Make 0 even, 1 odd.
    if ((cW[twoPower - 1]-'0') != parity[i])
      diffParity[i] = 1;
  }

  // Calculates the location of the error bit.
  for (i = 0; i < 4; i++) {
    // twoPower = (int) pow((double) 2, i);
    twoPower = 1 << i;
    bitSum += diffParity[i] * twoPower;
  }

  // Inverts bit at location of error.
  if (bitSum <= 11 && bitSum > 0) {
    if ((cW[bitSum - 1]-'0')) 
      cW[bitSum - 1] = '0';
    else
      cW[bitSum - 1] = '1';
  }
}

void TestP(const char * Test) {
  char buf[100];
  strcpy(buf, Test);
  parityCheck(buf);
  printf("'%s' '%s'\n", Test, buf);
}


int main(void) {
  TestP("00000000000");
  TestP("10011100101");
  TestP("10100111001");
}

It would have been useful had the OP posted test patterns.

-1
votes

Here's my implementation. It works. The public is free to use it at no charge.

I used the acronym "secded" as in, "single-error-correcting, double-error-detecting." You can re-wire this as a "triple error detector" if you want that instead. Really, some small part of this is secded and the rest is Hamming 7,4 -- but I named these methods what I did, when I did.

The "strings" here are not NUL-terminated, but counted. This code is excerpted from a Python module written in C. That is the provenance of the string type you see.

A key point here was realizing that there are only 16 Hamming 7,4 codes. I calculated secded_of_nibble() with some Python code, which unfortunately I no longer have.

static const unsigned char secded_of_nibble[] = 
{ 0x0, 0xd2, 0x55, 0x87, 0x99, 0x4b, 0xcc, 0x1e, 0xe1, 0x33, 0xb4, 0x66, 0x78, 0
xaa, 0x2d, 0xff };

int fec_secded_encode_cch_bits(const char * strIn, const int cchIn, char * strOu
t, const int cchOut)
{
    assert( cchIn * 2 == cchOut);
    if( cchIn * 2 != cchOut)
        return 0;

    if (!strIn || !strOut)
        return 0;

    int i;
    for (i = 0; i < cchIn; i ++)
    {
        char in_byte = strIn[i];
        char hi_byte = secded_of_nibble[(in_byte >> 4) & 0xf];
        char lo_byte = secded_of_nibble[in_byte & 0xf];

        strOut[i * 2] = hi_byte;
        strOut[i * 2 + 1] = lo_byte;
    }

    return 1;
}

char bv_H[] = {0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x8};

char val_nibble(char ch)
{
    return ((ch & 0x20) >> 2) | ((ch & 0xE) >> 1);
}

char correct_nibble(char ch)
{
    char nibble = 0;
    int i = 0;
    for (i = 0; i < 8; i++)
    if (ch & (1 << (7-i)))
        nibble ^= bv_H[i];

    return nibble;
}

void apply_correct(char nib_correct, char * pbyte, int * pcSec, int *pcDed)
{
    if (0 == nib_correct)
        return;

    if (nib_correct & 0x8)
    {
        (*pcSec) ++;

        int bit = (8 - (nib_correct & 0x7)) & 0x7;
        /*  fprintf(stderr, "bit %d, %02X\n", bit, 1 << bit);*/
        (*pbyte) ^= (1 << bit);
    }
    else
    {
        (*pcDed) ++;
    }
}

int fec_secded_decode_cch_bits
(
    const char * strIn, 
    const int cchIn, 
    char * strOut, 
    const int cchOut,
    int * pcSec,
    int * pcDed
)
{
    assert( cchIn == cchOut *2);
    if( cchIn != cchOut * 2)
        return 0;

    if (!strIn || !strOut)
        return 0;

    int i;
    for (i = 0; i < cchOut; i ++)
    {
        char hi_byte = strIn[i * 2];
        char lo_byte = strIn[i * 2 + 1];


        char hi_correct = correct_nibble(hi_byte);
        char lo_correct = correct_nibble(lo_byte);

        if (hi_correct || lo_correct)
        {
            apply_correct(hi_correct, &hi_byte, pcSec, pcDed);
            apply_correct(lo_correct, &lo_byte, pcSec, pcDed);
/*          fprintf(stderr, "Corrections %x %x.\n", hi_correct, lo_correct);*/
        }

        char hi_nibble = val_nibble(hi_byte);
        char lo_nibble = val_nibble(lo_byte);

        strOut[i] = (hi_nibble << 4) | lo_nibble;
    }

    return 1;
}