From a5d9e88f773a8303d4f832ee451cb4d39e2f8e71 Mon Sep 17 00:00:00 2001 From: tovjemam Date: Mon, 23 Dec 2024 12:27:13 +0100 Subject: [PATCH] osetreni nanu --- main.c | 10 +++---- math_functions.c | 45 +++++++++++++++++++++---------- math_functions.h | 10 ++++++- ps_graph.c | 11 +++++--- tree.c | 70 ++++++++++++++++++++++++++++++++++++++++-------- tree.h | 5 ++-- 6 files changed, 115 insertions(+), 36 deletions(-) diff --git a/main.c b/main.c index cbc004f..1b2b8ed 100644 --- a/main.c +++ b/main.c @@ -23,11 +23,11 @@ int main(int argc, char *argv[]) { return parser_get_error(&parser); } - graph.xmin = 0.0; - graph.xmax = 6.28; - graph.ymin = 0.0; - graph.ymax = 2.0; - graph.step = 0.001; + graph.xmin = -10.0; + graph.xmax = 10.0; + graph.ymin = -10.0; + graph.ymax = 10.0; + graph.step = 0.01; file = fopen("out.ps", "w"); ps_export_graph(file, node, &graph); diff --git a/math_functions.c b/math_functions.c index 1eb3c1f..e38d450 100644 --- a/math_functions.c +++ b/math_functions.c @@ -1,10 +1,15 @@ #include "math_functions.h" #include +#include #define MAKE_FUNCTION_1_ARG(name) \ - static double mf_##name(const double *args) { \ - return name(args[0]); \ + static enum eval_result mf_##name(double *y, const double *args) { \ + errno = 0; \ + *y = name(args[0]); \ + if (errno) \ + return EVAL_ERROR; \ + return EVAL_OK; \ } MAKE_FUNCTION_1_ARG(fabs) @@ -23,31 +28,43 @@ MAKE_FUNCTION_1_ARG(tanh) MAKE_FUNCTION_1_ARG(floor) MAKE_FUNCTION_1_ARG(ceil) -static double mf_sgn(const double *args) { +static double mf_sgn(double *y, const double *args) { if (args[0] < 0.0) - return -1.0; + *y = -1.0; else if (args[0] > 0.0) - return 1.0; + *y = 1.0; else - return 0.0; + *y = 0.0; + + return EVAL_OK; } -static double mf_min(const double *args) { +static double mf_min(double *y, const double *args) { if (args[0] < args[1]) - return args[0]; + *y = args[0]; + else + *y = args[1]; - return args[1]; + return EVAL_OK; } -static double mf_max(const double *args) { +static double mf_max(double *y, const double *args) { if (args[0] > args[1]) - return args[0]; + *y = args[0]; + else + *y = args[1]; - return args[1]; + return EVAL_OK; } -static double mf_mod(const double *args) { - return fmod(args[0], args[1]); +static double mf_mod(double *y, const double *args) { + errno = 0; + *y = fmod(args[0], args[1]); + + if (errno) + return EVAL_ERROR; + + return EVAL_OK; } const struct math_function *fns_get(void) { diff --git a/math_functions.h b/math_functions.h index 279253c..1798462 100644 --- a/math_functions.h +++ b/math_functions.h @@ -5,10 +5,18 @@ #define MAX_MATH_FUNCTION_ARGS 2 +/** + * @brief Výsledek vyhodnocení výrazu + */ +enum eval_result { + EVAL_OK, + EVAL_ERROR +}; + /** * @brief Ukazatel na vyhodnocovač matematické funkce */ -typedef double (*math_function_ptr)(const double*); +typedef enum eval_result (*math_function_ptr)(double* y, const double* args); /** * @brief Matematická funkce diff --git a/ps_graph.c b/ps_graph.c index 3aea447..30a0caa 100644 --- a/ps_graph.c +++ b/ps_graph.c @@ -1,8 +1,10 @@ #include "ps_graph.h" +#include #define GRAPH_SIZE 400 #define HALF_GRAPH_SIZE (GRAPH_SIZE / 2) #define GRID_STEP (GRAPH_SIZE / 10) +#define FUNCTION_SEGMENTS 1000 void ps_export_graph(FILE *file, const struct expr_node *node, const struct graph_range *range) { int i; @@ -87,12 +89,14 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap "newpath\n" ); - for (x = range->xmin; x <= range->xmax; x += range->step) { + for (i = 0; i < FUNCTION_SEGMENTS; ++i) { const char *cmd = "lineto"; double xpos, ypos; - double y = node_eval(node, x); + double y; - if (y != y) { + x = range->xmin + (range->xmax - range->xmin) * (double)i / (double)FUNCTION_SEGMENTS; + + if (node_eval(node, x, &y) != EVAL_OK) { first = 1; continue; } @@ -105,6 +109,7 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap first = 0; } fprintf(file, "%.2f %.2f %s\n", xpos, ypos, cmd); + } fprintf(file, diff --git a/tree.c b/tree.c index 3c62d88..51dfffb 100644 --- a/tree.c +++ b/tree.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "tree.h" static struct expr_node *alloc_node(void) { @@ -255,32 +256,79 @@ void node_debug_print_gv(const struct expr_node *node, FILE *output) { fprintf(output, "}\n"); } +#define INF (1.0e256) + +static int is_real(double x) { + return x == x && x < INF && x > -INF; +} + +static enum eval_result check_real(double x) { + if (is_real(x)) + return EVAL_OK; + else + return EVAL_ERROR; +} + +#define RETURN_CHECK_REAL(x) if (is_real((x))) return EVAL_OK; else return EVAL_ERROR; + +#define EVAL_CHECK(node, x, y) if (node_eval((node), (x), (y)) != EVAL_OK) return EVAL_ERROR; + +enum eval_result node_eval(const struct expr_node *node, double x, double *y) { + double tmp1, tmp2; -double node_eval(const struct expr_node *node, double x) { switch (node->type) { case EXPR_CONST: - return node->vals.num; + *y = node->vals.num; + return check_real(*y); case EXPR_X: - return x; + *y = x; + return check_real(*y); case EXPR_NEG: - return -node_eval(node->vals.unop, x); + EVAL_CHECK(node->vals.unop, x, &tmp1); + *y = -tmp1; + return EVAL_OK; case EXPR_ADD: - return node_eval(node->vals.binop.left, x) + node_eval(node->vals.binop.right, x); + EVAL_CHECK(node->vals.binop.left, x, &tmp1); + EVAL_CHECK(node->vals.binop.right, x, &tmp2); + *y = tmp1 + tmp2; + return check_real(*y); case EXPR_SUB: - return node_eval(node->vals.binop.left, x) - node_eval(node->vals.binop.right, x); + EVAL_CHECK(node->vals.binop.left, x, &tmp1); + EVAL_CHECK(node->vals.binop.right, x, &tmp2); + *y = tmp1 - tmp2; + return check_real(*y); case EXPR_MULT: - return node_eval(node->vals.binop.left, x) * node_eval(node->vals.binop.right, x); + EVAL_CHECK(node->vals.binop.left, x, &tmp1); + EVAL_CHECK(node->vals.binop.right, x, &tmp2); + *y = tmp1 * tmp2; + return check_real(*y); case EXPR_DIV: - return node_eval(node->vals.binop.left, x) / node_eval(node->vals.binop.right, x); + EVAL_CHECK(node->vals.binop.left, x, &tmp1); + EVAL_CHECK(node->vals.binop.right, x, &tmp2); + + if (tmp2 == 0.0) + return EVAL_ERROR; + + *y = tmp1 / tmp2; + return check_real(*y); case EXPR_POW: - return pow(node_eval(node->vals.binop.left, x), node_eval(node->vals.binop.right, x)); + EVAL_CHECK(node->vals.binop.left, x, &tmp1); + EVAL_CHECK(node->vals.binop.right, x, &tmp2); + + errno = 0; + *y = pow(tmp1, tmp2); + + if (errno) + return EVAL_ERROR; + + return check_real(*y); case EXPR_FN: { @@ -289,10 +337,10 @@ double node_eval(const struct expr_node *node, double x) { const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx]; for (i = 0; i < fn->num_args; ++i) { - inner_results[i] = node_eval(node->vals.fn.args[i], x); + EVAL_CHECK(node->vals.fn.args[i], x, &inner_results[i]); } - return fn->ptr(inner_results); + return fn->ptr(y, inner_results); } } diff --git a/tree.h b/tree.h index 8987c87..3abc821 100644 --- a/tree.h +++ b/tree.h @@ -123,9 +123,10 @@ void node_debug_print_gv(const struct expr_node *node, FILE *output); * * @param node Uzel * @param x Proměnná - * @return Hodnota v bodě x + * @param y Výsledek vyhodnocení + * @return Stav vyhodnocení */ -double node_eval(const struct expr_node *node, double x); +enum eval_result node_eval(const struct expr_node *node, double x, double *y); /** * @brief Uvolní uzel