Adding 10-bit binary numbers - c

I need to 2 strings (10-bit binary numbers). I's easy when i'm adding 1+0 0+0
But how I can modify this, to situation when i'll need to make 11-bit
like
1010101010+1111111111=11010101001
i = MAX+1;
while( i!=0) {
if ((str1[i - 1] == str2[i - 1]) && (str1[i - 1] == '0' )) {
str3[i] = '0';
}
else if ((str1[i - 1] != str2[i - 1])) {
str3[i] = '1';
}
else if ((str1[i - 1] == str2[i - 1]) && (str1[i - 1] == '1')) {
str3[i] = '0';
}
i--;
}
MAX=10

It's not clear exactly what the requirements are, but I wrote a function that takes three strings, figures out their lengths using strlen, and then sets the third string equal to the sum of the first two. Here is a program that adds the two 10-bit numbers you gave and prints the expected result of "11010101001".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void binary_string_add(const char * a, const char * b, char * sum)
{
size_t alen = strlen(a);
size_t blen = strlen(b);
size_t sumlen = strlen(sum);
int carry = 0;
for (size_t i = 0; i < sumlen; i++)
{
if (i < alen) { carry += a[alen - 1 - i] == '1'; }
if (i < blen) { carry += b[blen - 1 - i] == '1'; }
sum[sumlen - 1 - i] = '0' + (carry & 1);
carry >>= 1;
}
}
int main()
{
char str1[] = "1010101010";
char str2[] = "1111111111";
char str3[] = "xxxxxxxxxxx";
binary_string_add(str1, str2, str3);
printf("Sum: %s\n", str3);
}
By the way, each iteration of the loop actually implements a 1-bit adder.
Update: If you want an easier interface that allocates an output string for you of the appropriate length and returns it, this works:
char * binary_string_add2(const char * a, const char * b)
{
size_t alen = strlen(a);
size_t blen = strlen(b);
size_t sumlen = (alen > blen ? alen : blen) + 1;
char * sum = malloc(sumlen + 1);
if (sum == NULL) { /** Add error handling here. **/ }
memset(sum, 'x', sumlen);
sum[sumlen] = 0;
binary_string_add(a, b, sum);
return sum;
}

#define ADDCHAR(c1,c2) (((c1) == '1') + ((c2) == '1'))
char *add(char *res, const char *n1, const char *n2)
{
size_t ln1 = strlen(n1);
size_t ln2 = strlen(n2);
char *resend = res + (ln2 > ln1 ? ln2 + 2 : ln1 + 2);
unsigned rem = 0;
*resend-- = 0;
while(ln1 || ln2)
{
unsigned pres = rem + ADDCHAR(ln1 ? n1[ln1 - 1] : '0', ln2 ? n2[ln2 - 1] : '0');
*resend-- = '0' + (pres & 1);
rem = pres >> 1;
ln1 -= !!ln1;
ln2 -= !!ln2;
}
if(rem) *resend-- = '0' + rem;
while(resend >= res) *resend-- = ' ';
return res;
}

int a = 0 ;
for(int i = 0 ; i < 10 ; i++){
str3[i] = str1[i] + str2[i] + a ;
if(str3[i] > 1){
str3[i] %= 2 ;
a = 1 ;
}
else{
a = 0 ;
}
}

Related

int to string conversion not working properly

I'm trying to create a function that converts an integer into a string, basically what have I done is the following functions: when we get the numbers from the conversion they are reversed so I need a reverse function to make them in the right way. The intostring uses (I think? I got it from some website) the ascii table to convert the number into the string desired.
The problem is: when I enter the 2-digit number they are reversed the wrong way (I guess my reverse function doesn't work that well) and after a certain number of digit the conversion it's not any more accurate.
reverse function:
char reverse(char *stringa) {
int len = strlen(stringa) - 1;
for(int i = 0; i < len / 2; i++) {
char tmp = stringa[i];
stringa[i] = stringa[len - i];
stringa[len - i] = tmp;
}
}
intostring function:
void intostring(int num, char *str) {
int i = 0;
while (num != 0) {
int rem = num % 10;
str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
num = num / 10;
}
str[i] = '\0';
reverse(str);
}
The condition i<len/2 in the reverse function is wrong.
For example, if the string is 2-digit long, len will be 1 and len/2 will be 0. Therefore, no swap will occure while the two characters should be swapped.
the condition should be i<=len/2 or i<len-i.
/*
It works clearly . Checked.
*/
void reverse(char source[],char destination[]) {
int x,i;
//start from last char
i = i=(strlen(source)-1
for (x=0;x<strlen(source);x++){
//Insert char at i in source to x in destination
destination[x]=source[i];
destination[x]='\0';
i--;
}
}
There are multiple problems:
the reverse function fails for an empty string. You should not subtract 1 from the length, but adjust the offset inside the loop.
reverse is defined to return a char but does not return anything. Make it return a char * and return stringa.
intostring produces an empty string for num <= 0. You should loop while num > 9 and add the final digit after the loop.
intostring converts the digit into a character for bases up to 36 (assuming ASCII). This is unnecessarily complex since the base is 10. Use a simpler conversion: str[i++] = '0' + rem;
it may be useful for intostring to return a pointer to the destination array.
Here is a modified version:
#include <string.h>
char *reverse(char *str) {
size_t len = strlen(str);
for (size_t i = 0; i < len / 2; i++) {
char tmp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = tmp;
}
return str;
}
char *intostring(int num, char *str) {
int i = 0;
if (num >= 0) {
while (num > 9) {
str[i++] = '0' + num % 10;
num = num / 10;
}
str[i++] = '0' + num;
} else {
while (num < -9) {
str[i++] = '0' - num % 10;
num = num / 10;
}
str[i++] = '0' - num;
str[i++] = '-';
}
str[i] = '\0';
return reverse(str);
}
Here is an alternative approach for the reverse function using 2 index variables:
#include <string.h>
char *reverse(char *str) {
size_t i = 0;
size_t j = strlen(str);
while (j --> i) {
char c = str[j];
str[j] = str[i];
str[i++] = c;
}
return str;
}
The reverse function condition is worng.
If the integer in 32 then the string will be
s[0] = '2', s[1] = '3', s[2] = '\0' before string reversal.
so in reverse function the following swap operation has to be applied as
if number = 32 then len = 2
i = 0 then len - i - 1 = 1
so 0 and 1 will be swaped.
void reverse(char *stringa){
int len = strlen(stringa);
for(int i = 0; i < len / 2; i++){
char tmp = stringa[i];
stringa[i] = stringa[len - i - 1];
stringa[len - i - 1] = tmp;
}
}
void intostring(int num, char *str)
{
int i = 0;
if(num == 0){
str[i++] = '0';
str[i] = '\0';
}
else if(num > 0){
while(num != 0){
int rem = num % 10;
str[i++] = '0' + rem;
num = num/10;
}
str[i] = '\0';
}
else{
while(num != 0){
int rem = num % 10;
/*
(-5/2) => -2
-2 * 2 => -4
so a%b => -1
(5/-2) => -2
-2 * -2 => 4
so a%b => 1
*/
rem = abs(rem); // as the rem value is negative
str[i++] = '0' + rem;
num = num/10;
}
str[i++] = '-';
str[i] = '\0';
}
reverse(str);
}
Your reverse function is wrong. You can make it correct (and readable) like below:
void reverse(char *stringa) {
int i = 0; //Forwarding moving index
int j = strlen(stringa) - 1; // the end index
int tmp; // Edited to get the code compiled
for (; i < j; i++, j--) {
tmp = stringa[i];
stringa[i] = stringa[j];
stringa[j] = tmp;
}
}

Is binary to decimal conversion rounded? how?

Got to transform a binary number to decimal for recoding printf (no lib or functions allowed except malloc and write). i'm doing my calculs on char *, so it can't overflow. But when i hit a certain size, my result differ from a online binary converter, and i noticed that the binary converter keep always only 20 digits.
for exemple :
binary : 1.11111111111111111111111111
binary converter = 1.99999998509883880615,
my o converter == 1.99799896499882880605234375,
I guess the online converter keep the result rounded in an unsigned long long, but i don't understand how this rounding is calculated.
Do you have any clues?
Here is my code:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
char *ft_binary_pow(char *tmp, int i)
{
int j;
int div;
int remnant;
j = 0;
remnant = 0;
tmp[0] = '1';
tmp.sign = 0;
while (i > 0)
{
while (isdigit(tmp[j]) || remnant != 0)
{
if (tmp[j])
div = ((tmp[j] - '0') * 10) / 2;
else
div = 0;
tmp[j] = ((div / 10) + remnant) + '0';
remnant = div % 10;
j++;
}
j = 0;
i--;
}
return (tmp);
}
char *ft_add_tmp(char *ret, char *tmp)
{
int i;
int j;
int add;
int remnant;
i = strlen(tmp);
add = 0;
remnant = 0;
while (--i >= 0)
{
if (!ret[i])
add = tmp[i] - '0';
else
add = (ret[i] - '0') + (tmp[i] - '0');
if ((add % 10 + remnant) < 10)
ret[i] = (add % 10 + remnant) + '0';
else
ret[i] = '0';
remnant = add / 10 ? 1 : 0;
}
return (ret);
}
int main(void)
{
int i;
char *lol = "11111111111111111111111111";
char *ret;
char *tmp;
if (!(ret = (char *)calloc(340, sizeof(char))))
return (0);
i = 0;
ret[0] = '1';
while (lol[i])
{
if (lol[i] == '1')
{
if (!(tmp = (char *)calloc(50, sizeof(char))))
return (0);
tmp = ft_binary_pow(tmp, i + 1);
ret = ft_add_tmp(ret, tmp);
free(tmp);
}
i++;
}
printf("ret = %s\n", ret);
return (0);
}
Edited for more readable code
Thanks for your time!
Code fails even with lol = "111111111".
Code fails in ft_add_tmp() to handle a carry (overflow) into the next most significant digit.
else {
ret.decimal[i] = '0';
// add something like this and then also prorogate carry as needed to higher digits
ret.decimal[i-1]++;
}
Suggested correction and simplification:
char* ft_add_tmp(char *ret, const char *tmp) {
size_t i = strlen(tmp);
unsigned carry = 0;
while (i-- > 0) {
unsigned sum = ret[i] ? ret[i] - '0' : 0;
sum += tmp[i] - '0' + carry;
ret[i] = sum % 10 + '0';
carry = sum / 10;
}
assert(carry == 0);
return (ret);
}

Multiplying numbers as strings (corrupted size vs. prev_size)

I am doing a challenge in code war and I must multiply two numbers given as a string and return the result as a string.
here you can find the challenge :
https://www.codewars.com/kata/multiplying-numbers-as-strings/train/c
so I've manged to pass all the Sample Tests that includes multiplying big numbers with 25+ digits as you can see in the site.
but when I click in Attempt button I get this error :
*** Error in `./test': corrupted size vs. prev_size: 0x0000000001ec9918 ***
======= Backtrace: =========
you can copy my code below to see the full error text.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void zero(char *str,int len) //this function fill my *str with 0s;
{
int i = 0;
while (i <= len)
{
str[i] = '0';
i++;
}
}
//and this function below do multiplication that we learned when we were kids
//you can do printf to see how this function work
char *multiply(char *a, char *b) {
int l1 = strlen(a);
int l2 = strlen(b);
int index = l1 + l2;
int new_i = index;
int i = index;
char *total = malloc(index);
char *result = malloc(index);
zero(total,index);
int k = 0;
int add = 0;
int keep;
while (l2 > 0)
{
l1 = strlen(a);
k = 0;
while (l1 > 0)
{
keep = total[i] - '0';
total[i] = ((((total[i] - '0') + (( (b[l2 - 1] - '0') * (a[l1 - 1] - '0') + k ) % 10)) % 10) ) + '0';
add = ( ((keep) + (( (b[l2 - 1] - '0') * (a[l1 - 1] - '0') + k ) % 10)) / 10);
k = (((b[l2 - 1] - '0') * (a[l1 - 1] - '0')) + k) / 10;
if (k > 0 && l1 == 1)
total[i - 1] = k + '0';
if (add > 0)
{
if (total[i - 1] != '9')
total[i - 1] = ((total[i - 1] - '0') + add) + '0';
else
{
total[i - 1] = '0';
total[i - 2] = total[i - 2] + 1;
}
}
i--;
l1--;
}
i = index - 1;
index--;
l2--;
}
i = 0;
while (total[i] == '0') //to avoid coping 0s into result
i++;
if (total[i] == '\0') //in case of (0 * any positive number)
i--;
index = 0;
while (i <= new_i)
{
result[index] = total[i];
i++;
index++;
}
result[index] = '\0';
return result;
}
I don't know where is the problem is it malloc or something else?
Your issue looks like an edge case and I am commenting on "Corrupted size..." rather than actual logic of multiplication.
Within multiply function, I observed one issue. You are calculating an expected number of characters in final answer as "index = l1 + l2". However, when you are doing a "malloc", you must allocate "index + 1" bytes, so that you can store "\0" at the end even if your inputs generates largest possible answer.
Best edge test case will be to use large number with "9999..." as both inputs.

Big number adding function crashes program

I wrote an adding function for very large numbers and when it gets called, the program crashes. I am assuming that it has to do with the carrying. Here is the code:
char * bigadd(char a[], char b[]){
int i, temp;
char useadd[MAX];
char usea = strrev(a);
char useb = strrev(b);
char ret[strlen(useadd)];
char *pa, *pb, *padd;
padd = &useadd;
pa = &usea;
pb = &useb;
while(*pa != '\0' && *pb != '\0'){
if(atoi(*pa) + atoi(*pb) + temp > 9){
if(temp + atoi(*pa) + atoi(*pb) < 20){
temp = 1;
*padd = atoi(*pa) + atoi(*pb) - 10;
}
else{
temp = 2;
*padd = atoi(*pa) + atoi(*pb) - 20;
}
}
else{
*padd = atoi(*pa) + atoi(*pb);
temp = 0;
}
++padd;
++pa;
++pb;
}
i = 0;
while(useadd[i] != '\0'){
ret[i] = useadd[i];
++i;
}
return strrev(ret);
}
Thanks for all of the help. I'm sorry if this ends up being a stupid mistake.
Your program has so many problems!
char * bigadd(char a[], char b[]){
int i, temp;
char useadd[MAX]; // MAX might not be large enough
char usea = strrev(a); // should not modify argument a
// strrev() is not standard C undefined on my system
// if defined, it returns char*, not char
char useb = strrev(b); // see above
char ret[strlen(useadd)]; // useadd is uninitialized -> undefined behaviour
char *pa, *pb, *padd;
padd = &useadd; // & is incorrect, useadd is an array
pa = &usea; // same as above
pb = &useb; // idem
// forgot to initialize temp to 0
while(*pa != '\0' && *pb != '\0'){
if(atoi(*pa) + atoi(*pb) + temp > 9){ // atoi converts a string, not a char
if(temp + atoi(*pa) + atoi(*pb) < 20){ // same... sum cannot exceed 19
temp = 1;
*padd = atoi(*pa) + atoi(*pb) - 10; // atoi...
}
else{ // never reached
temp = 2;
*padd = atoi(*pa) + atoi(*pb) - 20; // atoi...
}
}
else{
*padd = atoi(*pa) + atoi(*pb); // same atoi problem
temp = 0;
}
++padd;
++pa;
++pb;
}
// if a and b have a different size, loop fails to copy digits and propagate carry
// if temp is not 0, you forget to add the leading '1'
// trailing '\0' is not set
i = 0;
while(useadd[i] != '\0'){ // undefined behaviour, '\0' not set.
ret[i] = useadd[i];
++i;
}
// forgot to set the final '\0'
// why not use strcpy?
return strrev(ret); // strrev not defined.
// if defined, returning ret, address of local array
}
Here is a complete rewrite:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *bigadd(const char a[], const char b[]) {
int ia = strlen(a);
int ib = strlen(b);
int size = 2 + (ia > ib ? ia : ib), ic = size - 1, temp = 0;
char *res = malloc(size);
if (res) {
res[--ic] = '\0';
while (ia + ib) {
if (ia > 0) temp += a[--ia] - '0';
if (ib > 0) temp += b[--ib] - '0';
res[--ic] = '0' + temp % 10;
temp /= 10;
}
if (temp) {
memmove(res + 1, res, size - 1);
*res = '1';
}
}
return res;
}
int main(int argc, char *argv[]) {
for (int i = 1; i + 1 < argc; i += 2) {
char *res = bigadd(argv[i], argv[i+1]);
printf("%s + %s = %s\n", argv[i], argv[i+1], res);
free(res);
}
}

C - Adding the numbers in 2 strings together if a different length

If I had two strings:
a = "1234"
b = "4321"
I could add the two numbers together like this:
for(i=0; i<width-1; i++){
sum = (a[width-2-i]-48) + (b[width-2-i]-48) + carry;
carry = 0;
if(sum > 9){
carry = 1;
sum-=10;
}
answer[i] = sum+48;
}
if(carry) answer[i++] = carry+48;
answer[i]= 0;
And then reverse it (width is equal to strlen(a)).
How could I do the same thing if the following?
a = "12345"
b = "4321"
Would I need to reallocate memory? Or what?
(BTW - the problem I'm trying to solve is using many numbers all with 50 digits, so strtoul or strtoull is out of the question as I understand. Here's my code so far.)
int getcharval(const char *s, int idx) {
if (idx < strlen(s))
return s[strlen(s) - idx - 1] - 48;
return 0;
}
void add() {
const char *a = "1234";
const char *b = "13210";
char answer[256];
int i, wa=strlen(a), wb=strlen(b), width, sum, carry;
width = wa > wb ? wa : wb;
for(i=0; i<width; i++){
char ca = getcharval(a, i);
char cb = getcharval(b, i);
printf("%d %d\n", ca, cb);
sum = ca + cb + carry;
carry = 0;
if(sum > 9){
carry = 1;
sum-=10;
}
answer[i] = sum+48;
}
if(carry) answer[i++] = carry+48;
answer[i]= 0;
for (i = 0; i < strlen(answer) / 2; i++) {
char t = answer[i];
answer[i] = answer[strlen(answer) - i - 1];
answer[strlen(answer) - i - 1] = t;
}
printf("%s\n", answer);
}
If you insist on using the "elementary school addition", find the length of both strings, advance to their ends, and then move back until the shorter string's length is exhausted. Then continue moving in only the longer string, assuming that the remaining digits of the shorter string are zeros:
12345
04321
You need to move all the way to the beginning of the longer string, and process the carry there. Note that you need to allocate a new result anyway, because adding two N-digit numbers may result in a N+1-digit number due to the carry.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define c2d(c) (c-'0')
#define d2c(c) (c+'0')
char* add(const char *a, const char *b, char *ans){
int alen, blen;
int i, carry=0;
char *wk;
char *awk=strdup(a);
char *bwk=strdup(b);
alen=strlen(strrev(awk));
blen=strlen(strrev(bwk));
if(alen<blen){
alen ^= blen;blen ^= alen;alen ^= blen;//swap
wk = awk ; awk = bwk ; bwk = wk;
}
ans[alen+1]=ans[alen]='\0';
for(i=0;i<alen;++i){
int sum = c2d(awk[i])+(i<blen ? c2d(bwk[i]): 0)+carry;
ans[i] = d2c(sum % 10);
carry = sum / 10;
}
if(carry){
ans[i++]='1';
}
free(awk);
free(bwk);
return strrev(ans);
}
int main(){
const char *a="12345";
const char *b="4321";
char ans[6];
printf("{%s}+{%s}={%s}\n", a, b, add(a,b, ans));
return 0;
}
cited from C - Adding the numbers in 2 strings together if a different length
answer, I write a more readable codeļ¼š
void str_reverse(char *beg, char *end){
if(!beg || !end)return;
char cTmp;
while(beg < end){
cTmp = *beg;
*beg++ = *end;
*end-- = cTmp;
}
}
#define c2d(c) (c - '0')
#define d2c(d) (d + '0')
void str_add(const char* s1, const char* s2, char* s_ret){
int s1_len = strlen(s1);
int s2_len = strlen(s2);
int max_len = s1_len;
int min_len = s2_len;
const char *ps_max = s1;
const char *ps_min = s2;
if(s2_len > s1_len){
ps_min = s1;min_len = s1_len;
ps_max = s2;max_len = s2_len;
}
int carry = 0;
int i, j = 0;
for (i = max_len - 1; i >= 0; --i) {
// this wrong-prone
int idx = (i - max_len + min_len) >=0 ? (i - max_len + min_len) : -1;
int sum = c2d(ps_max[i]) + (idx >=0 ? c2d(ps_min[idx]) : 0) + carry;
carry = sum / 10;
sum = sum % 10;
s_ret[j++] = d2c(sum);
}
if(carry)s_ret[j] = '1';
str_reverse(s_ret, s_ret + strlen(s_ret) - 1);
}
test code as below:
void test_str_str_add(){
char s1[] = "123";
char s2[] = "456";
char s3[10] = {'\0'};
str_add(s1, s2, s3);
std::cout<<s3<<std::endl;
char s4[] = "456789";
char s5[10] = {'\0'};
str_add(s1, s4, s5);
std::cout<<s5<<std::endl;
char s7[] = "99999";
char s8[] = "21";
char s9[10] = {'\0'};
str_add(s7, s8, s9);
std::cout<<s9<<std::endl;
}
output:
579
456912
100020
int num(char x,int len){
if(len <0)
return 0;
return ((x=='1') ? 1 : (x=='2') ? 2 : (x=='3') ? 3 : (x=='4') ? 4 : (x=='5') ? 5 : (x=='6') ? 6 : (x=='7') ? 7 : (x=='8') ? 8 : 9);
}
int main(){
int result[100];
int i=0;
char num1[] = "123456789123456789";
char num2[] = "1234567811111111111111111111";
int carry = 0;
int l1= strlen(num1)-1;
int l2 = strlen(num2)-1;
int result1;
while(1){
if(l1 < 0 && l2 <0 && carry == 0)
break;
result1 = num(num1[l1],l1) + num(num2[l2],l2);
l1--;
l2--;
if(carry>0){
result1 +=carry;
carry = 0;
}
carry = result1 / 10;
result[i] = (result1 % 10);
i++;
}
i--;
printf("\n");
while(i>=0){
printf("%d",result[i]);
i--;
}
}

Resources