From baaec2a3e04f7a5bd17055516936c23de34c308b Mon Sep 17 00:00:00 2001 From: Krishna Vedala Date: Thu, 2 Apr 2020 12:27:23 -0400 Subject: [PATCH 1/7] brute-force - compute abundant numbers every time --- project_euler/Problem 23/sol1.c | 108 ++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 project_euler/Problem 23/sol1.c diff --git a/project_euler/Problem 23/sol1.c b/project_euler/Problem 23/sol1.c new file mode 100644 index 00000000..1a2b6211 --- /dev/null +++ b/project_euler/Problem 23/sol1.c @@ -0,0 +1,108 @@ + +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +unsigned long MAX_N = 28123; + +/** + * Returns: + * -1 if N is deficient + * 1 if N is abundant + * 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; +} + +/** + * Find the next abundant number after N and not including N + **/ +unsigned long is_abundant(unsigned long N) +{ + return get_perfect_number(N) == 1 ? 1 : 0; +} + +/** + * Find the next abundant number after N and not including N + **/ +unsigned long get_next_abundant(unsigned long N) +{ + unsigned long i; + 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. + * 1 - if yes + * 0 - if not + **/ +char is_sum_of_abundant(unsigned long N) +{ + 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; +} + +int main(int argc, char **argv) +{ + unsigned long sum = 0; + if (argc == 2) + MAX_N = strtoul(argv[1], NULL, 10); + +#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(); +#ifdef _OPENMP +#pragma omp parallel for reduction(+ \ + : sum) schedule(runtime) +#endif + for (unsigned long i = 1; i <= MAX_N; i++) + { + if (!is_sum_of_abundant(i)) + sum += i; + // if (i % 100 == 0) + // printf("... %5lu: %8lu\r", i, sum); + } + clock_t end_time = clock(); + + printf("\nTime taken for final sum: %.4g ms\n", 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + printf("Sum of numbers that cannot be represented as sum of two abundant numbers : %lu\n", sum); + + return 0; +} From 50a113addbc81d756d597ea05c6e1e9d55f78f96 Mon Sep 17 00:00:00 2001 From: Krishna Vedala Date: Thu, 2 Apr 2020 12:28:04 -0400 Subject: [PATCH 2/7] sol1 optimized by storing abundant numbers in a condensed array --- project_euler/Problem 23/sol2.c | 153 ++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 project_euler/Problem 23/sol2.c diff --git a/project_euler/Problem 23/sol2.c b/project_euler/Problem 23/sol2.c new file mode 100644 index 00000000..5633810c --- /dev/null +++ b/project_euler/Problem 23/sol2.c @@ -0,0 +1,153 @@ + +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +/** + * Optimization 1 - compute & store abundant numbers once + * into a look-up array + **/ + +unsigned long MAX_N = 28123; +char *abundant_flags = NULL; + +/** + * Returns: + * -1 if N is deficient + * 1 if N is abundant + * 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; +} + +/** + * Find the next abundant number after N and not including N + **/ +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; +} + +/** + * Find the next abundant number after N and not including N + **/ +unsigned long get_next_abundant(unsigned long N) +{ + unsigned long i; + 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. + * 1 - if yes + * 0 - if not + **/ +char is_sum_of_abundant(unsigned long N) +{ + 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; +} + +int main(int argc, char **argv) +{ + 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); + +#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 */ +#ifdef _OPENMP +#pragma omp for schedule(runtime) +#endif + for (unsigned long 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); + + start_time = clock(); +#ifdef _OPENMP +#pragma omp parallel for reduction(+ \ + : sum) schedule(runtime) +#endif + for (unsigned long i = 1; i < MAX_N; i++) + { + if (!is_sum_of_abundant(i)) + sum += i; + // if (i % 100 == 0) + // printf("... %5lu\n", i); + } + end_time = clock(); + +#ifdef DEBUG + putchar('\n'); +#endif + double t2 = 1e3 * (end_time - start_time) / CLOCKS_PER_SEC; + printf("Time taken for final sum: %.4g ms\nTotal Time taken: %.4g ms\n", t2, t1 + t2); + printf("Sum of numbers that cannot be represented as sum of two abundant numbers : %lu\n", sum); + + free(abundant_flags); + // free(abundant_sum_flags); + + return 0; +} From f34164e601a000c02647e428e6d8710f928cda4b Mon Sep 17 00:00:00 2001 From: Krishna Vedala Date: Thu, 2 Apr 2020 13:15:25 -0400 Subject: [PATCH 3/7] added comments --- project_euler/Problem 23/sol1.c | 6 +++++- project_euler/Problem 23/sol2.c | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/project_euler/Problem 23/sol1.c b/project_euler/Problem 23/sol1.c index 1a2b6211..8c92d9da 100644 --- a/project_euler/Problem 23/sol1.c +++ b/project_euler/Problem 23/sol1.c @@ -38,7 +38,7 @@ char get_perfect_number(unsigned long N) } /** - * Find the next abundant number after N and not including N + * Is the given number an abundant number (1) or not (0) **/ unsigned long is_abundant(unsigned long N) { @@ -64,6 +64,10 @@ unsigned long get_next_abundant(unsigned long N) **/ 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)) { diff --git a/project_euler/Problem 23/sol2.c b/project_euler/Problem 23/sol2.c index 5633810c..36da4ebd 100644 --- a/project_euler/Problem 23/sol2.c +++ b/project_euler/Problem 23/sol2.c @@ -12,6 +12,14 @@ **/ unsigned long MAX_N = 28123; + +/** + * 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; /** @@ -44,7 +52,7 @@ char get_perfect_number(unsigned long N) } /** - * Find the next abundant number after N and not including N + * Is the given number an abundant number (1) or not (0) **/ char is_abundant(unsigned long N) { @@ -58,6 +66,7 @@ char is_abundant(unsigned long 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; @@ -71,6 +80,10 @@ unsigned long get_next_abundant(unsigned long N) **/ 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)) { From ba31018aef4a3d542a5764133b97920ce2aa4689 Mon Sep 17 00:00:00 2001 From: Krishna Vedala Date: Thu, 2 Apr 2020 13:23:51 -0400 Subject: [PATCH 4/7] time computation inside the loop & print loop info --- project_euler/Problem 23/sol1.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/project_euler/Problem 23/sol1.c b/project_euler/Problem 23/sol1.c index 8c92d9da..e7145946 100644 --- a/project_euler/Problem 23/sol1.c +++ b/project_euler/Problem 23/sol1.c @@ -91,21 +91,25 @@ int main(int argc, char **argv) printf("Not using parallleization!\n"); #endif - clock_t start_time = clock(); + clock_t dt = 0; #ifdef _OPENMP #pragma omp parallel for reduction(+ \ : sum) schedule(runtime) #endif for (unsigned long i = 1; i <= MAX_N; i++) { + clock_t start_time = clock(); if (!is_sum_of_abundant(i)) sum += i; - // if (i % 100 == 0) - // printf("... %5lu: %8lu\r", i, sum); - } - clock_t end_time = clock(); + clock_t end_time = clock(); + dt += end_time - start_time; - printf("\nTime taken for final sum: %.4g ms\n", 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + printf("... %5lu: %8lu\r", i, sum); + if (i % 100 == 0) + fflush(stdout); + } + + printf("Time taken: %.4g ms\n", 1e3 * dt / CLOCKS_PER_SEC); printf("Sum of numbers that cannot be represented as sum of two abundant numbers : %lu\n", sum); return 0; From 3598708121dbda86b7378c85d9a5e52dc57fcafa Mon Sep 17 00:00:00 2001 From: Krishna Vedala Date: Thu, 2 Apr 2020 13:25:26 -0400 Subject: [PATCH 5/7] faster parallleization --- project_euler/Problem 23/sol2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/project_euler/Problem 23/sol2.c b/project_euler/Problem 23/sol2.c index 36da4ebd..f05e5c80 100644 --- a/project_euler/Problem 23/sol2.c +++ b/project_euler/Problem 23/sol2.c @@ -140,12 +140,14 @@ int main(int argc, char **argv) start_time = clock(); #ifdef _OPENMP -#pragma omp parallel for reduction(+ \ - : sum) schedule(runtime) +#pragma omp for schedule(runtime) private(start_time, end_time) #endif for (unsigned long i = 1; i < MAX_N; i++) { if (!is_sum_of_abundant(i)) +#ifdef _OPENMP +#pragma omp critical +#endif sum += i; // if (i % 100 == 0) // printf("... %5lu\n", i); From fa24b792a78a459b6968365afd28fedc01e59c17 Mon Sep 17 00:00:00 2001 From: Krishna Vedala Date: Thu, 2 Apr 2020 13:26:54 -0400 Subject: [PATCH 6/7] move time computation inside loop + comments --- project_euler/Problem 23/sol2.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/project_euler/Problem 23/sol2.c b/project_euler/Problem 23/sol2.c index f05e5c80..9ee09498 100644 --- a/project_euler/Problem 23/sol2.c +++ b/project_euler/Problem 23/sol2.c @@ -57,7 +57,7 @@ char get_perfect_number(unsigned long N) 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; + return abundant_flags[N >> 3] & (1 << (N & 7)) ? 1 : 0; /* optimized modulo operation */ } /** @@ -105,6 +105,11 @@ int main(int argc, char **argv) * 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()); @@ -138,31 +143,38 @@ int main(int argc, char **argv) double t1 = 1e3 * (end_time - start_time) / CLOCKS_PER_SEC; printf("Time taken to get abundant numbers: %.4g ms\n", t1); - start_time = clock(); + clock_t t2 = 0; #ifdef _OPENMP #pragma omp for schedule(runtime) private(start_time, end_time) #endif for (unsigned long i = 1; i < MAX_N; i++) { + start_time = clock(); if (!is_sum_of_abundant(i)) #ifdef _OPENMP #pragma omp critical #endif sum += i; - // if (i % 100 == 0) - // printf("... %5lu\n", i); + end_time = clock(); +#ifdef _OPENMP +#pragma omp critical +#endif + t2 += end_time - start_time; + + printf("... %5lu: %8lu\r", i, sum); + if (i % 100 == 0) + fflush(stdout); } - end_time = clock(); #ifdef DEBUG putchar('\n'); #endif - double t2 = 1e3 * (end_time - start_time) / CLOCKS_PER_SEC; - printf("Time taken for final sum: %.4g ms\nTotal Time taken: %.4g ms\n", t2, t1 + t2); + 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); - // free(abundant_sum_flags); return 0; } From 64fe9b0718a61f322e8c98660770910428a36233 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Thu, 2 Apr 2020 17:27:59 +0000 Subject: [PATCH 7/7] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index b3907e20..4152c54d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -242,6 +242,9 @@ * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/Problem%2015/sol1.c) * Problem 16 * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/Problem%2016/sol1.c) + * Problem 23 + * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/Problem%2023/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/Problem%2023/sol2.c) ## Searching * [Binary Search](https://github.com/TheAlgorithms/C/blob/master/searching/Binary_Search.c)