From 3d3d0159a904d4db8c3ac777ac2f9859b094879d Mon Sep 17 00:00:00 2001 From: Ishan Pranav Date: Fri, 26 Jan 2024 14:15:41 -0500 Subject: [PATCH] Improve id0021 and id0023 using new libraries --- Makefile | 24 +++++++-------- lib/divisor_iterator.c | 13 -------- lib/divisor_iterator.h | 18 +++-------- lib/factor_iterator.c | 70 ++++++++++++++++++++++++++++++++++++++++++ lib/factor_iterator.h | 59 +++++++++++++++++++++++++++++++++++ lib/list.c | 18 +++++------ lib/list.h | 8 ++--- lib/sieve.c | 10 +----- src/id0003.c | 32 ++++++++----------- src/id0012.c | 32 +++++-------------- src/id0014.c | 4 +-- src/id0021.c | 21 +++++++++---- src/id0023.c | 18 ++++++++--- 13 files changed, 208 insertions(+), 119 deletions(-) create mode 100644 lib/factor_iterator.c create mode 100644 lib/factor_iterator.h diff --git a/Makefile b/Makefile index f904e19..234438d 100644 --- a/Makefile +++ b/Makefile @@ -28,11 +28,6 @@ miller_rabin_primality_test.o: \ lib/primality_tests/miller_rabin_primality_test.h $(CC) $(CFLAGS) -c $< -o $@ -sieve_primality_test.o: \ - lib/primality_tests/sieve_primality_test.c \ - lib/primality_tests/sieve_primality_test.h - $(CC) $(CFLAGS) -c $< -o $@ - boolean_set.o: lib/boolean_set.c lib/boolean_set.h $(CC) $(CFLAGS) -c $< -o $@ @@ -42,6 +37,9 @@ divisor_iterator.o: lib/divisor_iterator.c lib/divisor_iterator.h euler.o: lib/euler.c lib/euler.h $(CC) $(CFLAGS) -c $< -o $@ +factor_iterator.o: lib/factor_iterator.c lib/factor_iterator.h + $(CC) $(CFLAGS) -c $< -o $@ + list.o: lib/list.c lib/list.h $(CC) $(CFLAGS) -c $< -o $@ @@ -72,8 +70,8 @@ id0001.o: src/id0001.c euler.o id0002.o: src/id0002.c euler.o $(CC) $(CFLAGS) $< -o $@ euler.o -id0003.o: src/id0003.c euler.o $(SIEVE_O) - $(CC) $(CFLAGS) $< -o $@ euler.o $(SIEVE_O) -lm +id0003.o: src/id0003.c euler.o factor_iterator.o $(SIEVE_O) + $(CC) $(CFLAGS) $< -o $@ euler.o factor_iterator.o $(SIEVE_O) -lm id0004.o: src/id0004.c euler.o $(CC) $(CFLAGS) $< -o $@ euler.o @@ -99,8 +97,8 @@ id0010.o: src/id0010.c euler.o $(SIEVE_O) id0011.o: src/id0011.c euler.o $(CC) $(CFLAGS) $< -o $@ euler.o -id0012.o: src/id0012.c divisor_iterator.o euler.o $(SIEVE_O) - $(CC) $(CFLAGS) $< -o $@ divisor_iterator.o euler.o $(SIEVE_O) -lm +id0012.o: src/id0012.c euler.o factor_iterator.o $(SIEVE_O) + $(CC) $(CFLAGS) $< -o $@ euler.o factor_iterator.o $(SIEVE_O) -lm id0013.o: src/id0013.c euler.o $(CC) $(CFLAGS) $< -o $@ euler.o @@ -126,14 +124,14 @@ id0019.o: src/id0019.c euler.o id0020.o: src/id0020.c euler.o lp_string.o series.o $(CC) $(CFLAGS) $< -o $@ euler.o lp_string.o series.o -lgmp -id0021.o: src/id0021.c divisor_iterator.o euler.o - $(CC) $(CFLAGS) $< -o $@ divisor_iterator.o euler.o -lm +id0021.o: src/id0021.c euler.o factor_iterator.o $(SIEVE_O) + $(CC) $(CFLAGS) $< -o $@ euler.o factor_iterator.o $(SIEVE_O) -lm id0022.o: src/id0022.c euler.o $(LP_STRING_COLLECTION_O) $(CC) $(CFLAGS) $< -o $@ euler.o $(LP_STRING_COLLECTION_O) -id0023.o: src/id0023.c boolean_set.o divisor_iterator.o euler.o list.o - $(CC) $(CFLAGS) $< -o $@ boolean_set.o divisor_iterator.o euler.o list.o -lm +id0023.o: src/id0023.c euler.o factor_iterator.o $(SIEVE_O) + $(CC) $(CFLAGS) $< -o $@ euler.o factor_iterator.o $(SIEVE_O) -lm id0024.o: src/id0024.c euler.o list.o permutation_iterator.o $(CC) $(CFLAGS) $< -o $@ euler.o list.o permutation_iterator.o diff --git a/lib/divisor_iterator.c b/lib/divisor_iterator.c index b896363..45669d1 100644 --- a/lib/divisor_iterator.c +++ b/lib/divisor_iterator.c @@ -58,16 +58,3 @@ void divisor_next(DivisorIterator iterator) iterator->state = DIVISOR_ITERATOR_STATE_INITIAL; } } - -long long divisor_sum(long long n) -{ - int result = 0; - struct DivisorIterator it; - - for (divisor_begin(&it, n); !divisor_end(&it); divisor_next(&it)) - { - result += it.current; - } - - return result; -} diff --git a/lib/divisor_iterator.h b/lib/divisor_iterator.h index df0d523..99aa06f 100644 --- a/lib/divisor_iterator.h +++ b/lib/divisor_iterator.h @@ -17,34 +17,26 @@ struct DivisorIterator typedef struct DivisorIterator* DivisorIterator; /** - * Provides an iterator over the divisors of `n`. + * Provides an iterator over the proper divisors of `n`. * * @param iterator the iterator. - * @param n the number whose proper divisors to enumerate. + * @param n the number whose divisors to enumerate. */ void divisor_begin(DivisorIterator iterator, long long n); /** * Returns a value indicating whether the iterator can advance to the next - * divisor. + * proper divisor. * - * @param iterator + * @param iterator the iterator. * @return `true` if the iterator can successfully advance to the next divisor; * `false` if there are no more divisors. */ bool divisor_end(DivisorIterator iterator); /** - * Advances the iterator to the next divisor. + * Advances the iterator to the next proper divisor. * * @param iterator the iterator. */ void divisor_next(DivisorIterator iterator); - -/** - * Computes the sum of the proper divisors of a natural number. - * - * @param n the number whose proper divisors to sum. - * @return The sum of the proper divisors of `n`. -*/ -long long divisor_sum(long long n); diff --git a/lib/factor_iterator.c b/lib/factor_iterator.c new file mode 100644 index 0000000..25e2b62 --- /dev/null +++ b/lib/factor_iterator.c @@ -0,0 +1,70 @@ +// Licensed under the MIT License. + +#include +#include "factor_iterator.h" + +void factor_begin(FactorIterator iterator, long long n, Sieve primes) +{ + iterator->remainder = n; + + sieve_begin(&iterator->iterator, primes); + factor_next(iterator); +} + +bool factor_end(FactorIterator iterator) +{ + return !iterator->remainder; +} + +void factor_next(FactorIterator iterator) +{ + if (iterator->remainder == 1) + { + iterator->current = *iterator->iterator.current; + iterator->remainder = 0; + iterator->currentCount = 1; + + return; + } + + while (iterator->remainder % *iterator->iterator.current != 0) + { + sieve_next(&iterator->iterator); + } + + iterator->current = *iterator->iterator.current; + iterator->remainder /= iterator->current; + iterator->currentCount = 1; + + while (iterator->remainder % iterator->current == 0) + { + iterator->remainder /= iterator->current; + iterator->currentCount++; + } +} + +int factor_divisor_count(long long n, Sieve primes) +{ + int result = 1; + struct FactorIterator it; + + for (factor_begin(&it, n, primes); !factor_end(&it); factor_next(&it)) + { + result *= it.currentCount + 1; + } + + return result; +} + +int factor_divisor_sum(long long n, Sieve primes) +{ + int result = 1; + struct FactorIterator it; + + for (factor_begin(&it, n, primes); !factor_end(&it); factor_next(&it)) + { + result *= (pow(it.current, it.currentCount + 1) - 1) / (it.current - 1); + } + + return result; +} diff --git a/lib/factor_iterator.h b/lib/factor_iterator.h new file mode 100644 index 0000000..85e4430 --- /dev/null +++ b/lib/factor_iterator.h @@ -0,0 +1,59 @@ +// Licensed under the MIT License. + +#include "sieve_iterator.h" + +/** Iterates over the prime factors of a positive integer. */ +struct FactorIterator +{ + struct SieveIterator iterator; + long long current; + long long remainder; + int currentCount; +}; + +/** Iterates over the prime factors of a positive integer. */ +typedef struct FactorIterator* FactorIterator; + +/** + * Provides an iterator over the prime factors of `n`. + * + * @param iterator the iterator. + * @param n the number whose factors to enumerate. + * @param primes the prime sequence. +*/ +void factor_begin(FactorIterator iterator, long long n, Sieve primes); + +/** + * Returns a value indicating whether the iterator can advance to the next prime + * factor. + * + * @param iterator the iterator. + * @return `true` if the iterator can successfully advance to the next factor; + * `false` if there are no more factors. +*/ +bool factor_end(FactorIterator iterator); + +/** + * Advances the iterator to the next prime factor. + * + * @param iterator the iterator. +*/ +void factor_next(FactorIterator iterator); + +/** + * Returns the number of divisors of a positive integer. + * + * @param n the number whose divisors to count. + * @param primes the prime sequence. + * @return The number of divisors of `n`. +*/ +int factor_divisor_count(long long n, Sieve primes); + +/** + * Computes the sum of the divisors of a positive integer. + * + * @param n the number whose divisors to sum. + * @param primes the prime sequence. + * @return The sum of the divisors of `n`. +*/ +int factor_divisor_sum(long long n, Sieve primes); diff --git a/lib/list.c b/lib/list.c index 74d5670..a7610a5 100644 --- a/lib/list.c +++ b/lib/list.c @@ -96,15 +96,6 @@ static int long_long_compare(Object left, Object right) return 0; } -void list_sort(List instance) -{ - qsort( - instance->begin, - instance->end - instance->begin, - sizeof * instance->begin, - long_long_compare); -} - void list_reverse(List instance) { if (instance->begin == instance->end) @@ -124,6 +115,15 @@ void list_reverse(List instance) } } +void list_sort(List instance) +{ + qsort( + instance->begin, + instance->end - instance->begin, + sizeof * instance->begin, + long_long_compare); +} + bool list_equals(List left, List right) { size_t length = left->end - left->begin; diff --git a/lib/list.h b/lib/list.h index 7becce6..e3c6cfd 100644 --- a/lib/list.h +++ b/lib/list.h @@ -64,18 +64,18 @@ bool list_contains(List instance, long long item); void list_clear(List instance); /** - * Sorts the elements in the list. + * Reverses the order of the elements in the list. * * @param instance the `List` instance. */ -void list_sort(List instance); +void list_reverse(List instance); /** - * Reverses the order of the elements in the list. + * Sorts the elements in the list. * * @param instance the `List` instance. */ -void list_reverse(List instance); +void list_sort(List instance); /** * Determines whether two lists are equal. diff --git a/lib/sieve.c b/lib/sieve.c index f0d180b..b22e552 100644 --- a/lib/sieve.c +++ b/lib/sieve.c @@ -15,15 +15,7 @@ static Exception sieve_extend(Sieve instance, long long max) long long end = sqrt(max); - for (long long* p = instance->primes.begin; p < instance->primes.end; p++) - { - for (long long n = *p * *p; n < max; n += *p) - { - instance->composites.begin[n - 2] = true; - } - } - - for (long long m = instance->max; m <= end; m++) + for (long long m = 2; m <= end; m++) { if (instance->composites.begin[m - 2]) { diff --git a/src/id0003.c b/src/id0003.c index c4e5518..6fd5512 100644 --- a/src/id0003.c +++ b/src/id0003.c @@ -4,24 +4,7 @@ #include #include "../lib/euler.h" -#include "../lib/sieve_iterator.h" - -static long long math_max_prime_factor(Sieve primes, long long n) -{ - long long result = -1; - struct SieveIterator it; - - for (sieve_begin(&it, primes); n != 1; sieve_next(&it)) - { - while (n % *it.current == 0) - { - result = *it.current; - n /= *it.current; - } - } - - return result; -} +#include "../lib/factor_iterator.h" int main(void) { @@ -31,7 +14,16 @@ int main(void) euler_ok(); - long long max = math_max_prime_factor(&primes, 600851475143ll); + struct FactorIterator it; + + factor_begin(&it, 600851475143ll, &primes); + + while (!factor_end(&it)) + { + factor_next(&it); + } - return euler_submit(3, max, start); + finalize_sieve(&primes); + + return euler_submit(3, it.current, start); } diff --git a/src/id0012.c b/src/id0012.c index 5cd3d77..18bba4b 100644 --- a/src/id0012.c +++ b/src/id0012.c @@ -4,44 +4,26 @@ #include #include "../lib/euler.h" -#include "../lib/sieve_iterator.h" - -int math_divisors(Sieve primes, long n) -{ - int product = 1; - struct SieveIterator it; - - for (sieve_begin(&it, primes); n != 1; sieve_next(&it)) - { - int sum = 1; - - while (n % *it.current == 0) - { - sum++; - n /= *it.current; - } - - product *= sum; - } - - return product; -} +#include "../lib/factor_iterator.h" int main(void) { - long i = 1; - long n = 1; struct Sieve primes; clock_t start = clock(); Exception ex = sieve(&primes, 0); euler_ok(); - while (math_divisors(&primes, n) <= 500) + int i = 7; + long n = 28; + + while (factor_divisor_count(n, &primes) <= 500) { i++; n = n + i; } + finalize_sieve(&primes); + return euler_submit(12, n, start); } diff --git a/src/id0014.c b/src/id0014.c index 8ade921..6e38780 100644 --- a/src/id0014.c +++ b/src/id0014.c @@ -6,9 +6,9 @@ int main(void) { - clock_t start = clock(); - int maxLength = 10; int result = 0; + int maxLength = 10; + clock_t start = clock(); for (long i = 13; i < 1000000l; i++) { diff --git a/src/id0021.c b/src/id0021.c index 0592c55..2cbcad8 100644 --- a/src/id0021.c +++ b/src/id0021.c @@ -3,28 +3,36 @@ // Amicable Numbers #include -#include "../lib/divisor_iterator.h" #include "../lib/euler.h" #include "../lib/exception.h" +#include "../lib/factor_iterator.h" int main(void) { - long sum = 0; clock_t start = clock(); int* d = malloc(sizeof * d * 9998); + Exception ex; if (!d) { - Exception ex = EXCEPTION_OUT_OF_MEMORY; + ex = EXCEPTION_OUT_OF_MEMORY; euler_ok(); } - + + struct Sieve primes; + + ex = sieve(&primes, 0); + + euler_ok(); + for (int a = 2; a < 10000; a++) { - d[a - 2] = divisor_sum(a); + d[a - 2] = factor_divisor_sum(a, &primes) - a; } + int sum = 0; + for (int a = 2; a < 10000; a++) { int b = d[a - 2]; @@ -36,6 +44,7 @@ int main(void) } free(d); - + finalize_sieve(&primes); + return euler_submit(21, sum, start); } diff --git a/src/id0023.c b/src/id0023.c index e1867e9..7b50ad4 100644 --- a/src/id0023.c +++ b/src/id0023.c @@ -3,10 +3,8 @@ // Non-Abundant Sums #include -#include "../lib/boolean_set.h" -#include "../lib/divisor_iterator.h" #include "../lib/euler.h" -#include "../lib/list.h" +#include "../lib/factor_iterator.h" bool math_is_abundant_sum(int n, List list, BooleanSet set) { @@ -40,10 +38,19 @@ int main(void) euler_ok(); + struct Sieve primes; + + ex = sieve(&primes, 0); + + euler_ok(); + for (int n = 12; n < 28123; n++) { - set.begin[n - 2] = divisor_sum(n) > n; - + if ((factor_divisor_sum(n, &primes) - n) > n) + { + set.begin[n - 2] = true; + } + if (set.begin[n - 2]) { list_add(&abundants, n); @@ -62,6 +69,7 @@ int main(void) finalize_list(&abundants); finalize_boolean_set(&set); + finalize_sieve(&primes); return euler_submit(23, sum, start); }