From 5df74d7e1ebb4a6c53f18836cd6e91b036a69463 Mon Sep 17 00:00:00 2001 From: Ishan Pranav Date: Sun, 25 Feb 2024 20:15:10 -0500 Subject: [PATCH] Document RPN --- Makefile | 4 + lib/operator.h | 40 +++++++++ lib/operators/add_operator.c | 6 ++ lib/operators/div_operator.c | 6 ++ lib/operators/multiply_operator.c | 6 ++ lib/operators/subtract_operator.c | 6 ++ lib/rpn.c | 30 +++++-- lib/rpn.h | 19 ++++- lib/rpn_operator.c | 16 ---- lib/rpn_operator.h | 29 ------- src/id0093.c | 130 ++++++++++++++++++++++++++++++ src/id0094.c | 40 +++++++++ src/lc0150.c | 10 ++- 13 files changed, 285 insertions(+), 57 deletions(-) create mode 100644 lib/operator.h create mode 100644 lib/operators/add_operator.c create mode 100644 lib/operators/div_operator.c create mode 100644 lib/operators/multiply_operator.c create mode 100644 lib/operators/subtract_operator.c delete mode 100644 lib/rpn_operator.c delete mode 100644 lib/rpn_operator.h create mode 100644 src/id0093.c create mode 100644 src/id0094.c diff --git a/Makefile b/Makefile index 009e222..97f5106 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,7 @@ all: \ id0074$(E) id0075$(E) id0076$(E) id0077$(E) id0078$(E) id0079$(E) \ id0080$(E) id0081$(E) id0082$(E) id0083$(E) id0084$(E) id0085$(E) \ id0086$(E) id0087$(E) id0089$(E) id0091$(E) id0092$(E) id0093$(E) \ + id0094$(E) libeuler$(A): $(call RECURSE,lib,*.c) $(RM) *.o @@ -315,5 +316,8 @@ id0092$(E): src/id0092.c libeuler$(A) id0093$(E): src/id0093.c libeuler$(A) $(CC) $(CFLAGS) $< -o $@ $(LEULER) $(LM) +id0094$(E): src/id0094.c libeuler$(A) + $(CC) $(CFLAGS) $< -o $@ $(LEULER) $(LM) + clean: $(RM) *$(A) *.o diff --git a/lib/operator.h b/lib/operator.h new file mode 100644 index 0000000..13506a0 --- /dev/null +++ b/lib/operator.h @@ -0,0 +1,40 @@ +// Licensed under the MIT License. + +/** Represents a binary mathematical operator in reverse Polish notation. */ +typedef double (*Operator)(double left, double right); + +/** + * Adds two operands. + * + * @param left the left addend. + * @param right the right addend. + * @return The sum of `left` and `right`. +*/ +double add_operator(double left, double right); + +/** + * Subtracts one operand from an other. + * + * @param left the left addend. + * @param right the right addend. + * @return The difference of `left` and `right`. +*/ +double subtract_operator(double left, double right); + +/** + * Multiplies two operands. + * + * @param left the left factor. + * @param right the right factor. + * @return The product of `left` and `right`. +*/ +double multiply_operator(double left, double right); + +/** + * Performs integer division between two operands. + * + * @param left the dividend. + * @param right the divisor. + * @return The integer quotient of `left div right`. +*/ +double div_operator(double left, double right); diff --git a/lib/operators/add_operator.c b/lib/operators/add_operator.c new file mode 100644 index 0000000..9148b27 --- /dev/null +++ b/lib/operators/add_operator.c @@ -0,0 +1,6 @@ +// Licensed under the MIT License. + +double add_operator(double left, double right) +{ + return left + right; +} diff --git a/lib/operators/div_operator.c b/lib/operators/div_operator.c new file mode 100644 index 0000000..507135e --- /dev/null +++ b/lib/operators/div_operator.c @@ -0,0 +1,6 @@ +// Licensed under the MIT License. + +double div_operator(double left, double right) +{ + return (int)left / (int)right; +} diff --git a/lib/operators/multiply_operator.c b/lib/operators/multiply_operator.c new file mode 100644 index 0000000..9fdd99b --- /dev/null +++ b/lib/operators/multiply_operator.c @@ -0,0 +1,6 @@ +// Licensed under the MIT License. + +double multiply_operator(double left, double right) +{ + return left * right; +} diff --git a/lib/operators/subtract_operator.c b/lib/operators/subtract_operator.c new file mode 100644 index 0000000..d21dbb4 --- /dev/null +++ b/lib/operators/subtract_operator.c @@ -0,0 +1,6 @@ +// Licensed under the MIT License. + +double subtract_operator(double left, double right) +{ + return left - right; +} diff --git a/lib/rpn.c b/lib/rpn.c index 283aa55..17a0d85 100644 --- a/lib/rpn.c +++ b/lib/rpn.c @@ -1,29 +1,43 @@ // Licensed under the MIT License. +#include #include "rpn.h" #include "rpn_operator.h" -int rpn_evaluate(String tokens[], size_t length) +static RpnOperator rpn_get_operator(Rpn instance, String operator) +{ + switch (operator[0]) + { + case '+': return instance->add; + case '-': return instance->subtract; + case '*': return instance->multiply; + case '/': return instance->divide; + } + + return NULL; +} + +double rpn_evaluate(Rpn instance, String tokens[], size_t length) { size_t sp = 0; - int* stack = malloc(length * sizeof * stack); + double* stack = malloc(length * sizeof * stack); for (size_t i = 0; i < length; i++) { if (tokens[i][1] != '\0' || isdigit(tokens[i][0])) { - stack[sp] = atoi(tokens[i]); + stack[sp] = atof(tokens[i]); sp++; continue; } - stack[sp - 2] = rpn_operator_apply( - tokens[i][0], - stack[sp - 2], - stack[sp - 1]); + double left = stack[sp - 2]; + double right = stack[sp - 1]; + + stack[sp - 2] = rpn_get_operator(instance, tokens[i])(left, right); sp--; } - + return stack[0]; } diff --git a/lib/rpn.h b/lib/rpn.h index 30721fa..83761fa 100644 --- a/lib/rpn.h +++ b/lib/rpn.h @@ -2,11 +2,24 @@ #include "euler.h" +/** Represents a reverse Polish notation parser. */ +struct Rpn +{ + double (*add)(double left, double right); + double (*subtract)(double left, double right); + double (*multiply)(double left, double right); + double (*divide)(double left, double right); +}; + +/** Represents a reverse Polish notation parser. */ +typedef struct Rpn* Rpn; + /** * Evaluates a sequence of tokens in reverse Polish notation. * - * @param tokens the sequence of tokens consisting of operators and operands. - * @param length the number of tokens. + * @param instance the `Rpn` instance. + * @param tokens the sequence of tokens consisting of operators and operands. + * @param length the number of tokens. * @return The evaluated expression. */ -int rpn_evaluate(String tokens[], size_t length); +int rpn_evaluate(Rpn instance, String tokens[], size_t length); diff --git a/lib/rpn_operator.c b/lib/rpn_operator.c deleted file mode 100644 index bce217d..0000000 --- a/lib/rpn_operator.c +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed under the MIT License. - -#include "rpn_operator.h" - -int rpn_operator_apply(RpnOperator value, int left, int right) -{ - switch (value) - { - case RPN_OPERATOR_ADD: return left + right; - case RPN_OPERATOR_SUBTRACT: return left - right; - case RPN_OPERATOR_MULTIPLY: return left * right; - case RPN_OPERATOR_DIVIDE: return left / right; - } - - return 0; -} diff --git a/lib/rpn_operator.h b/lib/rpn_operator.h deleted file mode 100644 index bbdbdaa..0000000 --- a/lib/rpn_operator.h +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed under the MIT License. - -/** Represents a binary mathematical operator in reverse Polish notation. */ -enum RpnOperator -{ - /** The addition operator. */ - RPN_OPERATOR_ADD = '+', - - /** The subtraction operator. */ - RPN_OPERATOR_SUBTRACT = '-', - - /** The multiplication operator. */ - RPN_OPERATOR_MULTIPLY = '*', - - /** The division operator. */ - RPN_OPERATOR_DIVIDE = '/' -}; - -/** Represents a binary mathematical operator in reverse Polish notation. */ -typedef enum RpnOperator RpnOperator; - -/** - * Applies the given binary operator on two operands. - * - * @param left the left operand. - * @param right the right operand. - * @return The result of applying the given `value` on `left` and `right`. -*/ -int rpn_operator_apply(RpnOperator value, int left, int right); diff --git a/src/id0093.c b/src/id0093.c new file mode 100644 index 0000000..89d7afb --- /dev/null +++ b/src/id0093.c @@ -0,0 +1,130 @@ +// Licensed under the MIT License. + +// Arithmetic Expressions + +#include +#include +#include "../lib/combination_iterator.h" +#include "../lib/euler.h" +#include "../lib/permutation_iterator.h" +#include "../lib/rpn.h" + +void rpn_evaluate_formatted(bool results[], String format, ...) +{ + va_list argl; + char buffer[8]; + char longBuffer[14]; + char* expression[7]; + + va_start(argl, format); + vsprintf(buffer, format, argl); + va_end(argl); + + for (int i = 0; i < 7; i++) + { + longBuffer[i + i] = buffer[i]; + longBuffer[i + i + 1] = '\0'; + expression[i] = longBuffer + i + i; + } + + int result = rpn_evaluate(expression, 7); + + if (result > 0 && !results[result]) + { + results[result] = true; + } +} + +int math_arithmetic_expression_length(int digits[]) +{ + bool results[1001] = { 0 }; + struct PermutationIterator it; + + for (permutation_begin( + &it, + digits, + 4, + 1, + char_comparer); + !it.end; + permutation_next(&it)) + { + char* operators = "+-*/"; + + for (char* p = operators; *p; p++) + { + for (char* q = operators; *q; q++) + { + for (char* r = operators; *r; r++) + { + rpn_evaluate_formatted( + results, + "%d%d%d%d%c%c%c", + digits[0], digits[1], digits[2], digits[3], *p, *q, *r); + rpn_evaluate_formatted( + results, + "%d%d%d%c%d%c%c", + digits[0], digits[1], digits[2], *p, digits[3], *q, *r); + rpn_evaluate_formatted( + results, + "%d%d%d%c%c%d%c", + digits[0], digits[1], digits[2], *p, *q, digits[3], *r); + rpn_evaluate_formatted( + results, + "%d%d%c%d%d%c%c", + digits[0], digits[1], *p, digits[2], digits[3], *q, *r); + rpn_evaluate_formatted( + results, + "%d%d%c%d%c%d%c", + digits[0], digits[1], *p, digits[2], *q, digits[3], *r); + } + } + } + } + + int result = 0; + + for (int i = 1; i < 1000; i++) + { + if (!results[i]) + { + break; + } + + result++; + } + + return result; +} + +int main(void) +{ + int maxLength = 0; + int digits[4]; + int maxDigits[4] = { 0 }; + struct CombinationIterator it; + clock_t start = clock(); + + for (combination_begin(&it, digits, 9, 4); + !it.end; + combination_next(&it)) + { + int length = math_arithmetic_expression_length(digits); + + if (length > maxLength) + { + maxLength = length; + + memcpy(maxDigits, digits, sizeof digits); + } + } + + int result = 0; + + for (int i = 0; i < 4; i++) + { + result = result * 10 + maxDigits[i]; + } + + return euler_submit(92, result, start); +} diff --git a/src/id0094.c b/src/id0094.c new file mode 100644 index 0000000..4a48ba4 --- /dev/null +++ b/src/id0094.c @@ -0,0 +1,40 @@ +// Licensed under the MIT License. + +// Right Triangles with Integer Coordinates + +#include +#include "../lib/euler.h" + +int main(void) +{ + long x = 2; + long y = 1; + long sum = -2; + clock_t start = clock(); + + for (;;) + { + long long p = 2 * (3 * y - x) * (3 * y - x); + + if (p > 100000000) + { + break; + } + + sum += p; + p = 4 * x * x; + + if (p <= 100000000) + { + sum += p; + } + + long nextX = x + x + 3 * y; + long nextY = x + y + y; + + x = nextX; + y = nextY; + } + + return euler_submit(94, sum, start); +} diff --git a/src/lc0150.c b/src/lc0150.c index 6d51892..0f7eab4 100644 --- a/src/lc0150.c +++ b/src/lc0150.c @@ -6,5 +6,13 @@ int evalRPN(String tokens[], int tokensSize) { - return rpn_evaluate(tokens, tokensSize); + struct Rpn rpn = + { + .add = operator_add, + .subtract = , + .multiply = rpn_multiply, + .divide = rpn_div + }; + + return rpn_evaluate(&rpn, tokens, tokensSize); }