stack functions
authorLaurent Mazet <mazet@softndesign.org>
Sun, 5 Feb 2023 22:28:58 +0000 (23:28 +0100)
committerLaurent Mazet <mazet@softndesign.org>
Sun, 5 Feb 2023 22:28:58 +0000 (23:28 +0100)
calc.c
parser.c
parser.h

diff --git a/calc.c b/calc.c
index 3a78ddbe35ec19ea134446d81875be659bfa3a8b..34104364b030872bdd6061f55718deee3e35591e 100644 (file)
--- 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'
index ed2a4f03a605328dfc0cd9987a2b3742e434fd2a..326dad384b916b135d27ca3b80c786ce8495f5ee 100644 (file)
--- 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;
index 8d8a5d4350aa4c7b75d829a42ecad9e9b203aaca..27bc1e1843c2fc9f4fbd027de38a3d59b5fe39bc 100644 (file)
--- 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 */