2020-04-02 07:24:12 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* store arbitratily large integer values
|
|
|
|
* as a linked list of digits.
|
|
|
|
**/
|
|
|
|
typedef struct _big_int
|
|
|
|
{
|
|
|
|
char value; /** tens place (single digit) */
|
|
|
|
struct _big_int *next_digit; /** hundreds place */
|
|
|
|
struct _big_int *prev_digit; /** units place */
|
|
|
|
} big_int;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
void print_digit(const big_int *my_int)
|
|
|
|
{
|
|
|
|
printf("\tValue : %d\n\tNext : %p\n\tPrev : %p\n", my_int->value, my_int->next_digit, my_int->prev_digit);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function that allocates memory to add another
|
|
|
|
* digit at the MSB
|
|
|
|
**/
|
|
|
|
big_int *add_digit(big_int *digit, char value)
|
|
|
|
{
|
|
|
|
if (digit == NULL)
|
|
|
|
{
|
|
|
|
digit = (big_int *)malloc(sizeof(big_int));
|
|
|
|
if (!digit)
|
|
|
|
{
|
|
|
|
perror("Unable to allocate memory!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
digit->value = value;
|
|
|
|
digit->next_digit = NULL;
|
|
|
|
digit->prev_digit = NULL;
|
|
|
|
|
|
|
|
return digit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (digit->next_digit)
|
|
|
|
{
|
|
|
|
digit->next_digit->value = value;
|
|
|
|
return digit->next_digit;
|
|
|
|
}
|
|
|
|
|
|
|
|
digit->next_digit = (big_int *)malloc(sizeof(big_int));
|
|
|
|
if (digit->next_digit == NULL)
|
|
|
|
{
|
|
|
|
perror("Unable to allocate memory!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
digit->next_digit->value = value;
|
|
|
|
digit->next_digit->next_digit = NULL;
|
|
|
|
digit->next_digit->prev_digit = digit;
|
|
|
|
return digit->next_digit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Function to remove digits preceeding the
|
|
|
|
* current digit.
|
|
|
|
**/
|
|
|
|
char remove_digits(big_int *digit, int N)
|
|
|
|
{
|
|
|
|
if (digit == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (digit->next_digit == NULL)
|
|
|
|
{
|
|
|
|
free(digit);
|
|
|
|
digit = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (N > 0)
|
|
|
|
return remove_digits(digit->next_digit, N - 1);
|
|
|
|
|
|
|
|
return remove_digits(digit->next_digit, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
unsigned int N = 5;
|
|
|
|
big_int *ptr = add_digit(NULL, 1); /* start with 1 */
|
|
|
|
const big_int *ptr0 = ptr; /* save the first location */
|
|
|
|
unsigned long sum_digits = 0;
|
|
|
|
|
|
|
|
if (argc == 2)
|
|
|
|
N = atoi(argv[1]);
|
|
|
|
|
2020-04-02 07:26:41 +08:00
|
|
|
for (unsigned int i = 1; i <= N; i++)
|
2020-04-02 07:24:12 +08:00
|
|
|
{
|
|
|
|
int carry = 0;
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("%3d: ", i);
|
|
|
|
#endif
|
|
|
|
ptr = (big_int *)ptr0; /* multiply every digit with i */
|
|
|
|
while (ptr)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("%p\t", ptr);
|
|
|
|
#endif
|
|
|
|
int tmp = ptr->value * i + carry;
|
|
|
|
if (tmp >= 10)
|
|
|
|
{
|
|
|
|
div_t tmp2 = div(tmp, 10);
|
|
|
|
carry = tmp2.quot;
|
|
|
|
tmp = tmp2.rem;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
carry = 0;
|
2020-04-02 07:31:52 +08:00
|
|
|
|
2020-04-02 07:24:12 +08:00
|
|
|
if (carry > 0 && ptr->next_digit == NULL)
|
|
|
|
add_digit(ptr, 0);
|
2020-04-02 07:31:52 +08:00
|
|
|
|
2020-04-02 07:24:12 +08:00
|
|
|
ptr->value = tmp;
|
2020-04-02 07:31:52 +08:00
|
|
|
|
2020-04-02 07:24:12 +08:00
|
|
|
if (i == N)
|
2020-04-02 07:31:52 +08:00
|
|
|
/**
|
|
|
|
* sum digits on the last iteration
|
|
|
|
* this avoid having another loop over all digits
|
|
|
|
**/
|
2020-04-02 07:24:12 +08:00
|
|
|
sum_digits += tmp;
|
2020-04-02 07:31:52 +08:00
|
|
|
|
2020-04-02 07:24:12 +08:00
|
|
|
if (ptr->next_digit)
|
2020-04-02 07:31:52 +08:00
|
|
|
/* more digits available */
|
2020-04-02 07:24:12 +08:00
|
|
|
ptr = ptr->next_digit;
|
|
|
|
else
|
2020-04-02 07:31:52 +08:00
|
|
|
/* no more digits left - reached MSB */
|
2020-04-02 07:24:12 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("ptr = %p\n", ptr);
|
|
|
|
printf("%d! = ", N);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Notice that in the loop above, we make sure that at the end of the loop,
|
|
|
|
* ptr is pointing to the last digit. Thus we can avoid using another loop.
|
|
|
|
**/
|
|
|
|
// ptr = &my_int;
|
|
|
|
// /* move ptr to the MSB digit */
|
|
|
|
// while (ptr->next_digit)
|
|
|
|
// ptr = ptr->next_digit;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
putchar(ptr->value + 0x30); /* convert digit to ASCII char */
|
|
|
|
ptr = ptr->prev_digit;
|
|
|
|
} while (ptr); /* after coming to units place, there will be no valid ptr */
|
|
|
|
printf("\nDigit Sum = %lu\n", sum_digits);
|
|
|
|
|
|
|
|
remove_digits((big_int *)ptr0, -1);
|
|
|
|
return 0;
|
|
|
|
}
|