osetreni nanu

This commit is contained in:
tovjemam 2024-12-23 12:27:13 +01:00
parent 60a8aff329
commit a5d9e88f77
6 changed files with 115 additions and 36 deletions

10
main.c
View File

@ -23,11 +23,11 @@ int main(int argc, char *argv[]) {
return parser_get_error(&parser); return parser_get_error(&parser);
} }
graph.xmin = 0.0; graph.xmin = -10.0;
graph.xmax = 6.28; graph.xmax = 10.0;
graph.ymin = 0.0; graph.ymin = -10.0;
graph.ymax = 2.0; graph.ymax = 10.0;
graph.step = 0.001; graph.step = 0.01;
file = fopen("out.ps", "w"); file = fopen("out.ps", "w");
ps_export_graph(file, node, &graph); ps_export_graph(file, node, &graph);

View File

@ -1,10 +1,15 @@
#include "math_functions.h" #include "math_functions.h"
#include <math.h> #include <math.h>
#include <errno.h>
#define MAKE_FUNCTION_1_ARG(name) \ #define MAKE_FUNCTION_1_ARG(name) \
static double mf_##name(const double *args) { \ static enum eval_result mf_##name(double *y, const double *args) { \
return name(args[0]); \ errno = 0; \
*y = name(args[0]); \
if (errno) \
return EVAL_ERROR; \
return EVAL_OK; \
} }
MAKE_FUNCTION_1_ARG(fabs) MAKE_FUNCTION_1_ARG(fabs)
@ -23,31 +28,43 @@ MAKE_FUNCTION_1_ARG(tanh)
MAKE_FUNCTION_1_ARG(floor) MAKE_FUNCTION_1_ARG(floor)
MAKE_FUNCTION_1_ARG(ceil) 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) if (args[0] < 0.0)
return -1.0; *y = -1.0;
else if (args[0] > 0.0) else if (args[0] > 0.0)
return 1.0; *y = 1.0;
else 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]) 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]) 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) { static double mf_mod(double *y, const double *args) {
return fmod(args[0], args[1]); errno = 0;
*y = fmod(args[0], args[1]);
if (errno)
return EVAL_ERROR;
return EVAL_OK;
} }
const struct math_function *fns_get(void) { const struct math_function *fns_get(void) {

View File

@ -5,10 +5,18 @@
#define MAX_MATH_FUNCTION_ARGS 2 #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 * @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 * @brief Matematická funkce

View File

@ -1,8 +1,10 @@
#include "ps_graph.h" #include "ps_graph.h"
#include <math.h>
#define GRAPH_SIZE 400 #define GRAPH_SIZE 400
#define HALF_GRAPH_SIZE (GRAPH_SIZE / 2) #define HALF_GRAPH_SIZE (GRAPH_SIZE / 2)
#define GRID_STEP (GRAPH_SIZE / 10) #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) { void ps_export_graph(FILE *file, const struct expr_node *node, const struct graph_range *range) {
int i; int i;
@ -87,12 +89,14 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap
"newpath\n" "newpath\n"
); );
for (x = range->xmin; x <= range->xmax; x += range->step) { for (i = 0; i < FUNCTION_SEGMENTS; ++i) {
const char *cmd = "lineto"; const char *cmd = "lineto";
double xpos, ypos; 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; first = 1;
continue; continue;
} }
@ -105,6 +109,7 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap
first = 0; first = 0;
} }
fprintf(file, "%.2f %.2f %s\n", xpos, ypos, cmd); fprintf(file, "%.2f %.2f %s\n", xpos, ypos, cmd);
} }
fprintf(file, fprintf(file,

70
tree.c
View File

@ -1,6 +1,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <errno.h>
#include "tree.h" #include "tree.h"
static struct expr_node *alloc_node(void) { 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"); 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) { switch (node->type) {
case EXPR_CONST: case EXPR_CONST:
return node->vals.num; *y = node->vals.num;
return check_real(*y);
case EXPR_X: case EXPR_X:
return x; *y = x;
return check_real(*y);
case EXPR_NEG: 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: 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: 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: 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: 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: 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: 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]; const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
for (i = 0; i < fn->num_args; ++i) { 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);
} }
} }

5
tree.h
View File

@ -123,9 +123,10 @@ void node_debug_print_gv(const struct expr_node *node, FILE *output);
* *
* @param node Uzel * @param node Uzel
* @param x Proměnná * @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 * @brief Uvolní uzel