-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.c
More file actions
181 lines (164 loc) · 5.11 KB
/
main.c
File metadata and controls
181 lines (164 loc) · 5.11 KB
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
180
181
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define MAX_ITER_COUNT 100
#include "graph_writer.h"
#include "parser.h"
#include "lexer.h"
#include "calclator.h"
typedef enum mode
{
newton,
draw_graph_mode,
} Mode;
// テキストファイルに記述した関数のグラフを描画する
void draw_graph();
// ニュートン法を実行してグラフを出力する
void newton_method();
// 関数
double f(double x, Node *node);
// 微分係数を計算する
double dxdy(double x, Node *node);
// 接線の式
double tangent_line(double x, Node *node);
// 接線を描画して保存する
void write_tangent_line(Pixel *graph_image, Node *nodes_for_tangent_line, int count);
int main(void)
{
Mode mode;
int mode_input;
printf("グラフ描画&ニュートン法シミュレータ\n");
printf("モードを選んでください。\n%d: ニュートン法シミュレータ\n%d: 関数グラフ描画\n", newton, draw_graph_mode);
scanf("%d", &mode_input);
mode = (Mode)mode_input;
switch (mode)
{
case newton:
newton_method();
break;
case draw_graph_mode:
draw_graph();
break;
default:
break;
}
return 0;
}
// 接線の方程式を計算するためににグローバル変数にしている。
double xk;
void newton_method()
{
// ファイルから初期値、関数、導関数を読み込む
char *function_file_name = "newton_funcs.txt";
FILE *fp = fopen(function_file_name, "r");
if (fp == NULL)
{
perror("ファイルを開けませんでした。\n");
printf("ファイル名: %s\n", function_file_name);
exit(-1);
}
char expression[255];
Token *tokens;
Node *dxdy_node, *f_node;
// 初期値
double x0;
// 初期値を読み込む
fscanf(fp, "%lf", &x0);
// 関数の式を読み込む
fscanf(fp, "%s", expression);
tokens = lexical(expression);
f_node = parse(tokens);
// 導関数の式を読み込む
fscanf(fp, "%s", expression);
tokens = lexical(expression);
dxdy_node = parse(tokens);
// 接線描画用に構造体をコピーして配列にする(引数がNodeのポインタに制限されているので無理やり渡すには配列にするしかない)
Node nodes_for_tangent_line[2];
nodes_for_tangent_line[0] = *f_node;
nodes_for_tangent_line[1] = *dxdy_node;
// 許容誤差
double eps = 1.0e-10;
int i;
xk = x0;
Pixel *graph_image = init_graph_image();
draw_axis(graph_image);
Pixel color = {0, 0, 0};
draw_graph_func(graph_image, color, f_node, f);
srand(time(NULL));
for (i = 0; i < MAX_ITER_COUNT; i++)
{
write_tangent_line(graph_image, nodes_for_tangent_line, i);
xk = xk - f(xk, f_node) / dxdy(xk, dxdy_node);
printf("[繰り返し%d回目]\n近似解: %.16f\n", i + 1, xk);
if (fabs(f(xk, f_node)) < eps)
{
printf("%d反復で近似解: %.16fが求まりました。\n", i + 1, xk);
write_tangent_line(graph_image, nodes_for_tangent_line, i + 1);
return;
}
}
printf("%d反復では収束しませんでした。\n", MAX_ITER_COUNT);
write_tangent_line(graph_image, nodes_for_tangent_line, MAX_ITER_COUNT);
}
double dxdy(double x, Node *node)
{
return calclate(x, node);
}
double f(double x, Node *node)
{
return calclate(x, node);
}
// f(x)計算用nodeとf'(x)計算用nodeを渡す
// f(x) -> f'(x)という順でノードを渡す
double tangent_line(double x, Node *node)
{
return dxdy(xk, node + 1) * (x - xk) + f(xk, node);
}
void write_tangent_line(Pixel *graph_image, Node *nodes_for_tangent_line, int count)
{
char fileName[51];
Pixel color;
color.R = rand() % 256;
color.G = rand() % 256;
color.B = rand() % 256;
draw_graph_func(graph_image, color, nodes_for_tangent_line, tangent_line);
sprintf(fileName, "%s/%d-%s", "newton_method_images", count, "newton_method");
export_to_bmp(graph_image, fileName);
}
void draw_graph()
{
char *function_file_name = "graphs.txt";
FILE *fp = fopen(function_file_name, "r");
if (fp == NULL)
{
perror("ファイルを開けませんでした。\n");
printf("ファイル名: %s\n", function_file_name);
exit(-1);
}
char *file_name = (char *)calloc(51, sizeof(char));
fscanf(fp, "%s", file_name);
if (strlen(file_name) > 20)
{
printf("出力ファイル名は20文字までにしてください。\n");
exit(-1);
}
printf("%s.bmpにグラフを書き込みます。\n", file_name);
Pixel color;
char expression[255];
Pixel *graph_image = init_graph_image();
draw_axis(graph_image);
while (fscanf(fp, "%s %hhu %hhu %hhu", expression, &color.R, &color.G, &color.B) != EOF)
{
draw_graph_expression(graph_image, color, expression);
color.R = 0;
color.G = 0;
color.B = 0;
}
export_to_bmp(graph_image, file_name);
printf("%sを出力しました。\n", file_name);
dispose_image(graph_image);
free(file_name);
fclose(fp);
}