Function to add two binary numbers in C











up vote
3
down vote

favorite












I tried to write a function bin_add() in C to add two positive binary numbers represented as zero terminated strings:



#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

char* bin_add(char const *a, char const *b)
{
char const *inp = { a, b };
size_t ll = { strlen(a), strlen(b) };
size_t pp = { gpp(a), gpp(b) };
size_t OO[2], off[2];

for (size_t i = 0; i < 2; ++i) {
OO[i] = pp[i] ? pp[i] - 1 : ll[i];
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}

for (size_t i = 0; i < 2; ++i)
off[i] = OO[i] < OO[!i] ? OO[!i] - OO[i] : 0;

size_t ML = MAX(OO[0], OO[1]) + MAX(pp[0], pp[1]) + (!!pp[0] || !!pp[1]);
char *Ol = calloc(ML + 2, 1);
if(!Ol) return Ol;

char ops[2];
int xc = 0;
size_t lO = ML;
unsigned cc[2] = { 0 };
for (size_t i = ML; i; --i) {
bool pt = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= ll[l] + off[l] && i - off[l] - 1
< ll[l] ? inp[l][i - off[l] - 1] : '0';
if (ops[l] == '.') {
if (cc[l]) {
free(Ol);
return NULL;
}
pt = true;
++cc[l];
}
ops[l] -= '0';
}
if (pt) {
Ol[i] = '.';
continue;
}
if ((Ol[i] = ops[0] + ops[1] + xc) > 1) {
Ol[i] = 0;
xc = 1;
}
else xc = 0;
lO = (Ol[i] += '0') == '1' ? i : lO;
}
if((Ol[0] = '0' + xc) == '1') return Ol;
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];

return Ol;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
char *c = bin_add(a, b);
if (!c && errno == ENOMEM) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}
else if (!c) {
fputs("Input error :(nn", stderr);
goto clear;
}

char* O = { a, b, c };
size_t lO[3], Ol = 0;
for (size_t i = 0; i < 3; ++i) {
lO[i] = gpp(O[i]);
lO[i] = lO[i] ? lO[i] : strlen(i[O]) + 1;
Ol = lO[i] > Ol ? lO[i] : Ol;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < Ol - lO[i]; ++l, putchar(' '));
puts(O[i]);
}
putchar('n');

free(c);
clear :{ int c; while ((c = getchar()) != 'n' && c != EOF); }
}
}


The main() is just included to provide input to the function and pretty-print its results. Every C99 compliant compiler should be able to compile above code.



Do you see any flaws in my code and anything that could be improved?










share|improve this question
























  • "A revised version of the code will be posted in an update to this question." Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Sᴀᴍ Onᴇᴌᴀ
    Nov 30 at 16:12










  • @SᴀᴍOnᴇᴌᴀ I'll move the reply to an answer.
    – Swordfish
    Nov 30 at 16:26















up vote
3
down vote

favorite












I tried to write a function bin_add() in C to add two positive binary numbers represented as zero terminated strings:



#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

char* bin_add(char const *a, char const *b)
{
char const *inp = { a, b };
size_t ll = { strlen(a), strlen(b) };
size_t pp = { gpp(a), gpp(b) };
size_t OO[2], off[2];

for (size_t i = 0; i < 2; ++i) {
OO[i] = pp[i] ? pp[i] - 1 : ll[i];
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}

for (size_t i = 0; i < 2; ++i)
off[i] = OO[i] < OO[!i] ? OO[!i] - OO[i] : 0;

size_t ML = MAX(OO[0], OO[1]) + MAX(pp[0], pp[1]) + (!!pp[0] || !!pp[1]);
char *Ol = calloc(ML + 2, 1);
if(!Ol) return Ol;

char ops[2];
int xc = 0;
size_t lO = ML;
unsigned cc[2] = { 0 };
for (size_t i = ML; i; --i) {
bool pt = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= ll[l] + off[l] && i - off[l] - 1
< ll[l] ? inp[l][i - off[l] - 1] : '0';
if (ops[l] == '.') {
if (cc[l]) {
free(Ol);
return NULL;
}
pt = true;
++cc[l];
}
ops[l] -= '0';
}
if (pt) {
Ol[i] = '.';
continue;
}
if ((Ol[i] = ops[0] + ops[1] + xc) > 1) {
Ol[i] = 0;
xc = 1;
}
else xc = 0;
lO = (Ol[i] += '0') == '1' ? i : lO;
}
if((Ol[0] = '0' + xc) == '1') return Ol;
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];

return Ol;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
char *c = bin_add(a, b);
if (!c && errno == ENOMEM) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}
else if (!c) {
fputs("Input error :(nn", stderr);
goto clear;
}

char* O = { a, b, c };
size_t lO[3], Ol = 0;
for (size_t i = 0; i < 3; ++i) {
lO[i] = gpp(O[i]);
lO[i] = lO[i] ? lO[i] : strlen(i[O]) + 1;
Ol = lO[i] > Ol ? lO[i] : Ol;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < Ol - lO[i]; ++l, putchar(' '));
puts(O[i]);
}
putchar('n');

free(c);
clear :{ int c; while ((c = getchar()) != 'n' && c != EOF); }
}
}


The main() is just included to provide input to the function and pretty-print its results. Every C99 compliant compiler should be able to compile above code.



Do you see any flaws in my code and anything that could be improved?










share|improve this question
























  • "A revised version of the code will be posted in an update to this question." Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Sᴀᴍ Onᴇᴌᴀ
    Nov 30 at 16:12










  • @SᴀᴍOnᴇᴌᴀ I'll move the reply to an answer.
    – Swordfish
    Nov 30 at 16:26













up vote
3
down vote

favorite









up vote
3
down vote

favorite











I tried to write a function bin_add() in C to add two positive binary numbers represented as zero terminated strings:



#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

char* bin_add(char const *a, char const *b)
{
char const *inp = { a, b };
size_t ll = { strlen(a), strlen(b) };
size_t pp = { gpp(a), gpp(b) };
size_t OO[2], off[2];

for (size_t i = 0; i < 2; ++i) {
OO[i] = pp[i] ? pp[i] - 1 : ll[i];
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}

for (size_t i = 0; i < 2; ++i)
off[i] = OO[i] < OO[!i] ? OO[!i] - OO[i] : 0;

size_t ML = MAX(OO[0], OO[1]) + MAX(pp[0], pp[1]) + (!!pp[0] || !!pp[1]);
char *Ol = calloc(ML + 2, 1);
if(!Ol) return Ol;

char ops[2];
int xc = 0;
size_t lO = ML;
unsigned cc[2] = { 0 };
for (size_t i = ML; i; --i) {
bool pt = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= ll[l] + off[l] && i - off[l] - 1
< ll[l] ? inp[l][i - off[l] - 1] : '0';
if (ops[l] == '.') {
if (cc[l]) {
free(Ol);
return NULL;
}
pt = true;
++cc[l];
}
ops[l] -= '0';
}
if (pt) {
Ol[i] = '.';
continue;
}
if ((Ol[i] = ops[0] + ops[1] + xc) > 1) {
Ol[i] = 0;
xc = 1;
}
else xc = 0;
lO = (Ol[i] += '0') == '1' ? i : lO;
}
if((Ol[0] = '0' + xc) == '1') return Ol;
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];

return Ol;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
char *c = bin_add(a, b);
if (!c && errno == ENOMEM) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}
else if (!c) {
fputs("Input error :(nn", stderr);
goto clear;
}

char* O = { a, b, c };
size_t lO[3], Ol = 0;
for (size_t i = 0; i < 3; ++i) {
lO[i] = gpp(O[i]);
lO[i] = lO[i] ? lO[i] : strlen(i[O]) + 1;
Ol = lO[i] > Ol ? lO[i] : Ol;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < Ol - lO[i]; ++l, putchar(' '));
puts(O[i]);
}
putchar('n');

free(c);
clear :{ int c; while ((c = getchar()) != 'n' && c != EOF); }
}
}


The main() is just included to provide input to the function and pretty-print its results. Every C99 compliant compiler should be able to compile above code.



Do you see any flaws in my code and anything that could be improved?










share|improve this question















I tried to write a function bin_add() in C to add two positive binary numbers represented as zero terminated strings:



#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

char* bin_add(char const *a, char const *b)
{
char const *inp = { a, b };
size_t ll = { strlen(a), strlen(b) };
size_t pp = { gpp(a), gpp(b) };
size_t OO[2], off[2];

for (size_t i = 0; i < 2; ++i) {
OO[i] = pp[i] ? pp[i] - 1 : ll[i];
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}

for (size_t i = 0; i < 2; ++i)
off[i] = OO[i] < OO[!i] ? OO[!i] - OO[i] : 0;

size_t ML = MAX(OO[0], OO[1]) + MAX(pp[0], pp[1]) + (!!pp[0] || !!pp[1]);
char *Ol = calloc(ML + 2, 1);
if(!Ol) return Ol;

char ops[2];
int xc = 0;
size_t lO = ML;
unsigned cc[2] = { 0 };
for (size_t i = ML; i; --i) {
bool pt = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= ll[l] + off[l] && i - off[l] - 1
< ll[l] ? inp[l][i - off[l] - 1] : '0';
if (ops[l] == '.') {
if (cc[l]) {
free(Ol);
return NULL;
}
pt = true;
++cc[l];
}
ops[l] -= '0';
}
if (pt) {
Ol[i] = '.';
continue;
}
if ((Ol[i] = ops[0] + ops[1] + xc) > 1) {
Ol[i] = 0;
xc = 1;
}
else xc = 0;
lO = (Ol[i] += '0') == '1' ? i : lO;
}
if((Ol[0] = '0' + xc) == '1') return Ol;
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];

return Ol;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
char *c = bin_add(a, b);
if (!c && errno == ENOMEM) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}
else if (!c) {
fputs("Input error :(nn", stderr);
goto clear;
}

char* O = { a, b, c };
size_t lO[3], Ol = 0;
for (size_t i = 0; i < 3; ++i) {
lO[i] = gpp(O[i]);
lO[i] = lO[i] ? lO[i] : strlen(i[O]) + 1;
Ol = lO[i] > Ol ? lO[i] : Ol;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < Ol - lO[i]; ++l, putchar(' '));
puts(O[i]);
}
putchar('n');

free(c);
clear :{ int c; while ((c = getchar()) != 'n' && c != EOF); }
}
}


The main() is just included to provide input to the function and pretty-print its results. Every C99 compliant compiler should be able to compile above code.



Do you see any flaws in my code and anything that could be improved?







c strings






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 30 at 16:26

























asked Nov 30 at 0:18









Swordfish

1477




1477












  • "A revised version of the code will be posted in an update to this question." Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Sᴀᴍ Onᴇᴌᴀ
    Nov 30 at 16:12










  • @SᴀᴍOnᴇᴌᴀ I'll move the reply to an answer.
    – Swordfish
    Nov 30 at 16:26


















  • "A revised version of the code will be posted in an update to this question." Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    – Sᴀᴍ Onᴇᴌᴀ
    Nov 30 at 16:12










  • @SᴀᴍOnᴇᴌᴀ I'll move the reply to an answer.
    – Swordfish
    Nov 30 at 16:26
















"A revised version of the code will be posted in an update to this question." Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
– Sᴀᴍ Onᴇᴌᴀ
Nov 30 at 16:12




"A revised version of the code will be posted in an update to this question." Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
– Sᴀᴍ Onᴇᴌᴀ
Nov 30 at 16:12












@SᴀᴍOnᴇᴌᴀ I'll move the reply to an answer.
– Swordfish
Nov 30 at 16:26




@SᴀᴍOnᴇᴌᴀ I'll move the reply to an answer.
– Swordfish
Nov 30 at 16:26










2 Answers
2






active

oldest

votes

















up vote
3
down vote



accepted











Do you see any flaws in my code and anything that could be improved?




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.



No compilation errors



As posted now, I did not notice any warnings either- good.



Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.



Commenting some of the block of code would help too.



When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.



Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.



Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.



Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.



Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.



Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry.
size_t ML more meaningful as MaxLength.



Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a,b. This would help simplify - a NULL return would only indicate out-of-memory.



Good use of cast to ward off warnings



return n  ? (size_t)(n - s + 1) : 0;
// ^------^


Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {



Good use of const.



Good use of size_t.



Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);





Main



Do not assume EOF is -1



Simply test if the scanf() result is 2.



// while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {


ENOMEM



ENOMEM is not part of the standard C.



Test cases



Some specific example test cases would be useful.




maybe even C90/C89




Not quite.



Lots of error: 'for' loop initial declarations are only allowed in C99 or C11 mode problems



warning: control reaches end of non-void function [-Wreturn-type]



error: redefinition of 'i'






share|improve this answer























  • I replied to your great review in an answer to the question.
    – Swordfish
    Nov 30 at 16:28


















up vote
1
down vote













In reply to @chux review:




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.




I understand. Please note that I posted the code contained within one "file" to make copy & paste for testing easier for the readers. I concur, the code should be split up in a header and it's accompanying source file.




Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.




I wrote short specifications of the both functions to go in front of their declaration (prototype) and definition (implementation).




Commenting some of the block of code would help too.




I'd appreciate your input on where coments might be needed on the cleaned up version of the code since I believe in self-documenting code.




When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.




Um. Since the code "shifts away" all leading zeros I am not sure your conclusion and suggestion "As a final carry with this FP-like code is more rare, I'd shift when there is a carry" is applicable.




Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.




Yes, that is an oversight of the initial implementation. I'll add code to discard trailing zeros from the result.




Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.




Whith discarding leading zeros at an early stage as you suggest, it is no longer needed to keep track of the last '1' written to the output string. I'll add code to discard leading zeros in the input strings.




Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.




You are right, that bracket should to to the next line.




Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.




That was an oversight when posting the question. The original code is properly indented.




Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry. size_t ML more meaningful as MaxLength.




I'll think of better names.




Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a, b. This would help simplify - a NULL return would only indicate out-of-memory.




Good point. This will allow to drop counting of radix points from bin_add(). I'll implement a function bool is_valid_binary_string(char const *s).




Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {




Right. I changed the point of definition of ops[2]. cc[2] will be dropped as it is no longer needed if the function can rely on valid input.




Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);




This would help to avoid a pitfall if the code were ever to be changed to work with wide characters. Changed.




Do not assume EOF is -1



Simply test if the scanf() result is 2.




The original code does not assume EOF to be -1. It compares the result of scanf() to 2 just as you suggest, albeit in a rather obfuscated way. I'll change == 1 << 1 to == 2.




ENOMEM



ENOMEM is not part of the standard C.




Since it is no longer needed with bin_add() relying on valid input, I will drop checking errno for ENOMEM.



Also I'll drop the speculation about the code being C89/90 compliant from my post since it contains variable definitions local to for-loops which is not allowed in pre C99 code. Didn't think about that.



A revised version of the code:



#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* gpp() (get point position) expects a zero terminated string as input and
will return the 1-based position of the first occurrence of character '.'
or 0 if no such character is present in the input string.
*/
size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

/* Determines if its parameter is a valid binary number consisting only of
'0' and '1' and containing at most one radix point. The return value is
true if a valid binary number is passed and false otherwise.
*/
bool is_valid_binary_string(char const *s)
{
int num_points = 0;
for (; *s; ++s) {
if (*s != '1' && *s != '0' && *s != '.')
return false;
if (*s == '.' && ++num_points > 1)
return false;
}
return true;
}

/* bin_add() expects two zero terminated strings as input. The both strings
must not contain other characters than '0' and '1'. Both may contain no or
one radix point ('.'). The function returns a zero terminated string which
is the result of the addition of both input strings done in base 2. The
caller is responsible for deallocating the memory to which a pointer is
returned. If memory allocation failes the function returns NULL and errno
is ENOMEM. If one or both input strings do not conform to the expectations
of the function, it returns NULL.
*/
char* bin_add(char const *a, char const *b)
{
while (*a == '0') ++a;
while (*b == '0') ++b;

char const *input = { a, b };
size_t length = { strlen(a), strlen(b) };
size_t point_position = { gpp(a), gpp(b) };
size_t integer_part[2];
size_t offset[2];

for (size_t i = 0; i < 2; ++i) {
integer_part[i] = point_position[i] ? point_position[i] - 1 : length[i];
point_position[i] = point_position[i] ? length[i] - point_position[i] : 0;
}

for (size_t i = 0; i < 2; ++i)
offset[i] = integer_part[i] < integer_part[!i]
? integer_part[!i] - integer_part[i]
: 0;

size_t maximum_length = MAX(integer_part[0], integer_part[1]) +
MAX(point_position[0], point_position[1]) +
(!!point_position[0] || !!point_position[1]);

char *result = calloc(maximum_length + 2, sizeof(*result));
if (!result)
return NULL;

int carry = 0;
bool result_contains_point = false;
for (size_t i = maximum_length; i; --i) {
char ops[2];
bool is_radix_point = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= length[l] + offset[l] && i - offset[l] - 1
< length[l] ? input[l][i - offset[l] - 1] : '0';
if (ops[l] == '.') {
result_contains_point = is_radix_point = true;
break;
}
ops[l] -= '0';
}
if (is_radix_point) {
result[i] = '.';
continue;
}
if ((result[i] = ops[0] + ops[1] + carry) > 1) {
result[i] = 0;
carry = 1;
}
else carry = 0;
result[i] += '0';
}

result[0] = '0' + carry;

if(result_contains_point)
while (result[maximum_length] == '0')
result[maximum_length--] = '';

if (result[0] == '1')
return result;

for (size_t i = 0; i <= maximum_length + 1; ++i)
result[i] = result[i + 1];
return result;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {
if (!is_valid_binary_string(a) || !is_valid_binary_string(b)) {
fputs("Input error :(nn", stderr);
goto clear;
}

char *c = bin_add(a, b);
if (!c) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}

char* numbers = { a, b, c };
size_t point_position[3];
size_t offset = 0;

for (size_t i = 0; i < 3; ++i) {
point_position[i] = gpp(numbers[i]);
point_position[i] = point_position[i] ? point_position[i] : strlen(numbers[i]) + 1;
offset = point_position[i] > offset ? point_position[i] : offset;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < offset - point_position[i]; ++l, putchar(' '));
puts(numbers[i]);
}
putchar('n');

free(c);

clear: { int ch;
while ((ch = getchar()) != 'n' && ch != EOF);
}
}
}





share|improve this answer























  • Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
    – chux
    Nov 30 at 17:00










  • @chux I got you, but I really don't feel like rewriting the code based on this.
    – Swordfish
    Nov 30 at 17:02










  • is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
    – chux
    Nov 30 at 17:05










  • Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
    – Swordfish
    Nov 30 at 17:12










  • "" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
    – Swordfish
    Nov 30 at 17:13











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208734%2ffunction-to-add-two-binary-numbers-in-c%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
3
down vote



accepted











Do you see any flaws in my code and anything that could be improved?




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.



No compilation errors



As posted now, I did not notice any warnings either- good.



Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.



Commenting some of the block of code would help too.



When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.



Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.



Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.



Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.



Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.



Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry.
size_t ML more meaningful as MaxLength.



Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a,b. This would help simplify - a NULL return would only indicate out-of-memory.



Good use of cast to ward off warnings



return n  ? (size_t)(n - s + 1) : 0;
// ^------^


Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {



Good use of const.



Good use of size_t.



Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);





Main



Do not assume EOF is -1



Simply test if the scanf() result is 2.



// while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {


ENOMEM



ENOMEM is not part of the standard C.



Test cases



Some specific example test cases would be useful.




maybe even C90/C89




Not quite.



Lots of error: 'for' loop initial declarations are only allowed in C99 or C11 mode problems



warning: control reaches end of non-void function [-Wreturn-type]



error: redefinition of 'i'






share|improve this answer























  • I replied to your great review in an answer to the question.
    – Swordfish
    Nov 30 at 16:28















up vote
3
down vote



accepted











Do you see any flaws in my code and anything that could be improved?




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.



No compilation errors



As posted now, I did not notice any warnings either- good.



Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.



Commenting some of the block of code would help too.



When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.



Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.



Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.



Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.



Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.



Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry.
size_t ML more meaningful as MaxLength.



Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a,b. This would help simplify - a NULL return would only indicate out-of-memory.



Good use of cast to ward off warnings



return n  ? (size_t)(n - s + 1) : 0;
// ^------^


Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {



Good use of const.



Good use of size_t.



Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);





Main



Do not assume EOF is -1



Simply test if the scanf() result is 2.



// while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {


ENOMEM



ENOMEM is not part of the standard C.



Test cases



Some specific example test cases would be useful.




maybe even C90/C89




Not quite.



Lots of error: 'for' loop initial declarations are only allowed in C99 or C11 mode problems



warning: control reaches end of non-void function [-Wreturn-type]



error: redefinition of 'i'






share|improve this answer























  • I replied to your great review in an answer to the question.
    – Swordfish
    Nov 30 at 16:28













up vote
3
down vote



accepted







up vote
3
down vote



accepted







Do you see any flaws in my code and anything that could be improved?




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.



No compilation errors



As posted now, I did not notice any warnings either- good.



Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.



Commenting some of the block of code would help too.



When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.



Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.



Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.



Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.



Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.



Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry.
size_t ML more meaningful as MaxLength.



Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a,b. This would help simplify - a NULL return would only indicate out-of-memory.



Good use of cast to ward off warnings



return n  ? (size_t)(n - s + 1) : 0;
// ^------^


Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {



Good use of const.



Good use of size_t.



Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);





Main



Do not assume EOF is -1



Simply test if the scanf() result is 2.



// while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {


ENOMEM



ENOMEM is not part of the standard C.



Test cases



Some specific example test cases would be useful.




maybe even C90/C89




Not quite.



Lots of error: 'for' loop initial declarations are only allowed in C99 or C11 mode problems



warning: control reaches end of non-void function [-Wreturn-type]



error: redefinition of 'i'






share|improve this answer















Do you see any flaws in my code and anything that could be improved?




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.



No compilation errors



As posted now, I did not notice any warnings either- good.



Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.



Commenting some of the block of code would help too.



When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.



Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.



Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.



Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.



Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.



Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry.
size_t ML more meaningful as MaxLength.



Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a,b. This would help simplify - a NULL return would only indicate out-of-memory.



Good use of cast to ward off warnings



return n  ? (size_t)(n - s + 1) : 0;
// ^------^


Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {



Good use of const.



Good use of size_t.



Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);





Main



Do not assume EOF is -1



Simply test if the scanf() result is 2.



// while (scanf(" %80[0.1] %80[0.1]", a, b) & 1 << 1) {
while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {


ENOMEM



ENOMEM is not part of the standard C.



Test cases



Some specific example test cases would be useful.




maybe even C90/C89




Not quite.



Lots of error: 'for' loop initial declarations are only allowed in C99 or C11 mode problems



warning: control reaches end of non-void function [-Wreturn-type]



error: redefinition of 'i'







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 30 at 7:52









Toby Speight

23.2k538110




23.2k538110










answered Nov 30 at 3:43









chux

12.5k11343




12.5k11343












  • I replied to your great review in an answer to the question.
    – Swordfish
    Nov 30 at 16:28


















  • I replied to your great review in an answer to the question.
    – Swordfish
    Nov 30 at 16:28
















I replied to your great review in an answer to the question.
– Swordfish
Nov 30 at 16:28




I replied to your great review in an answer to the question.
– Swordfish
Nov 30 at 16:28












up vote
1
down vote













In reply to @chux review:




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.




I understand. Please note that I posted the code contained within one "file" to make copy & paste for testing easier for the readers. I concur, the code should be split up in a header and it's accompanying source file.




Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.




I wrote short specifications of the both functions to go in front of their declaration (prototype) and definition (implementation).




Commenting some of the block of code would help too.




I'd appreciate your input on where coments might be needed on the cleaned up version of the code since I believe in self-documenting code.




When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.




Um. Since the code "shifts away" all leading zeros I am not sure your conclusion and suggestion "As a final carry with this FP-like code is more rare, I'd shift when there is a carry" is applicable.




Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.




Yes, that is an oversight of the initial implementation. I'll add code to discard trailing zeros from the result.




Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.




Whith discarding leading zeros at an early stage as you suggest, it is no longer needed to keep track of the last '1' written to the output string. I'll add code to discard leading zeros in the input strings.




Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.




You are right, that bracket should to to the next line.




Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.




That was an oversight when posting the question. The original code is properly indented.




Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry. size_t ML more meaningful as MaxLength.




I'll think of better names.




Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a, b. This would help simplify - a NULL return would only indicate out-of-memory.




Good point. This will allow to drop counting of radix points from bin_add(). I'll implement a function bool is_valid_binary_string(char const *s).




Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {




Right. I changed the point of definition of ops[2]. cc[2] will be dropped as it is no longer needed if the function can rely on valid input.




Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);




This would help to avoid a pitfall if the code were ever to be changed to work with wide characters. Changed.




Do not assume EOF is -1



Simply test if the scanf() result is 2.




The original code does not assume EOF to be -1. It compares the result of scanf() to 2 just as you suggest, albeit in a rather obfuscated way. I'll change == 1 << 1 to == 2.




ENOMEM



ENOMEM is not part of the standard C.




Since it is no longer needed with bin_add() relying on valid input, I will drop checking errno for ENOMEM.



Also I'll drop the speculation about the code being C89/90 compliant from my post since it contains variable definitions local to for-loops which is not allowed in pre C99 code. Didn't think about that.



A revised version of the code:



#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* gpp() (get point position) expects a zero terminated string as input and
will return the 1-based position of the first occurrence of character '.'
or 0 if no such character is present in the input string.
*/
size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

/* Determines if its parameter is a valid binary number consisting only of
'0' and '1' and containing at most one radix point. The return value is
true if a valid binary number is passed and false otherwise.
*/
bool is_valid_binary_string(char const *s)
{
int num_points = 0;
for (; *s; ++s) {
if (*s != '1' && *s != '0' && *s != '.')
return false;
if (*s == '.' && ++num_points > 1)
return false;
}
return true;
}

/* bin_add() expects two zero terminated strings as input. The both strings
must not contain other characters than '0' and '1'. Both may contain no or
one radix point ('.'). The function returns a zero terminated string which
is the result of the addition of both input strings done in base 2. The
caller is responsible for deallocating the memory to which a pointer is
returned. If memory allocation failes the function returns NULL and errno
is ENOMEM. If one or both input strings do not conform to the expectations
of the function, it returns NULL.
*/
char* bin_add(char const *a, char const *b)
{
while (*a == '0') ++a;
while (*b == '0') ++b;

char const *input = { a, b };
size_t length = { strlen(a), strlen(b) };
size_t point_position = { gpp(a), gpp(b) };
size_t integer_part[2];
size_t offset[2];

for (size_t i = 0; i < 2; ++i) {
integer_part[i] = point_position[i] ? point_position[i] - 1 : length[i];
point_position[i] = point_position[i] ? length[i] - point_position[i] : 0;
}

for (size_t i = 0; i < 2; ++i)
offset[i] = integer_part[i] < integer_part[!i]
? integer_part[!i] - integer_part[i]
: 0;

size_t maximum_length = MAX(integer_part[0], integer_part[1]) +
MAX(point_position[0], point_position[1]) +
(!!point_position[0] || !!point_position[1]);

char *result = calloc(maximum_length + 2, sizeof(*result));
if (!result)
return NULL;

int carry = 0;
bool result_contains_point = false;
for (size_t i = maximum_length; i; --i) {
char ops[2];
bool is_radix_point = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= length[l] + offset[l] && i - offset[l] - 1
< length[l] ? input[l][i - offset[l] - 1] : '0';
if (ops[l] == '.') {
result_contains_point = is_radix_point = true;
break;
}
ops[l] -= '0';
}
if (is_radix_point) {
result[i] = '.';
continue;
}
if ((result[i] = ops[0] + ops[1] + carry) > 1) {
result[i] = 0;
carry = 1;
}
else carry = 0;
result[i] += '0';
}

result[0] = '0' + carry;

if(result_contains_point)
while (result[maximum_length] == '0')
result[maximum_length--] = '';

if (result[0] == '1')
return result;

for (size_t i = 0; i <= maximum_length + 1; ++i)
result[i] = result[i + 1];
return result;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {
if (!is_valid_binary_string(a) || !is_valid_binary_string(b)) {
fputs("Input error :(nn", stderr);
goto clear;
}

char *c = bin_add(a, b);
if (!c) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}

char* numbers = { a, b, c };
size_t point_position[3];
size_t offset = 0;

for (size_t i = 0; i < 3; ++i) {
point_position[i] = gpp(numbers[i]);
point_position[i] = point_position[i] ? point_position[i] : strlen(numbers[i]) + 1;
offset = point_position[i] > offset ? point_position[i] : offset;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < offset - point_position[i]; ++l, putchar(' '));
puts(numbers[i]);
}
putchar('n');

free(c);

clear: { int ch;
while ((ch = getchar()) != 'n' && ch != EOF);
}
}
}





share|improve this answer























  • Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
    – chux
    Nov 30 at 17:00










  • @chux I got you, but I really don't feel like rewriting the code based on this.
    – Swordfish
    Nov 30 at 17:02










  • is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
    – chux
    Nov 30 at 17:05










  • Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
    – Swordfish
    Nov 30 at 17:12










  • "" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
    – Swordfish
    Nov 30 at 17:13















up vote
1
down vote













In reply to @chux review:




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.




I understand. Please note that I posted the code contained within one "file" to make copy & paste for testing easier for the readers. I concur, the code should be split up in a header and it's accompanying source file.




Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.




I wrote short specifications of the both functions to go in front of their declaration (prototype) and definition (implementation).




Commenting some of the block of code would help too.




I'd appreciate your input on where coments might be needed on the cleaned up version of the code since I believe in self-documenting code.




When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.




Um. Since the code "shifts away" all leading zeros I am not sure your conclusion and suggestion "As a final carry with this FP-like code is more rare, I'd shift when there is a carry" is applicable.




Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.




Yes, that is an oversight of the initial implementation. I'll add code to discard trailing zeros from the result.




Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.




Whith discarding leading zeros at an early stage as you suggest, it is no longer needed to keep track of the last '1' written to the output string. I'll add code to discard leading zeros in the input strings.




Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.




You are right, that bracket should to to the next line.




Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.




That was an oversight when posting the question. The original code is properly indented.




Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry. size_t ML more meaningful as MaxLength.




I'll think of better names.




Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a, b. This would help simplify - a NULL return would only indicate out-of-memory.




Good point. This will allow to drop counting of radix points from bin_add(). I'll implement a function bool is_valid_binary_string(char const *s).




Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {




Right. I changed the point of definition of ops[2]. cc[2] will be dropped as it is no longer needed if the function can rely on valid input.




Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);




This would help to avoid a pitfall if the code were ever to be changed to work with wide characters. Changed.




Do not assume EOF is -1



Simply test if the scanf() result is 2.




The original code does not assume EOF to be -1. It compares the result of scanf() to 2 just as you suggest, albeit in a rather obfuscated way. I'll change == 1 << 1 to == 2.




ENOMEM



ENOMEM is not part of the standard C.




Since it is no longer needed with bin_add() relying on valid input, I will drop checking errno for ENOMEM.



Also I'll drop the speculation about the code being C89/90 compliant from my post since it contains variable definitions local to for-loops which is not allowed in pre C99 code. Didn't think about that.



A revised version of the code:



#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* gpp() (get point position) expects a zero terminated string as input and
will return the 1-based position of the first occurrence of character '.'
or 0 if no such character is present in the input string.
*/
size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

/* Determines if its parameter is a valid binary number consisting only of
'0' and '1' and containing at most one radix point. The return value is
true if a valid binary number is passed and false otherwise.
*/
bool is_valid_binary_string(char const *s)
{
int num_points = 0;
for (; *s; ++s) {
if (*s != '1' && *s != '0' && *s != '.')
return false;
if (*s == '.' && ++num_points > 1)
return false;
}
return true;
}

/* bin_add() expects two zero terminated strings as input. The both strings
must not contain other characters than '0' and '1'. Both may contain no or
one radix point ('.'). The function returns a zero terminated string which
is the result of the addition of both input strings done in base 2. The
caller is responsible for deallocating the memory to which a pointer is
returned. If memory allocation failes the function returns NULL and errno
is ENOMEM. If one or both input strings do not conform to the expectations
of the function, it returns NULL.
*/
char* bin_add(char const *a, char const *b)
{
while (*a == '0') ++a;
while (*b == '0') ++b;

char const *input = { a, b };
size_t length = { strlen(a), strlen(b) };
size_t point_position = { gpp(a), gpp(b) };
size_t integer_part[2];
size_t offset[2];

for (size_t i = 0; i < 2; ++i) {
integer_part[i] = point_position[i] ? point_position[i] - 1 : length[i];
point_position[i] = point_position[i] ? length[i] - point_position[i] : 0;
}

for (size_t i = 0; i < 2; ++i)
offset[i] = integer_part[i] < integer_part[!i]
? integer_part[!i] - integer_part[i]
: 0;

size_t maximum_length = MAX(integer_part[0], integer_part[1]) +
MAX(point_position[0], point_position[1]) +
(!!point_position[0] || !!point_position[1]);

char *result = calloc(maximum_length + 2, sizeof(*result));
if (!result)
return NULL;

int carry = 0;
bool result_contains_point = false;
for (size_t i = maximum_length; i; --i) {
char ops[2];
bool is_radix_point = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= length[l] + offset[l] && i - offset[l] - 1
< length[l] ? input[l][i - offset[l] - 1] : '0';
if (ops[l] == '.') {
result_contains_point = is_radix_point = true;
break;
}
ops[l] -= '0';
}
if (is_radix_point) {
result[i] = '.';
continue;
}
if ((result[i] = ops[0] + ops[1] + carry) > 1) {
result[i] = 0;
carry = 1;
}
else carry = 0;
result[i] += '0';
}

result[0] = '0' + carry;

if(result_contains_point)
while (result[maximum_length] == '0')
result[maximum_length--] = '';

if (result[0] == '1')
return result;

for (size_t i = 0; i <= maximum_length + 1; ++i)
result[i] = result[i + 1];
return result;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {
if (!is_valid_binary_string(a) || !is_valid_binary_string(b)) {
fputs("Input error :(nn", stderr);
goto clear;
}

char *c = bin_add(a, b);
if (!c) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}

char* numbers = { a, b, c };
size_t point_position[3];
size_t offset = 0;

for (size_t i = 0; i < 3; ++i) {
point_position[i] = gpp(numbers[i]);
point_position[i] = point_position[i] ? point_position[i] : strlen(numbers[i]) + 1;
offset = point_position[i] > offset ? point_position[i] : offset;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < offset - point_position[i]; ++l, putchar(' '));
puts(numbers[i]);
}
putchar('n');

free(c);

clear: { int ch;
while ((ch = getchar()) != 'n' && ch != EOF);
}
}
}





share|improve this answer























  • Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
    – chux
    Nov 30 at 17:00










  • @chux I got you, but I really don't feel like rewriting the code based on this.
    – Swordfish
    Nov 30 at 17:02










  • is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
    – chux
    Nov 30 at 17:05










  • Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
    – Swordfish
    Nov 30 at 17:12










  • "" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
    – Swordfish
    Nov 30 at 17:13













up vote
1
down vote










up vote
1
down vote









In reply to @chux review:




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.




I understand. Please note that I posted the code contained within one "file" to make copy & paste for testing easier for the readers. I concur, the code should be split up in a header and it's accompanying source file.




Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.




I wrote short specifications of the both functions to go in front of their declaration (prototype) and definition (implementation).




Commenting some of the block of code would help too.




I'd appreciate your input on where coments might be needed on the cleaned up version of the code since I believe in self-documenting code.




When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.




Um. Since the code "shifts away" all leading zeros I am not sure your conclusion and suggestion "As a final carry with this FP-like code is more rare, I'd shift when there is a carry" is applicable.




Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.




Yes, that is an oversight of the initial implementation. I'll add code to discard trailing zeros from the result.




Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.




Whith discarding leading zeros at an early stage as you suggest, it is no longer needed to keep track of the last '1' written to the output string. I'll add code to discard leading zeros in the input strings.




Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.




You are right, that bracket should to to the next line.




Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.




That was an oversight when posting the question. The original code is properly indented.




Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry. size_t ML more meaningful as MaxLength.




I'll think of better names.




Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a, b. This would help simplify - a NULL return would only indicate out-of-memory.




Good point. This will allow to drop counting of radix points from bin_add(). I'll implement a function bool is_valid_binary_string(char const *s).




Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {




Right. I changed the point of definition of ops[2]. cc[2] will be dropped as it is no longer needed if the function can rely on valid input.




Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);




This would help to avoid a pitfall if the code were ever to be changed to work with wide characters. Changed.




Do not assume EOF is -1



Simply test if the scanf() result is 2.




The original code does not assume EOF to be -1. It compares the result of scanf() to 2 just as you suggest, albeit in a rather obfuscated way. I'll change == 1 << 1 to == 2.




ENOMEM



ENOMEM is not part of the standard C.




Since it is no longer needed with bin_add() relying on valid input, I will drop checking errno for ENOMEM.



Also I'll drop the speculation about the code being C89/90 compliant from my post since it contains variable definitions local to for-loops which is not allowed in pre C99 code. Didn't think about that.



A revised version of the code:



#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* gpp() (get point position) expects a zero terminated string as input and
will return the 1-based position of the first occurrence of character '.'
or 0 if no such character is present in the input string.
*/
size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

/* Determines if its parameter is a valid binary number consisting only of
'0' and '1' and containing at most one radix point. The return value is
true if a valid binary number is passed and false otherwise.
*/
bool is_valid_binary_string(char const *s)
{
int num_points = 0;
for (; *s; ++s) {
if (*s != '1' && *s != '0' && *s != '.')
return false;
if (*s == '.' && ++num_points > 1)
return false;
}
return true;
}

/* bin_add() expects two zero terminated strings as input. The both strings
must not contain other characters than '0' and '1'. Both may contain no or
one radix point ('.'). The function returns a zero terminated string which
is the result of the addition of both input strings done in base 2. The
caller is responsible for deallocating the memory to which a pointer is
returned. If memory allocation failes the function returns NULL and errno
is ENOMEM. If one or both input strings do not conform to the expectations
of the function, it returns NULL.
*/
char* bin_add(char const *a, char const *b)
{
while (*a == '0') ++a;
while (*b == '0') ++b;

char const *input = { a, b };
size_t length = { strlen(a), strlen(b) };
size_t point_position = { gpp(a), gpp(b) };
size_t integer_part[2];
size_t offset[2];

for (size_t i = 0; i < 2; ++i) {
integer_part[i] = point_position[i] ? point_position[i] - 1 : length[i];
point_position[i] = point_position[i] ? length[i] - point_position[i] : 0;
}

for (size_t i = 0; i < 2; ++i)
offset[i] = integer_part[i] < integer_part[!i]
? integer_part[!i] - integer_part[i]
: 0;

size_t maximum_length = MAX(integer_part[0], integer_part[1]) +
MAX(point_position[0], point_position[1]) +
(!!point_position[0] || !!point_position[1]);

char *result = calloc(maximum_length + 2, sizeof(*result));
if (!result)
return NULL;

int carry = 0;
bool result_contains_point = false;
for (size_t i = maximum_length; i; --i) {
char ops[2];
bool is_radix_point = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= length[l] + offset[l] && i - offset[l] - 1
< length[l] ? input[l][i - offset[l] - 1] : '0';
if (ops[l] == '.') {
result_contains_point = is_radix_point = true;
break;
}
ops[l] -= '0';
}
if (is_radix_point) {
result[i] = '.';
continue;
}
if ((result[i] = ops[0] + ops[1] + carry) > 1) {
result[i] = 0;
carry = 1;
}
else carry = 0;
result[i] += '0';
}

result[0] = '0' + carry;

if(result_contains_point)
while (result[maximum_length] == '0')
result[maximum_length--] = '';

if (result[0] == '1')
return result;

for (size_t i = 0; i <= maximum_length + 1; ++i)
result[i] = result[i + 1];
return result;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {
if (!is_valid_binary_string(a) || !is_valid_binary_string(b)) {
fputs("Input error :(nn", stderr);
goto clear;
}

char *c = bin_add(a, b);
if (!c) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}

char* numbers = { a, b, c };
size_t point_position[3];
size_t offset = 0;

for (size_t i = 0; i < 3; ++i) {
point_position[i] = gpp(numbers[i]);
point_position[i] = point_position[i] ? point_position[i] : strlen(numbers[i]) + 1;
offset = point_position[i] > offset ? point_position[i] : offset;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < offset - point_position[i]; ++l, putchar(' '));
puts(numbers[i]);
}
putchar('n');

free(c);

clear: { int ch;
while ((ch = getchar()) != 'n' && ch != EOF);
}
}
}





share|improve this answer














In reply to @chux review:




Segregate code



Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.




I understand. Please note that I posted the code contained within one "file" to make copy & paste for testing easier for the readers. I concur, the code should be split up in a header and it's accompanying source file.




Some comments would help



gpp() would benefit with at least a line comment about its goal, expected input, output, etc. Same for bin_add() - which should alert that the return pointer needs to be free'd. This becomes even more important when the user only has access to the declaration in a .h file.




I wrote short specifications of the both functions to go in front of their declaration (prototype) and definition (implementation).




Commenting some of the block of code would help too.




I'd appreciate your input on where coments might be needed on the cleaned up version of the code since I believe in self-documenting code.




When to shift



When there is not a final carry, code shifts Ol. As a final carry with this FP-like code is more rare, I'd shift when there is a carry.




Um. Since the code "shifts away" all leading zeros I am not sure your conclusion and suggestion "As a final carry with this FP-like code is more rare, I'd shift when there is a carry" is applicable.




Collapsing



With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.




Yes, that is an oversight of the initial implementation. I'll add code to discard trailing zeros from the result.




Leading zero digits are possible based on input. Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though.




Whith discarding leading zeros at an early stage as you suggest, it is no longer needed to keep track of the last '1' written to the output string. I'll add code to discard leading zeros in the input strings.




Inconsistent bracket style



//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.




You are right, that bracket should to to the next line.




Inconsistent indentation



if((Ol[0] = '0' + xc) == '1') return Ol;
// v Why indented here?
for (size_t i = 0; i <= ML - lO + 1; ++i)
Ol[i] = Ol[lO + i];


This implies code is not auto formatted. Save time, and use auto-formatting.




That was an oversight when posting the question. The original code is properly indented.




Terse digit like object names lose clarity



The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11. Consider more clear alternatives.



Other examples:
int xc as the carry bit looks more clear as int carry. size_t ML more meaningful as MaxLength.




I'll think of better names.




Input error detection



I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume valid strings a, b. This would help simplify - a NULL return would only indicate out-of-memory.




Good point. This will allow to drop counting of radix points from bin_add(). I'll implement a function bool is_valid_binary_string(char const *s).




Misc.



ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {




Right. I changed the point of definition of ops[2]. cc[2] will be dropped as it is no longer needed if the function can rely on valid input.




Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);




This would help to avoid a pitfall if the code were ever to be changed to work with wide characters. Changed.




Do not assume EOF is -1



Simply test if the scanf() result is 2.




The original code does not assume EOF to be -1. It compares the result of scanf() to 2 just as you suggest, albeit in a rather obfuscated way. I'll change == 1 << 1 to == 2.




ENOMEM



ENOMEM is not part of the standard C.




Since it is no longer needed with bin_add() relying on valid input, I will drop checking errno for ENOMEM.



Also I'll drop the speculation about the code being C89/90 compliant from my post since it contains variable definitions local to for-loops which is not allowed in pre C99 code. Didn't think about that.



A revised version of the code:



#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX(x, y) ((x) > (y) ? (x) : (y))

/* gpp() (get point position) expects a zero terminated string as input and
will return the 1-based position of the first occurrence of character '.'
or 0 if no such character is present in the input string.
*/
size_t gpp(char const *s)
{
char *n = strchr(s, '.');
return n ? (size_t)(n - s + 1) : 0;
}

/* Determines if its parameter is a valid binary number consisting only of
'0' and '1' and containing at most one radix point. The return value is
true if a valid binary number is passed and false otherwise.
*/
bool is_valid_binary_string(char const *s)
{
int num_points = 0;
for (; *s; ++s) {
if (*s != '1' && *s != '0' && *s != '.')
return false;
if (*s == '.' && ++num_points > 1)
return false;
}
return true;
}

/* bin_add() expects two zero terminated strings as input. The both strings
must not contain other characters than '0' and '1'. Both may contain no or
one radix point ('.'). The function returns a zero terminated string which
is the result of the addition of both input strings done in base 2. The
caller is responsible for deallocating the memory to which a pointer is
returned. If memory allocation failes the function returns NULL and errno
is ENOMEM. If one or both input strings do not conform to the expectations
of the function, it returns NULL.
*/
char* bin_add(char const *a, char const *b)
{
while (*a == '0') ++a;
while (*b == '0') ++b;

char const *input = { a, b };
size_t length = { strlen(a), strlen(b) };
size_t point_position = { gpp(a), gpp(b) };
size_t integer_part[2];
size_t offset[2];

for (size_t i = 0; i < 2; ++i) {
integer_part[i] = point_position[i] ? point_position[i] - 1 : length[i];
point_position[i] = point_position[i] ? length[i] - point_position[i] : 0;
}

for (size_t i = 0; i < 2; ++i)
offset[i] = integer_part[i] < integer_part[!i]
? integer_part[!i] - integer_part[i]
: 0;

size_t maximum_length = MAX(integer_part[0], integer_part[1]) +
MAX(point_position[0], point_position[1]) +
(!!point_position[0] || !!point_position[1]);

char *result = calloc(maximum_length + 2, sizeof(*result));
if (!result)
return NULL;

int carry = 0;
bool result_contains_point = false;
for (size_t i = maximum_length; i; --i) {
char ops[2];
bool is_radix_point = false;
for (size_t l = 0; l < 2; ++l) {
ops[l] = i <= length[l] + offset[l] && i - offset[l] - 1
< length[l] ? input[l][i - offset[l] - 1] : '0';
if (ops[l] == '.') {
result_contains_point = is_radix_point = true;
break;
}
ops[l] -= '0';
}
if (is_radix_point) {
result[i] = '.';
continue;
}
if ((result[i] = ops[0] + ops[1] + carry) > 1) {
result[i] = 0;
carry = 1;
}
else carry = 0;
result[i] += '0';
}

result[0] = '0' + carry;

if(result_contains_point)
while (result[maximum_length] == '0')
result[maximum_length--] = '';

if (result[0] == '1')
return result;

for (size_t i = 0; i <= maximum_length + 1; ++i)
result[i] = result[i + 1];
return result;
}

int main(void)
{
char a[81], b[81];

while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {
if (!is_valid_binary_string(a) || !is_valid_binary_string(b)) {
fputs("Input error :(nn", stderr);
goto clear;
}

char *c = bin_add(a, b);
if (!c) {
fputs("Not enough memory :(nn", stderr);
return EXIT_FAILURE;
}

char* numbers = { a, b, c };
size_t point_position[3];
size_t offset = 0;

for (size_t i = 0; i < 3; ++i) {
point_position[i] = gpp(numbers[i]);
point_position[i] = point_position[i] ? point_position[i] : strlen(numbers[i]) + 1;
offset = point_position[i] > offset ? point_position[i] : offset;
}

putchar('n');
for (size_t i = 0; i < 3; ++i) {
for (size_t l = 0; l < offset - point_position[i]; ++l, putchar(' '));
puts(numbers[i]);
}
putchar('n');

free(c);

clear: { int ch;
while ((ch = getchar()) != 'n' && ch != EOF);
}
}
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 30 at 17:10

























answered Nov 30 at 16:27









Swordfish

1477




1477












  • Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
    – chux
    Nov 30 at 17:00










  • @chux I got you, but I really don't feel like rewriting the code based on this.
    – Swordfish
    Nov 30 at 17:02










  • is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
    – chux
    Nov 30 at 17:05










  • Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
    – Swordfish
    Nov 30 at 17:12










  • "" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
    – Swordfish
    Nov 30 at 17:13


















  • Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
    – chux
    Nov 30 at 17:00










  • @chux I got you, but I really don't feel like rewriting the code based on this.
    – Swordfish
    Nov 30 at 17:02










  • is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
    – chux
    Nov 30 at 17:05










  • Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
    – Swordfish
    Nov 30 at 17:12










  • "" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
    – Swordfish
    Nov 30 at 17:13
















Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
– chux
Nov 30 at 17:00




Re: "final carry with this FP-like code is more rare" --> bin_add("101010", "111"), bin_add("0.101010", "111") do not generate a carry. Same magnitude ones do like bin_add("101010", "101010") - and hence more rare.
– chux
Nov 30 at 17:00












@chux I got you, but I really don't feel like rewriting the code based on this.
– Swordfish
Nov 30 at 17:02




@chux I got you, but I really don't feel like rewriting the code based on this.
– Swordfish
Nov 30 at 17:02












is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
– chux
Nov 30 at 17:05




is_valid_binary_string("") and is_valid_binary_string(".") return true. I'd expect false - your call.
– chux
Nov 30 at 17:05












Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
– Swordfish
Nov 30 at 17:12




Oh i see you have updated. – Yes, didn't want to lose a point to you for that one too ^^
– Swordfish
Nov 30 at 17:12












"" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
– Swordfish
Nov 30 at 17:13




"" and "." are both considered "0"` by bin_add() so they are valid as far as bin_add() is concerned.
– Swordfish
Nov 30 at 17:13


















draft saved

draft discarded




















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208734%2ffunction-to-add-two-binary-numbers-in-c%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Сан-Квентин

8-я гвардейская общевойсковая армия

Алькесар