double compute(int size, unsigned int form, double_string *ds, counter *ops) { rpn_stack s = malloc(sizeof(rpn_stack)); unsigned int shift = form; int ops_p = 0; double v = 0.0; int i = 0; for(i = 0 ; i < size; i++) { if((shift & 0x01) == 1) { rpn_push(&s, ds->value); ds = ds->next; } else { switch(ops->values[ops_p++]) { case 0 : v = rpn_calc(&s, '+'); break; case 1 : v = rpn_calc(&s, '-'); break; case 2 : v = rpn_calc(&s, '*'); break; case 3 : v = rpn_calc(&s, '/'); break; } } shift = shift >> 1; } rpn_destroy(s); return v; }
enum RPNError rpn_run(byte *rpnExpr, word rpnLen, Float *yValue, Float *xValue) { rpnStackIndex = 0; word reader = 0; while (reader < rpnLen) { byte op = rpnExpr[reader++]; switch (op) { case RPN_VAR: // put a copy of the independent variable's value on rpnStack if (rpnStackIndex == RPN_STACK_SIZE) return RPN_ERR_OVERFLOW; rpn_push(xValue); break; case RPN_FUNC: { if (rpnStackIndex < 1) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 1)); byte funcIndex = rpnExpr[reader++]; if (funcIndex == UNKNOWN_FUNCTION_INDEX) { --reader; return RPN_ERR_INVALID_FUNC; } // Check the argument (FP0). void *check = knownFunctions[funcIndex].checkArgFuncPtr; if (check) { enum RPNError e = (*check)(); // check FP0 if (e != RPN_ERR_NONE) return e; } // Argument (FP0) is valid. Apply the function to it. (*knownFunctions[funcIndex].evalFuncPtr)(); --rpnStackIndex; rpn_push(FP0ADDR); // push the result break; } case RPN_NUM: // put FP that follows on rpnStack if (rpnStackIndex == RPN_STACK_SIZE) return RPN_ERR_OVERFLOW; rpn_push((Float *) (rpnExpr + reader)); // push 6-byte accumulator reader += sizeof(Float); break; case RPN_ADD: case RPN_SUB: case RPN_MUL: if (rpnStackIndex < 2) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 2)); fp1load(rpn_get(rpnStackIndex - 1)); switch (op) { case RPN_ADD: fpadd(); break; case RPN_SUB: fpsub(); break; case RPN_MUL: fpmul(); break; } rpnStackIndex -= 2; rpn_push(FP0ADDR); // push the result break; case RPN_DIV: { if (rpnStackIndex < 2) return RPN_ERR_UNDERFLOW; // Check if the divisor is too close to zero Float *divisor = rpn_get(rpnStackIndex - 1); fp0load(divisor); fpabs(); if (fpcmp(&verySmall) < 0) // if abs(divisor) too small return RPN_ERR_DIV_BY_ZERO; // avoid enormous (and unusable) quotient fp0load(divisor); fp1load(rpn_get(rpnStackIndex - 2)); // dividend fpdiv(); rpnStackIndex -= 2; rpn_push(FP0ADDR); // push the result break; } case RPN_NEG: if (rpnStackIndex < 1) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 1)); fpneg(); --rpnStackIndex; rpn_push(FP0ADDR); // push the result break; case RPN_POW: if (rpnStackIndex < 2) return RPN_ERR_UNDERFLOW; fp0load(rpn_get(rpnStackIndex - 1)); // power fp1load(rpn_get(rpnStackIndex - 2)); // base if (fp1sgn() < 0 && ! fpisint()) // if negative base and non-int power return RPN_ERR_POW_OF_NEG; fppow(); rpnStackIndex -= 2; rpn_push(FP0ADDR); // push the result break; default: --reader; return RPN_ERR_UNEXPECTED; } } if (rpnStackIndex != 1) return RPN_ERR_INVALID_EXPR; #if 0 fp0load(rpn_get(0)); char buf[FPSTRBUFSIZ]; char *decimalResult = fpstr(buf); printf("Result: [%s]\n", decimalResult); #endif fpcpy(yValue, rpn_get(0)); return RPN_ERR_NONE; }
double compute_verbose(int size, unsigned int form, double_string *ds, counter *ops) { rpn_stack s = malloc(sizeof(rpn_stack)); unsigned int shift = form; int ops_p = 0; double v = 0.0; double p1, p2; int op_last = 0; int i = 0; for(i = 0 ; i < size; i++) { if((shift & 0x01) == 1) { rpn_push(&s, ds->value); ds = ds->next; op_last = 0; } else { switch(ops->values[ops_p++]) { case 0 : p1 = s->value; p2 = s->p->value; v = rpn_calc(&s, '+'); if(op_last == 0) printf("%.2f + %.2f = %.2f\n", p1, p2, v); else printf(" + %.2f = %.2f\n", p2, v); op_last = 1; break; case 1 : p1 = s->value; p2 = s->p->value; v = rpn_calc(&s, '-'); if(op_last == 0) printf("%.2f - %.2f = %.2f\n", p1, p2, v); else printf(" - %.2f = %.2f\n", p2, v); op_last = 1; break; case 2 : p1 = s->value; p2 = s->p->value; v = rpn_calc(&s, '*'); if(op_last == 0) printf("%.2f * %.2f = %.2f\n", p1, p2, v); else printf(" * %.2f = %.2f\n", p2, v); op_last = 1; break; case 3 : p1 = s->value; p2 = s->p->value; v = rpn_calc(&s, '/'); if(op_last == 0) printf("%.2f / %.2f = %.2f\n", p1, p2, v); else printf(" / %.2f = %.2f\n", p2, v); op_last = 1; break; } } shift = shift >> 1; } rpn_destroy(s); return v; }