Skip to content

Commit

Permalink
Document RPN
Browse files Browse the repository at this point in the history
  • Loading branch information
ishanpranav committed Feb 26, 2024
1 parent 60b2d5c commit 5df74d7
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 57 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
40 changes: 40 additions & 0 deletions lib/operator.h
Original file line number Diff line number Diff line change
@@ -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);
6 changes: 6 additions & 0 deletions lib/operators/add_operator.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed under the MIT License.

double add_operator(double left, double right)
{
return left + right;
}
6 changes: 6 additions & 0 deletions lib/operators/div_operator.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed under the MIT License.

double div_operator(double left, double right)
{
return (int)left / (int)right;
}
6 changes: 6 additions & 0 deletions lib/operators/multiply_operator.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed under the MIT License.

double multiply_operator(double left, double right)
{
return left * right;
}
6 changes: 6 additions & 0 deletions lib/operators/subtract_operator.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Licensed under the MIT License.

double subtract_operator(double left, double right)
{
return left - right;
}
30 changes: 22 additions & 8 deletions lib/rpn.c
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
// Licensed under the MIT License.

#include <ctype.h>
#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];
}
19 changes: 16 additions & 3 deletions lib/rpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
16 changes: 0 additions & 16 deletions lib/rpn_operator.c

This file was deleted.

29 changes: 0 additions & 29 deletions lib/rpn_operator.h

This file was deleted.

130 changes: 130 additions & 0 deletions src/id0093.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Licensed under the MIT License.

// Arithmetic Expressions

#include <stdarg.h>
#include <string.h>
#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);
}
40 changes: 40 additions & 0 deletions src/id0094.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed under the MIT License.

// Right Triangles with Integer Coordinates

#include <math.h>
#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);
}
10 changes: 9 additions & 1 deletion src/lc0150.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 5df74d7

Please sign in to comment.