diff --git a/.gitignore b/.gitignore index 74ab857f..bb4f20a6 100644 --- a/.gitignore +++ b/.gitignore @@ -18,11 +18,10 @@ csharp/*/obj csharp/*/bin **/TestResults docs/_build -rust/target +*/target **/.coverage **/.coverage.* **/coverage **/dist/* -docs/_static/test-js.html javascript/src/lib/fallbacks -java/target \ No newline at end of file +docs/languages*.svg \ No newline at end of file diff --git a/README.rst b/README.rst index 10de4c58..e32f8001 100644 --- a/README.rst +++ b/README.rst @@ -80,16 +80,16 @@ Olivia's Project Euler Solutions +------------+----------------------------+--------+-------------------+ | JavaScript | Node 12+ |br| | 25 | |JavaScript| |br| | | | Bun 1.0+ |br| | | |Js-Cov| |br| | -| | Browser [2]_ | | |CodeQL| |br| | +| | Browser [#]_ | | |CodeQL| |br| | | | | | |ESLint| | +------------+----------------------------+--------+-------------------+ | Python | CPython 3.6+ |br| | 79 | |Python| |br| | | | Pypy 3.6+ |br| | | |Py-Cov| |br| | | | GraalPy 23.1+ |br| | | |CodeQL| |br| | -| | Browser [3]_ | | |PythonLint| | +| | Browser [#]_ | | |PythonLint| | +------------+----------------------------+--------+-------------------+ | Rust | 1.69+ |br| | 28 | |Rust| |br| | -| | Browser [4]_ | | |Rs-Cov| |br| | +| | Browser [#]_ | | |Rs-Cov| |br| | | | | | |RustClippy| | +------------+----------------------------+--------+-------------------+ @@ -106,11 +106,11 @@ Olivia's Project Euler Solutions click here! .. [1] This is the earliest standard the MSVC explicitly supports. -.. [2] While these solutions do run in most browsers, they need to be bundled with WebPack 5.93+ & Babel 7.25+ first, +.. [#] While these solutions do run in most browsers, they need to be bundled with WebPack 5.93+ & Babel 7.25+ first, and these tests not yet automated as in Nodejs and Bun. To run these tests yourself, |test-js-link| -.. [3] While these solutions do run in most browsers, they need to be bundled with Pyodide 0.26.2+ first, and these +.. [#] While these solutions do run in most browsers, they need to be bundled with Pyodide 0.26.2+ first, and these tests are not yet automated as in CPython and pypy. To run these tests yourself, |test-py-link| -.. [4] While these solutions will run in most browsers, they need to be bundled with wasm-pack 0.2+ first, and these +.. [#] While these solutions will run in most browsers, they need to be bundled with wasm-pack 0.2+ first, and these tests are not yet automated as on non-web platforms. To run these tests yourself, |test-rs-link| Coverage diff --git a/c/src/include/bcd.h b/c/src/include/bcd.h index 741f0e16..2bdfec29 100644 --- a/c/src/include/bcd.h +++ b/c/src/include/bcd.h @@ -20,13 +20,41 @@ typedef struct { size_t decimal_digits; bool negative : 1; bool zero : 1; + bool even : 1; + bool constant : 1; } BCD_int; + +const BCD_int BCD_two = { + .digits = (packed_BCD_pair[]) {2}, + .bcd_digits = 1, + .decimal_digits = 1, + .even = true, + .constant = true +}; // note that non-specified values are initialized to NULL or 0 + + +const BCD_int BCD_one = { + .digits = (packed_BCD_pair[]) {1}, + .bcd_digits = 1, + .decimal_digits = 1, + .constant = true +}; // note that non-specified values are initialized to NULL or 0 + + +const BCD_int BCD_zero = { + .zero = true, + .even = true, + .constant = true +}; // note that non-specified values are initialized to NULL or 0 + void free_BCD_int(BCD_int x); inline void free_BCD_int(BCD_int x) { - free(x.digits); - x.digits = NULL; - x.bcd_digits = x.decimal_digits = x.negative = x.zero = 0; + if (!x.constant) { + free(x.digits); + x.digits = NULL; + x.bcd_digits = x.decimal_digits = x.negative = x.zero = 0; + } } BCD_int new_BCD_int(uintmax_t a, bool negative) { @@ -539,6 +567,12 @@ inline BCD_int shift_bcd_right(BCD_int a, uintmax_t tens) { return div_bcd_pow_10(a, tens); } +void iadd_bcd(BCD_int *const x, const BCD_int y) { + BCD_int ret = add_bcd(*x, y); + free_BCD_int(*x); + *x = ret; +} + uintmax_t bcd_to_unsigned(BCD_int a) { if (a.zero) return 0; diff --git a/c/src/include/macros.h b/c/src/include/macros.h index 972aca79..3688efca 100644 --- a/c/src/include/macros.h +++ b/c/src/include/macros.h @@ -65,6 +65,10 @@ #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif +#ifndef swap + #define swap(x, y, T) do { T SWAP = x; x = y; y = SWAP; } while (0) +#endif + #if !(CL_COMPILER || TCC_COMPILER) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) diff --git a/c/src/p0022.c b/c/src/p0022.c index 42c2243b..02a305e7 100644 --- a/c/src/p0022.c +++ b/c/src/p0022.c @@ -1,17 +1,17 @@ -/** - * Project Euler Problem 22 - * - * I know that this could be done faster with a traditional for loop, but I wanted - * to see if iterators were reasonably possible in C, since it makes the prime - * number infrastructure a lot easier to set up. - * - * Problem: - * - * If we list all the natural numbers below 10 that are multiples of 3 or 5, we - * get 3, 5, 6 and 9. The sum of these multiples is 23. - * - * Find the sum of all the multiples of 3 or 5 below 1000. - */ +/* +Project Euler Problem 22 + +I know that this could be done faster with a traditional for loop, but I wanted +to see if iterators were reasonably possible in C, since it makes the prime +number infrastructure a lot easier to set up. + +Problem: + +If we list all the natural numbers below 10 that are multiples of 3 or 5, we +get 3, 5, 6 and 9. The sum of these multiples is 23. + +Find the sum of all the multiples of 3 or 5 below 1000. +*/ #ifndef EULER_P0022 #define EULER_P0022 #include diff --git a/c/src/p0025.c b/c/src/p0025.c new file mode 100644 index 00000000..d1274c39 --- /dev/null +++ b/c/src/p0025.c @@ -0,0 +1,54 @@ +/* +Project Euler Problem 25 + +Problem: + +The Fibonacci sequence is defined by the recurrence relation: + + Fn = Fn−1 + Fn−2, where F1 = 1 and F2 = 1. + +Hence the first 12 terms will be: + + F1 = 1 + F2 = 1 + F3 = 2 + F4 = 3 + F5 = 5 + F6 = 8 + F7 = 13 + F8 = 21 + F9 = 34 + F10 = 55 + F11 = 89 + F12 = 144 + +The 12th term, F12, is the first term to contain three digits. + +What is the index of the first term in the Fibonacci sequence to contain 1000 digits? +*/ +#ifndef EULER_P0025 +#define EULER_P0025 +#include +#include "include/bcd.h" + +unsigned long long p0025() { + unsigned long long answer = 2; + BCD_int a = BCD_one, b = BCD_one; + while (b.decimal_digits < 1000) { + iadd_bcd(&a, b); + swap(a, b, BCD_int); + answer++; + } + free_BCD_int(a); + free_BCD_int(b); + return answer; +} + +#ifndef UNITY_END +int main(int argc, char const *argv[]) { + unsigned long long answer = p0025(); + printf("%llu\n", answer); + return 0; +} +#endif +#endif diff --git a/c/src/p0030.c b/c/src/p0030.c new file mode 100644 index 00000000..ab6313dd --- /dev/null +++ b/c/src/p0030.c @@ -0,0 +1,47 @@ +/* +Project Euler Problem 30 + +Problem: + +Surprisingly there are only three numbers that can be written as the sum of fourth powers of their digits: + + 1634 = 1^4 + 6^4 + 3^4 + 4^4 + 8208 = 8^4 + 2^4 + 0^4 + 8^4 + 9474 = 9^4 + 4^4 + 7^4 + 4^4 + +As 1 = 1^4 is not a sum it is not included. + +The sum of these numbers is 1634 + 8208 + 9474 = 19316. + +Find the sum of all the numbers that can be written as the sum of fifth powers of their digits. +*/ +#ifndef EULER_P0030 +#define EULER_P0030 +#include +#include "include/digits.h" + +unsigned long long p0030() { + unsigned long long answer = 0, sum, tmp; + for (unsigned long long i = 2; i < 1000000; i++) { + digit_counter dc = digits(i); + sum = 0; + while (!dc.exhausted) { + tmp = next(dc); + sum += tmp * tmp * tmp * tmp * tmp; + } + if (sum == i) { + answer += i; + } + free_digit_counter(dc); + } + return answer; +} + +#ifndef UNITY_END +int main(int argc, char const *argv[]) { + unsigned long long answer = p0030(); + printf("%llu\n", answer); + return 0; +} +#endif +#endif diff --git a/c/test.c b/c/test.c index 690f4994..9ced1bdf 100644 --- a/c/test.c +++ b/c/test.c @@ -19,6 +19,8 @@ #include "src/p0017.c" #include "src/p0020.c" #include "src/p0022.c" +#include "src/p0025.c" +#include "src/p0030.c" #include "src/p0034.c" #include "src/p0076.c" #include "src/p0836.c" @@ -48,6 +50,8 @@ const Answer answers[] = { {17, 21124, p0017}, {20, 648, p0020}, {22, 871198282, p0022}, + {25, 4782, p0025}, + {30, 443839, p0030}, {34, 40730, p0034}, {76, 190569291, (unsigned long long (*)()) p0076}, }; diff --git a/c/test_euler.py b/c/test_euler.py index aad73a72..aff51c37 100644 --- a/c/test_euler.py +++ b/c/test_euler.py @@ -25,6 +25,8 @@ *range(1, 18), 20, 22, + 25, + 30, 34, 76, 836, diff --git a/docs/index.rst b/docs/index.rst index fc051ea9..cb5f2853 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -124,7 +124,7 @@ Problems Solved +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`24` | | | | | |:py-d:`0024`|:rs-d:`0024`| +-----------+------------+------------+------------+------------+------------+------------+------------+ -|:prob:`25` | | | | | |:py-d:`0025`| | +|:prob:`25` |:c-i:`0025` | | | | |:py-d:`0025`| | +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`27` | | | | |:js-d:`0027`|:py-d:`0027`|:rs-d:`0027`| +-----------+------------+------------+------------+------------+------------+------------+------------+ @@ -132,7 +132,7 @@ Problems Solved +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`29` | | | | | |:py-d:`0029`| | +-----------+------------+------------+------------+------------+------------+------------+------------+ -|:prob:`30` | | | | | |:py-d:`0030`| | +|:prob:`30` |:c-d:`0030` | | | | |:py-d:`0030`| | +-----------+------------+------------+------------+------------+------------+------------+------------+ |:prob:`31` | | | | | |:py-d:`0031`| | +-----------+------------+------------+------------+------------+------------+------------+------------+ diff --git a/docs/src/c/lib/bcd.rst b/docs/src/c/lib/bcd.rst index 5e79565f..982d332d 100644 --- a/docs/src/c/lib/bcd.rst +++ b/docs/src/c/lib/bcd.rst @@ -83,6 +83,10 @@ It was also a good exercise in x86 assembly, as several portions are accellerate Returns ``x // 10**tens``. +.. c:function:: void iadd_bcd(BCD_int *const x, const BCD_int y) + + Transforms ``x`` to be ``x + y`` without needing to make a new assignment. + .. c:function:: signed char cmp_bcd(BCD_int x, BCD_int y) Returns 1 if ``x > y``, -1 if ``y > x``, and otherwise 0. diff --git a/docs/src/c/p0025.rst b/docs/src/c/p0025.rst new file mode 100644 index 00000000..ad5cd4ec --- /dev/null +++ b/docs/src/c/p0025.rst @@ -0,0 +1,25 @@ +C Implementation of Problem 25 +============================== + +View source code :source:`c/src/p0025.c` + +Includes +-------- + +- `bcd.h <./lib/bcd.html>`__ + +Solution +-------- + +.. c:function:: unsigned long long p0025() + +.. c:function:: int main(int argc, char const *argv[]) + + .. note:: + + This function is only present in the Python test runner, or when compiling as a standalone program. + It is not present when compiling for the Unity test runner. + +.. literalinclude:: ../../../c/src/p0025.c + :language: C + :linenos: diff --git a/docs/src/c/p0030.rst b/docs/src/c/p0030.rst new file mode 100644 index 00000000..2f97e8d6 --- /dev/null +++ b/docs/src/c/p0030.rst @@ -0,0 +1,25 @@ +C Implementation of Problem 30 +============================== + +View source code :source:`c/src/p0030.c` + +Includes +-------- + +- `digits.h <./lib/digits.html>`__ + +Solution +-------- + +.. c:function:: unsigned long long p0030() + +.. c:function:: int main(int argc, char const *argv[]) + + .. note:: + + This function is only present in the Python test runner, or when compiling as a standalone program. + It is not present when compiling for the Unity test runner. + +.. literalinclude:: ../../../c/src/p0030.c + :language: C + :linenos: