diff options
| author | Franklin Wei <me@fwei.tk> | 2018-05-18 20:51:00 -0400 |
|---|---|---|
| committer | Franklin Wei <me@fwei.tk> | 2018-05-18 20:51:00 -0400 |
| commit | b5fe0bd4a9896c54445b2c9e33fe65b9fe3cd74f (patch) | |
| tree | ba5523a2be8255d71c63fbd8a28a1dcbe6e7f4a6 | |
| parent | b7d50370731a52431582b3dc9074f5db6648370b (diff) | |
| download | yacas-b5fe0bd4a9896c54445b2c9e33fe65b9fe3cd74f.zip yacas-b5fe0bd4a9896c54445b2c9e33fe65b9fe3cd74f.tar.gz yacas-b5fe0bd4a9896c54445b2c9e33fe65b9fe3cd74f.tar.bz2 yacas-b5fe0bd4a9896c54445b2c9e33fe65b9fe3cd74f.tar.xz | |
add basic integration
| -rw-r--r-- | yacas.c | 64 |
1 files changed, 57 insertions, 7 deletions
@@ -34,13 +34,13 @@ struct expression { }; } __attribute__((packed)); -enum { OP_POW = 0, OP_MUL, OP_DIV, OP_ADD, OP_SUB, OP_DIFF, OP_ASSIGN, OP_EQUALS, OP_LAST, /* not a real operator: */ OP_LPAREN }; +enum { OP_POW = 0, OP_MUL, OP_DIV, OP_ADD, OP_SUB, OP_DIFF, OP_INT, OP_ASSIGN, OP_EQUALS, OP_LAST, /* not a real operator: */ OP_LPAREN }; enum { T_CONST = 0, T_VAR, T_SUBEXPR, T_SPECFUNC }; enum { FN_LOG = 0, FN_EXP, FN_SIN, FN_COS, FN_TAN, FN_CSC, FN_SEC, FN_COT, FN_ASIN, FN_ACOS, FN_ATAN, FN_ACSC, FN_ASEC, FN_ACOT, FN_ABS, FN_NEGATE, FN_SQRT, FN_LAST }; enum { RIGHT, LEFT }; const char *op_names[] = { - "^", "*", "/", "+", "-", "diff", "=", "==", "none", "(" + "^", "*", "/", "+", "-", "diff", "int", "=", "==", "none", "(" }; const char *type_names[] = { @@ -66,6 +66,7 @@ bool check_boolean(const char *varname); double eval_numexpr(struct expression *expr); double eval_numexpr_and_free(struct expression *expr); struct expression *diff(struct expression *expr, const char *var); +struct expression *integrate(struct expression *expr, const char *var); struct expression *dup_expr(struct expression *expr); struct expression *eval_expr(struct expression *expr); struct expression *simp(struct expression *expr); @@ -171,6 +172,7 @@ int expr_prec(struct expression expr) case OP_EQUALS: return 1; case OP_DIFF: + case OP_INT: return 2; case OP_ADD: case OP_SUB: @@ -235,6 +237,13 @@ struct expression *diff_and_free(struct expression *expr, const char *var) return ret; } +struct expression *integrate_and_free(struct expression *expr, const char *var) +{ + struct expression *ret = integrate(expr, var); + free_expr(expr); + return ret; +} + /* simplify as much as possible, while freeing original */ struct expression *simp_and_free_max(struct expression *expr) { @@ -673,6 +682,12 @@ struct expression *eval_op(int op, struct expression *lexpr, struct expression * fail("diff operator must take variable as second operand"); } } + else if(op == OP_INT) + { + struct expression *result = integrate_and_free(eval_expr(lexpr), rexpr->varname); + if(!result) + return new_op(op, dup_expr(lexpr), dup_expr(rexpr)); + } else if(op == OP_ASSIGN) { if(lexpr->type != T_VAR) @@ -928,8 +943,9 @@ struct expression *simp(struct expression *expr) } return new_op(expr->subexpr.op, simp(expr->subexpr.left), simp(expr->subexpr.right)); case OP_DIFF: - assert(expr->subexpr.right->type == T_VAR); return new_op(OP_DIFF, simp(expr->subexpr.left), dup_expr(expr->subexpr.right)); + case OP_INT: + return new_op(OP_INT, simp(expr->subexpr.left), dup_expr(expr->subexpr.right)); case OP_ASSIGN: return new_op(OP_ASSIGN, dup_expr(expr->subexpr.left), simp(expr->subexpr.right)); case OP_EQUALS: @@ -957,6 +973,37 @@ struct expression *simp(struct expression *expr) } } +/* integrate with respect to "var", treating all other variables as + * CONSTANTS; probably won't work (in which case it will return NULL) */ +struct expression *integrate(struct expression *expr, const char *var) +{ + switch(expr->type) + { + case T_CONST: + return new_op(OP_MUL, new_const(expr->constant), new_var(var)); + case T_VAR: + if(!strcmp(expr->varname, var)) + return new_op(OP_MUL, + new_const(.5), + new_op(OP_POW, + new_var(var), + new_const(2))); + return new_op(OP_MUL, dup_expr(expr), new_var(var)); + case T_SUBEXPR: + switch(expr->subexpr.op) + { + case OP_ADD: + case OP_SUB: + return new_op(expr->subexpr.op, integrate(expr->subexpr.left, var), integrate(expr->subexpr.right, var)); + default: + return NULL; + } + case T_SPECFUNC: + default: + return NULL; + } +} + /* differentiate with respect to "var", returns entirely new object */ struct expression *diff(struct expression *expr, const char *var) { @@ -1026,15 +1073,18 @@ struct expression *diff(struct expression *expr, const char *var) new_specfunc(FN_LOG, dup_expr(expr->subexpr.left))))))); } case OP_DIFF: - //if(expr->subexpr.left->type == T_VAR && !is_var(expr->subexpr.left->varname)) return simp_and_free(new_op(OP_DIFF, dup_expr(expr), new_var(var))); - /*return diff_and_free(diff(expr->subexpr.left, expr->subexpr.right->varname), var);*/ + case OP_INT: + /* d/dx int f(x) dx = f(x) */ + if(expr->subexpr.right->type == T_VAR && !strcmp(expr->subexpr.right->varname, var)) + return simp(expr->subexpr.left); + + /* otherwise return nothing */ + return simp_and_free(new_op(OP_INT, dup_expr(expr), new_var(var))); case OP_ASSIGN: - /* todo: how to make this logical? */ fail("cannot differentiate assignment operator (did you mean == ?)"); case OP_EQUALS: return simp_and_free(new_op(OP_EQUALS, diff(expr->subexpr.left, var), diff(expr->subexpr.right, var))); - /* todo: how to make this logical? */ default: fatal("fall through"); } |