Hamming code Implementation in C++ with receiver side verification of code
Last Updated :
15 Mar, 2023
Hamming code is an error-correcting code used for detecting and correcting errors in data transmission. It adds redundant bits to the data being transmitted which can be used to detect and correct errors that may occur during transmission. Developed by Richard W. Hamming in the 1950s, it is widely used in applications where reliable data transmission is critical, such as computer networks and telecommunication systems.
To implement the Hamming code in C++, we can use bitwise operations and arrays to represent the data and the redundant bits. The following code snippet demonstrates how to implement the Hamming code in C++ with receiver-side verification:
Example:
C++
#include <iostream>
using namespace std;
// function to calculate the parity bit for a given position
int parity(int n, int *arr) {
int p = 0;
for (int i = 0; i < n; i++) {
if (i != (1 << p) - 1) {
p++;
}
else {
p++;
i += (1 << p) - 2;
}
}
int sum = 0;
for (int i = 0; i < n; i++) {
if ((i & (1 << p - 1)) == 0) {
sum ^= arr[i];
}
}
return sum;
}
// function to encode the data using the Hamming code
void encode(int *data, int n, int *encoded) {
int r = 0;
while ((1 << r) < n + r + 1) {
r++;
}
int j = 0;
for (int i = 0; i < n + r; i++) {
if ((i & (i + 1)) == 0) {
encoded[i] = 0;
}
else {
encoded[i] = data[j];
j++;
}
}
for (int i = 0; i < r; i++) {
int p = parity(n + r, encoded);
encoded[(1 << i) - 1] = p;
}
}
// function to decode the data using the Hamming code
bool decode(int *data, int n, int *received) {
int r = 0;
while ((1 << r) < n + r + 1) {
r++;
}
int error = 0;
for (int i = 0; i < r; i++) {
int p = parity(n + r, received);
if (p != received[(1 << i) - 1]) {
error += (1 << i) - 1;
}
}
if (error != 0) {
received[error - 1] ^= 1;
}
int j = 0;
for (int i = 0; i < n + r; i++) {
if ((i & (i + 1)) != 0) {
data[j] = received[i];
j++;
}
}
return error == 0;
}
int main() {
int n = 4; // size of data
int r = 3; // number of redundant bits
int data[n] = {1, 0, 1, 1}; // data to be transmitted
int encoded[n + r] = {0}; // encoded data
C++
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
class hamming{
public:
string data; //it is the raw data received
int m , r = 0; // n is the length of raw data and r is the number of redundant bits
char * msg; // it will store the all bits (data + redundant). We made it dynamic because at compile time we dont know how much redundant bits will be there, we will initialize memory to it once we know the number of redundant bits.
hamming(string data){
this->data = data;
//reversing the data received
reverse(data.begin(),data.end());
m = data.size();
int power = 1;
//finding the number of redundant bits and storing them in r
while(power < (m + r + 1)){
r++;
power*=2;
}
//Allocating memory to our dynamic msg array(Note we are using one based indexing).
msg = new char[m+r+1];
int curr = 0;
//initializing the msg with data bits and for redundant bits, an initial value of n
for(int i = 1 ; i <= m+r ; i++){
if(i & (i-1)){
msg[i] = data[curr++];
}
else msg[i] = 'n';
}
//function call to set the redundant bits
setRedundantBits();
}
//function to show the whole msg
void showmsg(){
cout << "the data packet to be sent is : ";
for(int i = m+r ; i >= 1 ; i--){
cout << msg[i] << " ";
}
cout << endl;
}
void setRedundantBits(){
//for first redundant bit, check all those data bits at index where the first bit of index is set(1) similarly for second redundant bit, check all those data bits at index where the second bit of index is set(1), similarly for third redundant bit check all those data bits at index where the third bit of index is set to 1 and so on.
int bit = 0;
//outer loop runs for redundant bits (1 ,2 ,4 ,8 ....)
for(int i = 1 ; i <= m+r ; i*=2){
int count = 0;
//inner loop runs for data bits
for(int j = i+1 ; j<=m+r ; j++){
// checking if the data bit corresponds to our redundant bit or not using bit manipulation
if(j & (1 << bit)){
if(msg[j] == '1') count++; // counting the number of ones in corresponding data bits
}
}
//setting up redundant bits
if(count & 1) msg[i] = '1';
else msg[i] = '0';
//increasing the bit position.
bit++;
}
//showing up the message to be sent(data + redundant)
showmsg();
}
void receiver(){
//this ans will store the redundant bits, if they were right then according to even parity they will store 0 else if some error was made in a bit it will store 1
string ans = "";
int bit = 0;
//this loop corresponds to the logic used in set redundant bits function
for(int i = 1 ; i <= m+r ; i*=2){
int count = 0;
for(int j = i+1 ; j<=m+r ; j++){
if(j & (1 << bit)){
if(msg[j] == '1') count++;
}
}
//incrementing the ans variable with the parity of redundant bit
// if it was right then add 0 else 1
if(count & 1){
if(msg[i] == '1') ans.push_back('0');
else ans.push_back('1');
}
else{
if(msg[i]=='0') ans.push_back('0');
else ans.push_back('1');
}
bit++;
}
// if the ans had any occurrence of 1 then there is some fault
if(ans.find('1') != string::npos){
int power = 1;
int wrongbit = 0;
//evaluating the binary expression of ans variable
for(int i = 0 ; i < ans.size() ; i++){
if(ans[i]=='1') wrongbit+=power;
power*=2;
}
cout << "bit number " << wrongbit << " is wrong and having error " << endl;
}
// if the ans dont have any occurrence of 1 then it is correct
else{
cout << "correct data packet received " << endl;
}
}
};
int main(){
string data = "1011001";
hamming h(data);
// manipulating any ith data bit to check if receiver is detecting a error in that bit. If you eliminate the following line then correct code will be sent to receiver following that no error is received
//h.msg[i] == '0' ? h.msg[i] = '1' : h.msg[i] = '0';
h.receiver();
return 0;
}
//time complexity = O(nlogn) where , n = databits + redundant bits
//this code is contributed by Mayank Sharma.
Outputthe data packet to be sent is : 1 0 1 0 1 0 0 1 1 1 0
correct data packet received
Pre-requisite: Hamming Code
Given a message bit in the form of an array msgBit[], the task is to find the Hamming Code of the given message bit.
Examples:
Input: S = "0101"
Output:
Generated codeword:
r1 r2 m1 r4 m2 m3 m4
0 1 0 0 1 0 1
Explanation:
Initially r1, r2, r4 is set to '0'.
r1 = Bitwise XOR of all bits position that has '1' in its 0th-bit position.
r2 = Bitwise XOR of all bits that has '1' in its 1st-bit position.
r3 = Bitwise XOR of all bits that has '1' in its 2nd-bit position.
Input: S = "0111"
Output:
Generated codeword:
r1 r2 m1 r4 m2 m3 m4
0 0 0 1 1 1 1
Approach: The idea is to first find the number of redundant bits which can be found by initializing r with 1 and then incrementing it by 1 each time while 2r is smaller than (m + r + 1) where m is the number of bits in the input message. Follow the below steps to solve the problem:
- Initialize r by 1 and increment it by 1 until 2r is smaller than m+r+1.
- Initialize a vector hammingCode of size r + m which will be the length of the output message.
- Initialize all the positions of redundant bits with -1 by traversing from i = 0 to r - 1 and setting hammingCode [2i - 1] = -1. Then place the input message bits in all the positions where hammingCode[j] is not -1 in order where 0 <= j < (r + m).
- Initialize a variable one_count with 0 to store the number of ones and then traverse from i = 0 to (r + m - 1).
- If the current bit i.e., hammingCode[i] is not -1 then find the message bit containing set bit at log2(i+1)th position by traversing from j = i+2 to r+m by incrementing one_count by 1 if (j & (1<<x)) is not 0 and hammingCode[j - 1] is 1.
- If for index i, one_count is even, set hammingCode[i] = 0 otherwise set hammingCode[i] = 1.
- After traversing, print the hammingCode[] vector as the output message.
Below is the implementation of the above approach:
C
// C program for the above approach
#include <math.h>
#include <stdio.h>
// Store input bits
int input[32];
// Store hamming code
int code[32];
int ham_calc(int, int);
void solve(int input[], int);
// Function to calculate bit for
// ith position
int ham_calc(int position, int c_l)
{
int count = 0, i, j;
i = position - 1;
// Traverse to store Hamming Code
while (i < c_l) {
for (j = i; j < i + position; j++) {
// If current bit is 1
if (code[j] == 1)
count++;
}
// Update i
i = i + 2 * position;
}
if (count % 2 == 0)
return 0;
else
return 1;
}
// Function to calculate hamming code
void solve(int input[], int n)
{
int i, p_n = 0, c_l, j, k;
i = 0;
// Find msg bits having set bit
// at x'th position of number
while (n > (int)pow(2, i) - (i + 1)) {
p_n++;
i++;
}
c_l = p_n + n;
j = k = 0;
// Traverse the msgBits
for (i = 0; i < c_l; i++) {
// Update the code
if (i == ((int)pow(2, k) - 1)) {
code[i] = 0;
k++;
}
// Update the code[i] to the
// input character at index j
else {
code[i] = input[j];
j++;
}
}
// Traverse and update the
// hamming code
for (i = 0; i < p_n; i++) {
// Find current position
int position = (int)pow(2, i);
// Find value at current position
int value = ham_calc(position, c_l);
// Update the code
code[position - 1] = value;
}
// Print the Hamming Code
printf("\nThe generated Code Word is: ");
for (i = 0; i < c_l; i++) {
printf("%d", code[i]);
}
}
// Driver Code
void main()
{
// Given input message Bit
input[0] = 0;
input[1] = 1;
input[2] = 1;
input[3] = 1;
int N = 4;
// Function Call
solve(input, N);
}
C++
// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
// Function to generate hamming code
vector<int> generateHammingCode(
vector<int> msgBits, int m, int r)
{
// Stores the Hamming Code
vector<int> hammingCode(r + m);
// Find positions of redundant bits
for (int i = 0; i < r; ++i) {
// Placing -1 at redundant bits
// place to identify it later
hammingCode[pow(2, i) - 1] = -1;
}
int j = 0;
// Iterate to update the code
for (int i = 0; i < (r + m); i++) {
// Placing msgBits where -1 is
// absent i.e., except redundant
// bits all positions are msgBits
if (hammingCode[i] != -1) {
hammingCode[i] = msgBits[j];
j++;
}
}
for (int i = 0; i < (r + m); i++) {
// If current bit is not redundant
// bit then continue
if (hammingCode[i] != -1)
continue;
int x = log2(i + 1);
int one_count = 0;
// Find msg bits containing
// set bit at x'th position
for (int j = i + 2;
j <= (r + m); ++j) {
if (j & (1 << x)) {
if (hammingCode[j - 1] == 1) {
one_count++;
}
}
}
// Generating hamming code for
// even parity
if (one_count % 2 == 0) {
hammingCode[i] = 0;
}
else {
hammingCode[i] = 1;
}
}
// Return the generated code
return hammingCode;
}
// Function to find the hamming code
// of the given message bit msgBit[]
void findHammingCode(vector<int>& msgBit)
{
// Message bit size
int m = msgBit.size();
// r is the number of redundant bits
int r = 1;
// Find no. of redundant bits
while (pow(2, r) < (m + r + 1)) {
r++;
}
// Generating Code
vector<int> ans
= generateHammingCode(msgBit, m, r);
// Print the code
cout << "Message bits are: ";
for (int i = 0; i < msgBit.size(); i++)
cout << msgBit[i] << " ";
cout << "\nHamming code is: ";
for (int i = 0; i < ans.size(); i++)
cout << ans[i] << " ";
}
// Driver Code
int main()
{
// Given message bits
vector<int> msgBit = { 0, 1, 0, 1 };
// Function Call
findHammingCode(msgBit);
return 0;
}
Time Complexity: O((M + R)2) where M is the number of bits in the input message and R is the number of redundant bits
Auxiliary Space: O(M + R) the algorithm needs space proportional to input data size (M) plus output data size (R). This is common in data manipulation algorithms like sorting or searching. Excessive memory usage can limit problem scale, so it's important to consider auxiliary space complexity alongside time complexity.
Similar Reads
DSA Tutorial - Learn Data Structures and Algorithms DSA (Data Structures and Algorithms) is the study of organizing data efficiently using data structures like arrays, stacks, and trees, paired with step-by-step procedures (or algorithms) to solve problems effectively. Data structures manage how data is stored and accessed, while algorithms focus on
7 min read
What is OSI Model? - Layers of OSI Model The OSI (Open Systems Interconnection) Model is a set of rules that explains how different computer systems communicate over a network. OSI Model was developed by the International Organization for Standardization (ISO). The OSI Model consists of 7 layers and each layer has specific functions and re
13 min read
Quick Sort QuickSort is a sorting algorithm based on the Divide and Conquer that picks an element as a pivot and partitions the given array around the picked pivot by placing the pivot in its correct position in the sorted array. It works on the principle of divide and conquer, breaking down the problem into s
12 min read
Merge Sort - Data Structure and Algorithms Tutorials Merge sort is a popular sorting algorithm known for its efficiency and stability. It follows the divide-and-conquer approach. It works by recursively dividing the input array into two halves, recursively sorting the two halves and finally merging them back together to obtain the sorted array. Merge
14 min read
Bubble Sort Algorithm Bubble Sort is the simplest sorting algorithm that works by repeatedly swapping the adjacent elements if they are in the wrong order. This algorithm is not suitable for large data sets as its average and worst-case time complexity are quite high.We sort the array using multiple passes. After the fir
8 min read
Data Structures Tutorial Data structures are the fundamental building blocks of computer programming. They define how data is organized, stored, and manipulated within a program. Understanding data structures is very important for developing efficient and effective algorithms. What is Data Structure?A data structure is a st
2 min read
Breadth First Search or BFS for a Graph Given a undirected graph represented by an adjacency list adj, where each adj[i] represents the list of vertices connected to vertex i. Perform a Breadth First Search (BFS) traversal starting from vertex 0, visiting vertices from left to right according to the adjacency list, and return a list conta
15+ min read
Binary Search Algorithm - Iterative and Recursive Implementation Binary Search Algorithm is a searching algorithm used in a sorted array by repeatedly dividing the search interval in half. The idea of binary search is to use the information that the array is sorted and reduce the time complexity to O(log N). Binary Search AlgorithmConditions to apply Binary Searc
15 min read
Insertion Sort Algorithm Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into its correct position in a sorted portion of the list. It is like sorting playing cards in your hands. You split the cards into two groups: the sorted cards and the unsorted cards. T
9 min read
Dijkstra's Algorithm to find Shortest Paths from a Source to all Given a weighted undirected graph represented as an edge list and a source vertex src, find the shortest path distances from the source vertex to all other vertices in the graph. The graph contains V vertices, numbered from 0 to V - 1.Note: The given graph does not contain any negative edge. Example
12 min read