Skip to main content
Tweeted twitter.com/StackCodeReview/status/887497559349932032
added 3 characters in body; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Compressing a 'char' array using bit packing using C

I have a large array (around 1 MB) of type unsigned char (i.e. uint8_t). I know that the bytes in it can have only one of 5 values (i.e. 0, 1, 2, 3, 4). Moreover, we do not need to preserve '3's from the input, they can be safely lost when we encode/decode.

So I guessed bit packing would be the simplest way to compress it, so every byte can be converted to 2 bits (00, 01..., 11).

As mentioned, all elements of value 3 can be removed (i.e. saved as 0). Which, which gives me option to save '4' as '3'. While reconstructing (decompressing) I restore 3's to 4's.

I wrote a small function for the compression but I feel this has too many operations and is just not efficient enough. Any suggestions or hints on how to handle the operations more efficiently but maintaining the readability will be of much help.

/// Compress by packing ...
void compressByPacking (uint8_t* out, uint8_t* in, uint32_t length)
{
  for (int loop = 0; loop < length/4; loop ++, in += 4, out++)
  {
    uint8_t temp[4];

    for (int small_loop = 0; small_loop < 4; small_loop++)
    {
      temp[small_loop] = *in;           // Load into local variable

      if (temp[small_loop] == 3)        // 3's are discarded
        temp[small_loop] = 0;
      else if (temp[small_loop] == 4)   // and 4's are converted to 3
        temp[small_loop] = 3;

    } // end small loop

    // Pack the bits into write pointer
    *out = (uint8_t)((temp[0] & 0x03) << 6) |
                    ((temp[1] & 0x03) << 4) |
                    ((temp[2] & 0x03) << 2) |
                    ((temp[3] & 0x03));

  } // end loop
}

Cross-posted from SO .

Compressing a 'char' array using bit packing using C

I have a large array (around 1 MB) of type unsigned char (i.e. uint8_t). I know that the bytes in it can have only one of 5 values (i.e. 0, 1, 2, 3, 4). Moreover we do not need to preserve '3's from the input, they can be safely lost when we encode/decode.

So I guessed bit packing would be the simplest way to compress it, so every byte can be converted to 2 bits (00, 01..., 11).

As mentioned all elements of value 3 can be removed (i.e. saved as 0). Which gives me option to save '4' as '3'. While reconstructing (decompressing) I restore 3's to 4's.

I wrote a small function for the compression but I feel this has too many operations and just not efficient enough. Any suggestions or hints on how to handle the operations more efficiently but maintaining the readability will be of much help.

/// Compress by packing ...
void compressByPacking (uint8_t* out, uint8_t* in, uint32_t length)
{
  for (int loop = 0; loop < length/4; loop ++, in += 4, out++)
  {
    uint8_t temp[4];

    for (int small_loop = 0; small_loop < 4; small_loop++)
    {
      temp[small_loop] = *in;           // Load into local variable

      if (temp[small_loop] == 3)        // 3's are discarded
        temp[small_loop] = 0;
      else if (temp[small_loop] == 4)   // and 4's are converted to 3
        temp[small_loop] = 3;

    } // end small loop

    // Pack the bits into write pointer
    *out = (uint8_t)((temp[0] & 0x03) << 6) |
                    ((temp[1] & 0x03) << 4) |
                    ((temp[2] & 0x03) << 2) |
                    ((temp[3] & 0x03));

  } // end loop
}

Cross-posted from SO .

Compressing a 'char' array using bit packing

I have a large array (around 1 MB) of type unsigned char (i.e. uint8_t). I know that the bytes in it can have only one of 5 values (i.e. 0, 1, 2, 3, 4). Moreover, we do not need to preserve '3's from the input, they can be safely lost when we encode/decode.

So I guessed bit packing would be the simplest way to compress it, so every byte can be converted to 2 bits (00, 01..., 11).

As mentioned, all elements of value 3 can be removed (i.e. saved as 0), which gives me option to save '4' as '3'. While reconstructing (decompressing) I restore 3's to 4's.

I wrote a small function for the compression but I feel this has too many operations and is just not efficient enough. Any suggestions or hints on how to handle the operations more efficiently but maintaining the readability will be of much help.

/// Compress by packing ...
void compressByPacking (uint8_t* out, uint8_t* in, uint32_t length)
{
  for (int loop = 0; loop < length/4; loop ++, in += 4, out++)
  {
    uint8_t temp[4];

    for (int small_loop = 0; small_loop < 4; small_loop++)
    {
      temp[small_loop] = *in;           // Load into local variable

      if (temp[small_loop] == 3)        // 3's are discarded
        temp[small_loop] = 0;
      else if (temp[small_loop] == 4)   // and 4's are converted to 3
        temp[small_loop] = 3;

    } // end small loop

    // Pack the bits into write pointer
    *out = (uint8_t)((temp[0] & 0x03) << 6) |
                    ((temp[1] & 0x03) << 4) |
                    ((temp[2] & 0x03) << 2) |
                    ((temp[3] & 0x03));

  } // end loop
}

Cross-posted from SO

Added mention of cross-posting
Source Link
avikpram
  • 171
  • 1
  • 7

I have a large array (around 1 MB) of type unsigned char (i.e. uint8_t). I know that the bytes in it can have only one of 5 values (i.e. 0, 1, 2, 3, 4). Moreover we do not need to preserve '3's from the input, they can be safely lost when we encode/decode.

So I guessed bit packing would be the simplest way to compress it, so every byte can be converted to 2 bits (00, 01..., 11).

As mentioned all elements of value 3 can be removed (i.e. saved as 0). Which gives me option to save '4' as '3'. While reconstructing (decompressing) I restore 3's to 4's.

I wrote a small function for the compression but I feel this has too many operations and just not efficient enough. Any suggestions or hints on how to handle the operations more efficiently but maintaining the readability will be of much help.

/// Compress by packing ...
void compressByPacking (uint8_t* out, uint8_t* in, uint32_t length)
{
  for (int loop = 0; loop < length/4; loop ++, in += 4, out++)
  {
    uint8_t temp[4];

    for (int small_loop = 0; small_loop < 4; small_loop++)
    {
      temp[small_loop] = *in;           // Load into local variable

      if (temp[small_loop] == 3)        // 3's are discarded
        temp[small_loop] = 0;
      else if (temp[small_loop] == 4)   // and 4's are converted to 3
        temp[small_loop] = 3;

    } // end small loop

    // Pack the bits into write pointer
    *out = (uint8_t)((temp[0] & 0x03) << 6) |
                    ((temp[1] & 0x03) << 4) |
                    ((temp[2] & 0x03) << 2) |
                    ((temp[3] & 0x03));

  } // end loop
}

Cross-posted from SO .

I have a large array (around 1 MB) of type unsigned char (i.e. uint8_t). I know that the bytes in it can have only one of 5 values (i.e. 0, 1, 2, 3, 4). Moreover we do not need to preserve '3's from the input, they can be safely lost when we encode/decode.

So I guessed bit packing would be the simplest way to compress it, so every byte can be converted to 2 bits (00, 01..., 11).

As mentioned all elements of value 3 can be removed (i.e. saved as 0). Which gives me option to save '4' as '3'. While reconstructing (decompressing) I restore 3's to 4's.

I wrote a small function for the compression but I feel this has too many operations and just not efficient enough. Any suggestions or hints on how to handle the operations more efficiently but maintaining the readability will be of much help.

/// Compress by packing ...
void compressByPacking (uint8_t* out, uint8_t* in, uint32_t length)
{
  for (int loop = 0; loop < length/4; loop ++, in += 4, out++)
  {
    uint8_t temp[4];

    for (int small_loop = 0; small_loop < 4; small_loop++)
    {
      temp[small_loop] = *in;           // Load into local variable

      if (temp[small_loop] == 3)        // 3's are discarded
        temp[small_loop] = 0;
      else if (temp[small_loop] == 4)   // and 4's are converted to 3
        temp[small_loop] = 3;

    } // end small loop

    // Pack the bits into write pointer
    *out = (uint8_t)((temp[0] & 0x03) << 6) |
                    ((temp[1] & 0x03) << 4) |
                    ((temp[2] & 0x03) << 2) |
                    ((temp[3] & 0x03));

  } // end loop
}

I have a large array (around 1 MB) of type unsigned char (i.e. uint8_t). I know that the bytes in it can have only one of 5 values (i.e. 0, 1, 2, 3, 4). Moreover we do not need to preserve '3's from the input, they can be safely lost when we encode/decode.

So I guessed bit packing would be the simplest way to compress it, so every byte can be converted to 2 bits (00, 01..., 11).

As mentioned all elements of value 3 can be removed (i.e. saved as 0). Which gives me option to save '4' as '3'. While reconstructing (decompressing) I restore 3's to 4's.

I wrote a small function for the compression but I feel this has too many operations and just not efficient enough. Any suggestions or hints on how to handle the operations more efficiently but maintaining the readability will be of much help.

/// Compress by packing ...
void compressByPacking (uint8_t* out, uint8_t* in, uint32_t length)
{
  for (int loop = 0; loop < length/4; loop ++, in += 4, out++)
  {
    uint8_t temp[4];

    for (int small_loop = 0; small_loop < 4; small_loop++)
    {
      temp[small_loop] = *in;           // Load into local variable

      if (temp[small_loop] == 3)        // 3's are discarded
        temp[small_loop] = 0;
      else if (temp[small_loop] == 4)   // and 4's are converted to 3
        temp[small_loop] = 3;

    } // end small loop

    // Pack the bits into write pointer
    *out = (uint8_t)((temp[0] & 0x03) << 6) |
                    ((temp[1] & 0x03) << 4) |
                    ((temp[2] & 0x03) << 2) |
                    ((temp[3] & 0x03));

  } // end loop
}

Cross-posted from SO .

edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
Source Link
avikpram
  • 171
  • 1
  • 7
Loading