안녕하세요!
저는 지금 미적분I 수업 시간에 과제연구를 진행하고 있습니다. 저는 제 분야에 맞게 C언어를 이용하여 3차 이하의 방정식의 해를 미분을 이용하여 구할 수 있게 해주는 프로그램을 코딩해보았습니다.
약 3시간 정도가 소요되었으며 쉬울 것이라고 생각했는데 생각보다는 어려웠습니다. 그럼 한번 코드를 볼까요?
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
|
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct module
{
int coef;
int index;
}module;
float solF(float x, int a, int b, int c, int d)
{
return (d + c*x + b*x*x + a*x*x*x);
}
int main(void)
{
printf("미적분 과제연구 - 미분을 이용하여 3차 이하 함수의 실근의 개수 구하기\n171037 이호은\n\n");
int i; int n;
do{
printf("함수의 차수를 입력해주세요 (3차 이하, 상수함수는 0차) : ");
scanf("%d", &n);
}while(n>3||n<0);
//상수함수 처리
int sl = 0;
if(n==0){
printf("상수함수를 입력받습니다.\n");
printf("1. x = k\n2. y = k\n\n");
printf("선택하세요 : ");
scanf("%d", &sl);
if(sl==1){
printf("상수 k를 입력하세요 : ");
scanf("%d", &sl);
printf("입력한 함수의 실근의 개수는 0개입니다.");
}
else if(sl==2){
printf("상수 k를 입력하세요 : ");
scanf("%d", &sl);
if(sl==0){
printf("입력한 함수는 모든 실수를 근으로 갖습니다.");
}
else
printf("입력한 함수의 실근의 개수는 1개입니다.");
}
else
printf("올바른 값이 아닙니다.");
return 0;
}
printf("%d차함수를 입력받습니다.\n", n);
module arr[(n+1)];
int cf;
//상수항 입력
printf("상수항의 계수 : ");
scanf("%d", &cf);
arr[0].coef = cf;
arr[0].index = 0;
//1차항부터 최고차항까지 계수 입력
for(i=1;i<=n;i++){
printf("%d차항의 계수 : ", i);
scanf("%d", &cf);
arr[i].coef = cf;
arr[i].index = i;
}
printf("입력받은 다항함수 : ");
//입력받은 함수 출력
for(i=n;i>1;i--){
if((arr[i].coef)!=0){
printf("%dx^%d", arr[i].coef, arr[i].index);
if(i==1)
break;
printf(" + ");
}
}
if((arr[1].coef)!=0)
printf("%dx", arr[1].coef);
if((arr[0].coef)!=0)
printf(" + %d", arr[0].coef);
//함수의 도함수를 구하기
module Calarr[n];
for(i=0;i<n;i++){
Calarr[i].index = i;
Calarr[i].coef = (arr[(i+1)].index)*(arr[(i+1)].coef);
}
//도함수 출력
printf("\n입력한 함수의 도함수 : ");
for(i=n-1;i>=1;i--){
if((arr[(i+1)].coef)!=0){
printf("%dx^%d", Calarr[i].coef, Calarr[i].index);
if(Calarr[0].coef!=0)
printf(" + ");
}
}
if((Calarr[0].coef)!=0)
printf("%d", Calarr[0].coef);
printf("\n");
int sol; //실근
int P; //판별식 값
if(n==3){
printf("삼차함수의 근의 개수를 구합니다.\n\n");
int a = arr[3].coef;
int b = arr[2].coef;
int c = arr[1].coef;
int d = arr[0].coef;
/** 3차방정식의 근의공식 사용 **/
/*P = (b*b*c*c)-(4*a*c*c*c)-(4*b*b*b*d)-(27*a*a*d*d)+(18*a*b*c*d);
if(P>0){
printf("입력한 함수의 실근의 개수는 3개입니다.");
return 0;
}
else if(P=0){
printf("입력한 함수는 1개의 실근과 중근을 갖습니다.");
return 0;
}
else if(P<0){
printf("입력한 함수는 1개의 실근과 2개의 허근을 갖습니다.");
return 0;
}
if((9*a*b*c)==(2*b*b*b)+(27*a*a*d)){
printf("입력한 함수는 1개의 실근으로 삼중근을 갖습니다.");
return 0;
}
printf("입력 오류");*/
a = Calarr[2].coef;
b = Calarr[1].coef;
c = Calarr[0].coef;
float Sone;
float Stwo;
Sone = ( (-b) + (sqrt(P)) ) / (2*a);
Stwo = ( (-b) - (sqrt(P)) ) / (2*a);
//도함수의 실근 출력
printf("입력한 함수의 도함수의 실근은 %f.3, %f.3입니다.\n\n", Sone, Stwo) ;
//두 근 크기 비교
int Splus;
int Sminus;
if(Sone>=0&&Sone!=Stwo){
float Splus = Sone;
float Sminus = Stwo;
}
else if(Sone==Stwo){
Splus = Sone;
Stwo = Splus;
}
else{
Splus = Stwo;
Sminus = Sone;
}
a = arr[3].coef;
b = arr[2].coef;
c = arr[1].coef;
d = arr[0].coef;
//극값 계산
float Zeroone = solF(Sone, a, b, c, d);
float Zerotwo = solF(Stwo, a, b, c, d);
float MaxF;
float MinF;
if(Zeroone > Zerotwo){
MaxF = Zeroone;
MinF = Zerotwo;
printf("입력한 함수의 극댓값은 %f(x=%f), 극솟값은 %f(x=%f)입니다.", MaxF, Sone, MinF, Stwo);
}
else{
MaxF = Zerotwo;
MinF = Zeroone;
printf("입력한 함수의 극댓값은 %f(x=%f), 극솟값은 %f(x=%f)입니다.", MaxF, Stwo, MinF, Sone);
}
//극댓값, 극솟값을 이용해서 실근의 개수 구하기
if(MinF > 0 || MaxF<0)
sol = 1;
else if(MaxF == 0 || MinF == 0){
printf("입력한 함수의 실근의 개수는 1개이며 중근을 갖습니다.");
return 0;
}
else if(MaxF>0&&MinF<0){
sol = 3;
}
printf("입력한 함수의 실근의 개수는 %d개입니다.", sol);
return 0;
}
else if(n==2){
printf("이차함수의 근의 개수를 구합니다.\n");
int a = arr[2].coef;
int b = arr[1].coef;
int c = arr[0].coef;
P = (b*b)+((-4)*a*c);
sol = 0;
if(P>0){
sol = 2;
}
else if(P==0){
sol = 1;
}
else if(P<0){
sol = 0;
}
printf("\n입력한 함수의 실근의 개수는 %d개입니다.\n", sol);
return 0;
}
else if(n==1){
printf("일차함수의 근의 개수를 구합니다.\n");
if((arr[1].coef)!=0)
sol = 1;
else
sol = 0;
//실근의 개수 출력
printf("입력한 함수의 실근의 개수는 %d개입니다.", sol);
return 0;
}
return 0;
system("pause");
}
|
cs |
전체 코드입니다.
그럼 이제 자세히 살펴볼까요?
가장 먼저 알고리즘입니다. 모든 코딩은 알고리즘이 가장 중요합니다. 이 단계가 튼튼하지 못하면 코딩 단계에서 늪에 빠지게 됩니다.
<알고리즘>
1. 차수를 입력받아 변수 n에 저장한다.
2-1. n이 0이라면 상수함수, 1이라면 일차, 2라면 이차, 3이라면 삼차함수이다. n이 0부터 3까지의 범위를 벗어나면 다시 값을 받는다.
3. 상수함수라면 x=k인지 y=k인지 입력받는다.
x=k라면 실근은 무조건 1개, y=k일때는 k=0이라면 모든 실수를 실근으로 갖고 나머지의 경우는 근이 없다.
4. 일차함수라면 기울기가 0일때를 제외하고는 모든 함수가 1개의 실근을 갖습니다.
5. 이차함수라면 판별식을 이용해 실근의 개수를 구합니다.
6. 삼차함수라면 미분을 하여 도함수를 구합니다.
7. 도함수의 이차방정식의 근의공식을 이용해 도함수의 실근을 구합니다.
8. 도함수의 실근을 이용하여 극솟값과 극댓값을 구합니다.
9. 사잇값정리를 이용해 실근의 개수를 구합니다.
위와 같은 알고리즘을 바탕으로 코딩해봅시다.
1
2
3
4
5
6
7
8
9
|
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct module
{
int coef;
int index;
}module;
|
cs |
먼저 구조체를 선언해주었는데요. 한 개의 항의 계수와 지수를 하나로 묶어 module 이라는 구조체를 선언해주었습니다.
1
2
3
4
|
float solF(float x, int a, int b, int c, int d)
{
return (d + c*x + b*x*x + a*x*x*x);
}
|
cs |
다음으로는 입력 받은 함수의 f(x)값을 반환해주는 함수입니다. 아래에서 자세히 다루겠습니다.
1
2
3
4
5
6
7
8
9
10
|
int main(void)
{
printf("미적분 과제연구 - 미분을 이용하여 3차 이하 함수의 실근의 개수 구하기\n171037 이호은\n\n");
int i; int n;
do{
printf("함수의 차수를 입력해주세요 (3차 이하, 상수함수는 0차) : ");
scanf("%d", &n);
}while(n>3||n<0);
|
cs |
메인함수를 선언해주고 printf와 scanf를 통하여 차수를 입력받습니다.
이때 while문을 사용하여 n값이 0과 3 사이가 아니라면 계속 반복하여 0에서 3까지의 값을 받습니다.
4차 이상의 함수는 미분으로 실근의 개수를 구하기 어렵기 때문에 0차(상수함수)부터 삼차함수까지만 입력을 받습니다.
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
|
//상수함수 처리
int sl = 0;
if(n==0){
printf("상수함수를 입력받습니다.\n");
printf("1. x = k\n2. y = k\n\n");
printf("선택하세요 : ");
scanf("%d", &sl);
if(sl==1){
printf("상수 k를 입력하세요 : ");
scanf("%d", &sl);
printf("입력한 함수의 실근의 개수는 0개입니다.");
}
else if(sl==2){
printf("상수 k를 입력하세요 : ");
scanf("%d", &sl);
if(sl==0){
printf("입력한 함수는 모든 실수를 근으로 갖습니다.");
}
else
printf("입력한 함수의 실근의 개수는 1개입니다.");
}
else
printf("올바른 값이 아닙니다.");
return 0;
}
|
cs |
만약 n이 0이라면 상수함수이므로 위 알고리즘에 따라 상수함수를 처리해줍니다. 알고리즘에서
3. 상수함수라면 x=k인지 y=k인지 입력받는다.
x=k라면 실근은 무조건 1개, y=k일때는 k=0이라면 모든 실수를 실근으로 갖고 나머지의 경우는 근이 없다.
이므로 이를 코드로 구현하였습니다.
이제 일차함수부터 삼차함수의 경우입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
printf("%d차함수를 입력받습니다.\n", n);
module arr[(n+1)];
int cf;
//상수항 입력
printf("상수항의 계수 : ");
scanf("%d", &cf);
arr[0].coef = cf;
arr[0].index = 0;
//1차항부터 최고차항까지 계수 입력
for(i=1;i<=n;i++){
printf("%d차항의 계수 : ", i);
scanf("%d", &cf);
arr[i].coef = cf;
arr[i].index = i;
}
printf("입력받은 다항함수 : ");
|
cs |
처음 새롭게 정의한 구조체 형식의 배열을 n+1 크기로 선언합니다. n차함수일때 상수항까지 항이 n+1개이기 때문입니다.
가장 먼저 상수항을 입력받고 for문을 이용해서 오름차순으로 값을 입력받습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//입력받은 함수 출력
for(i=n;i>1;i--){
if((arr[i].coef)!=0){
printf("%dx^%d", arr[i].coef, arr[i].index);
if(i==1)
break;
printf(" + ");
}
}
if((arr[1].coef)!=0)
printf("%dx", arr[1].coef);
if((arr[0].coef)!=0)
printf(" + %d", arr[0].coef);
|
cs |
입력받은 함수를 출력해서 보여줍니다. 마찬가지로 ()문을 이용하여 내림차순으로 (i번째 항의 계수)X^(지수)의 형태로 출력하였습니다. 만약 i가 1일때는 1차항까지 모두 출력한 것이므로 반복문을 빠져나오고 상수항을 따로 출력하여 줍니다.
1
2
3
4
5
6
7
8
|
//함수의 도함수를 구하기
module Calarr[n];
for(i=0;i<n;i++){
Calarr[i].index = i;
Calarr[i].coef = (arr[(i+1)].index)*(arr[(i+1)].coef);
}
|
cs |
입력받은 함수의 도함수를 구합니다. 간단한 미분법을 식으로 구현하였는데요.
이므로 for문을 이용하여 계수와 지수를 곱한 후 지수의 차수를 1만큼 내려주는 작업을 하였습니다.
이때 구조체 안에 멤버변수인 index(지수)와 coef(계수)에 접근하기 위해서는 '변수명.멤버변수명'의 형식을 이용하면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//도함수 출력
printf("\n입력한 함수의 도함수 : ");
for(i=n-1;i>=1;i--){
if((arr[(i+1)].coef)!=0){
printf("%dx^%d", Calarr[i].coef, Calarr[i].index);
if(Calarr[0].coef!=0)
printf(" + ");
}
}
if((Calarr[0].coef)!=0)
printf("%d", Calarr[0].coef);
printf("\n");
|
cs |
이후 위와 같은 방식으로 도함수도 출력해줍니다.
1
2
|
int sol; //실근
int P; //판별식 값
|
cs |
실근을 저장할 변수와 판별식 D의 값을 저장할 변수를 선언해주었습니다.
1
2
3
4
5
6
7
8
9
|
if(n==3){
printf("삼차함수의 근의 개수를 구합니다.\n\n");
a = Calarr[2].coef;
b = Calarr[1].coef;
c = Calarr[0].coef;
float Sone;
float Stwo;
|
cs |
지금부터는 조금 복잡해집니다. if문으로 삼차일때만 접근할 수 있도록 하였습니다.
먼저 미분된 도함수의 계수를 각각 a, b, c에 대입해준 후 실근 변수인 Sone과 Stwo를 실수형으로 선언해줍니다.
1
2
3
4
5
6
7
|
Sone = ( (-b) + (sqrt(P)) ) / (2*a);
Stwo = ( (-b) - (sqrt(P)) ) / (2*a);
//도함수의 실근 출력
printf("입력한 함수의 도함수의 실근은 %f.3, %f.3입니다.\n\n", Sone, Stwo) ;
|
cs |
이후 이차방정식의 근의공식을 이용하여 두 실근을 구합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//두 근 크기 비교
int Splus;
int Sminus;
if(Sone>=0&&Sone!=Stwo){
float Splus = Sone;
float Sminus = Stwo;
}
else if(Sone==Stwo){
Splus = Sone;
Stwo = Splus;
}
else{
Splus = Stwo;
Sminus = Sone;
}
|
cs |
두 근의 크기를 지정해주었습니다. 두 근이 하나는 양수, 다른 하나는 음수가 나오는 경우가 많기 때문에 두 수의 크기를 비교해 각각 양수의 근은 Splus에 음수의 근은 Sminus에 저장해줍니다.
1
2
3
4
5
6
7
8
|
a = arr[3].coef;
b = arr[2].coef;
c = arr[1].coef;
d = arr[0].coef;
//극값 계산
float Zeroone = solF(Sone, a, b, c, d);
float Zerotwo = solF(Stwo, a, b, c, d);
|
cs |
이후 함수값을 구하기 위해 다시 a, b, c, d를 원시함수의 계수로 초기화해줍니다.
극값을 계산합니다. Zeroone과 Zerotwo이라는 변수 각각의
f(x)값을 계산하기 위해 함수 solF()를 호출해줍니다. 이때 함수값의 x와 계수들을 넘깁니다.
1
2
3
4
5
|
float solF(float x, int a, int b, int c, int d)
{
return (d + c*x + b*x*x + a*x*x*x);
}
|
cs |
다시 한 번 함수 solF()를 살펴보면
위와 같은데요. x값과 계수를 받아와 함수값을 계산해준 후 return으로 실수형으로 함수값을 반환합니다.
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
|
float MaxF;
float MinF;
if(Zeroone > Zerotwo){
MaxF = Zeroone;
MinF = Zerotwo;
printf("입력한 함수의 극댓값은 %f(x=%f), 극솟값은 %f(x=%f)입니다.", MaxF, Sone, MinF, Stwo);
}
else{
MaxF = Zerotwo;
MinF = Zeroone;
printf("입력한 함수의 극댓값은 %f(x=%f), 극솟값은 %f(x=%f)입니다.", MaxF, Stwo, MinF, Sone);
}
//극댓값, 극솟값을 이용해서 실근의 개수 구하기
if(MinF > 0 || MaxF<0)
sol = 1;
else if(MaxF == 0 || MinF == 0){
printf("입력한 함수의 실근의 개수는 1개이며 중근을 갖습니다.");
return 0;
}
else if(MaxF>0&&MinF<0){
sol = 3;
}
printf("입력한 함수의 실근의 개수는 %d개입니다.", sol);
return 0;
}
|
cs |
위 알고리즘에 따라 사잇값정리를 이용해 실근의 개수를 구합니다. sol 변수에 개수를 저장한 수 printf를 이용해 출력합니다.
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
|
else if(n==2){
printf("이차함수의 근의 개수를 구합니다.\n");
int a = arr[2].coef;
int b = arr[1].coef;
int c = arr[0].coef;
P = (b*b)+((-4)*a*c);
sol = 0;
if(P>0){
sol = 2;
}
else if(P==0){
sol = 1;
}
else if(P<0){
sol = 0;
}
printf("\n입력한 함수의 실근의 개수는 %d개입니다.\n", sol);
return 0;
}
|
cs |
이제 이차함수입니다. 아까와 마찬가지로 a, b, c에 함수의 계수를 대입하여 판별식인
을 이용해 실근의 개수를 구합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
else if(n==1){
printf("일차함수의 근의 개수를 구합니다.\n");
if((arr[1].coef)!=0)
sol = 1;
else
sol = 0;
//실근의 개수 출력
printf("입력한 함수의 실근의 개수는 %d개입니다.", sol);
return 0;
}
|
cs |
마지막으로 1차함수입니다. 위 알고리즘에 따라 기울기가 0이라면 실근이 0개, 기울기가 0이 아니라면 실근이 1개로 출력하도록 합니다.
1
2
3
4
|
return 0;
system("pause");
}
|
cs |
마지막 코드입니다. main함수의 끝을 알리는 return 0과 콘솔창에서 창이 닫히지 않게 해주는 system("pause") 명령어를 입력하였습니다.
긴 코드를 하나하나 살펴보았습니다. 위 프로그램의 실행영상입니다. (유튜브에서 보기)
문제 없이 실행되는 것을 확인하실 수 있습니다.
여러분들도 수학적 개념을 접목시켜 알고리즘을 짠 뒤 코드를 작성해보면 수학 실력과 코딩 실력에 많은 도움이 될 것입니다.
감사합니다!