-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
/
sol1.c
183 lines (160 loc) · 4.46 KB
/
sol1.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/**
* \file
* \brief [Problem 20](https://projecteuler.net/problem=20) solution
* \author [Krishna Vedala](https://github.com/kvedala)
*
* Implementation uses a custom `big_int` structure that can store arbitrarily
* large integer numbers.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.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
/** print a digit from large integer */
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);
}
/** Main function */
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;
unsigned long num_digits = 0;
if (argc == 2)
N = atoi(argv[1]);
clock_t start_time = clock();
for (unsigned int i = 1; i <= N; i++)
{
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
unsigned int tmp = ptr->value * i + carry;
if (tmp >= 10)
{
div_t tmp2 = div(tmp, 10);
carry = tmp2.quot;
tmp = tmp2.rem;
}
else
carry = 0;
if (carry > 0 && ptr->next_digit == NULL)
add_digit(ptr, 0);
ptr->value = tmp;
if (i == N)
/*
* sum digits on the last iteration
* this avoid having another loop over all digits
*/
sum_digits += tmp;
if (ptr->next_digit)
/* more digits available */
ptr = ptr->next_digit;
else
/* no more digits left - reached MSB */
break;
}
#ifdef DEBUG
printf("\n");
#endif
}
clock_t end_time = clock();
#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;
num_digits++;
} while (ptr); /* after coming to units place, there will be no valid ptr */
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);
remove_digits((big_int *)ptr0, -1);
return 0;
}