24 Nguyen Thanh Trung 03

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 69

TRƯỜNG ĐẠI HỌC CÔNG NGHỆ - ĐHQGHN

KHOA ĐIỆN TỬ VIỄN THÔNG

BÀI TẬP LỚN:


Code thuật toán giải bài tập
Phương Pháp Tính

Họ tên: Nguyễn Thành Trung


MSV: 21021640
Lớp học phần : INT3102_21

Giảng viên hướng dẫn: Lê Phê Đô

Hà Nội, ngày 7 June 2024


MỤ C LỤ C
CHƯƠNG 1: GIẢI GẦN ĐÚNG PHƯƠNG TRÌNH.......................................................................3
1. Phương pháp chia đôi......................................................................................................3
2. Phương pháp điểm bất động (Phương pháp lặp đơn).................................................7
a. Cách giải bài toán.............................................................................................................7
3. Phương pháp điểm sai.....................................................................................................9
4. Phương pháp Newton....................................................................................................11
5. Phương pháp dây cung.................................................................................................14
CHƯƠNG 2: GIẢI PHƯƠNG TRÌNH..........................................................................................16
1. Phương pháp khử Gauss – Jordan..............................................................................16
2. Phương pháp khử Gauss..............................................................................................19
3. Phương pháp tìm ma trận nghịch đảo sử dụng phương pháp Gauss – Jordan.....22
2. Phương pháp lặp Gauss – Jacobi................................................................................26
3. Phương pháp phân tích A=LU.......................................................................................29
CHƯƠNG 3: BÀI TOÁN NỘI SUY..............................................................................................32
1. Phương pháp Nội suy Newton......................................................................................32
2. Phương pháp nội suy Lagrange...................................................................................36
3. Phương pháp nội suy Speline.......................................................................................39
CHƯƠNG 4: PHƯƠNG PHÁP BÌNH PHƯƠNG TỐI THIỂU.....................................................41
1. Phương pháp bình phương tối thiểu rời rạc...............................................................41
2. Phương pháp bình phương tối thiểu liên tục bằng đa thức......................................45
3. Phương pháp bình phương tối thiểu liên tục va trực giao........................................48
CHƯƠNG 5: TÍNH GẦN ĐÚNG ĐẠO HÀM, TÍCH PHÂN.........................................................51
1. Phương pháp tích phân: quy tắc hình thang...............................................................51
2. Phương pháp tích phân Simpson.................................................................................53
3. Phương pháp Romberg cơ bản....................................................................................57
CHƯƠNG 6: GIẢI GẦN ĐÚNG PHƯƠNG TRÌNH VI PHÂN.................................................59
1. Phương pháp chuỗi Taylo.............................................................................................59
2. Phương pháp Euler’s.....................................................................................................59
3. Phương pháp điểm giữa................................................................................................60
4. Phương pháp RUNGE-KUTTA 4....................................................................................62
5. Phương pháp hiệu chỉnh nhiều bước Adam - Moulton..............................................64
6. Phương pháp Huen........................................................................................................65
7. Phương pháp hiệu chỉnh nhiều bước Adam - Moulton..............................................68
CHƯƠNG 1: GIẢI GẦN ĐÚNG PHƯƠNG TRÌNH

1. Phương pháp chia đôi


a. Cách giải bài tập
- Giả sử f là hàm số xác định và liên tục trên khoảng [a, b], với f (a) và f (b) của
dấu trái. Định lý giá trị trung gian nói rằng tồn tại một số p trong (a, b) với f (p)
= 0.
- Phương thức tiến hành:
o Chia đôi [a, b], nếu điểm giữa p = (a + b)/2 thỏa mãn f(p)=0, thì p là
nghiệm cần tìm.
o Nếu f(p) ≠ 0, thì nghiệm nằm trong khoảng [a, p] hoặc [p, b].
- Để bắt đầu, ta đặt a1 = a và b1=b, và đặt p1 là điểm giữa của [a, b]; nghĩa là:

o Nếu f(p1) = 0 thì p = p1, và chúng ta xong rồi.


o Nếu f(p1) ≠ 0 thì f (p1) có cùng dấu với f(a1) hoặc f(b1).
o Nếu f(p1) và f a1) có cùng dấu, p ∈ ( p1, b1). Đặt a2 = p1 và b2 = b1.
o Nếu f(p1) và f(a1) có dấu hiệu trái ngược nhau, p∈(a1, p1). Bộ a2 =
a1 và b2 = p1.
o Sau đó áp dụng lại quy trình cho khoảng [a2, b2].
b. Đặt bài toán và Source code
- Bài toán: sử dụng phương pháp chia đôi để tìm lời giải có độ chính xác
trong khoảng 10-5 cho bài toán sau

- Source code
#include<stdio.h>
#include<conio.h>
#include<math.h>
/*
Định nghĩa phương trình cần giải.
Thay đổi phương trình này để giải quyết vấn đề khác.
*/
#define f(x) x*cos(x) - 2*x*x +3*x -1

void main()
{
float x0, x1, x2, f0, f1, f2, e;
int step = 1;
printf("\nNhập hai giá trị đoán ban đầu:\n");
scanf("%f%f", &x0, &x1);
printf("Nhập sai số có thể chấp nhận:\n");
scanf("%f", &e);
/* Tính giá trị hàm số */
f0 = f(x0);
f1 = f(x1);
/* Kiểm tra xem hai giá trị đoán có nằm cùng một phía của nghiệm hay không.
*/
if (f0 * f1 > 0.0)
{
printf("Giá trị đoán ban đầu không chính xác.\n");

}
/* Thực hiện Phương pháp Chia Đôi */
printf("\nBước\t\tx0\t\tx1\t\tx2\t\tf(x2)\n");
do
{
x2 = (x0 + x1) / 2;
f2 = f(x2);

printf("%d\t\t%f\t%f\t%f\t%f\n", step, x0, x1, x2, f2);

if (f0 * f2 < 0)
{
x1 = x2;
f1 = f2;
}
else
{
x0 = x2;
f0 = f2;
}
step = step + 1;
} while (fabs(f2) > e);
printf("\nNghiệm là: %f", x2);
}

- Ket qua thu duoc:


2. Phương pháp điểm bất động (Phương pháp lặp đơn)
a. Cách giải bài toán
- Bước 1: Xác định hàm số: Điểm bất động của một hàm số ( f(x) ) là giá trị ( x )
sao cho (f(x) =x ).
- Bước 2: Lập phương trình: Đặt ( f(x) = x ) và giải phương trình này để tìm
điểm bất động.
- Bước 3: Kiểm tra điều kiện: Đảm bảo rằng giá trị tìm được thỏa mãn các
điều kiện của bài toán, như điều kiện xác định của hàm số.
- Bước 4: Chứng minh: Sử dụng các phương pháp chứng minh toán học để
xác nhận rằng giá trị tìm được thực sự là điểm bất động.
b. Đặt bài toán
Bài toán: sử dụng thao tác đại số để chỉ ra rằng mỗi hàm số sau có một
điểm cố định tại p chính xác khi f(p)=0 trong đó f(x) = X^4+2X^2-X-3

#include<stdio.h>
#include <math.h>
#include<stdlib.h>
// Định nghĩa hàm f(x) cần giải
#define f(x) x*x*x*x + 2*x*x - x -3

// Viết lại f(x) dưới dạng x = g(x) và định nghĩa g(x)


#define g(x) (3*x*x*x*x + 2*x*x +3) / (4*x*x*x +4*x -1)

int main() {
int step = 1, N;
float x0, x1, e;

// Nhập dữ liệu
printf("Nhập giá trị đoán ban đầu: ");
scanf("%f", &x0);
printf("Nhập sai số chấp nhận được: ");
scanf("%f", &e);
printf("Nhập số lần lặp tối đa: ");
scanf("%d", &N);

// Thực hiện phương pháp lặp điểm bất động


printf("\nBước\t x0\t\t f(x0)\t\t x1\t\t f(x1)\n");
do {
x1 = g(x0);
printf("%d\t%f\t%f\t%f\t%f\n", step, x0, f(x0), x1, f(x1));
step = step + 1;

if (step > N) {
printf("Không hội tụ.\n");
exit(0);
}

x0 = x1;
} while (fabs(f(x1)) > e);

printf("\nNghiệm là %f\n", x1);


return 0;
}

- Soulution
3. Phương pháp điểm sai
a. Thuật toán và source code bài toán phương pháp điểm sai
1. Khởi tạo và Đầu vào:
- Khai báo các biến x0, x1 (giá trị đoán ban đầu), x2 (nghiệm tìm
được), f0, f1, f2 (giá trị hàm số tại các điểm tương ứng), và e (sai số có thể
chấp nhận).
- Nhập giá trị đoán ban đầu và sai số có thể chấp nhận từ người dùng.
2. Tính toán Giá trị Hàm số:
- Tính giá trị hàm số tại x0 và x1 sử dụng định nghĩa hàm f(x).
3. Kiểm tra Giá trị Đoán:
- Kiểm tra xem hai giá trị đoán x0 và x1 có bao quanh nghiệm hay không bằng
cách nhân f0 và f1. Nếu tích lớn hơn 0, thông báo rằng giá trị đoán không
chính xác.
4. Lặp để Tìm Nghiệm:
- Thực hiện vòng lặp do-while với điều kiện là giá trị tuyệt đối của f2 lớn hơn
sai số e.
- Trong mỗi lần lặp:
o Tính x2 sử dụng công thức Regula Falsi.
o Tính f2 tại x2 mới này.
o In ra bước hiện tại và các giá trị x0, x1, x2, f(x2).
o Cập nhật x0 hoặc x1 dựa trên dấu của f0 * f2.
o Tăng số bước lên 1.
5. Kết quả:
- Khi điều kiện dừng của vòng lặp được thỏa mãn, tức là f2 nhỏ hơn hoặc bằng
sai số e, in ra nghiệm x2.
- Ví dụ: sử dụng phương pháp Điểm sai để tìm nghiệm có độ chính xác 10-6
cho bài toán

#include<stdio.h>
#include<conio.h>
#include<math.h>
/* Định nghĩa phương trình cần giải.
Thay đổi phương trình này để giải quyết vấn đề khác. */
#define f(x) x – cos(x)

int main()
{
float x0, x1, x2, f0, f1, f2, e;
int step = 1;
printf("\nNhập hai giá trị đoán ban đầu:\n");
scanf("%f%f", &x0, &x1);
printf("Nhập sai số có thể chấp nhận:\n");
scanf("%f", &e);
/* Tính toán Giá trị Hàm số */
f0 = f(x0);
f1 = f(x1);
/* Kiểm tra xem các giá trị đoán có bao quanh nghiệm hay không. */
if (f0 * f1 > 0.0)
{
printf("Giá trị đoán ban đầu không chính xác.\n");

}
/* Thực hiện Phương pháp Điểm Sai */
printf("\nBước\t\tx0\t\tx1\t\tx2\t\tf(x2)\n");
do
{
x2 = x0 - (x0 - x1) * f0 / (f0 - f1);
f2 = f(x2);
printf("%d\t\t%f\t%f\t%f\t%f\n", step, x0, x1, x2, f2);

if (f0 * f2 < 0)
{
x1 = x2;
f1 = f2;
}
else
{
x0 = x2;
f0 = f2;
}
step = step + 1;

} while (fabs(f2) > e);

printf("\nNghiệm là: %f", x2);


return 0;
}

- Soulution
4. Phương pháp Newton
a. Bài toán
- Tìm nghiệm của phương tình f(x) = 4 * sin(x) - exp(x)
1. Định nghĩa phương trình và đạo hàm của nó:
- Phương trình: f(x) = 4 * sin(x) - exp(x)
- Đạo hàm: g(x) = 4 * cos(x) - exp(x)
2. Chọn giá trị đoán ban đầu (x0) và sai số có thể chấp nhận ( e ).
3. Thực hiện các bước lặp theo phương pháp Newton-Raphson:
- Tính giá trị hàm (f(x0) ) và đạo hàm ( g(x0) ).
- Kiểm tra điều kiện dừng: Nếu (|f ( x 0 )|≤ e), nghiệm đã được tìm thấy.
f ( x 0)
- Cập nhật giá trị (x0) bằng công thức: x 1=x 0− .
g (x 0)
- Lặp lại các bước trên cho đến khi điều kiện dừng được thỏa mãn hoặc số lần
lặp vượt quá giới hạn cho phép.
/* Chương trình: Tìm nghiệm thực của phương trình phi tuyến bằng phương pháp
Newton-Raphson */
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>

/* Định nghĩa phương trình cần giải.


Thay đổi phương trình này để giải quyết vấn đề khác. */

#define f(x) 4 * sin(x) - exp(x)

/* Định nghĩa đạo hàm của g(x).


Khi bạn thay đổi f(x), thay đổi hàm này nữa. */

#define g(x) 4 * cos(x) - exp(x)

void main()
{
float x0, x1, f0, f1, g0, e;
int step = 1, N;

printf("----------------------------------------------------\n\n");
printf("Tìm nghiệm bằng phương pháp NEWTON-RAPHSON\n\n");
printf("----------------------------------------------------\n\n");
/* Nhập liệu */
printf("\nNhập giá trị đoán ban đầu:\n");
scanf("%f", &x0);
printf("Nhập sai số có thể chấp nhận:\n");
scanf("%f", &e);
printf("Nhập số lần lặp tối đa:\n");
scanf("%d", &N);
/* Thực hiện phương pháp Newton Raphson */
printf("\nBước\t\tx0\t\tf(x0)\t\tx1\t\tf(x1)\n");
do
{
g0 = g(x0);
f0 = f(x0);
if (g0 == 0.0)
{
printf("Lỗi Toán học.");
exit(0);
}
x1 = x0 - f0 / g0;

printf("%d\t\t%f\t%f\t%f\t%f\n", step, x0, f0, x1, f1);


x0 = x1;

step = step + 1;

if (step > N)
{
printf("Không hội tụ.");
exit(0);
}

f1 = f(x1);

} while (fabs(f1) > e);

printf("\nNghiệm theo phương pháp Newton-Raphson sau %d lần lặp là: %f",
step - 1, x1);
getch();
}

- Soulution run code


5. Phương pháp dây cung
a. Bài toán
Ví dụ: sử dụng phương pháp dây cung để tìm nghiệm có kết quả sai số 10-6 với
f(x) = x*x*x - 2*x*x – 5 [1,4]
thuật toán:
1. Định nghĩa phương trình chuyển động của vật thể:
- Phương trình có dạng ( f(x) = x^3 -2*x^2 - 5 ),
2. Chọn giá trị đoán ban đầu x0 và x1 cùng với sai số có thể chấp nhận e .
3. Thực hiện các bước lặp theo phương pháp Secant:

- Tính giá trị hàm ( f(x_0) ) và ( f(x_1) ).


- Kiểm tra điều kiện dừng: Nếu (|f ( x 2 )|≤ e ) nghiệm đã được tìm thấy.
- Cập nhật giá trị x0 và x1 bằng công thức:

- Lặp lại các bước trên cho đến khi điều kiện dừng được thỏa mãn hoặc số lần
lặp vượt quá giới hạn cho phép.

#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<stdlib.h>

/* Định nghĩa phương trình cần giải.


Thay đổi phương trình này để giải quyết vấn đề khác. */
#define f(x) x*x*x - 2*x*x – 5 //[1,4]

void main()
{
float x0, x1, x2, f0, f1, f2, e;
int step = 1, N;

printf("\nNhập giá trị đoán ban đầu:\n");


scanf("%f%f", &x0, &x1);
printf("Nhập sai số có thể chấp nhận:\n");
scanf("%f", &e);
printf("Nhập số lần lặp tối đa:\n");
scanf("%d", &N);

/* Thực hiện Phương pháp Secant */


printf("\nBước\t\tx0\t\tx1\t\tx2\t\tf(x2)\n");
do
{
f0 = f(x0);
f1 = f(x1);
if (f0 == f1)
{
printf("Lỗi Toán học.");
exit(0);
}

x2 = x1 - (x1 - x0) * f1 / (f1 - f0);


f2 = f(x2);

printf("%d\t\t%f\t%f\t%f\t%f\n", step, x0, x1, x2, f2);

x0 = x1;
f0 = f1;
x1 = x2;
f1 = f2;

step = step + 1;
if (step > N)
{
printf("Không hội tụ.");
exit(0);
}
} while (fabs(f2) > e);

printf("\nNghiệm là: %f", x2);

- Soulution run code:

CHƯƠNG 2: GIẢI PHƯƠNG TRÌNH


1. Phương pháp khử Gauss – Jordan
a. Bài toán:
Ví du:

1. Xác định Hệ Phương Trình Tuyến Tính:


- Giả sử chúng ta có hệ phương trình sau:

2x+3y−z4 =5

x+y+2z = 6

−3x+2y+4z = 10

2. Chuyển Hệ Phương Trình thành Ma trận Hệ số:

- Ma trận hệ số ( A ) và ma trận cột ( B ) cho hệ phương trình trên sẽ là:

[ ] []
2 3 −1 5
A= 4 1 2 , B= 6
−3 2 4 10

3. Nhập Ma trận vào Chương Trình:

- Sử dụng chương trình bạn đã cung cấp, nhập ma trận ( A ) vào chương trình
khi được yêu cầu.

4. Chạy Chương Trình và Nhận Ma trận Nghịch Đảo:

- Chương trình sẽ thực hiện các phép biến đổi hàng để chuyển ma trận ( A )
thành ma trận đơn vị ( I ), và phần mở rộng của nó sẽ trở thành ma trận nghịch
đảo ( A^{-1} ).

5. Sử dụng Ma trận Nghịch Đảo để Tìm Nghiệm:

- Nghiệm của hệ phương trình có thể được tìm thấy bằng cách nhân ma trận
nghịch đảo ( A^{-1} ) với ma trận cột ( B ):
−1
X =A B

6. Kiểm Tra và So Sánh Kết Quả:

- So sánh kết quả thu được từ chương trình với phương pháp giải thủ công hoặc
sử dụng máy tính để đảm bảo tính chính xác.

#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<stdlib.h>
#define SIZE 10

int main()
{
float a[SIZE][SIZE], x[SIZE], ratio;
int i, j, k, n;

printf("Nhập cấp của ma trận: ");


scanf("%d", &n);
/* 2. Đọc Ma trận */
printf("Nhập hệ số của Ma trận:\n");
for (i = 1;i <= n;i++)
{
for (j = 1;j <= n;j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%f", &a[i][j]);
}
}
/* Bổ sung Ma trận Đơn vị cấp n */
for (i = 1;i <= n;i++)
{
for (j = 1;j <= n;j++)
{
if (i == j)
{
a[i][j + n] = 1;
}
else
{
a[i][j + n] = 0;
}
}
}
/* Áp dụng Phương pháp Gauss Jordan */
for (i = 1;i <= n;i++)
{
if (a[i][i] == 0.0)
{
printf("Lỗi Toán học!");
exit(0);
}
for (j = 1;j <= n;j++)
{
if (i != j)
{
ratio = a[j][i] / a[i][i];
for (k = 1;k <= 2 * n;k++)
{
a[j][k] = a[j][k] - ratio * a[i][k];
}
}
}
}
/* Thao tác hàng để làm cho Đường chéo chính thành 1 */
for (i = 1;i <= n;i++)
{
for (j = n + 1;j <= 2 * n;j++)
{
a[i][j] = a[i][j] / a[i][i];
}
}
/* Hiển thị Ma trận Nghịch đảo */
printf("\nMa trận Nghịch đảo là:\n");
for (i = 1;i <= n;i++)
{
for (j = n + 1;j <= 2 * n;j++)
{
printf("%0.3f\t", a[i][j]);
}
printf("\n");
}

return(0);
}

2. Phương pháp khử Gauss


a. Bài toán
Ví dụ:

1. Xác định Hệ Phương Trình Tuyến Tính:

- Giả sử chúng ta có hệ phương trình sau:


3x +2 y + z=1
2x −2 y 4 z=−2
−1 x +0.5 y −z=0

2. Chuyển Hệ Phương Trình thành Ma trận Tăng cường:

- Ma trận tăng cường cho hệ phương trình trên sẽ là:

[ ]
3 21∨1
2−2 4∨−2
−1 0.5−1∨0

3. Nhập Ma trận vào Chương Trình:

- Sử dụng chương trình bạn đã cung cấp, nhập ma trận tăng cường vào chương trình khi
được yêu cầu.

4. Chạy Chương Trình và Nhận Giải pháp:

- Chương trình sẽ thực hiện các phép biến đổi hàng để chuyển ma trận tăng cường thành
dạng bậc thang rồi thực hiện thay thế ngược để tìm giải pháp cho hệ phương trình.

5. Kiểm Tra và So Sánh Kết Quả:

- So sánh kết quả thu được từ chương trình với phương pháp giải thủ công hoặc sử dụng
máy tính để đảm bảo tính chính xác.

#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<stdlib.h>

#define SIZE 10

int main()
{
float a[SIZE][SIZE], x[SIZE], ratio;
int i, j, k, n;

printf("Nhập số lượng ẩn số: ");


scanf("%d", &n);
/* 2. Đọc Ma trận Tăng cường */
for (i = 1;i <= n;i++)
{
for (j = 1;j <= n + 1;j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%f", &a[i][j]);
}
}
/* Áp dụng Phương pháp Loại trừ Gauss */
for (i = 1;i <= n - 1;i++)
{
if (a[i][i] == 0.0)
{
printf("Lỗi Toán học!");
exit(0);
}
for (j = i + 1;j <= n;j++)
{
ratio = a[j][i] / a[i][i];

for (k = 1;k <= n + 1;k++)


{
a[j][k] = a[j][k] - ratio * a[i][k];
}
}
}
/* Đạt được Giải pháp bằng Cách Thay thế Ngược */
x[n] = a[n][n + 1] / a[n][n];

for (i = n - 1;i >= 1;i--)


{
x[i] = a[i][n + 1];
for (j = i + 1;j <= n;j++)
{
x[i] = x[i] - a[i][j] * x[j];
}
x[i] = x[i] / a[i][i];
}
/* Hiển thị Giải pháp */
printf("\nGiải pháp:\n");
for (i = 1;i <= n;i++)
{
printf("x[%d] = %0.3f\n", i, x[i]);
}

return(0);
}

- Soulution run code:

3. Phương pháp tìm ma trận nghịch đảo sử dụng phương pháp Gauss – Jordan
a. Bài toán
Ví du:

1. Xác định Hệ Phương Trình Tuyến Tính:

- Giả sử chúng ta có hệ phương trình sau:


3x +2 y + z=1
2x −2 y 4 z=−2
−1 x +0.5 y −z=0

2.Chuyển Hệ Phương Trình thành Ma trận Hệ số:

- Ma trận hệ số ( A ) và ma trận cột ( B ) cho hệ phương trình trên sẽ là:

[ ]
3 21∨1
2−2 4∨−2 
−1 0.5−1∨0

3. Nhập Ma trận vào Chương Trình:

- Sử dụng chương trình bạn đã cung cấp, nhập ma trận ( A ) vào chương trình khi
được yêu cầu.

4. Chạy Chương Trình và Nhận Ma trận Nghịch Đảo:

- Chương trình sẽ thực hiện các phép biến đổi hàng để chuyển ma trận ( A ) thành
ma trận đơn vị ( I ), và phần mở rộng của nó sẽ trở thành ma trận nghịch đảo
( A^{-1} ).

5. Sử dụng Ma trận Nghịch Đảo để Tìm Nghiệm:

- Nghiệm của hệ phương trình có thể được tìm thấy bằng cách nhân ma trận
nghịch đảo ( A^{-1} ) với ma trận cột ( B ):

X=A^−1*B

6. Kiểm Tra và So Sánh Kết Quả:

- So sánh kết quả thu được từ chương trình với phương pháp giải thủ công hoặc sử
dụng máy tính để đảm bảo tính chính xác.

#include<stdio.h>
#include<conio.h>
#include<math.h>
#define SIZE 10
int main()
{
float a[SIZE][SIZE], x[SIZE], ratio;
int i, j, k, n;
/* 1. Đọc cấp của ma trận */
printf("Nhập cấp của ma trận: ");
scanf("%d", &n);
/* 2. Đọc Ma trận */
printf("Nhập hệ số của Ma trận:\n");
for (i = 1;i <= n;i++)
{
for (j = 1;j <= n;j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%f", &a[i][j]);
}
}
/* Bổ sung Ma trận Đơn vị cấp n */
for (i = 1;i <= n;i++){
for (j = 1;j <= n;j++){
if (i == j){
a[i][j + n] = 1;
}else
{
a[i][j + n] = 0;
}
}
}
/* Áp dụng Phương pháp loại trừ Gauss Jordan */
for (i = 1;i <= n;i++)
{
if (a[i][i] == 0.0)
{
printf("Lỗi Toán học!");
break;
}
for (j = 1;j <= n;j++)
{
if (i != j)
{
ratio = a[j][i] / a[i][i];
for (k = 1;k <= 2 * n;k++)
{
a[j][k] = a[j][k] - ratio * a[i][k];
}
}
}
}
/* Thao tác hàng để làm cho Đường chéo chính thành 1 */
for (i = 1;i <= n;i++)
{
for (j = n + 1;j <= 2 * n;j++)
{
a[i][j] = a[i][j] / a[i][i];
}
}
/* Hiển thị Ma trận Nghịch đảo */
printf("\nMa trận Nghịch đảo là:\n");
for (i = 1;i <= n;i++)
{
for (j = n + 1;j <= 2 * n;j++)
{
printf("%0.3f\t", a[i][j]);
}
printf("\n");
}
return(0);
}

- Soulution run code:


-

2. Phương pháp lặp Gauss – Jacobi


a. Bai toan
Vi du:

Bài toán: Giả sử chúng ta cần giải hệ phương trình sau:

20 x+ y−5 z=403 x+ 20 y−44 z=−182 x−3 y +20 z=25

Phương pháp lặp đơn sẽ được sử dụng như sau:

1. Định nghĩa các hàm lặp tương ứng với mỗi biến:
40− y+ 5 z
o f 1 ( x , y , z )=
20
−18−3 x +44 z
o f 2 ( x , y , z )=
20
25−2 x +3 z
o f 3 ( x , y , z )=
20
2. Chọn giá trị ban đầu cho ( x ), ( y ), và ( z ). Trong trường hợp này, giá trị ban
đầu là 0 cho cả ba biến.
3. Thực hiện lặp:
o Tính giá trị mới cho mỗi biến dựa trên giá trị hiện tại của các biến khác.
o Kiểm tra sai số giữa giá trị mới và giá trị cũ cho mỗi biến.
o Tiếp tục lặp cho đến khi sai số cho mỗi biến nhỏ hơn sai số có thể chấp
nhận được ( e ).
4. In ra kết quả:
o Khi sai số đủ nhỏ, in ra giá trị của ( x ), ( y ), và ( z ) là nghiệm của hệ
phương trình.

#include<stdio.h>
#include<conio.h>
#include<math.h>

#define f1(x,y,z) (40-y+5*z)/20


#define f2(x,y,z) (-18-3*x+44*z)/20
#define f3(x,y,z) (25-2*x+3*y)/20

int main()
{
float x0 = 0, y0 = 0, z0 = 0, x1, y1, z1, e1, e2, e3, e;
int count = 1;

printf("Nhập sai số có thể chấp nhận được:\n");


scanf("%f", &e);

printf("\nLần\tX\tY\tZ\n");
do
{
/* Tính toán */
x1 = f1(x0, y0, z0);
y1 = f2(x0, y0, z0);
z1 = f3(x0, y0, z0);
printf("%d\t%0.4f\t%0.4f\t%0.4f\n", count, x1, y1, z1);

/* Sai số */
e1 = fabs(x0 - x1);
e2 = fabs(y0 - y1);
e3 = fabs(z0 - z1);

count++;
/* Đặt giá trị cho lần lặp tiếp theo */
x0 = x1;
y0 = y1;
z0 = z1;
} while (e1 > e && e2 > e && e3 > e);

printf("\nNghiệm: x=%0.3f, y=%0.3f và z = %0.3f\n", x1, y1, z1);


return 0;
}

- Soulution run code:

3. Phương pháp phân tích A=LU


a. Bai toan
Vi du:

Giả sử chúng ta cần giải hệ phương trình tuyến tính:

2 x+ y−z=8−x− y +2 z=−11−x + y +2 z=3

Chúng ta có thể biểu diễn hệ phương trình này dưới dạng ma trận ( A ) và vector cột ( b )
như sau:

[ ] [ ]
2 1−1 8
A= −3−12 , b= −11
−2 12 3

Bây giờ, chúng ta sẽ sử dụng code đã cho để thực hiện phân tích LU trên ma trận ( A ).
Sau khi phân tích, chúng ta sẽ có hai ma trận ( L ) và ( U ) mà ( A = LU ). Sử dụng ( L )
và ( U ), chúng ta có thể giải hệ phương trình bằng cách giải hai hệ phương trình con:

1. ( Ld = b ) để tìm ( d ) (sử dụng thay thế tiến).


2. ( Ux = d ) để tìm ( x ) (sử dụng thay thế ngược).

#include <stdio.h>
#include <stdlib.h>

#define N 3

// Hàm để thực hiện phân tích LU


void luDecomposition(float a[N][N], float l[N][N], float u[N][N]) {
int i, j, k;
for (i = 0; i < N; i++) {
for (j = 0; j < N; j++) {
if (j < i)
l[j][i] = 0;
else {
l[j][i] = a[j][i];
for (k = 0; k < i; k++) {
l[j][i] = l[j][i] - l[j][k] * u[k][i];
}
}
}
for (j = 0; j < N; j++) {
if (j < i)
u[i][j] = 0;
else if (j == i)
u[i][j] = 1;
else {
u[i][j] = a[i][j] / l[i][i];
for (k = 0; k < i; k++) {
u[i][j] = u[i][j] - ((l[i][k] * u[k][j]) / l[i][i]);
}
}
}
}
}

int main() {
float a[N][N];
int i, j;
// khai bao ma tran
for (i = 0;i < N;i++)
{
for (j = 0;j < N;j++)
{
printf("a[%d][%d] = ", i, j);
scanf("%f", &a[i][j]);
}
}

float l[N][N] = { 0 }; // Ma trận L


float u[N][N] = { 0 }; // Ma trận U

luDecomposition(a, l, u);

printf("Ma trận L:\n");


for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%f ", l[i][j]);
}
printf("\n");
}

printf("Ma trận U:\n");


for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%f ", u[i][j]);
}
printf("\n");
}

return 0;
}

- Soulution run code:

CHƯƠNG 3: BÀI TOÁN NỘI SUY


1. Phương pháp Nội suy Newton
a. Bài tập
#include<stdio.h>
#include<math.h>
int giaiThua(int);
float tinhToan1(float, int);
float tinhToan2(float, int);
int main() {
printf("--------------------------------------------------------------------------\n");
printf("Phương Pháp Nội Suy Newton\n");
printf("--------------------------------------------------------------------------\n\n\n");
int n;
printf("Nhập số lượng dữ liệu mẫu cần nhập: ");
scanf("%d", &n);

float x_val[n];
float fx_val[n][n];

int i, j = 0;

for (i = 0;i < n;i++) {


printf("\nNhập giá trị x: ");
scanf("%f", &x_val[i]);
printf("\nNhập giá trị f(x) tương ứng: ");
scanf("%f", &fx_val[0][i]);

float x;
printf("\nNhập điểm nội suy:");
scanf("%f", &x);
int c = 10;

float s1, s2;


while (c != 0) {
printf("\nNhập 1 để sử dụng Phương Pháp Loại Trừ Tiến \n 2 để sử dụng
Phương Pháp Loại Trừ Lùi \n 0 để thoát.");
scanf("%d", &c);
switch (c) {
case 0:
break;
case 1:
for (i = 0;i < (n - 1);i++) {
for (j = 0;j < (n - i - 1);j++) {
fx_val[i + 1][j] = fx_val[i][j + 1] - fx_val[i][j];
}
}
printf("\n\n\n");
for (i = 0;i < n;i++) {
printf("\n");
for (j = 0;j < (n - i);j++) {
printf("%f ", fx_val[j][i]);
}
}
s1 = (x - x_val[0]) / (x_val[1] - x_val[0]);

float in1 = fx_val[0][0];


for (i = 0;i < n - 1;i++) {
in1 = in1 + (tinhToan1(s1, (i + 1)) / giaiThua(i + 1)) *
fx_val[i + 1][0];
}
printf("\nGiá trị nội suy theo phương pháp nội suy Newton là: %f\
n\n", in1);
break;

case 2:
for (i = 0;i < (n - 1);i++) {
for (j = 0;j < (n - i - 1);j++) {
fx_val[i + 1][j] = fx_val[i][j + 1] - fx_val[i][j];
}
}

printf("\n\n\n");
for (j = 0;j < (n - i);j++) {
printf("%f ", fx_val[j][i]);
}

s2 = (x - x_val[n - 1]) / (x_val[1] - x_val[0]);


float in2 = fx_val[0][n - 1];
for (i = 0;i < n - 1;i++) {
in2 = in2 + (tinhToan2(s2, (i + 1)) / giaiThua(i + 1)) *
fx_val[i + 1][n - i - 2];
}
printf("\nGiá trị nội suy theo phương pháp nội suy Newton là: %f\
n\n", in2);
break;

}
}
}
int giaiThua(int x) {
int f = 1;
int i = 0;
for (i = 1;i <= x;i++) {
f = f * i;
}
return f;
}

float tinhToan1(float s, int n) {


int i = 0;
float r = 1;

for (i = 0;i < n;i++) {


r = r * (s - i);
}
return r;
}

float tinhToan2(float s, int n) {


int i = 0;
float r = 1;

for (i = 0;i < n;i++) {


r = r * (s + i);
}
return r;
}

- Soulution run code:


2. Phương pháp nội suy Lagrange
a. Bai toan

#include<stdio.h>
#include<math.h>

int main() {
printf("--------------------------------------------------------------------------\n");
printf("Phương Pháp Nội Suy Lagrange\n");
printf("--------------------------------------------------------------------------\n\n\n");
int p;
printf("Nhập số lượng giá trị mẫu cần nhập: ");
scanf("%d", &p);
float x_val[p];
float fx_val[p];

int i = 0;

for (i = 0;i < p;i++) {


printf("\nNhập giá trị x: ");
scanf("%f", &(x_val[i]));
printf("Nhập giá trị fx tương ứng: ");
scanf("%f", &(fx_val[i]));

}
printf("\nCác giá trị x đã nhập và giá trị hàm tương ứng là\n\n ");
printf("-----------------------------------------------\n");
for (i = 0;i < p;i++) {
printf("%f ", x_val[i]);
}
printf("\n");
for (i = 0;i < p;i++) {
printf("%f ", fx_val[i]);
}
printf("\n-----------------------------------------------\n");
float x;

printf("\nNhập giá trị cần nội suy: ");


scanf("%f", &x);
float l = 1;
float ip = 0;
int j = 0;

for (i = 0;i < p;i++) {


for (j = 0;j < p;j++) {
if (i != j) {
l = l * ((x - x_val[j]) / (x_val[i] - x_val[j]));

ip = ip + (l * fx_val[i]);
l = 1;
}

printf("\n\nGiá trị nội suy tại x=%f theo phương pháp nội suy Lagrange là %f: ",
x, ip);
}

- Soulution run code:


3. Phương pháp nội suy Speline
a. Bai toan
Vi du:

Áp dụng các số liệu bài 4 để tính nội suy Speline


#include <stdio.h>
#include <math.h>

// Hàm để tính nội suy spline tại điểm x


double splineInterpolation(double x[], double y[], int n, double xp) {
double h[n], alpha[n], l[n], mu[n], z[n];
double c[n], b[n], d[n];
int i;

// Bước 1: Tính h và alpha


for (i = 0; i < n - 1; i++) {
h[i] = x[i + 1] - x[i];
alpha[i] = (3 / h[i]) * (y[i + 1] - y[i]) - (3 / h[i - 1]) * (y[i] - y[i - 1]);
}

// Bước 2: Giải hệ phương trình tuyến tính để tìm l, mu và z


l[0] = 1;
mu[0] = z[0] = 0;

for (i = 1; i < n - 1; i++) {


l[i] = 2 * (x[i + 1] - x[i - 1]) - h[i - 1] * mu[i - 1];
mu[i] = h[i] / l[i];
z[i] = (alpha[i] - h[i - 1] * z[i - 1]) / l[i];
}

l[n - 1] = 1;
z[n - 1] = c[n - 1] = 0;

// Bước 3: Tính c, b và d
for (i = n - 2; i >= 0; i--) {
c[i] = z[i] - mu[i] * c[i + 1];
b[i] = (y[i + 1] - y[i]) / h[i] - h[i] * (c[i + 1] + 2 * c[i]) / 3;
d[i] = (c[i + 1] - c[i]) / (3 * h[i]);
}

// Bước 4: Tính giá trị nội suy tại xp


double yp = 0;
for (i = 0; i < n - 1; i++) {
if (xp >= x[i] && xp <= x[i + 1]) {
yp = y[i] + b[i] * (xp - x[i]) + c[i] * pow(xp - x[i], 2) + d[i] * pow(xp - x[i], 3);
break;
}
}

return yp;
}

int main() {
// Mảng các điểm dữ liệu x và y
double x[] = { /* Điền giá trị x */ };
double y[] = { /* Điền giá trị y */ };
int n = sizeof(x) / sizeof(x[0]); // Số lượng điểm dữ liệu

// Điểm cần nội suy


double xp = /* Điền giá trị xp */;

// Tính và in ra giá trị nội suy


double yp = splineInterpolation(x, y, n, xp);
printf("Gia tri noi suy tai x = %lf la: %lf\n", xp, yp);

return 0;
}

- Soulution run code:


CHƯƠNG 4: PHƯƠNG PHÁP BÌNH PHƯƠNG TỐI THIỂU

1. Phương pháp bình phương tối thiểu rời rạc


a. Thuật toán giải phương pháp bình phương tối thiểu rời rạc
- Bước 1: Tính tổng các phần tử của mảng (sum): Hàm sum nhận vào một
mảng arr và số lượng phần tử n, sau đó tính tổng tất cả các phần tử trong mảng.
- Bước 2: Tính tổng các phần tử của tích hai mảng (sumOfProducts):
Hàm sumOfProducts nhận vào hai mảng arr1 và arr2 cùng với số lượng phần
tử n, sau đó tính tổng các tích tương ứng của từng cặp phần tử trong hai mảng.
- Bước 3: Thực hiện hồi quy tuyến tính (linreg): Hàm linreg sử dụng hai
mảng x và y là dữ liệu đầu vào, cùng với hai biến con trỏ m và b để lưu hệ số
góc và hệ số tự do của đường hồi quy tuyến tính. Hàm này sẽ tính toán các giá
trị này dựa trên công thức hồi quy tuyến tính.
- Bước 4: Kiểm tra điều kiện định thức (denom): Trong hàm linreg, denom là
định thức của ma trận hệ số. Nếu denom bằng 0, điều này có nghĩa là không
thể tìm được hồi quy tuyến tính vì các điểm dữ liệu có thể cùng nằm trên một
đường thẳng hoặc không đủ để tạo thành một mô hình tuyến tính.
- Bước 5; Tính toán hệ số góc và hệ số tự do: Nếu denom khác 0, hàm sẽ tiếp tục
tính toán hệ số góc m và hệ số tự do b dựa trên công thức đã cho.
- Với m = a0, b = a1
-
- Bước 6: In kết quả: Trong hàm main, sau khi gọi hàm linreg, nếu hồi quy tuyến
tính thành công, chương trình sẽ in ra phương trình đường thẳng hồi quy.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// Hàm để tính tổng các phần tử của mảng


double sum(const double arr[], int n) {
double total = 0.0;
for (int i = 0; i < n; i++) {
total += arr[i];
}
return total;
}

// Hàm để tính tổng các phần tử của tích hai mảng


double sumOfProducts(const double arr1[], const double arr2[], int n) {
double total = 0.0;
for (int i = 0; i < n; i++) {
total += arr1[i] * arr2[i];
}
return total;
}

// Hàm linreg để thực hiện hồi quy tuyến tính


int linreg(int n, const double x[], const double y[], double* m, double* b) {
double sumx = sum(x, n); // Tổng của x
double sumx2 = sumOfProducts(x, x, n); // Tổng của x^2
double sumxy = sumOfProducts(x, y, n); // Tổng của x*y
double sumy = sum(y, n); // Tổng của y

double denom = n * sumx2 - sumx * sumx;


if (denom == 0) {
// Trường hợp không thể thực hiện hồi quy tuyến tính
return -1;
}

*m = (n * sumxy - sumx * sumy) / denom;


*b = (sumy * sumx2 - sumx * sumxy) / denom;
return 0; // Thành công
}

int main() {
// Mảng dữ liệu x và y
double x[] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; // có thể thay đổi dữ liệu x và y//
double y[] = { 2.1, 3.9, 6.0, 8.2, 9.9 };
int n = sizeof(x) / sizeof(x[0]); // Số lượng điểm dữ liệu

double m, b; // Hệ số góc và hệ số tự do của đường thẳng

// Thực hiện hồi quy tuyến tính


if (linreg(n, x, y, &m, &b) == 0) {
printf("Phuong trinh duong thang y = %f*x + %f\n", m, b);
}
else {
printf("Khong the thuc hien hoi quy tuyen tinh.\n");
}

return 0;
}

- Soulution run code:


o Với x và y nhập vào như sau:
o
1.0 2.0 3.0 4.0 5.0
2.1 3.9 6.0 8.2 9.9
2. Phương pháp bình phương tối thiểu liên tục bằng đa thức
a. Bài toán
Giả sử f ∈ C[a, b] và Pn(x) là đa thức có bậc lớn nhất là n, ta yêu 1 2 cầu xác
định Pn(x) sao cho sai số sau là nhỏ nhất
b

∫ [ f ( x )− pn ( x) ] dx
2

a
Để xác định một xấp xỉ đa thức bình phương tối thiểu, tức là, một đa thức làm
n
+ …+a1 x+ a0=∑ ak ( x ) E=
n n−1 k
cực tiểu giá trị này, đặt (x) pn ( x )=a n x +an−1 x
k=0

[ ]
b n 2

E2 ( a 0 , a 1 , … , an ) =∫ f ( x )−∑ a k ( x )
k
dx
a k=0

Bài toán là tìm các hệ số a0, a1, …, an để làm cực tiểu E. Khi đó cần phải giải
các phương trình

(∑ )
b n b b n 2
δE
=0 , j=0 ,1 , 2 , … ,n E=∫ f ( x )2 dx −2 ∑ ak ∫ f ( x ) x k dx +∫ ak ( x ) k
dx
δ aj a k=0 a a k=0
b n b
δE
=−2∫ ( x ) f ( x ) dx +¿ 2∑ ak ∫ ( x ) dx j = 0, 1, 2, ...
j k+ j
Ta có:
δ aj a k=0 a
Từ đó, để tìm Pn(x), ta cần phải giải (n+1) phương trình tuyến tính chuẩn:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// Hàm để tính tổng các phần tử của mảng


double sum(const double arr[], int n) {
double total = 0.0;
for (int i = 0; i < n; i++) {
total += arr[i];
}
return total;
}

// Hàm để tính tổng các phần tử của tích hai mảng


double sumOfProducts(const double arr1[], const double arr2[], int n) {
double total = 0.0;
for (int i = 0; i < n; i++) {
total += arr1[i] * arr2[i];
}
return total;
}

// Hàm polyfit để thực hiện hồi quy đa thức


int polyfit(int n, const double x[], const double y[], int degree, double coeff[]) {
// Khởi tạo ma trận và vectơ cần thiết cho phép tính
double X[2 * degree + 1]; // Mảng chứa tổng các lũy thừa của x
for (int i = 0; i < 2 * degree + 1; i++) {
X[i] = sumOfProducts(x, x, n); // Tính tổng các lũy thừa của x
}

double B[degree + 1]; // Mảng chứa tổng của x lũy thừa nhân với y
for (int i = 0; i < degree + 1; i++) {
B[i] = sumOfProducts(x, y, n); // Tính tổng của x lũy thừa nhân với y
}

double A[degree + 1][degree + 1]; // Ma trận hệ số


for (int i = 0; i <= degree; i++) {
for (int j = 0; j <= degree; j++) {
A[i][j] = X[i + j]; // Điền ma trận hệ số với tổng các lũy thừa của x
}
}

// Thực hiện các phép tính để tìm hệ số đa thức


// Giải hệ phương trình tuyến tính Ax = B để tìm hệ số đa thức
// ...

return 0; // Thành công


}

int main() {
// Mảng dữ liệu x và y
double x[] = { 1.0, 2.0, 3.0, 4.0, 5.0 }; //du lieu dau bai cho san
double y[] = { 2.1, 3.9, 6.0, 8.2, 9.9 };
int n = sizeof(x) / sizeof(x[0]); // Số lượng điểm dữ liệu
int degree = 2; // Bậc của đa thức
double coeff[degree + 1]; // Mảng chứa hệ số đa thức

// Thực hiện hồi quy đa thức


if (polyfit(n, x, y, degree, coeff) == 0) {
printf("Phuong trinh da thuc xap xi la: ");
for (int i = 0; i <= degree; i++) {
printf("%f*x^%d ", coeff[i], i);
}
printf("\n");
}
else {
printf("Khong the thuc hien hoi quy da thuc.\n");
}

return 0;
}

- Soulution run code:


3. Phương pháp bình phương tối thiểu liên tục va trực giao

#include <stdio.h>
#include <math.h>

// Hàm để tính tích vô hướng của hai vectơ


double dot_product(const double* a, const double* b, int n) {
double sum = 0.0;
for (int i = 0; i < n; i++) {
sum += a[i] * b[i];
}
return sum;
}
// Hàm để thực hiện quá trình trực giao hóa Gram-Schmidt
void gram_schmidt(double* a[], double* q[], int n) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
q[i][j] = a[i][j];
}
for (int j = 0; j < i; j++) {
double r = dot_product(q[j], a[i], n);
for (int k = 0; k < n; k++) {
q[i][k] -= r * q[j][k];
}
}
double norm = sqrt(dot_product(q[i], q[i], n));
for (int j = 0; j < n; j++) {
q[i][j] /= norm;
}
}
}

// Hàm để thực hiện phương pháp bình phương tối thiểu


void least_squares(double* q[], double* b, double* x, int n) {
for (int i = 0; i < n; i++) {
x[i] = dot_product(q[i], b, n);
}
}

int main() {
// Khai báo và khởi tạo dữ liệu
int n = /* Số chiều dữ liệu */;
double* a[n]; // Ma trận A
double* q[n]; // Ma trận Q sau khi trực giao hóa
double b[n]; // Vectơ b
double x[n]; // Nghiệm x

// Khởi tạo ma trận A và vectơ b


// ...

// Thực hiện trực giao hóa Gram-Schmidt


gram_schmidt(a, q, n);

// Thực hiện phương pháp bình phương tối thiểu


least_squares(q, b, x, n);
// In ra nghiệm x
for (int i = 0; i < n; i++) {
printf("x[%d] = %f\n", i, x[i]);
}

return 0;
}
CHƯƠNG 5: TÍNH GẦN ĐÚNG ĐẠO HÀM, TÍCH PHÂN

1. Phương pháp tích phân: quy tắc hình thang


a. Bài toán

#include<stdio.h>
#include<conio.h>
#include<math.h>

/* Định nghĩa hàm tại đây */


#define f(x) 1/(1+pow(x,2))

int main()
{
float canDuoi, canTren, tichPhan = 0.0, buocNhay, k;
int i, soDoanNho;

printf("Nhập cận dưới của tích phân: ");


scanf("%f", &canDuoi);
printf("Nhập cận trên của tích phân: ");
scanf("%f", &canTren);
printf("Nhập số đoạn nhỏ: ");
scanf("%d", &soDoanNho);

/* Tính toán */
/* Tìm kích thước bước nhảy */
buocNhay = (canTren - canDuoi) / soDoanNho;

/* Tìm giá trị tích phân */


tichPhan = f(canDuoi) + f(canTren);
for (i = 1; i <= soDoanNho - 1; i++)
{
k = canDuoi + i * buocNhay;
tichPhan = tichPhan + 2 * f(k);
}
tichPhan = tichPhan * buocNhay / 2;
printf("\nGiá trị tích phân cần tìm là: %.3f", tichPhan);
getch();
return 0;
}
- Soulution run code:
-
2. Phương pháp tích phân Simpson
a. Bai toan
Vi du:

Áp dụng với quy tắm Simpson


#include<stdio.h>
#include<conio.h>
#include<math.h>

/* Định nghĩa hàm tại đây */


#define f(x) 1/(1+x*x)

int main()
{
float canDuoi, canTren, tichPhan = 0.0, buocNhay, k;
int i, soDoanNho;

printf("Nhập cận dưới của tích phân: ");


scanf("%f", &canDuoi);
printf("Nhập cận trên của tích phân: ");
scanf("%f", &canTren);
printf("Nhập số đoạn nhỏ: ");
scanf("%d", &soDoanNho);

/* Tính toán */
/* Tìm kích thước bước nhảy */
buocNhay = (canTren - canDuoi) / soDoanNho;

/* Tìm giá trị tích phân */


tichPhan = f(canDuoi) + f(canTren);
for (i = 1; i <= soDoanNho - 1; i++)
{
k = canDuoi + i * buocNhay;
if (i % 2 == 0)
{
tichPhan = tichPhan + 2 * f(k);
}
else
{
tichPhan = tichPhan + 4 * f(k);
}
}
tichPhan = tichPhan * buocNhay / 3;
printf("\nGiá trị tích phân cần tìm là: %.3f", tichPhan);
getch();
return 0;
}
- Soulution run code;
3. Phương pháp Romberg cơ bản
a. Bài toán
Ví dụ:

#include <stdio.h>
#include <math.h>

// Hàm f(x) mà bạn muốn tính tích phân


double f(double x) {
return 1 / (1 + x * x); // Ví dụ: tính tích phân của hàm 1/(1+x^2)
}

void print_row(size_t i, double* R) {


printf("R[%2zu] = ", i);
for (size_t j = 0; j <= i; ++j) {
printf("%f ", R[j]);
}
printf("\n");
}

double romberg(double (*f)(double), double a, double b, size_t max_steps, double acc)


{
double R1[max_steps], R2[max_steps]; // Buffers
double* Rp = &R1, * Rc = &R2; // Rp is previous row, Rc is current row
double h = b - a; // Step size
Rp[0] = (f(a) + f(b)) * h * 0.5; // First trapezoidal step
print_row(0, Rp);

for (size_t i = 1; i < max_steps; ++i) {


h /= 2.;
double c = 0;
size_t ep = 1 << (i - 1); // 2^(n-1)
for (size_t j = 1; j <= ep; ++j) {
c += f(a + (2 * j - 1) * h);
}
Rc[0] = h * c + 0.5 * Rp[0]; // R(i,0)
for (size_t j = 1; j <= i; ++j) {
double n_k = pow(4, j);
Rc[j] = (n_k * Rc[j - 1] - Rp[j - 1]) / (n_k - 1); // Compute R(i,j)
}
print_row(i, Rc);
if (i > 1 && fabs(Rp[i - 1] - Rc[i]) < acc) {
return Rc[i]; // Return the best estimate
}

// Swap Rp and Rc as we only need the last row


double* rt = Rp;
Rp = Rc;
Rc = rt;
}
return Rp[max_steps - 1]; // Return our best guess
}

int main() {
double a, b; // Lower and upper limits of integration
size_t max_steps; // Maximum steps
double acc; // Desired accuracy

printf("Enter lower limit of integration: ");


scanf("%lf", &a);
printf("Enter upper limit of integration: ");
scanf("%lf", &b);
printf("Enter maximum steps: ");
scanf("%zu", &max_steps);
printf("Enter desired accuracy: ");
scanf("%lf", &acc);

double result = romberg(f, a, b, max_steps, acc);


printf("\nApproximate value of the integral is: %.3f\n", result);

return 0;
}

- Soulution run code:


-
-
CHƯƠNG 6: GIẢI GẦN ĐÚNG PHƯƠNG TRÌNH VI PHÂN

1. Phương pháp chuỗi Taylo


a. Bài toán
Đây là một công cụ toán học quan trọng có nhiều ứng dụng trong thực tế,
từ khoa học tự nhiên đến kỹ thuật và tài chính. Dưới đây là một ví dụ về
cách áp dụng phương pháp này vào một bài toán thực tế:

Ví Dụ: Giả sử bạn là một nhà kinh tế học và muốn dự đoán sự tăng trưởng
kinh tế dựa trên lãi suất liên tục. Lãi suất liên tục được mô tả bởi công thức
rt
A=P e

nơi ( P ) là số tiền ban đầu, ( r ) là lãi suất hàng năm, và ( t ) là thời gian tính
bằng năm.
Giả sử bạn muốn tính số tiền tương lai ( A ) sau 5 năm với số tiền ban đầu là
1000 đô la và lãi suất hàng năm là 5%. Bạn có thể sử dụng chuỗi Taylor để tính
giá trị gần đúng của ( e^{rt} ) như sau:

#include <stdio.h>
#include <math.h>

// Hàm f(x, y) định nghĩa phương trình vi phân dy/dx = f(x, y)


double f(double x, double y) {
return /* Định nghĩa hàm f(x, y) tại đây */;
}

// Phương pháp Adam-Moulton


void adam_moulton(double (*func)(double, double), double x0, double y0, double h,
int n) {
double y[n + 1], x[n + 1];
y[0] = y0;
x[0] = x0;
// Sử dụng phương pháp Runge-Kutta bậc 4 để tính giá trị ban đầu
for (int i = 1; i <= 3; ++i) {
double k1 = h * func(x[i - 1], y[i - 1]);
double k2 = h * func(x[i - 1] + h / 2, y[i - 1] + k1 / 2);
double k3 = h * func(x[i - 1] + h / 2, y[i - 1] + k2 / 2);
double k4 = h * func(x[i - 1] + h, y[i - 1] + k3);
y[i] = y[i - 1] + (k1 + 2 * k2 + 2 * k3 + k4) / 6;
x[i] = x[i - 1] + h;
}
// Áp dụng phương pháp Adam-Moulton
for (int i = 4; i <= n; ++i) {
x[i] = x[i - 1] + h;
y[i] = y[i - 1]; // Giá trị ban đầu cho y[i], cần được hiệu chỉnh
for (int j = 0; j < 5; ++j) { // Lặp để hiệu chỉnh giá trị y[i]
y[i] = y[i - 1] + h / 24 * (9 * func(x[i], y[i]) + 19 * func(x[i - 1], y[i - 1]) - 5 *
func(x[i - 2], y[i - 2]) + func(x[i - 3], y[i - 3]));
}
}

// In kết quả
for (int i = 0; i <= n; ++i) {
printf("x[%d] = %f, y[%d] = %f\n", i, x[i], i, y[i]);
}
}
int main() {
double x0, y0, h;
int n;
printf("Nhập giá trị ban đầu x0: ");
scanf("%lf", &x0);
printf("Nhập giá trị ban đầu y0: ");
scanf("%lf", &y0);
printf("Nhập bước nhảy h: ");
scanf("%lf", &h);
printf("Nhập số bước n: ");
scanf("%d", &n);

adam_moulton(f, x0, y0, h, n);

return 0;
}
- Soulution run code:
2. Phương pháp Euler’s

#include <stdio.h>
#include <stdlib.h>

// Hàm để tính giá trị gần đúng của hàm mũ sử dụng chuỗi Taylor
float Taylor_exponential(int n, float x) {
float exp_sum = 1; // Khởi tạo tổng là 1 (thành phần đầu tiên của chuỗi Taylor)
// Vòng lặp để tính từng thành phần của chuỗi Taylor cho hàm mũ
for (int i = n - 1; i > 0; --i) {
exp_sum = 1 + x * exp_sum / i; // Tính thành phần tiếp theo của chuỗi và cập nhật
tổng
}
return exp_sum; // Trả về kết quả gần đúng của chuỗi Taylor cho $$ e^x $$
}
// Hàm chính
int main(void) {
int n = 25; // Số thành phần của chuỗi Taylor
float x = 5.0; // Giá trị của x trong $$ e^x $$

// Kiểm tra n và x có lớn hơn 0 trước khi tiếp tục


if (n > 0 && x > 0) {
printf("Giá trị của n = %d và x = %f ", n, x);
printf("e^x gần đúng là: %f", Taylor_exponential(n, x)); // Tính và in ra kết quả
của $$ e^x $$
}
return 0;
}

3. Phương pháp điểm giữa

#include <stdio.h>
#include <math.h>

/* Định nghĩa hàm f(x) mà bạn muốn tính tích phân */


#define f(x) 1/(1 + (x) * (x))

/* Hàm tính tích phân sử dụng phương pháp điểm giữa */


double midpoint_integral(double (*func)(double), double a, double b, int n) {
double h = (b - a) / n; // Tính kích thước mỗi phân đoạn
double area = 0.0; // Biến lưu trữ kết quả tích phân
double xi;

for (int i = 0; i < n; i++) {


xi = a + (i + 0.5) * h; // Tính điểm giữa của phân đoạn thứ i
area += func(xi); // Cộng dồn giá trị hàm tại điểm giữa
}

area *= h; // Nhân với kích thước mỗi phân đoạn để có diện tích
return area;
}

int main() {
double lower_limit, upper_limit;
int sub_intervals;

printf("Nhập cận dưới của tích phân: ");


scanf("%lf", &lower_limit);
printf("Nhập cận trên của tích phân: ");
scanf("%lf", &upper_limit);
printf("Nhập số lượng phân đoạn: ");
scanf("%d", &sub_intervals);

double result = midpoint_integral(f, lower_limit, upper_limit, sub_intervals);


printf("Giá trị tích phân xấp xỉ là: %.5f\n", result);

return 0;
}
4. Phương pháp RUNGE-KUTTA 4

#include<stdio.h>
#include<math.h>

/* Định nghĩa hàm f(x, y) ở đây (Ví dụ: dy/dx = f(x, y)) */
double f(double x, double y) {
return 2 * x * x - 3 * x + 4;
}

int main()
{
int i;
double x, y, x0, y0, h, k1, k2, k3, k4;
printf("---------------------------------------------------------------------------\n");
printf("PHƯƠNG PHÁP RUNGE - KUTTA - BẬC 4\n\n");
printf("---------------------------------------------------------------------------\n\n");
printf("Nhập điều kiện ban đầu cho y: ");
scanf("%lf", &y0);
printf("Nhập điều kiện ban đầu cho x: ");
scanf("%lf", &x0);
printf("Nhập giá trị của x mà tại đó y cần được tìm: ");
scanf("%lf", &x);
printf("Nhập bước nhảy h: ");
scanf("%lf", &h);
printf("x\t\ty\t\tk1\t\tk2\t\tk3\t\tk4\t\tk_avg\n");

printf("__________________________________________________________________
________________________________________\n");
// Bắt đầu quy trình Runge-Kutta
while ((x - x0) > 0.0000000001) {
k1 = h * f(x0, y0);
k2 = h * f(x0 + h / 2.0, y0 + k1 / 2.0);
k3 = h * f(x0 + h / 2.0, y0 + k2 / 2.0);
k4 = h * f(x0 + h, y0 + k3);
printf("%lf\t%lf\t%lf\t%lf\t%lf\t%lf\t%lf\n", x0, y0, k1, k2, k3, k4, 1 / 6.0 * (k1 + 2
* k2 + 2 * k3 + k4));
y = y0 + 1 / 6.0 * (k1 + 2 * k2 + 2 * k3 + k4);
y0 = y;
x0 = x0 + h;
}
printf("%lf\t%lf\n", x0, y0);
printf("__________________________________________________________________
__________________________________________\n");
printf("Giá trị của y theo phương pháp Runge-Kutta bậc 4 là %.4lf\n\n", y);

return 0;
}
5. Phương pháp Huen
a. Bài toán
#include &lt;stdio.h&gt;
#include &lt;math.h&gt;
// Hàm f(t, y) biểu diễn phương trình vi phân dy/dt = f(t, y)
double f(double t, double y) {
return -y + sin(t); // Ví dụ: dy/dt = -y + sin(t)
}
// Phương pháp Heun
void heun(double y0, double t0, double h, int n) {
double t = t0;
double y = y0;
double y_pred, f0, f1;
for (int i = 0; i & lt; n; ++i) {
f0 = f(t, y); // Giá trị ban đầu của hàm f(t, y)
y_pred = y + h * f0; // Dự đoán giá trị y tại t+h
f1 = f(t + h, y_pred); // Giá trị của hàm f(t+h, y dự đoán)
y = y + (h / 2) * (f0 + f1); // Cập nhật giá trị y bằng trung bình cộng của f0 và f1
t += h; // Cập nhật thời gian
printf(&quot;Tại t = % f, y = % f\n & quot;, t, y);
}
}
int main() {
double y0 = 1; // Giá trị ban đầu của y
double t0 = 0; // Thời gian bắt đầu
double h = 0.1; // Kích thước bước
int n = 10; // Số bước lặp
heun(y0, t0, h, n);
return 0;
}
- Soulution run code:
6. Phương pháp hiệu chỉnh nhiều bước Adam - Moulton
a. Bài toán:

Adam-Moulton: một phương pháp đa bước để giải các phương trình vi phân thông
thường. Đây là một phương pháp hiệu quả để giải các bài toán vi phân trong thực tế, đặc
biệt khi chúng ta cần độ chính xác cao và ổn định trong các bước tính toán.

Bài toán thực tế: Giả sử chúng ta muốn mô hình hóa sự tăng trưởng của một quần thể
sinh vật, nơi tốc độ tăng trưởng phụ thuộc vào kích thước hiện tại của quần thể. Phương
trình vi phân có thể được biểu diễn như sau:

dy y
=ry (1− )
dt K

trong đó:

 ( y ) là kích thước quần thể tại thời điểm ( t ),


 ( r ) là tỷ lệ tăng trưởng cơ bản,
 ( K ) là kích thước tối đa mà môi trường có thể hỗ trợ (sức chứa).

Chúng ta có thể sử dụng phương pháp Adam-Moulton để giải phương trình này với các
giá trị cụ thể cho ( r ), ( K ), và điều kiện ban đầu ( y_0 ).

Để áp dụng code cho bài toán này, bạn cần thay đổi hàm ( f(t, y) ) để phản ánh mô hình
tăng trưởng quần thể và cập nhật các giá trị ban đầu và tham số phù hợp.

#include <stdio.h>
#include <math.h>

// Hàm f(t, y) biểu diễn phương trình vi phân dy/dt = f(t, y)


double f(double t, double y) {
double r = 0.1; // Giả sử tỷ lệ tăng trưởng cơ bản là 0.1
double K = 1000; // Giả sử sức chứa môi trường là 1000
return r * y * (1 - y / K);
}
// Phương pháp Adam-Moulton
void adamMoulton(double y0, double t0, double h, int n) {
double t = t0;
double y = y0;
double w[n + 1];
w[0] = y0; // Giá trị ban đầu

// Tính toán giá trị ban đầu bằng phương pháp Euler hoặc một phương pháp một
bước khác
w[1] = w[0] + h * f(t0, w[0]);

for (int i = 1; i < n; ++i) {


t += h; // Cập nhật thời gian
// Sử dụng phương trình sai phân Adam-Moulton
w[i + 1] = w[i] + h * (5 * f(t, w[i + 1]) + 8 * f(t - h, w[i]) - f(t - 2 * h, w[i -
1])) / 12;

// Cần phải giải một phương trình ngầm để tìm w[i+1]


// Điều này có thể được thực hiện bằng cách sử dụng phương pháp Newton
hoặc một phương pháp khác

printf("Tại t = %f, y = %f\n", t, w[i + 1]);


}
}
int main() {
double y0 = 50; // Giả sử kích thước quần thể ban đầu là 50
double t0 = 0; // Thời gian bắt đầu
double h = 0.1; // Kích thước bước
int n = 100; // Số bước lặp

adamMoulton(y0, t0, h, n);

return 0;
}

- Soulution run code:

You might also like