From: Laurent Mazet Date: Sun, 5 Feb 2023 22:28:58 +0000 (+0100) Subject: stack functions X-Git-Tag: v1.0~3 X-Git-Url: https://secure.softndesign.org/git/?a=commitdiff_plain;h=226557a3339d4f3f98547eef6deeb4ec512366d1;p=calc.git stack functions --- diff --git a/calc.c b/calc.c index 3a78ddb..3410436 100644 --- a/calc.c +++ b/calc.c @@ -394,6 +394,9 @@ int main (int argc, char *argv[]) // test: echo -e 'prog (1, {set (1, 2), push (arg (1)), show});\ncall (1, 10);\nshow\ndel (1)' | calc.exe -n | grep -q 'stack:$' // test: echo -e 'prog (1, {set (1, 2), push (arg (1)), show});\ncall (1, 10);\nlen' | calc.exe -n | grep -q '=> 0' // test: echo -e 'prog (1, {mem (2), sto (1, arg (1) - rcl (1) / 2)})\ncall (1, 1)\ncall (1, 2)\ncall (1, 3)\nprog (1, {mem (2), sto (2, rcl (1)), sto (1, arg (1)), rcl (2)})\ncall (1, 10)' | calc.exe -n | grep -q '=> 2.25' +// test: echo -e 'set (1, 2, -5, 6, -8, 9, -2, 23, 4)\nord\nshow' | calc.exe | grep -q 'stack: -8 -5 -2 1 2 4 6 9 23' +// test: echo -e 'set (1, 2, -5, 6, -8, 9, -2, 23, 4)\nmin (5, -3)\nmax (-1)\nmin\nmean\nmed\nmax\nprod\nsum\nvar' | calc.exe | awk 'BEGIN { split("9 -3 -1 -8 3.33333 2 23 -794880 30 73.3333", v) } /=>/ { for (i in v) if ($2 == v[i]) n++ } END { exit n != 10 }' +// test: echo -e 'min\nmean\nmed\nmax\nprod\nsum\nvar\nord' | calc.exe -n | grep -c error | xargs test 8 = // Gauss sequence // test: echo -e '{sto (1, 0), sto (10, 0), while (inc (10) < 100, {sto (1, rcl (1) + rcl (10)), print (rcl (1))})};' | calc.exe | grep -q '=> 5050' diff --git a/parser.c b/parser.c index ed2a4f0..326dad3 100644 --- a/parser.c +++ b/parser.c @@ -137,7 +137,7 @@ keyword_t operators[NB_OPERATORS] = { { "|", Or, 2, 1, -2} }; -#define NB_FUNCTIONS 42 +#define NB_FUNCTIONS 50 keyword_t functions[NB_FUNCTIONS] = { { "sqrt", Sqr, 1, 4, 5}, { "pow", Pow, 2, 3, 5}, @@ -180,7 +180,15 @@ keyword_t functions[NB_FUNCTIONS] = { { "push", Push, 1, 4, 5}, { "put", Put, 2, 3, 5}, { "set", Set, MAX_ARGS, 3, 5}, - { "show", Show, 0, 4, 5}, + { "show", Show, 0, 4, 5}, + { "max", Max, 2, 3, 5}, + { "mean", Mean, 2, 4, 5}, + { "med", Median, 0, 3, 5}, + { "min", Min, 2, 3, 5}, + { "ord", Order, 0, 3, 5}, + { "prod", Prod, 0, 4, 5}, + { "sum", Sum, 0, 3, 5}, + { "var", Variance, 2, 3, 5}, }; #define NB_CONSTANTS 3 @@ -577,6 +585,14 @@ void print_element (element_t *root, int level) case Put: func = "Put"; break; case Set: func = "Set"; break; case Show: func = "Show"; break; + case Max: func = "Maximum"; break; + case Mean: func = "Mean"; break; + case Median: func = "Median"; break; + case Min: func = "Minimum"; break; + case Order: func = "Order"; break; + case Prod: func = "Product"; break; + case Sum: func = "Sum"; break; + case Variance: func = "Variance"; break; } fprintf (stdout, "Function: %s\n", func); @@ -967,7 +983,9 @@ void savestring (int id, char *string) // free ((programs + n)->string); //} - (programs + n)->string = strdup (string); + if (string) { + (programs + n)->string = strdup (string); + } } void del (int id) @@ -1107,6 +1125,140 @@ void show (void) fprintf (stdout, "\n"); } +/* stack functions */ + +double max () +{ + double ret = 0; + int i; + if (stack_size < 1) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + ret = stack[0]; + for (i = 1; i < stack_size; i++) { + if (stack[i] > ret) { + ret = stack[i]; + } + } + return ret; +} + +double mean () +{ + double ret = 0; + int i; + if (stack_size < 1) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + for (i = 0; i < stack_size; i++) { + ret += stack[i]; + } + return ret / stack_size; +} + +double min () +{ + double ret = 0; + int i; + if (stack_size < 1) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + ret = stack[0]; + for (i = 1; i < stack_size; i++) { + if (stack[i] < ret) { + ret = stack[i]; + } + } + return ret; +} + +void order () +{ + int i, j; + if (stack_size < 1) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return; + } + for (i = 0; i < stack_size - 1; i++) { + int done = 0; + for (j = 0; j < stack_size - 1; j++) { + if (stack[j] > stack[j + 1]) { + double tmp = stack[j]; + stack[j] = stack[j + 1]; + stack[j + 1] = tmp; + done = 1; + } + } + if (done == 0) { + break; + } + } +} + +double median () +{ + double ret = 0; + if (stack_size < 3) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + double *tmp = (double *) callocordie (stack_size, sizeof (double)); + memcpy (tmp, stack, stack_size * sizeof (double)); + order (); + ret = stack[(stack_size - 1)/ 2]; + memcpy (stack, tmp, stack_size * sizeof (double)); + free (tmp); + return ret; +} + +double prod () +{ + double ret = 1; + int i; + if (stack_size < 1) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + for (i = 0; i < stack_size; i++) { + ret *= stack[i]; + } + return ret; +} + +double sum () +{ + double ret = 0; + int i; + if (stack_size < 1) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + for (i = 0; i < stack_size; i++) { + ret += stack[i]; + } + return ret; +} + +double variance () +{ + double ret = 0; + double m = 0; + int i; + if (stack_size < 2) { + VERBOSE (WARNING, fprintf (stdout, "error not enough element in stack (%d)\n", stack_size)); + return 0; + } + m = mean (); + for (i = 0; i < stack_size; i++) { + ret += (stack[i] - m) * (stack[i] - m); + } + return ret / stack_size; +} + + /* help message */ void help (void) @@ -1134,6 +1286,8 @@ void help (void) fprintf (stdout, " arg call del edit ls prog\n"); fprintf (stdout, "stack management:"); fprintf (stdout, " get len pop push put set show\n"); + fprintf (stdout, "stack func.:"); + fprintf (stdout, " max mean med min ord prod sum var\n"); fprintf (stdout, "control management:"); fprintf (stdout, " help quit\n"); fprintf (stdout, "constants:"); @@ -1250,6 +1404,10 @@ double evaluate_element (element_t *root, char mask) case Pop: case Set: case Show: + case Median: + case Order: + case Prod: + case Sum: break; case While: if (root->ops[0] == NULL) { @@ -1270,6 +1428,14 @@ double evaluate_element (element_t *root, char mask) } op1 = (root->ops[1]) ? evaluate_element (root->ops[1], 0) : answer; break; + case Max: + case Mean: + case Min: + case Variance: + if (root->ops[0]) { + op0 = evaluate_element (root->ops[0], 0); + op1 = (root->ops[1]) ? evaluate_element (root->ops[1], 0) : answer; + } } switch (root->func) { @@ -1356,6 +1522,33 @@ double evaluate_element (element_t *root, char mask) } return set (nb, root->ops); case Show: show (); break; + case Max: + if (root->ops[0]) { + return op0 > op1 ? op0 : op1; + } + return max (); + case Mean: + if (root->ops[0]) { + return (op0 + op1) / 2; + } + return mean (); + case Median: return median (); + case Min: + if (root->ops[0]) { + return op0 < op1 ? op0 : op1; + } + return min (); + case Order: order (); break; + case Prod: return prod (); + case Sum: return sum (); + case Variance: + if (root->ops[0]) { + double m = (op0 + op1) / 2; + op0 -= m; + op1 -= m; + return op0 * op0 + op1 * op1; + } + return variance (); } return 0; diff --git a/parser.h b/parser.h index 8d8a5d4..27bc1e1 100644 --- a/parser.h +++ b/parser.h @@ -23,7 +23,8 @@ typedef enum { And, Or, Not, Cond, While, Code, Print, Prog, Arg, Call, List, Edit, Del, - Get, Length, Pop, Push, Put, Set, Show + Get, Length, Pop, Push, Put, Set, Show, + Max, Mean, Median, Min, Order, Prod, Sum, Variance } func_t; /* keyword type */