Mathe OpenSource Library für C
-
Guten Morgen,
ich suche eine Library in C womit ich ausdrücke wie:
(11+2)*4^2
berechnen kann, kann mir da jemand weiterhelfen?
-
Ich kann dir zwar keine empfehlen (weil ich nie eine benutzt habe), aber ich kann dir helfen, eine zu finden:
Google: c math parser
-
Ich hab sowas noch hier rumliegen. Es ist zwar nicht ganz für die Bibliotheksform geschrieben - eine vernünftige Fehlerbehandlung wirst du noch einpflegen müssen - aber vielleicht hilft es dir ja weiter. Das ganze implementiert den Shunting-Yard-Algorithmus.
Ich hoffe nur, das Formu nimmt mir so viel Quellcode nicht übel...also:
// token.h #ifndef INCLUDED_TOKEN_H #define INCLUDED_TOKEN_H #include <stddef.h> enum token_type { tok_num, tok_op }; struct token { union { double num; char op; } v; enum token_type type; }; struct token *get_token(char const **pos, struct token *dest); struct token_node { struct token_node *prev; struct token_node *next; struct token val; }; struct token_node *token_node_new (struct token_node *pos, struct token val); void token_node_delete(struct token_node *); struct token_list { struct token_node *head; struct token_node *tail; size_t size; }; void token_list_new (struct token_list *); void token_list_delete(struct token_list *); void token_list_insert (struct token_list *, struct token_node *pos, struct token val); void token_list_push_front(struct token_list *, struct token); void token_list_push_back (struct token_list *, struct token); void token_list_remove (struct token_list *, struct token_node *); struct token token_list_pop_front (struct token_list *); struct token token_list_pop_back (struct token_list *); struct token token_list_peek_front(struct token_list const *); struct token token_list_peek_back (struct token_list const *); #endif
// token.c #include "token.h" #include <ctype.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static char const *const op_chars = "+-*/^()"; struct token *get_token(char const **pos, struct token *dest) { int n; double num; char const *line = *pos; while(line[0] == ' ') { ++line; } if(strchr(op_chars, line[0]) != NULL) { dest->v.op = line[0]; dest->type = tok_op; *pos = line + 1; } else if(sscanf(line, "%lf%n", &num, &n) == 1) { dest->v.num = num; dest->type = tok_num; *pos = line + n; } else { return NULL; } return dest; } struct token_node *token_node_new(struct token_node *pos, struct token val) { struct token_node *n = calloc(1, sizeof(struct token_node)); n->prev = pos->prev; n->next = pos; n->prev->next = n; n->next->prev = n; n->val = val; return n; } void token_node_delete(struct token_node *n) { n->prev->next = n->next; n->next->prev = n->prev; free(n); } void token_list_new(struct token_list *l) { l->size = 0; l->head = calloc(1, sizeof(struct token_node)); l->tail = calloc(1, sizeof(struct token_node)); l->head->next = l->tail->next = l->tail; l->tail->prev = l->head->prev = l->head; } void token_list_delete(struct token_list *l) { while(l->size > 0) { token_list_pop_front(l); } free(l->head); free(l->tail); } void token_list_remove(struct token_list *l, struct token_node *n) { if(l->size > 0) { token_node_delete(n); --l->size; } } struct token token_list_pop_front(struct token_list *l) { struct token tok = token_list_peek_front(l); token_list_remove(l, l->head->next); return tok; } struct token token_list_pop_back(struct token_list *l) { struct token tok = token_list_peek_back(l); token_list_remove(l, l->tail->prev); return tok; } void token_list_insert(struct token_list *l, struct token_node *pos, struct token val) { token_node_new(pos, val); ++l->size; } void token_list_push_back(struct token_list *l, struct token val) { token_list_insert(l, l->tail, val); } void token_list_push_front(struct token_list *l, struct token val) { token_list_insert(l, l->head->next, val); } struct token token_list_peek_front(struct token_list const *l) { return l->head->next->val; } struct token token_list_peek_back(struct token_list const *l) { return l->tail->prev->val; }
// syard.h #ifndef INCLUDED_SYARD_H #define INCLUDED_SYARD_H #include "token.h" struct token_list make_rpn(char const *line); double eval_rpn(struct token_list *rpn); double eval_string(char const *expr); #endif
// syard.c #include "syard.h" #include <math.h> #include <stdio.h> #include <stdlib.h> static int op_pcd(char op) { switch(op) { case '+': case '-': return 0; case '*': case '/': return 1; case '^': return 3; } return -1; } struct token_list make_rpn(char const *line) { struct token_list result; struct token_list stack; struct token tok; char const *pos = line; token_list_new(&result); token_list_new(&stack); while(get_token(&pos, &tok)) { switch(tok.type) { case tok_num: { token_list_push_back(&result, tok); break; } case tok_op: { char op = tok.v.op; if(op == '(') { token_list_push_back(&stack, tok); } else if(op == ')') { while(token_list_peek_back(&stack).v.op != '(') { if(stack.size == 0) { fputs("Mismatched parentheses\n", stderr); exit(-1); } token_list_push_back(&result, token_list_pop_back(&stack)); } token_list_pop_back(&stack); } else { while(op != '^' && stack.size != 0 && op_pcd(op) <= op_pcd(token_list_peek_back(&stack).v.op)) { token_list_push_back(&result, token_list_pop_back(&stack)); } token_list_push_back(&stack, tok); } break; } } } while(stack.size > 0) { if(token_list_peek_back(&stack).v.op == '(') { fputs("Mismatched parentheses\n", stderr); exit(-1); } token_list_push_back(&result, token_list_pop_back(&stack)); } token_list_delete(&stack); return result; } double eval_rpn(struct token_list *q) { struct token_list stack; double r; token_list_new(&stack); while(q->size > 0) { struct token tok = token_list_peek_front(q); switch(tok.type) { case tok_num: { token_list_push_back(&stack, tok ); break; } case tok_op: { struct token operand1, operand2, result; if(stack.size < 2) { fputs("RPN: Zu wenig Zahlen\n", stderr); exit(-1); } operand2 = token_list_pop_back(&stack); operand1 = token_list_pop_back(&stack); result.type = tok_num; switch(tok.v.op) { case '+': result.v.num = operand1.v.num + operand2.v.num; break; case '-': result.v.num = operand1.v.num - operand2.v.num; break; case '*': result.v.num = operand1.v.num * operand2.v.num; break; case '/': result.v.num = operand1.v.num / operand2.v.num; break; case '^': result.v.num = pow(operand1.v.num, operand2.v.num); break; } token_list_push_back(&stack, result); break; } default: fputs("RPN: Unbekannter Token-Typ", stderr); exit(-1); break; } token_list_pop_front(q); } if(stack.size != 1) { fputs("RPN: Zu viel oder zu wenig Zahlen\n", stderr); exit(-1); } r = token_list_peek_back(&stack).v.num; token_list_delete(&stack); return r; } double eval_string(char const *expr) { struct token_list q = make_rpn(expr); double d = eval_rpn(&q); token_list_delete(&q); return d; }
// main.c #include "token.h" #include "syard.h" #include <stdio.h> #include <stdlib.h> #include <math.h> int main(void) { char line[1024]; if(fgets(line, 1024, stdin) != NULL) { printf("%g\n", eval_string(line)); } return 0; }
Und die Makefile:
#!/usr/bin/make TARGET = calc CC = gcc CFLAGS = -Wall -Wextra -pedantic -g LDFLAGS = -lm SRCS = $(wildcard *.c) OBJS = $(SRCS:%.c=%.o) DEPFILE = .depend all: dep $(TARGET) dep: $(DEPFILE) $(DEPFILE): $(SRCS) $(CC) -MM $+ > $@ $(TARGET): $(OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $+ -o $@ clean: rm $(OBJS) distclean: clean rm $(TARGET) .PHONY: all dep clean distclean
-
Hat niemand eine Empfehlung für einen "fertigen" Parser?
-
lern programmieren
-
bartek schrieb:
Hat niemand eine Empfehlung für einen "fertigen" Parser?
Das geht mit GNU Octave oder Matlab. Je nach dem, ob du mit der GPL leben kannst, oder genug Geld hast.