-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
Copy pathsol2.c
205 lines (186 loc) · 4.74 KB
/
sol2.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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/**
* \file
* \brief [Problem 23](https://projecteuler.net/problem=23) solution -
* optimization using look-up array
* \author [Krishna Vedala](https://github.com/kvedala)
*
* Optimization applied - compute & store abundant numbers once
* into a look-up array.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifdef _OPENMP
#include <omp.h>
#endif
/**
* This is the global array to be used to store a flag to identify
* if a particular number is abundant (1) or not (0).
* Using a whole byte to store a binary info would be redundant.
* We will use each byte to represent 8 numbers by relying on bits.
* This saves memory required by 1/8
*/
char *abundant_flags = NULL;
/**
* \returns -1 if N is deficient
* \returns 1 if N is abundant
* \returns 0 if N is perfect
*/
char get_perfect_number(unsigned long N)
{
unsigned long sum = 1;
char ret = 0;
for (unsigned long i = 2; i * i <= N; i++)
{
if (N % i == 0)
{
sum += i;
unsigned long tmp = N / i;
if (tmp != i)
{
sum += tmp;
}
}
}
ret = sum == N ? 0 : (sum > N ? 1 : -1);
#ifdef DEBUG
printf("%5lu: %5lu : %d\n", N, sum, ret);
#endif
return ret;
}
/**
* Is the given number an abundant number (1) or not (0)
*/
char is_abundant(unsigned long N)
{
// return abundant_flags[N >> 3] & (1 << N % 8) ? 1 : 0;
return abundant_flags[N >> 3] & (1 << (N & 7))
? 1
: 0; /* optimized modulo operation */
}
/**
* Find the next abundant number after N and not including N
*/
unsigned long get_next_abundant(unsigned long N)
{
unsigned long i;
/* keep checking successive numbers till an abundant number is found */
for (i = N + 1; !is_abundant(i); ++i)
{
;
}
return i;
}
/**
* check if a given number can be represented as a sum
* of two abundant numbers.
* \returns 1 - if yes
* \returns 0 - if not
*/
char is_sum_of_abundant(unsigned long N)
{
/* optimized logic:
* i + j = N where both i and j should be abundant
* hence we can simply check for j = N - i as we loop through i
*/
for (unsigned long i = get_next_abundant(1); i <= (N >> 1);
i = get_next_abundant(i))
{
if (is_abundant(N - i))
{
#ifdef DEBUG
printf("\t%4lu + %4lu = %4lu\n", i, N - i, N);
#endif
return 1;
}
}
return 0;
}
/** Main function */
int main(int argc, char **argv)
{
long MAX_N = 28123; /* Limit of numbers to check */
unsigned long sum = 0;
if (argc == 2)
{
MAX_N = strtoul(argv[1], NULL, 10);
}
/* byte array to store flags to identify abundant numbers
* the flags are identified by bits
*/
abundant_flags = (char *)calloc(MAX_N >> 3, 1);
if (!abundant_flags)
{
perror("Unable to allocate memoey!");
return -1;
}
#ifdef _OPENMP
printf("Using OpenMP parallleization with %d threads\n",
omp_get_max_threads());
#else
printf("Not using parallleization!\n");
#endif
clock_t start_time = clock();
/* Loop to set abundant flags */
long N;
#ifdef _OPENMP
#pragma omp for schedule(runtime)
#endif
for (N = 1; N <= MAX_N; N++)
{
char ret = get_perfect_number(N);
if (ret == 1)
{
// int byte_offset = N % 8, index = N >> 3;
int byte_offset = N & 7, index = N >> 3;
#ifdef _OPENMP
#pragma omp critical
#endif
abundant_flags[index] |= ret << byte_offset;
}
// if (i % 100 == 0)
// printf("... %5lu: %8lu\r", i, sum);
}
clock_t end_time = clock();
double t1 = 1e3 * (end_time - start_time) / CLOCKS_PER_SEC;
printf("Time taken to get abundant numbers: %.4g ms\n", t1);
clock_t t2 = 0;
long i;
#ifdef _OPENMP
#pragma omp parallel for schedule(runtime) reduction(+ : sum)
#endif
for (i = 1; i < MAX_N; i++)
{
clock_t start_time1 = clock();
if (!is_sum_of_abundant(i))
{
// #ifdef _OPENMP
// #pragma omp critical
// #endif
sum += i;
}
clock_t end_time1 = clock();
#ifdef _OPENMP
#pragma omp critical
#endif
t2 += end_time1 - start_time1;
printf("... %5lu: %8lu\r", i, sum);
if (i % 100 == 0)
{
fflush(stdout);
}
}
#ifdef DEBUG
putchar('\n');
#endif
double t22 = 1e3 * t2 / CLOCKS_PER_SEC;
printf("Time taken for final sum: %.4g ms\nTotal Time taken: %.4g ms\n",
t22, t1 + t22);
printf("Memory used: %lu bytes\n", MAX_N >> 3);
printf(
"Sum of numbers that cannot be represented as sum of two abundant "
"numbers : %lu\n",
sum);
free(abundant_flags);
return 0;
}