TheAlgorithms-C/project_euler/problem_20/sol1.c

174 lines
4.2 KiB
C
Raw Normal View History

2020-04-02 07:24:12 +08:00
#include <stdio.h>
#include <stdlib.h>
2020-04-02 07:58:45 +08:00
#include <time.h>
2020-04-02 07:24:12 +08:00
/**
* 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);
2020-04-02 07:24:12 +08:00
}
#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;
2020-04-02 07:41:57 +08:00
unsigned long num_digits = 0;
2020-04-02 07:24:12 +08:00
if (argc == 2)
N = atoi(argv[1]);
2020-04-02 07:58:45 +08:00
clock_t start_time = clock();
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
2020-04-02 07:35:45 +08:00
unsigned int tmp = ptr->value * i + carry;
2020-04-02 07:24:12 +08:00
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
}
2020-04-02 07:58:45 +08:00
clock_t end_time = clock();
2020-04-02 07:24:12 +08:00
#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;
2020-04-02 07:41:57 +08:00
num_digits++;
2020-04-02 07:24:12 +08:00
} while (ptr); /* after coming to units place, there will be no valid ptr */
2020-04-02 07:58:45 +08:00
printf("\nTime taken: %.4g millisecond\n",
1e3 * (end_time - start_time) / CLOCKS_PER_SEC);
printf(
"Digit Sum = %lu\tNumber of digits = %lu\tStorage space = %.3gkb\t \n",
sum_digits, num_digits, num_digits * sizeof(big_int) / 1024.0);
2020-04-02 07:24:12 +08:00
remove_digits((big_int *)ptr0, -1);
return 0;
}