-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
/
sol1.c
155 lines (138 loc) · 3.24 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
/**
* \file
* \brief [Problem 401](https://projecteuler.net/problem=401) solution -
* Sum of squares of divisors
* \author [Krishna Vedala](https://github.com/kvedala)
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#ifdef _OPENMP
#include <omp.h>
#endif
#define MOD_LIMIT (uint64_t)1e9 /**< modulo limit */
#define MAX_LENGTH 5000 /**< chunk size of array allocation */
/**
* Check if a number is present in given array
* \param[in] N number to check
* \param[in] D array to check
* \param[in] L length of array
* \returns 1 if present
* \returns 0 if absent
*/
char is_in(uint64_t N, uint64_t *D, uint64_t L)
{
uint64_t i;
for (i = 0; i < L; i++)
{
if (D[i] == N)
{
return 1;
}
}
return 0;
}
/**
* Get all integer divisors of a number
* \param[in] N number to find divisors for
* \param[out] D array to store divisors in
* \returns number of divisors found
*/
uint64_t get_divisors(uint64_t N, uint64_t *D)
{
uint64_t q, r;
int64_t i, num = 0;
if (N == 1)
{
D[0] = 1;
return 1;
}
// search till sqrt(N)
// because after this, the pair of divisors will repeat themselves
for (i = 1; i * i <= N + 1; i++)
{
r = N % i; // get reminder
// reminder = 0 if 'i' is a divisor of 'N'
if (r == 0)
{
q = N / i;
if (!is_in(i, D, num)) // if divisor was already stored
{
D[num] = i;
num++;
}
if (!is_in(q, D, num)) // if divisor was already stored
{
D[num] = q;
num++;
}
}
if (num == MAX_LENGTH)
{ // limit of array reached, allocate more space
D = (uint64_t *)realloc(D, MAX_LENGTH * sizeof(uint64_t) << 1);
}
}
return num;
}
/**
* compute sum of squares of all integer factors of a number
* \param[in] N
* \returns sum of squares
*/
uint64_t sigma2(uint64_t N)
{
uint64_t sum = 0, L;
int64_t i;
uint64_t *D = (uint64_t *)malloc(MAX_LENGTH * sizeof(uint64_t));
L = get_divisors(N, D);
for (i = 1; i < L; i++)
{
uint64_t DD = (D[i] * D[i]) % MOD_LIMIT;
sum += DD;
}
free(D);
return sum % MOD_LIMIT;
}
/**
* sum of squares of factors of numbers
* from 1 thru N
*/
uint64_t sigma(uint64_t N)
{
uint64_t s, sum = 0;
int64_t i;
#ifdef _OPENMP
// parallelize on threads
#pragma omp parallel for reduction(+ : sum)
#endif
for (i = 0; i <= N; i++)
{
s = sigma2(i);
sum += s;
}
return sum % MOD_LIMIT;
}
/** Main function */
int main(int argc, char **argv)
{
uint64_t N = 1000;
if (argc == 2)
{
N = strtoll(argv[1], NULL, 10);
}
else if (argc > 2)
{
fprintf(stderr, "Wrong number of input arguments!\n");
printf("Usage:\t ./sol1.c [N=1000]");
return -1;
}
clock_t start_time = clock();
uint64_t result = sigma(N);
double dtime = clock() - start_time;
printf("N = %" PRIu64 "\nSum: %" PRIu64 "\n", N, result);
printf("Time taken: %.4gms\n", dtime * 1e3 / CLOCKS_PER_SEC);
return 0;
}