예제 #1
0
파일: calc.c 프로젝트: stephenpearson/sums
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;
}
예제 #2
0
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;
}
예제 #3
0
파일: calc.c 프로젝트: stephenpearson/sums
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;
}