For my mathematical research, I am to deal with very large numbers and I know that the standard C types are not going to stand a chance against them due to their limited capacity, so I decided to write a super calculator in C language in hope that I won't have to resort to a super computer.
I started with an add function that I want to be reviewed for bugs if any, and possible improvement in performance and general programming aspects. Note that, on my system, the program was able to add a number consisting of 200 million digits of 9 to the same number in 0.98 seconds, which is pretty impressive, but still, if there is anything in performance that can be enhanced, let me know. That is because the multiplication function is going to be dependent on this function, and things will get slower because multiplication is repeated addition.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char *add(char *x, char *y);
int main(void)
{
clock_t t1 = clock();
/* ............................................................................................................................. */
size_t nd = 200 * 1000 * 1000; // 2 hundred million digits
char *x = (char *)malloc(nd + 1);
char *y = (char *)malloc(nd + 1);
if (!x || !y) {
fputs("error: memory allocation failed.\n", stderr);
goto dismantle;
}
/* assign x and y */
for (size_t i = 0; i < nd; i++) {
x[i] = '9';
y[i] = '9';
}
/* NUL-terminate the arrays */
x[nd] = '\0';
y[nd] = '\0';
/* add x and y */
char *z = add(x, y);
if (z) {
//printf("x + y = %s\n", z);
free(z);
}
dismantle:
if (x) free(x);
if (y) free(y);
/* ............................................................................................................................. */
clock_t t2 = clock();
fprintf(stderr, "time elapsed: %.4f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
fprintf(stderr, "Press any key to continue . . . ");
getchar();
return 0;
}
void ReverseArray(char *buf)
{
char tmp, *ptr = buf + strlen(buf) - 1;
while (buf < ptr) {
tmp = *buf;
*buf++ = *ptr;
*ptr-- = tmp;
}
}
char *add(char *x, char *y)
{
/* store number of digits in size_t variables*/
size_t xlen = strlen(x);
size_t ylen = strlen(y);
/* essential variables */
char *z = NULL;
int r = -1;
int val, var = (xlen >= ylen);
size_t n = 0;
/* pointers to x and y */
char *p1, *p2;
char *t1, *t2;
/* assign pointers according to the value of var */
if (var) {
p1 = x + xlen - 1; t1 = x;
p2 = y + ylen - 1; t2 = y;
z = (char *)malloc(xlen + 2);
}
else {
p1 = y + ylen - 1; t1 = y;
p2 = x + xlen - 1; t2 = x;
z = (char *)malloc(ylen + 2);
}
/* check for allocation failure */
if (!z) {
fputs("error: memory allocation failed.\n", stderr);
return NULL;
}
/* stage 1 */
while (p2 >= t2)
{
if (r == -1) {
val = (*p1-- - '0') + (*p2-- - '0');
}
else {
val = (*p1-- - '0') + (*p2-- - '0') + 1;
}
if (val > 9) {
r = val - 10;
z[n++] = r + '0';
}
else {
z[n++] = val + '0';
r = -1;
}
}
/* stage 2 */
while (p1 >= t1)
{
if (r == -1) {
z[n++] = *p1--;
}
else {
val = (*p1-- - '0') + 1;
if (val > 9) {
r = val - 10;
z[n++] = r + '0';
}
else {
z[n++] = val + '0';
r = -1;
}
}
}
/* stage 3 */
if (r != -1) {
z[n++] = 1 + '0';
}
z[n] = '\0';
ReverseArray(z);
return z;
}
200 * 1000 * 1000--> Careful with using narrow constants to build wide values.(size_t)200 * 1000 * 1000is more portable. \$\endgroup\$