aboutsummaryrefslogtreecommitdiffstats
path: root/main_23.c
blob: f6936da107fa80004d9d2dea5000e5bd68099529 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

struct dval { double x, y; };
typedef double (*func_t)(double);

#ifdef PIPE_GNUPLOT
	#include <unistd.h>
	#include <fcntl.h>
	
	void print_table(FILE*, const struct dval *, long int);
	/// This function is creating a 'gnuplot' pipe 
	/// and writing data to it to be plotted
	void pipe_gnuplot(struct dval *table, long len) {
		FILE* gp = popen("gnuplot", "w");
		if (!gp) return;
		fputs("plot '-' with lines\n", gp);
		print_table(gp, table, len);
		fputs("e\n", gp);
		fflush(gp);

		getchar();
		pclose(gp);
	}
#endif // PIPE_GNUPLOT

#ifdef DYNAMIC_LOAD
	#include <dlfcn.h>
	void* handle = NULL;
#endif // DYNAMIC_LOAD

double sin2(double x) {
	double y = sin(x);
	return y*y;
}
double cos2(double x) {
	double y = cos(x);
	return y*y;
}
double __sincos(double x) {
	// sin(x)cos(x) = sin(2x)/2
	return sin(2*x)/2;
}
double sin2x(double x) {
	return sin(2*x);
}

/// generates the table as asked in the task.
/// The core function for task 2
struct dval *get_table(func_t f, double start, double end, double step, long *length) {
	long tlength = lround((end-start)/step);
	struct dval *vals = calloc(tlength, sizeof(struct dval));
	for (long i = 0; i < tlength; ++i) {
		double x = start + step * i;
		// Not accumulative because if step is too small, 
		// start will never increment
		vals[i] = (struct dval){.x = x, .y = f(x)};
	}
	*length = tlength;
	return vals;
}

/// generates the table for derivative of function f.
/// The core function for task 3
struct dval *differentiate(func_t f, double start, double end, double step, long *length) {
	long tlength = lround((end-start)/step);
	struct dval *vals = calloc(tlength, sizeof(struct dval));
	for (long i = 0; i < tlength; ++i) {
		double x = start + step * i;
		// central difference 
		double y = (f(x+step) - f(x-step))/ (2*step);
		vals[i] = (struct dval){.x = x, .y = y};
	}
	*length = tlength;
	return vals;
}

void print_table(FILE* stream, const struct dval *table, long size) {
	for (long i = 0; i < size; ++i) {
		fprintf(stream, "%lg %lg\n", table[i].x, table[i].y);
	}
}


void print_help(int status) {
	const char *help = 
		"This program is Licensed under 'the unlicense license'\n\n"
		"Usage: ./t23 -f func_name -o output_file [-x number -h -d]\n"
		"\t-h: this help\n"
		"\t-d: differentiate function (do task 3)\n"
		"\t-f: function: either 'sin2', 'cos2', 'sincos', 'tg' or 'sin2x' .\n"
		"\t\tif compiled with -DDYNAMIC_LOAD, file name with dynamic function.\n"
		"\t-o: output file.\n"
		"\t-x: only needed with -d flag - differentiation step (the dx)\n\n"
		"NOTE: the function in dynamic library must be named 'f'.\n"
		"NOTE 2: with flag -DPIPE_GNUPLOT output will be piped in gnuplot\n";
	puts(help);
	exit(status);
}

/// Get the function based on the command line flags - either use 
/// existing or load one from dynamic library
func_t get_function(const char* name) {
	if (!strcmp(name, "cos2"))
		return &cos2;
	if (!strcmp(name, "sin2"))
		return &sin2;
	if (!strcmp(name, "sincos"))
		return &__sincos;
	if (!strcmp(name, "tg"))
		return &tan;
	if (!strcmp(name, "sin2x"))
		return &sin2x;
#ifndef DYNAMIC_LOAD
	fputs("ERROR: unknown function. To use dynamic loading, compile with `-DDYNAMIC_LOAD`.\n", stderr);
	exit(EXIT_FAILURE);
#else  // DYNAMIC_LOAD
	handle = dlopen(name, RTLD_NOW);
	if (!handle) goto fail;
	func_t f = dlsym(handle, "f");
	if (!f) goto fail;
	return f;
fail:
	fputs(dlerror(), stderr);
	exit(EXIT_FAILURE);
#endif // DYNAMIC_LOAD
}

int main(int argc, char *argv[]) {
	func_t function = NULL;
	const char *out = NULL;
	char task2 = 1;
	float dx = 0.0;
	// casual argument loop
	for (int i = 1; i < argc; ++i) {
		if (!strcmp(argv[i], "-h"))
			print_help(EXIT_SUCCESS);
		else if (!strcmp(argv[i], "-f"))
			function = get_function(argv[++i]);
		else if (!strcmp(argv[i], "-o"))
			out = argv[++i];
		else if (!strcmp(argv[i], "-d"))
			task2 = 0;
		else if (!strcmp(argv[i], "-x"))
			dx = atof(argv[++i]);
		else print_help(EXIT_FAILURE);
	}
	// if function or output file is not set, or if dx is not set for task3,
	// then exit with failure
	if ((!function || !out) || (!task2 && dx == 0.0))
		print_help(EXIT_FAILURE);

	long table_len;
	struct dval *table = NULL;
	if (task2)
		table = get_table(function, 0, 3, 0.01, &table_len);
	else // task 3
		table = differentiate(function, -3, 3, dx, &table_len);

	// print data to stdout and to file
	print_table(stdout, table, table_len);
	FILE *f = fopen(out, "w+");
	if (f) print_table(f, table, table_len);
	else perror(out);

#ifdef PIPE_GNUPLOT 
	pipe_gnuplot(table, table_len);
#endif // PIPE_GNUPLOT

	fclose(f);
	free(table);
#ifdef DYNAMIC_LOAD
	if (handle) dlclose(handle);
#endif // DYNAMIC_LOAD
	exit(EXIT_SUCCESS);
}