Recently I was studying bitwise operators and bit-manipulation algorithms and I found out an algorithm to add two binary numbers.
Pseudocode is as follows:
function add(A, B):
while B is greater than 0:
U = A XOR B, where XOR = Bitwise XOR of A and B.
V = A AND B, where AND = Bitwise AND of A and B.
A = U
B = V * 2, this instruction is equivalent to V << 1
return A
A
and B
are bit strings of length N
and M
where the limits for N
and M
are: 0 < N <= 10^5 and 0 < M <= 10^5. Both the bit strings can be of different lengths.
I was wondering about finding out how many times the while
loop runs before the B = 0
.
Problem Statement:
How many times does the
while
loop run beforeB = 0
?
I wrote an algorithm in C which takes two strings A
and B
as input. If the length of both the strings is not same then first make them same, then perform bitwise XOR and bitwise AND and bitwise left-shift to implement multiplication by 2
as described in the above algorithm.
Source code is as follows:
#include<stdio.h>
#include<stdlib.h>
#include<inttypes.h>
#include<string.h>
#include<stdbool.h>
#include<assert.h>
#define STRING_LENGTH_MAX 100001
static const uint64_t binary_to_decimal(char[*]);
static const uint64_t binary_exponentiation(uint64_t,uint64_t);
static const uint32_t binary_addition_integers(uint64_t,uint64_t);
static char* make_string_equal(char[*],uint32_t);
static const bool check_all_zeroes(char[*]);
static const uint32_t binary_addition_strings(char[*],char[*]);
static char* bitwise_xor_strings(char[*],char[*]);
static char* bitwise_and_strings(char[*],char[*]);
static char* bitwise_left_shift_by_one_strings(char[*]);
int main(void) {
int32_t test;
printf("Enter the number of test-cases\n");
scanf("%"SCNd32, &test);
assert(test > 0 && test < 100001);
while(test--) {
char *binary_string_A = calloc(STRING_LENGTH_MAX,sizeof(char));
char *binary_string_B = calloc(STRING_LENGTH_MAX,sizeof(char));
printf("Enter the bit-strings A and B\n");
scanf("%s%s", binary_string_A,binary_string_B);
uint32_t len_binary_string_A = strlen(binary_string_A);
uint32_t len_binary_string_B = strlen(binary_string_B);
uint32_t loop_count = 0;
if(len_binary_string_A < 63 && len_binary_string_B < 63) {
uint64_t a = binary_to_decimal(binary_string_A);
uint64_t b = binary_to_decimal(binary_string_B);
if(!b) {
loop_count = 0;
} else if(!a) {
loop_count = 1;
} else if(a == b) {
loop_count = 2;
} else {
loop_count = binary_addition_integers(a,b);
}
} else {
if(len_binary_string_A < len_binary_string_B) {
binary_string_A = make_string_equal(binary_string_A,len_binary_string_B);
if(!binary_string_A) {
fprintf(stderr,"Line number: %u: Not able to allocate the memory to *binary_string_A\n", __LINE__);
return EXIT_FAILURE;
}
} else {
binary_string_B = make_string_equal(binary_string_B,len_binary_string_A);
if(!binary_string_B) {
fprintf(stderr,"Line number: %u: Not able to allocate memory to *binary_string_B\n", __LINE__);
return EXIT_FAILURE;
}
}
if(check_all_zeroes(binary_string_B)) {
loop_count = 0;
} else if(check_all_zeroes(binary_string_A)) {
loop_count = 1;
} else if(!strncmp(binary_string_A,binary_string_B,strlen(binary_string_A))) {
loop_count = 2;
} else {
loop_count = binary_addition_strings(binary_string_A,binary_string_B);
}
}
free(binary_string_A);
free(binary_string_B);
printf("Loop-Runs: %"PRIu32"\n", loop_count);
}
return EXIT_SUCCESS;
}
static const uint64_t binary_to_decimal(char binary_string[]) {
uint32_t string_len = strlen(binary_string);
uint64_t decimal_value = 0;
for(int8_t i = (string_len - 1), power = 0; i >= 0; --i,++power) {
if(!(binary_string[i] == '0')) {
if(i == (string_len - 1)) {
decimal_value += binary_string[i] - '0';
} else {
decimal_value += (binary_string[i] - '0') * binary_exponentiation(2,power);
}
}
}
return decimal_value;
}
static const uint64_t binary_exponentiation(uint64_t base,uint64_t expo) {
uint64_t result = 1;
if(!expo) {
return result;
} else if(expo == 1) {
return base;
} else {
while(expo) {
if(expo & 1) {
result *= base;
}
base *= base;
expo >>= 1;
}
}
return result;
}
static const uint32_t binary_addition_integers(uint64_t a,uint64_t b) {
uint32_t loop_count = 0;
while(b) {
++loop_count;
uint64_t x = a ^ b;
uint64_t y = a & b;
a = x;
b = y << 1;
}
return loop_count;
}
static char* make_string_equal(char binary_string[],uint32_t target_len) {
uint32_t prev_len = strlen(binary_string);
binary_string = realloc(binary_string,(sizeof(char) * (target_len + 1)));
if(binary_string) {
for(int32_t i = (prev_len - 1), j = (target_len - 1); i >= 0; --i,--j) {
binary_string[j] = binary_string[i];
}
uint32_t limit = target_len - prev_len;
for(uint32_t i = 0; i < limit; ++i) {
binary_string[i] = '0';
}
binary_string[target_len] = '\0';
} else {
fprintf(stderr,"Line number: %u: Not able to re-allocate %lu bytes of memory\n", __LINE__,(sizeof(char) * target_len));
return NULL;
}
return binary_string;
}
static const bool check_all_zeroes(char binary_string[]) {
bool is_all_zeroes = true;
for(uint32_t i = 0; binary_string[i] != '\0'; ++i) {
if(binary_string[i] != '0') {
is_all_zeroes = false;
break;
}
}
return is_all_zeroes;
}
static const uint32_t binary_addition_strings(char *binary_string_A,char *binary_string_B) {
uint32_t loop_count = 0;
while(!check_all_zeroes(binary_string_B)) {
++loop_count;
char *binary_string_X = bitwise_xor_strings(binary_string_A,binary_string_B);
char *binary_string_Y = bitwise_and_strings(binary_string_A,binary_string_B);
binary_string_A = binary_string_X;
binary_string_B = bitwise_left_shift_by_one_strings(binary_string_Y);
binary_string_A = make_string_equal(binary_string_A,strlen(binary_string_B));
}
return loop_count;
}
static char* bitwise_xor_strings(char binary_string_A[],char binary_string_B[]) {
uint32_t xor_result_len = strlen(binary_string_A) + 1;
char *xor_result = calloc(xor_result_len,sizeof(char));
if(xor_result) {
for(int32_t i = (xor_result_len - 2); i >= 0; --i) {
xor_result[i] = ((binary_string_A[i] - '0') ^ (binary_string_B[i] - '0')) + '0';
}
xor_result[xor_result_len - 1] = '\0';
} else {
fprintf(stderr,"Line number: %u: Not able to allocate %lu bytes of memory to *xor_result\n", __LINE__,(sizeof(char) * xor_result_len));
xor_result = NULL;
}
return xor_result;
}
static char* bitwise_and_strings(char binary_string_A[],char binary_string_B[]) {
uint32_t and_result_len = strlen(binary_string_A) + 1;
char *and_result = calloc(and_result_len,sizeof(char));
if(and_result) {
for(int32_t i = (and_result_len - 2); i >= 0; --i) {
and_result[i] = ((binary_string_A[i] - '0') & (binary_string_B[i] - '0')) + '0';
}
and_result[and_result_len - 1] = '\0';
} else {
fprintf(stderr,"Line number: %u: Not able to allocate %lu bytes of memory to *and_result\n", __LINE__,(sizeof(char) * and_result_len));
and_result = NULL;
}
return and_result;
}
static char* bitwise_left_shift_by_one_strings(char binary_string[]) {
uint32_t bitwise_left_shift_by_one_result_len = strlen(binary_string) + 2;
char *bitwise_left_shift_by_one_result = realloc(binary_string,(sizeof(char) * bitwise_left_shift_by_one_result_len));
if(bitwise_left_shift_by_one_result) {
bitwise_left_shift_by_one_result[bitwise_left_shift_by_one_result_len - 2] = '0';
bitwise_left_shift_by_one_result[bitwise_left_shift_by_one_result_len - 1] = '\0';
} else {
fprintf(stderr,"Line number: %u: Not able to re-allocate memory block to *bitwise_left_shift_by_one_result\n", __LINE__);
bitwise_left_shift_by_one_result = NULL;
}
return bitwise_left_shift_by_one_result;
}
Program Output:
Enter the number of test-cases
4
Enter the bit-strings A and B
100010
0
Loop-Runs: 0
Enter the bit-strings A and B
0
100010
Loop-Runs: 1
Enter the bit-strings A and B
11100
1010
Loop-Runs: 3
Enter the bit-strings A and B
1111111111111111111111111111111111111111111111111111111111111111111
11111111111111111111111111111111111111111111111111111111111
Loop-Runs: 10
As you can see the algorithm which I come up with does execute all the steps in order to find out the answer i.e. loop count, but as I am only interested in how many times the loop runs and if there are any other way of finding that value.
How can I optimize the code if the number of bits in the binary numbers is > 500?
What I did was if the number of bits in the given binary numbers A
and B
<= 63, I find their decimal equivalent and use the bitwise operators defined in C, but as you know if the length of the string becomes > 64 its decimal equivalent cannot be stored in a normal 64-bit unsigned integer in C/C++. So I just implemented the above algorithm on bit strings without finding their decimal equivalent but the algorithm which I designed is not fast enough if n > 500 so, can you tell how can I optimize my code.
However, I can use the following Python code to accomplish the task:
def binary_addition(a,b):
loop_count = 0
while b != 0:
loop_count += 1
x = a ^ b
y = a & b
a = x
b = y << 1
return loop_count
def main():
test = int(input())
for t in range(test):
a = int('0b' + input().rstrip(),base = 2)
b = int('0b' + input().rstrip(),base = 2)
if not b:
print("0")
elif not a:
print("1")
elif a == b:
print("2")
else:
print(binary_addition(a,b))
if __name__ == "__main__":
main()
while
loop runs is equal to number of times carry is generated? In the question I need to find out how many times thewhile
loop runs, and the above implementation takes(O(n) for XOR + O(n) for AND + O(n) for Left shift by one) * Number of times while loop executes
in worst-case. Can I do better? \$\endgroup\$