Professional Documents
Culture Documents
Phương Pháptính: Nguyễn Thế Hùng, Trần Văn Chính
Phương Pháptính: Nguyễn Thế Hùng, Trần Văn Chính
PHƯƠNG PHÁPTÍNH
ĐÀ NẴNG 2012
LỜI NÓI ĐẦU
Giáo trình Phương pháp tính được biên soạn trên cơ sở các bài giảng của các tác giả cho
các lớp Cao học và Đại học ngành Điện, Xây dựng, thuộc Đại học Đà Nẵng và một số Đại học
khác mà các Tác giả có dịp tham gia giảng dạy.
Nội dung của Giáo trình bao quát những vấn đề cơ bản nhất và mở rộng của phương pháp
tính hiện đại, làm cơ sở để tính toán, giải quyết những vấn đề khoa học, kỹ thuật thường gặp thuộc
các ngành kỹ thuật, đặc biệt là ngành Điện và Xây dựng.
Để giúp độc giả dể dàng nắm bắt bài giảng và vận dụng lý thuyết, thuận lợi trong việc tính
toán, ở mổi mục khó của cuốn sách thường có kèm theo ví dụ tính toán đặc trưng, chương trình tính
và cuối mổi chương thường có một số bài tập.
Ngoài các ngành Điện và Xây dựng cơ bản, Giáo trình này còn làm tài liệu tham khảo cho
các ngành khoa học kỹ thuật khác liên quan đến các vấn đề tính toán gần đúng.
Các Tác giả cảm ơn các Trợ giảng và Trợ lý đã bổ sung các bài tập, đánh máy bản thảo
làm cho nội dung Giáo trình được phong phú, đẹp đẽ thêm.
Các Tác giả rất mong được bạn đọc góp ý, bổ khuyết để lần tái bản tới Giáo trình Phương
pháp tính này được hoàn hảo hơn.
Chương 5: Các phương pháp số của đại số tuyến tính ................... 139
5.1. Ma trận .............................................................................................139
5.1.1. Các định nghĩa ................................................................................ 139
5.1.2. Định thức của ma trận .................................................................... 139
5.1.3. Nghịch đảo ma trận ......................................................................... 145
5.1.4. Tích hai ma trận .............................................................................. 151
5.1.5. Phép biến đổi tuyến tính trong không gian n chiều ......................... 155
5.1.6. Các phép tính ma trận ..................................................................... 157
a. Nghịch đảo ma trận ........................................................................ 158
b. Nhân hai ma trận ........................................................................ 164
5.1.7. Véc tơ riêng, trị riêng và
các dạng toàn phương của ma trận ................................................................... 168
Phương pháp Mises .......................................................................... 174
5.2. Giải hệ đại tuyến ..............................................................................187
5.2.1. Phương pháp giải trực tiếp .............................................................. 188
a. Phương pháp khử Gauss ............................................................... 188
b. Phương pháp Gaus – Jordan .......................................................... 193
c. Phân tích LU và phân tích Cholesky ............................................. 200
5.2.2. Phương pháp lặp giải hệ phương trình ........................................... 218
a. Phương pháp lặp đơn hệ phương trình ........................................... 218
b. Phương pháp lặp Seidel ................................................................. 225
c. Phương pháp lặp với hệ số giảm dư SOR ...................................... 232
d. Phương pháp Gradient liên hợp ..................................................... 234
5.2.3. Hệ phương trình số phức .................................................................. 236
Chương 6: Nghiệm gần đúng của hệ phương trình vi phân thường ....... 243
6.1. Mở đầu ...........................................................................................243
6.2. Nghiệm gần đúng của bài toán Cauchy đối với phương
trình vi phân thường ................................................................................243
6.2.1. Phương pháp xấp xỉ liên tiếp Pica .................................................. 244
Ứng dụng lập trình ...................................................................... 245
6.2.2. Phương pháp Euler .......................................................................... 246
Ứng dụng lập trình ................................................................ 247
6.2.3. Phương pháp Runghe-Kutta bậc 4 .................................................. 251
Ứng dụng lập trình ...................................................................... 253
6.2.4. Phương pháp Adam ....................................................................... 256
1
tính mới. Phương pháp tính nhờ đó phát triển rất mạnh mẽ; nó là cầu nối giữa toán học
và thực tiễn; là môn học không thể thiếu đối với các kỹ sư.
Ngoài nhiệm vụ chính của phương pháp tính là tìm các phương pháp giải gần
đúng các bài toán không tìm được lời giải giải tích hoặc lời giải giải tích quá phức tạp,
nó còn có nhiệm vụ khác như nghiên cứu tính chất nghiệm, nghiên cứu bài toán cực
trị, xấp xỉ hàm v.v...
1.1.2. Các đặc điểm của phương pháp tính
Đặc điểm về phương pháp của môn học này là hữu hạn hoá và rời rạc hoá.
Phương pháp tính thường biến cái vô hạn thành cái hữu hạn, cái liên tục thành
cái rời rạc và sau cùng lại trở về với cái vô hạn, cái liên tục. Nhưng cần chú ý rằng quá
trình trở lại cái vô hạn, cái liên tục phải trả giá đắt vì khối lượng tính toán tăng lên rất
nhiều. Cho nên trong thực tế người ta phải dừng lại khi nghiệm gần đúng sát với
nghiệm đúng ở một mức độ nào đó.
Đặc điểm thứ hai của môn học là sự tiến đến kết quả bằng quá trình liên tiếp.
Đó là quá trình chia ngày càng nhỏ hơn, càng dày đặc hơn hoặc quá trình tính toán
bước sau dựa vào các kết quả của các bước trước. Công việc tính toán lặp đi lặp lại
này rất thích hợp với máy điện toán.
Khi nghiên cứu phương pháp tính người ta thường triệt để lợi dụng các kết quả
đã đạt được trong toán học. Cùng một bài toán có thể có nhiều phương pháp tính khác
nhau.
Trong phương pháp tính, người ta thường quan tâm đến hai vấn đề chính:
Phương pháp để giải bài toán.
Sai số của lời giải.
Một phương pháp tính được coi là tốt nếu nó đạt các yêu cầu sau:
- Phương pháp tính được biểu diễn bằng một dãy hữu hạn các bước tính cụ
thể. Các bước tính toán cụ thể này của phương pháp tính được gọi là thuật toán. Thuật
toán càng đơn giản càng tốt.
- Đánh giá được sai số và sai số càng nhỏ càng tốt.
- Thuật toán thực hiện được trên máy điện toán và thời gian chạy máy ít
nhất.
Giải gần đúng nghĩa là lời giải của bài toán so với lời giải đúng có một sai số
nào đó. Sai số thường do rất nhiều nguồn tạo nên và nhiều khi rất khó ước lượng được.
2
Ví dụ khi cần tìm lời giải của phương trình phi tuyến, ta sẽ có nhiều phương pháp giải
khác nhau; mổi phương pháp giải cần thời gian tính toán và độ chính xác khác nhau.
Một người kỹ sư xây dựng khi tính toán để thiết kế một công trình, thực hiện rất nhiều
phép tính, và nhiều khi rất khó xác định sai số tích lũy trong quá trình tính toán;
nhưng kết quả vẫn được cơ quan có thẩm quyền duyệt chấp nhận. Tuy nhiên đối với
các bài toán phức tạp, số lượng phép tính lớn, cần độ chính xác cao, nhất thiết phải
được khảo sát nghiên cứu đầy đủ về sai số của lời giải.
Máy tính số có thể biểu diễn với độ chính xác bình thường (single), độ chính
xác gấp đôi (double) hay độ chính xác mở rộng (extended). Nếu ta biết được mối liên
hệ giữa lời giải số với lời giải đúng, sẽ biết nên chọn độ chính xác nào để kết quả đáp
ứng được yêu cầu thực tế.
1.1.3. Những dạng sai số thường gặp
Trong thực tế, khi bài toán tìm xấp xỉ một mô hình toán học đã biết, ví dụ tìm
nghiệm của một phương trình đã biết, tính tích phân xác định của một hàm số nào đó
trên miền cho trước hoặc có những bài toán thực tế mà ngay cả mô hình toán học cũng
chưa biết; ví dụ, dự báo về lượng mưa thay đổi do biến đổi khí hậu toàn cầu, nhu cầu
thuê bao internet, … Trong những trường hợp này, ta phải bắt đầu từ việc thu thập số
liệu, xây dựng mô hình toán rồi tìm phương pháp giải số thích hợp … Nói chung khi
thực hiện một bài toán bằng phương pháp số ta thường gặp những loại sai số sau đây:
Sai số do mô hình hoá bài toán, do ta không thể tính được hết những yếu tố
quan trọng ảnh hưởng đến bài toán, hoặc do ta biết được những yếu tố ảnh hưởng
nhưng phải đơn giản hóa mô hình để có thể tính toán được.
Sai số do phương pháp: Phương pháp thay bài toán phức tạp bằng bài toán đơn
giản (mổi phương pháp gần đúng đều có sai số và thường các sai số này là khác nhau)
sẽ tạo ra sai số phương pháp.
Sai số do số liệu: Khi đo đạc ta phải sử dụng dụng cụ đo, mổi dụng đo đều có
sai số.
Sai số tính toán và chặt cụt: Sai số tính toán là sai số do ta làm tròn bởi tất cả
các lần qui tròn trong quá trình tính toán; sai số chặt cụt là sai số gây ra khi phải chặt
cụt dãy số khai triển.
Những sai số trên đây, tùy theo bài toán, tích lũy lại nhiều khi dẫn đến những
lời giải không thể chấp nhận được. Chính vì vậy việc tìm ra những phương pháp tốt,
3
thuật toán hữu hiệu để giải các bài toán thực tế là điều rất cần thiết. Các phương pháp
số hiện nay có rất nhiều, và còn nhiều vấn đề hiện nay vẫn còn bỏ ngỏ. Trong cuốn
sách này chúng tôi chỉ giới thiệu một số phương pháp và thuật toán thông dụng để các
kỹ sư và độc giả quan tâm có thể sử dụng được.
1.2 . Sai số tuyệt đối
Gọi a là giá trị gần đúng của A, ta viết được A = a a
a : gọi là sai số tuyệt đối giới hạn
1.3 . Sai số tương đối
a
a = , dạng khác: A = a (1 a)
a
Sai số tuyệt đối không nói lên đầy đủ “chất lượng“ của 1 số xấp xỉ, chất lượng
ấy được phản ảnh qua sai số tương đối.
1.4. Cách viết số xấp xỉ
Chữ số có nghĩa: Đó là chữ số 0 đầu tiên tính từ trái sang phải
Ví dụ. 002,74 2,74
00,0207 0,0207
Chữ số đáng tin: Một số a có thể được viết a = 10s
s
a 'a a’ thì a’ = a + a’ (tức tăng sai số tuyệt đối)
4
1.7. Ảnh hưởng của sai số quy tròn
Áp dụng nhị thức Newton, ta có:
2 1 10 3363 2378 2
2 Vế trái Vế phải
1,4 0,0001048576 33,8
1,41 0,00013422659 10,02
1,414 0,000147912 0,508
1,41421 0,00014866394 0,00862
1,414213563 0,00014867678 0,0001472
Ta có u = x + y u x y
u X Y X Y
5
U X Y
Do đó : U = X + Y
u x y
x
+ Nếu u = , với y 0, U = X + Y
y
Ví dụ. Tìm sai số tuyệt đối giới hạn và sai số tương đối giới hạn của thể tích
hình cầu.
1
V= .d 3 .
6
v = 0,0005+3.0,0135 = 0,04.
1
Mặt khác: V= .d 3 = 26,5cm3.
6
6
n 1 ^ n3
an 2
và an 3
n n
^ ^
Mặc dù cả hai giới hạn limn→∞ αn = 0 và limn→∞ an = 0, nhưng dãy số { an } hội
tụ đến giới hạn này nhanh hơn nhiều so với {αn}.
n 1 n n 1
Từ an 0 2
2 2.
n n n
^ n 3 n 3n 1
Và an 0 3
3
4. 2
n n n
1 ^
1
ta có: an 0 O và an 0 O 2
n n
Kết quả này có nghĩa là sự hội tụ của chuỗi {αn} tương tự như hội tụ của {1/n}
^
tới không. Dãy số { an } hội tụ một cách tương tự và nhanh hơn, như hội tụ dãy số
{1/n2}.
Chúng ta cũng sử dụng khái niệm " độ lớn - big oh" để mô tả tốc độ hội tụ của
các hàm, đặc biệt là khi các biến độc lập tiệm cận bằng không.
Giả sử F là một hàm số hội tụ đến một số L như là h tiến về không. Nếu các
hằng số dương p và K tồn tại với:
|F(h) − L| ≤ Khp , với h → 0
Thì F(h) hội tụ tới L với tốc độ, hoặc bậc, của hội tụ O (hp). Cái này viết như
F(h) = L + O (hp) và được ghi là "F (h) → L với tốc độ hội tụ hp."
Chúng ta thường quan tâm đến giá trị lớn nhất của p để cho F(h) = L + O (hp).
Định nghĩa "độ lớn - oh" cho các hàm số cũng có thể được mở rộng để kết hợp tổng
quát hơn các hàm hội tụ về 0 trong chổ của hp.
7
với sự lựa chọn một số điều kiện ban đầu; những phương pháp nầy được gọi là ổn định
có điều kiện (ví dụ, chúng ta hay gặp vấn đề này đối với các lược đồ sai phân).
Câu hỏi:
1) Định nghĩa sai số tuyệt đối, sai số tương đối ? Trong thực tế tính toán, người ta
sử dụng sai số tuyệt đối hay sai số tương đối ? Vì sao ?
2) Trình bày các quy tắc tính sai số?
3) Nêu sự khác nhau giữa sai số tính toán và sai số phương pháp? Hãy nêu ra một
quá trình tính có số liệu cụ thể minh họa và chỉ ra sai số tính toán và sai số
phương pháp ?
4) Đưa ra vài ví dụ tính toán, chỉ ra sự cần thiết phải chú ý đến sai số qui tròn ?
i t p:
1) Hãy xác định chữ số tin tưởng trong các số sau:
a) x = 0, 1 với x = 0,25.10-2
y = 0,11 2 với y = 0,1.10-3
3) Hãy qui tròn các số dưới đây để có được chữ số tin tưởng và xác định sai số
tuyệt đối và sai số tương đối của chúng:
a) x=2,1514
b) y=0,16152
c) z=1,1225
d) v=0,01204
4) Hãy tính thương u = x1/x2 của hai số xấp xỉ: x1 = 5,735; x2 = 1,2 và xác định
sai số tương đối giới hạn u , và sai số tuyệt đối giới hạn u
5) Hãy xác định sai số tương đối giới hạn a , sai số tuyệt đối giới hạn a và số
chữ số đáng tin của cạnh a của hình vuông, biết diện tích hình vuông
s = 16,45 cm2 với s = 0,01
8
áp số:
1) a) 2; b) 3; c)4
2) a) x = 0,13.102
b) y = 0,9.10-1
3) a) 2,15; x = 0,14.10-2; x = 0,65.10-3
b) 0,162; y = 0,48.10-3; y = 0,3.10-2
c) 1,23; z = 0,5.10-2; z = 0,41.10-2
d) 0,0120; v = 0,4.10-4; v = 0,33.10-2
4) u = 4,66; u 0,0042; u 0,02
5) a = x = 4,056cm; a 0,0003 ; a 0,0012; a có ba chữ số đáng tin
9
Chương 2 NỘI SUY
(INTERPOLATION)
Trong nhiều bài toán kỹ thuật, ta phải tìm các trị yi tại các điểm xi bên trong
đoạn [a, b] đã biết trước, hoặc khi quan hệ giải tích y = f(x) đã có sẵn nhưng phức tạp,
rất khó để tìm đạo hàm, tích phân… Khi đó ta dùng phép nội suy để dễ dàng tính toán
mà vẫn đảm bảo độ chính xác theo yêu cầu của thực tế.
2.1. Nội suy đa thức
2.1.1. Sự duy nhất của đa thức nội suy
Xét mẫu đo đạt gồm (n+1) cặp các giá trị đã biết của hai trạm x và y: (x0,y0),
(x1, y1),. . . ,(xn, yn). Hãy xây dựng một đa thức có bậc m ≤ n có dạng:
Pm(x) = a0 + a1x1+ . . . am-1xm-1 + amxm (2.1)
sao cho Pm(xi) = yi , với i = 0, 1,..., n (2.2)
Đây là bài toán nội suy đa thức, và đa thức Pm(x) được gọi là đa thức nội suy.
Ta có định lý:
Định lý: Tồn tại duy nhất một đa thức có bậc không quá n và đi qua (n + 1)
điểm cho trước (x0, y0), (x1, y1), . . . ,(xn, yn).
Chứng minh: Xét đa thức có dạng (2.1) ở trên và thỏa mãn (2.2). Kết hợp (2.1)
và (2.2), ta có:
y0 1 x0 x02 x0n a0
y1 1 x1 x12 x1n a1
(2.3)
yn 1 xn xn2 xnn an
10
Do ta đã giả thiết các điểm xi ≠ xj , do đó ma trận này khác 0 nên hệ phương
trình (2.3) có nghiệm duy nhất cho các ai, nên đa thức Pn(x) được xác định duy nhất.
2.1.2. Tính giá trị đa thức bằng phương pháp Horner
Với bài toán nội suy đa thức, thường phải tính giá trị của đa thức Pm(x)= a0 +
a1x1 + . . . am-1xm-1 + amxm tại điểm x. Khi tính trực tiếp, phải thực hiện khá nhiều
phép tính, và khi tính các giá trị mũ của x, có thể gặp các giá trị lớn, mặc dù trong
thực tế thường các thành phần của đa thức triệt tiêu lẫn nhau và giá trị của đa thức
không lớn. Để loại trừ các nhược điểm nêu trên, Horner đã đưa ra cách tính như sau:
Viết lại đa thức Pm(x) dưới dạng:
Pm(x) = amxm + am-1xm-1 + . . . + a1x1 + a0 = (...((amx + am-1)x + am-2)x+...+a1)x+a0
Thuật toán thiết lập cho máy tính, để tính Pm(x) như sau:
Đặt Pm = am
Pm-1 = Pmx + am-1
...
Pi = Pi-1x + ai
Chỉ cần lưu trữ Pi trong một ô nhớ của máy tính. Thuật toán trên trở thành:
Đặt P = am
Thiết lập vòng lặp i = m -1 → 0, tức là gán i = m -1, m -2,..., 0
Tính P = P.x + ai
Giá trị P cuối cùng (ứng với i = 0), cho ta giá trị của đa thức tại x.
Sau đây là chương trình thực hiện thuật toán trên:
Chương trình 1-1
#include <conio.h>
#include <stdio.h>
#define m 10
void main(void)
{
int k,n;
float p,x;
float a[m];
clrscr();
printf("\nCho bac cua da thuc n = ");
11
scanf("\%d",&n);
printf("Vao cac he so a:\n");
for (k=1;k<=n+1;k++)
{
printf("a[%d] = ",k-1);
scanf("%f",&a[k]);
};
printf("Cho gia tri x = ");
scanf("%f",&x);
p=0.0;
for (k=1;k<=n+1;k++)
p=p*x+a[k];
printf("Tri so cua da thuc P tai x =%.2f la :%.5f",x,p);
getch();
}
Sơ đồ Horner tổng quát: Giả sử chúng ta có đa thức:
Pn(x) = a0xn + a1xn - 1 + a2xn - 2 +....+ an (2.6)
Khai triển Taylor của đa thức tại x = xo có dạng:
P( x0 ) P( x0 ) P ( n ) ( x0 )
Pn ( x) Pn ( x0 ) ( x x0 ) ( x x0 ) 2 ( x x0 ) n (2.7)
1! 2! 2!
Mặt khác chúng ta có thể biến đổi đa thức về dạng:
Pn(x) = (x - xo)Pn-1(x) + Pn(xo) (2.8)
Trong đó Pn-1(x) là đa thức bậc n - 1 và có dạng:
Pn-1(x) = boxn-1 + bo-1xn - 2 + b2xn - 3 +....+ bn-1 (2.9)
Thuật toán để tìm các hệ số nhận được bằng cách so sánh (2.6) và (2.8):
bo = ao
bi = ai + bi-1xo
bn = Pn(xo)
So sánh (2.7) và (2.8) ta có:
P( x0 ) P( x0 )
( x x0 ) Pn 1 ( x0 ) Pn ( x0 ) Pn ( x0 ) ( x x0 ) ( x x0 ) 2
1! 2!
(2.10)
P ( n ) ( x0 )
( x x0 ) n
2!
12
Hay:
P( x0 ) P( x0 ) P ( n ) ( x0 )
( x x0 ) Pn 1 ( x) ( x x0 ) ( x x0 )
2
( x x0 ) n (2.11)
1! 2! 2!
Và khi chia hai vế cho (x - x0) ta nhận được :
P( x0 ) P( x0 ) P ( n ) ( x0 )
Pn 1 ( x) ( x x0 ) ( x x0 ) n 1 (2.12)
1! 2! 2!
So sánh (2.9) và (2.12) ta nhận được kết quả :
P( x0 )
Pn 1 ( x0 ) (2.13)
1!
Trong đó Pn-1(x) lại có thể phân tích giống như Pn(x) dạng (2.3) để tìm ra
Pn-1(xo). Quá trình này được tiếp tục cho đến khi ta tìm hết các hệ số của chuỗi Taylor
của Pn(x).
Tổng quát thuật toán thể hiện ở bảng sau:
Pn(x) ao a1 a2 a3 ... an-1 an
x = xo 0 boxo b1xo b2xo bn-2xo bn-1xo
void main(void)
{
float a[m],b[m],c[m];
int n,i,j,k;
float x;
clrscr();
printf(“Cho bac cua da thuc n = “);
scanf(“%d”,&n);
printf(“Cho gia tri x = “);
scanf(“%f”,&x);
printf(“Vao cac he so a\n”);
for (k=n;k>=0;k--)
{
printf(“a[%d] = “,n-k);
scanf(“%f”,&a[k]);
}
printf(“\n”);
b[n] = a[n];
c[n] = a[n];
for (k=0;k<=n-1;k++)
{
for (i=n-1;i>=k;i--)
14
b[i] = b[i+1]*x + a[i];
c[k] = b[k];
for (j=n;j>=k+1;j--)
a[j] = b[j];
}
printf(“\nSo do Horner tong quat”);
printf(« \nKhai trien tai x = %.4f\n »,x) ;
for (k=n;k>=0;k--)
printf(“%10.4f\t”,c[k]);
getch();
}
2.1.3. Các phép tính trên đa thức
a. Phép cộng hai đa thức: Giả sử chúng ta có hai đa thức A(x) bậc n và B(x) bậc
m với n > m. Khi cộng hai đa thức này, chúng ta cộng lần lượt các hệ số cùng bậc của
chúng với nhau. Ta có chương trình sau:
Chương trình 1-3
#include <conio.h>
#include <stdio.h>
#define t 10
void main(void)
{
int k,n,m;
float a[t],b[t],c[t];
clrscr();
printf("Cho bac cua da thuc A n = ");
scanf("%d",&n);
printf("Vao cac he so a\n");
for (k=1;k<=n+1;k++)
{
printf("a[%d] = ",k-1);
15
scanf("%f",&a[k]);
}
printf("Cho bac cua da thuc B m = ");
scanf("%d",&m);
printf("Vao cac he so b\n");
for (k=1;k<=m+1;k++)
{
printf("b[%d] = ",k-1);
scanf("%f",&b[k]);
}
printf("\n");
for (k=1;k<=n+1;k++)
if (k<=n-m)
c[k] = a[k];
else
c[k] = a[k] + b[k-n+m];
printf("Cac he so cua da thuc tong C la :\n");
for (k=1;k<=n+1;k++)
printf("%.4f\t",c[k]);
getch();
}
b. Phép nhân hai đa thức: Để thấy rõ thuật toán xác định các hệ số của đa thức
C(x) là kết quả của phép nhân hai đa thức A(x) và B(x) ta cho một ví dụ cụ thể:
A(x) = aox5 + a1x4 + a2x3 + a3x2+ a4x + a5
B(x) = box3 + b1x2 + b2x + b3
C(x) = A(x).B(x) (2.14)
= aobox8 + (aob1 + a1bo)x7 +( aob2 + a1b1 + a2bo)x6 +
+ (aob3 + a1b2 + a2b1+ a3bo )x5 + (a1b3 + a2b2 + a3b1 + a4bo)x4 +
+ (a2b3 + a3b2 + a4b1 + a5b+)x3 + ( a3b3 + a4b2 + a5b1)x2 + a5b2x + a5b3
Các hệ số của đa thức kết quả là:
Co = aobo
C1 = aob1 + a1bo
16
C2 = aob2 + a1b1 + a2bo
C3 = aob3 + a1b2 + a2b1+ a3bo
C4 = a1b3 + a2b2 + a3b1 + a4bo
C5 = a2b3 + a3b2 + a4b1 + a5bo
C6 = a3b3 + a4b2 + a5b1
C7 = a5b2
C8 = a5b3
Ta nhận thấy là hệ số Ck của C(x) là tổng các tích các hệ số của đơn thức bậc i
của A(x) và bậc (k - i) của B(x). Chỉ số i = 0 khi k ≤ m + 1 và i = k + m khi k > m+1.
Chỉ số j = k khi k ≤ n + 1 và j = n +1 khi k > n + 1.
Sau đây là chương trình tính tích hai đa thức:
Chương trình 1-4
#include <conio.h>
#include <stdio.h>
#define t 10
void main()
{
int k,n,m,l,i,j,p;
float a[t],b[t],c[2*t];
clrscr();
printf("Cho bac cua da thuc A n = ");
scanf("%d",&n);
printf("Vao cac he so a\n");
for (k=1;k<=n+1;k++)
{
printf("a[%d] = ",k-1);
scanf("%f",&a[k]);
}
printf("Cho bac cua da thuc B m = ");
scanf("%d",&m);
printf("Vao cac he so b\n");
for (k=1;k<=m+1;k++)
17
{
printf("b[%d] = ",k-1);
scanf("%f",&b[k]);
}
printf("\n");
l=n+m;
for (k=1;k<=l+1;k++)
{
if (k<=(n+1))
j=k;
else
j=n+1;
if (k<=(m+1))
p=1;
else
p= k-m;
c[k]=0;
for (i=p;i<=j;i++)
c[k] = c[k] + a[i]*b[k-i+1];
}
printf("Cac he so cua da thuc tich C voi bac %d la :\n",l);
for (k=1;k<=l+1;k++)
printf("%.4f\t",c[k]);
getch();
}
c. Chia hai đa thức: Giả sử ta có hai đa thức là An(x) và Bm(x) với n m.
Thương hai đa thức này là:
An ( x) R ( x)
Qn m ( x) m1 (2.15)
Bm ( x) Bm ( x)
18
Chương trình 1-5
#include <stdio.h>
#include <conio.h>
#include <math.h>
#define t 10
void main()
{
int k,n,m,l,i,j,jp;
float a[t],b[t],q[t],r[t],epsi;
clrscr();
printf("Cho bac cua da thuc A n = ");
scanf("%d",&n);
printf("Vao cac he so a\n");
for (k=1;k<=n+1;k++)
{
printf("a[%d] = ",k-1);
scanf("%f",&a[k]);
}
printf("\n");
printf("Cho bac cua da thuc B m = ");
scanf("%d",&m);
printf("Vao cac he so b\n");
for (k=1;k<=m+1;k++)
{
printf("b[%d] = ",k-1);
scanf("%f",&b[k]);
}
printf("\n");
printf("Cho gia tri sai so epsilon epsi = ");
scanf("%f",&epsi);
if ((m+1)>1)
{
19
l=n-m+1;
for (i=0;i<=t;i++)
r[i]=a[i];
j=n;
for (k=1;k<=l;k++)
{
q[k]=r[1]/b[1];
for (i=1;i<=j;i++)
if ((i<m+1))
r[i]=r[i+1]-q[k]*b[i+1];
else
r[i]=r[i+1];
j=j-1;
}
while ((abs(r[i])<epsi)&&(j>0))
{
for (i=1;i<=j;i++)
r[i]=r[i+1];
j=j-1;
}
if (abs(r[1])<epsi)
r[1]=0.0;
jp=j+1;
}
else
{
l=n+1;
for (k=1;k<=l;k++)
q[k]=a[k]/b[1];
jp=1;
r[1]=0.0;
}
20
printf("\n");
printf("Cac he so cua thuong Q(x) bac %d la : ",l);
for (k=1;k<=l;k++)
printf("%.3f\t",q[k]);
printf("\n");
printf("Cac he so cua phan du R(x) bac %d la : ",jp-1);
for (k=1;k<=jp;k++)
printf("%.3f",r[k]);
getch();
}
2.1.4. Sai số của đa thức nội suy
Định lý Rolle phát biểu:
Định lý Rolle: Cho f(x) là hàm số thực liên tục trên khoảng kín [a, b] và khả vi
trên khoảng hở (a, b) và f(a) = f(b). Khi đó tồn tại điểm ξ∈ (a, b) sao cho f '(ξ) = 0.
Định lý: Giả sử hàm f(x) có đạo hàm liên tục đến cấp (n + 1) trên khoảng kín
[a, b] và Pm(x) là đa thức nội suy, tức là: Pm(xi) = f(xi) = yi , với i = 0, 1,..., n. Với
các mốc nội suy là a = x0 < x1 < ... < xn = b.
n
Đặt n1 x x x và
i 0
i r(x) = f(x) - Pm(x)
Khi đó với ∀ x ∈ [a, b] tồn tại η ∈ [a, b] (phụ thuộc vào x) sao cho:
f ( n1) ( )
r ( x) n1 ( x) (2.16)
(n 1)!
Hệ quả:
Gọi M sup f ( n1) ( x) khi đó ta có:
a x b
M
r ( x) f ( x) pm ( x) n 1 ( x) (2.17)
(n 1)!
đây là công thức đánh giá sai số của đa thức nội suy.
2.2. Đa thức nội suy Lagrange
Giả sử ta có các cặp điểm quan sát được cho ở bảng sau:
Bảng các giá trị:
x x1 x2 x3 .... . .. xn
y y1 y2 y3 ... ...yn
21
Cần lập đa thức: Pn(x) có bậc m n - 1, nhận các giá trị yi cho trước ứng với
các xi:
yi = f(xi), với i = 1, 2, 3,…. ...,n
Ký hiệu: (x) = (x - x1)(x - x2)... ... (x - xn)
Ta có được đẳng thức:
y1 (x) y2 (x)
Pn (x) ...
(x - x1 )( x1 x2 )( x1 x3 )...( x1 xn ) ( x x2 )( x2 x1 )( x2 x3 )....( x2 xn )
(2.18)
yn ( x)
( x xn )( xn x1 )( xn x2 ).......( xn xn1 )
n
yk ( x )
Hay: Pn(x) =
k 1 ( xk ).( x xk )
'
(2.19)
M
rn ( x) ( x) (2.21)
n 1!
Ví dụ. Cho bảng giá trị:
x 0 1 2 3
y 3 4 7 8
Tìm đa thức nội suy Lagrange và tìm y khi biết x = 1,5.
Ta có: (x) = (x-x1)(x-x2)(x-x3)(x-x4)
= x(x-1)(x-2)(x-3)
3.x.( x 1).( x 2).( x 3) 4.x.( x 1).( x 2).( x 3)
Pn(x) =
x.(1).(2).( 3) ( x 1).1.( 1).( 2)
7.x.( x 1).( x 2).( x 3) 8.x.( x 1).( x 2).( x 3)
( x 2).2.1.(1) ( x 3).3.2.1
= -1/2(x-1)(x-2)(x-3)+2x(x-2)(x-3)-7/2x(x-1)(x-3)+4/3x(x-1)(x-2)
22
Tại x =1,5 thế vào Pn(x) ta có y = 5,67.
Đa thức nội suy Lagrange có ưu điểm là đơn giản, nhưng nếu thêm nút nội suy
thì phải tính lại toàn bộ, nhược điểm này sẽ được khắc phục trong công thức nội suy
Newton.
Ứng dụng lập trình
a. Dùng C++
#include <conio.h>
#include <stdio.h>
#include <ctype.h>
#define max 21
int maxkq,n;
float x[max],y[max],a[max],xx[max],yy[max];
float x0,p0;
void main()
{
int i,k;
char ok ;
void vaosolieu(void);
float lagrange(int,float [],float [],float);
void inkq(void);
clrscr();
printf("%24cNOI SUY DA THUC LAGRANGE\n",' ');
vaosolieu();
k=0;
ok='c';
while (ok=='c')
{
printf("Tinh gia tri cua y voi x la x0 = ");
scanf("%f",&x0);
23
p0=lagrange(n,x,y,x0);
printf("Gia tri cua y = %15.5f\n",p0);
printf("\n");
k=k+1;
maxkq=k;
xx[k]=x0;
yy[k]=p0;
flushall();
printf("Tinh tiep khong(c/k)?");
scanf("%c",&ok);
}
inkq();
}
void vaosolieu()
{
int i,t;
char ok;
printf("\n");
printf("Ham y = f(x)\n");
printf("So cap (x,y) nhieu nhat la max = 20\n");
printf("So diem da cho truoc n = ");
scanf("%d",&n);
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
printf("\n");
24
printf(" SO LIEU BAN VUA NHAP\n");
printf(" x y\n");
for (i=1;i<=n;i++)
printf("%8.4f %8.4f\n",x[i],y[i]);
ok=' ';
t=1;
flushall();
while (t)
{
printf("\nCo sua so lieu khong(c/k):?");
scanf("%c",&ok);
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
flushall();
}
if (toupper(ok)!='C')
t=0;
}
}
25
p0=0.0;
for (k=1;k<=n;k++)
{
g0=1.0;
for (i=1;i<=n;i++)
if (i!=k)
g0=g0*(x0-x[i])/(x[k]-x[i]);
p0=p0+y[k]*g0;
}
return(p0);
}
void inkq()
{
int i,j,k;
printf("\n");
printf("%24cBANG SO LIEU\n",' ');
printf("%18cx %24cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%20.4f %25.4f\n",x[i],y[i]);
printf("\n");
printf("%24cKET QUA TINH TOAN\n",' ');
printf("%14cx %10cy\n",' ',' ');
for (k=1;k<=maxkq;k++)
printf("%15.5f %15.5f\n",xx[k],yy[k]);
getch();
}
x 0 3 -2 2 4
y 0 -3.75 10 -2 4
Dùng chương trình tính nội suy, tại x = 2,5 tìm được: y = -3,3549.
26
b. Dùng Matlab
Xây dựng hàm nội suy:
function [l,L] = lagrange(x,y)
%Dua vao : x = [x0 x1 ... xn], y = [y0 y1 ... yn]
%ket qua: l = He so cua da thuc Lagrange bac n
% L = Da thuc Lagrange
n = length(x)-1; %bac cua da thucl
l = 0;
for m = 1:n + 1
p = 1;
for k = 1:n + 1
if k ~= m
p = conv(p,[1 -x(k)])/(x(m)-x(k));
end
end
L(m,:) = p; %da thuc Lagrange
l = l + y(m)*p;
end
x -2 -1 1 2
y -6 0 0 6
27
2.3. Nội suy Newton
Trong mục này, đề cập đến đa thức nội suy khi biết các mẫu quan sát rời rạc
(xi, yi), sao cho mỗi lần bổ sung thêm số liệu, thì ta vẫn kế thừa được đa thức nội suy
đã tính trước đó.
2.3.1. Nội suy Newton với mốc cách đều
Giả sử y0, y1, y2, ... là những giá trị nào đó của hàm y = f(x) tương ứng với các
giá trị cách đều nhau của các đối số x0, x1, x2 ...tức là:
xk + 1 - xk = xk = const
Ký hiệu:
y1 - y0 = y0 ; y2 - y1 = y1 ; ... ... ; yn - yn - 1 = yn - 1 là sai phân cấp 1.
y1 - y0 = 2y0 ; y2 - y1 = 2y1 ; ..... là sai phân cấp 2.
ny1 - ny0 = n + 1y0 ; ny2 - ny1 = n + 1 y1 ; ..... là sai phân cấp n + 1.
Tiến hành các phép thế liên tiếp, ta nhận được:
..., 2y0 = y2 - 2y1 + y0 ; 3y0 = y3 - 3y2 + 3y1 - y0 ,….
n
y0
n
(1)
K 0
K
CnK yn K (2.22)
28
Đánh giá sai số:
f ( n 1) (c) n 1
rn ( x) h t t 1 t n ; c [a, b] (2.26)
n 1!
Trong đó: a ≤ x0 ≤ x1 ≤ x2 ≤ … ≤ xn ≤ b
Nếu gọi M = max f ( n1) ( x) ; x a, b thì sai số nội suy:
M
rn ( x) hn 1 t t 1 t n ; (2.27)
n 1 !
Vídụ. x 1 2 3 4
y 5 7 10 12
Giải: Ta có:
Sai phân cấp 1 : y0 y1 - y0 = 7 - 5 = 2
29
Các điểm dữ liệu được sử dụng để tính các hệ số b0, b1, .... bn. Đối với một đa
thức bậc thứ n, có (n + 1) điểm dữ liệu được yêu cầu. Chúng ta sử dụng các điểm dữ
liệu và các phương trình sau đây để xác định các hệ số:
b0 f ( x0 )
b1 f [ x1 , x0 ]
b2 f [ x2 , x1 , x0 ]
.
.
.
bn f [ xn , xn1 ,..., x1 , x0 ]
Thay các hệ số trên vào phương trình (2.9) ta nhận được đa thức nội suy Newton:
Pn f ( x0 ) ( x x0 ). f [ x1 , x0 ] ( x x0 ).( x x1 ) f [ x2 , x1, x0 ]
.... ( x x0 ).( x x1 )...( x xn 1 ) f [ xn , xn 1,..., x0 ] (2.29)
void main()
30
{
int i,j,k,n,t;
float a[max],b[max],x[max],y[max];
char ok;
float x0,p;
clrscr();
printf("So diem da cho n = ");
scanf("%d",&n);
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
printf("%10cBANG SO LIEU\n",' ');
printf("%8cx%30cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%4c%8.4f%23c%8.4f\n",' ',x[i],' ',y[i]);
ok=' ';
t=0;
flushall();
while (t)
{
printf("Co sua so lieu khong(c/k): ");
scanf("%c",&ok);
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
31
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
flushall();
}
if (toupper(ok)!='C')
t=0;
}
a[1]=y[1];
for (j=1;j<=n-1;j++)
{
for (i=1;i<=n-j;i++)
y[i]=(y[i+1]-y[i])/(x[i+j]-x[i]);
a[j+1]=y[1];
}
b[n]=a[n];
for (k=n-1;k>=1;k--)
{
for (j=n-1;j>=1;j--)
b[j]=a[j] ;
for (i=n-1;i>=k;i--)
a[i]=a[i]-b[i+1]*x[k];
}
for (i=n;i>=1;i--)
printf("He so bac %d la :%8.4f\n",i-1,a[i]);
printf("\n");
k=0;
ok='c';
flushall();
while (ok=='c')
{
32
printf("Tinh gia tri cua y tai x = ");
scanf("%f",&x0);
p=0;
for (k=n;k>=1;k--)
p=p*x0+a[k];
printf("Tri so noi suy tai x0 = %4.2f la : %10.5f\n",x0,p);
getch();
printf("Ban co muon tinh tiep cac diem khac khong(c/k)");
do
scanf("%c",&ok);
while ((ok!='c')&&(ok!='k'));
}
}
Áp dụng. Dùng chương trình này nội suy các giá trị cho trong bảng sau:
Ta có các hệ số của đa thức nội suy: 0.0139(bậc 5), 0.0349(bậc 4), 0.1704(bậc 3),
0.4991(bậc 2), 1.0001(bậc 1) và 1.0000 (bậc 0).
b. Dùng Matlab
33
DD(m,k) = (DD(m + 1,k - 1) - DD(m,k - 1))/(x(m + k - 1)- x(m));
end
end
a = DD(1,:);
n = a(N+1);
for k = N:-1:1
n = [n a(k)] - [0 n*x(k)];
end
x -2 -1 1 2 4
y -6 0 0 6 60
x = [-2 -1 1 2 4];
y = [-6 0 0 6 60];
a = newton(x, y)
yx = polyval(a, 2.5)
Các đa thức Lagrange, Newton thích hợp với bài toán mà hàm f xác định tại
các điểm cho trước; các giá trị của f thường được xác định từ quan sát hay đo đạc.
Tuy nhiên trong một số trường hợp ngoài việc xác định hàm f còn phải xác
định đạo hàm f ’ của nó nữa. Ví dụ, trường hợp biến độc lập là thời gian và hàm f mô
tả vị trí của một đối tượng; đạo hàm của hàm f trong trường hợp này là vận tốc v = f ‘;
hoặc bài toán kết cấu tính dầm trên nền đàn hồi, ta phải xác định chuyển vị yi và góc
xoay αi của dầm; thông số góc xoay αi chính là đạo hàm của chuyển vị yi, .
dy
i ( )i yi,
dx
34
Trong mục này, chúng ta sẽ xem xét nội suy Hermite, xác định đa thức phù hợp
với hàm và đạo hàm bậc nhất tại các điểm cho trước. Giả sử rằng (n + 1) điểm dữ liệu
và các giá trị của hàm (x0, f (x0)), (x1, f (x1)), ..., (xn, f (xn)), được cho, và hàm f có đạo
hàm liên tục bậc nhất trên khoảng kín [a, b] có chứa các điểm x0, x1, ..., xn. Đa thức
Lagrange thích hợp với f tại những điểm này, thường sẽ có bậc n. Nhưng nếu chúng ta
yêu cầu đạo hàm đa thức xác định còn phải phù hợp với đạo hàm của f tại x0, x1, ..., xn,
nữa, thì ta phải sử dụng nội suy Hermite và cần phải bổ sung (n +1) điều kiện nữa và
bậc của đa thức Hermite sẽ là (2n + 1).
Giả sử f ∈ C1 [a, b] và x0, x1,..., xn là các trị số khác biệt trong khoảng kín [a, b].
Đa thức duy nhất có bậc phù hợp nhất với f và f ‘ tại x0, ..., xn là đa thức có bậc lớn
nhất là (2n + 1) cho bởi
H 2 n1 ( x) f x j H n, j x f ' x j H n, j x
n n ^
j 0 j 0
(2.30)
Trong đó: H n, j x 1 2 x x j L'n, j x j L2n, j x
H n, j x x x j L2 n, j x
^
Và:
Ở đây:
( x)
Ln,k ( x)
( xk ).( x xk )
,
35
Nếu f ∈ Cn [a, b] và x0, x1, ..., xn là các giá trị khác biệt trong [a, b], thì tồn tại trị
số ξ trong (a, b) với:
f ( n )
f x0 , x1 , xn
n! (2.32)
Để sử dụng kết quả này tạo ra các đa thức Hermite, giả thiết đầu cho rằng
những trị số riêng biệt x0, x1, ..., xn được cho cùng với các giá trị của f và f ‘ tại những
trị số này. Xác định một chuỗi mới z0, z1, ..., z2n +1 bởi:
z2k z2k 1 xk với k = 0, 1, 2, ..n
Bây giờ xây dựng bảng sai phân bằng cách sử dụng các biến z0, z1, ..., z2n+1. Từ
z2k = z2k +1 = xk cho mổi trị số k, chúng ta không thể xác định f [z2k, z2k +1] bởi mối
quan hệ sai phân cơ bản:
f [z2 k ] - f [z2 k 1 ]
f [z2 k , z2 k 1 ]=
z2 k z2 k 1 (2.33)
Tuy nhiên, đối với mỗi trị số k chúng ta có f [xk, xk+1] = f ’(ξk) với một số ξk
trong (xk, xk +1), và lim xk+1→xk , f [xk, xk+1]= f’(xk). Vì vậy, một sự thay thế hợp lý
trong tình huống này là f [z2k, z2k+1] = f’(xk), và chúng ta sử dụng:
f ' x0 , f ' x1 , f ' xn
Sai phân còn lại được tạo ra như thường lệ, và sự xấp xỉ sai phân được sử dụng
như trong công thức sai phân của Newton. Điều này cung cấp cho chúng ta với một
phương pháp thay thế, dễ dàng hơn đánh giá, để xác định hệ số của đa thức Hermite.
Nếu f ∈ C1 [a, b] và x0, x1, ..., xn là các trị số khác biệt trong [a, b], thì
2 n 1
H 2n+1 (x)= f[z 0 ]+ f[z 0 ,z1 ,...,z k ](x - z0 ),..., (x - z k-1 )
k 1 (2.34)
Với z2k z2k 1 xk và f z2k , z2k 1 f ' xk với k = 0, 1, 2,…,n
Bảng sai phân cho thấy các mục đã được sử dụng cho ba cột sai phân đầu tiên
khi xác định các đa thức Hermite H5(x) cho x0, x1, và x2. Mục còn lại được tạo ra theo
cách sai phân bình thường.
36
z f(z) sai phân bậc 1 sai phân bậc 2
z0 = x0 f [z0] = f (x0)
f [z0, z1]= f’(x0)
f [z2 ,z1 ] - f [z1 ,z0 ]
z1 = x0 f [z1] = f (x0) f [z0 , z1 , z2 ]=
z 2 z0
f [z2 ] - f [z1 ]
f [z1 , z2 ]=
z2 z1
f [z3 ,z2 ] - f [z2 ,z1 ]
z2 = x1 f [z2] = f (x1) f [z1 , z2 , z3 ]=
z3 z1
f z2 , z3 f ' x1
f [z4 ,z3 ] - f [z3 ,z2 ]
z3 = x1 f [z3] = f (x1) f [z2 , z3 , z4 ]=
z4 z2
f [z4 ] - f [z3 ]
f [z3 , z4 ]=
z4 z3
f [z5 ,z4 ] - f [z4 ,z3 ]
z4 = x2 f [z4] = f (x2) f [z3 , z4 , z5 ]=
z5 z3
f z4 , z5 f ' x2
z5 = x2 f [z5] = f (x2)
Ví dụ. Cho dữ liệu cho trong bảng dưới đây, dùng nội suy Hermite tính f(1.5).
Trong đó các mục gạch đít là các dữ liệu cho, phần còn lại được tạo ra theo phương
pháp sai phân chuẩn.
1.3 0.6200860
−0.5220232
1.3 0.6200860 −0.0897427
−0.5489460 0.0663657
1.6 0.4554022 −0.0698330 0.0026663
−0.5698959 0.0679655 −0.0027738
1.6 0.4554022 −0.0290537 0.0010020
−0.5786120 0.0685667
1.9 0.2818186 −0.0084837
−0.5811571
1.9 0.2818186
37
H5(1.5) = 0.6200860 − 0.5220232(1.5 − 1.3) − 0.0897427(1.5 − 1.3)2 +
+ 0.0663657(1.5 − 1.3)2(1.5 − 1.6) + 0.0026663(1.5 − 1.3)2(1.5 − 1.6)2 –
− 0.0027738(1.5 − 1.3)2(1.5 − 1.6)2(1.5 − 1.9)
= 0.5118277
Như vậy, với sử dụng nội suy Hermite, ta tính được giá trị của hàm f tại x = 1.5 là:
H5(1.5) = 0.5118277
f1(x)
y0
x1
f2(x)
f3(x)
y2
y3
x0 x1 x2 x3 x
Trong các mục trước, ta đã xét các bài toán nội suy bằng đa thức và thấy rằng:
các đa thức nội suy thường có bậc rất lớn, khi số điểm mốc lớn; mặt khác có nhiều
hiện tượng vật lý như: sự phân bố mặn theo chiều sâu, mặt cong của sóng gián
đoạn,…nếu sử dụng theo các nội suy này sẽ gây ra sai số lớn. Do đó, cần phải sử dụng
một phương pháp nội suy khác sao cho phù hợp với hiện tượng vật lý quan sát và
không quá phức tạp thuật toán.
Trong mục này, ta nghiên cứu phương pháp nội suy spline, nó có thể đáp ứng
được một số bài toán trong thực tế.
Phương pháp Spline nội suy bằng cách gắn một số đa thức bậc thấp với nhau; ở
đây chỉ nghiên cứu nội suy Spline bậc 3, vì thường đáp ứng yêu cầu trong nhiều bài
toán thực tế và lời giải không phức tạp lắm.
38
Hình vẽ bên chỉ ra nội suy 4 điểm bằng cách dùng 3 hàm bậc 3 (cubic): f1(x),
f2(x), f3(x). Tổng quát nếu có (n + 1) điểm, ta cần n hàm Spline bậc 3 dạng:
fi(x) = A1i + A2i x + A3i x2 + A4i x3 , i = 1,2,3, . . . , n
Có 4n hệ số Aji có thể xác định theo các điều kiện sau:
(i) Hàm Cubic phải gặp tất cả các điểm ở bên trong: có được 2n phương trình
fi(xi) = yi , i = 1, . . . n ; fi + 1(xi) = yi , i = 0,1, . . . n - 1
(ii) Đạo hàm bậc 1 phải liên tục tại các điểm bên trong, dẫn đến được (n – 1)
phương trình:
f’i(xi) = f’i + 1(xi), i = 1, 2,. . . ,n - 1
(iii) Đạo hàm bậc 2 cũng phải liên tục tại các điểm bên trong, thêm được (n – 1)
phương trình nữa:
f”i(xi) = f”i + 1(xi), i = 1,2, . . ., n-1
(iv) Hai điều kiện cuối cùng dựa vào 2 điểm cuối của đường Spline, ở đây thường
đặt f”1(x0) = 0 và f”n(xn) = 0.
Sắp xếp lại hàm fi(x), ta chỉ cần (n - 1) phương trình cần thiết để giải, có dạng:
39
y1 y2
x x
1 2
y2 y3
= 6. x2 x3 (2.37)
yn 1 yn
x x
n 1 n
Giải hệ đại tuyến này ta tìm được f”(xi), với i = 1, 2, . . . , n - 1 cộng với hai
điều kiện biên 2 đầu:
f”(x0) = f”(xn) = 0, đường cong nội suy sẽ hoàn toàn xác định.
Ví dụ. x 1 2 2,2 3 4
y 5 7 ? 10 12
Tìm y = f(x) theo phương pháp nội suy spline bậc 3 và tính y (x = 2,2) = ?
Giải:
Ta có: x1 x2 x3 1
2 3
2(1 1)1
f ''
( x1
) 1 1
. '' 6 .
1 2(1 1) f ( x2 ) 3 2
1 1
4 f ( x1 ) f ( x2 ) 6
" "
f " ( x1 ) 2
" "
f ( x1 ) 4 f ( x2 ) 6
f ( x2 ) 2
"
y = f(x) = y = fi(x) =
y f " ( x1 )x2
f " ( x1 )( x2 x) 3 f " ( x2 )( x x1 ) 3 y f " ( x2 )x2
1 x2 x 2 x x1
6x2 6x2 x2 6 x2 6
2(3 x) 3 (2)( x 2) 3 7 2.1 10 (2).1
3 x x 2
6.1 6.1 1 6 1 6
(3 x) 3 ( x 2) 3 203 x 31x 2
3 3 3 3
Thay vào ta được, tại x = 2.2 y = 7.568
40
Xây dựng hàm nội suy:
function y = cubicspline(xData, yData, x)
%Ham nay xap xi bang da thuc bac 3 spline
%Cu phap: [yi,f] = cubicspline(xData, yData, x)
n = length(xData);
c = zeros(n-1,1); d = ones(n, 1);
e = zeros(n-1,1); k = zeros(n, 1);
c(1:n-2) = xData(1:n-2) - xData(2:n-1);
d(2:n-1) = 2*(xData(1:n-2) - xData(3:n));
e(2:n-1) = xData(2:n-1) - xData(3:n);
k(2:n-1) = 6*(yData(1:n-2) - yData(2:n-1))...
./(xData(1:n-2) - xData(2:n-1))...
- 6*(yData(2:n-1) - yData(3:n))...
./(xData(2:n-1) - xData(3:n));
[c,d,e] = band3(c,d,e);
k = band3sol(c,d,e,k);
i = findseg(xData,x);
h = xData(i) - xData(i+1);
y = ((x - xData(i+1))^3/h - (x - xData(i+1))*h)*k(i)/6.0...
- ((x - xData(i))^3/h - (x - xData(i))*h)*k(i+1)/6.0...
+ yData(i)*(x - xData(i+1))/h...
- yData(i+1)*(x - xData(i))/h;
2.6. Phương pháp bình phương cực tiểu (Least squares method)
Trong nội suy đa thức, đòi hỏi đa thức phải đi qua cặp điểm quan sát. Trong
thực tế, có những hiện tượng vật lý mà các cặp điểm quan trắc này chưa chắc đã chính
xác, ví dụ quan hệ lượng mưa giữa hai trạm đo mưa nào đó, do đó việc tìm đường
cong nội suy qua các cặp điểm này không hẳn là phù hợp. Hoặc thông qua kết quả
thực nghiệm, ta mường tượng được công thức tính toán và dựa vào số liệu thực
nghiệm này ta xác định các tham số của công thức này sao cho sai số ít nhất.
Giả sử có các mẫu quan sát (xi, yi ) của hàm y = f(x). Ta chọn hàm f(x) có dạng:
f(x) = a0f0(x) + a1f1(x) + a2f2(x)... (2.38)
41
Trong đó các hàm f0(x), f1(x), f2(x) v.v… là (m + 1) hàm độc lập tuyến tính mà
ta có thể chọn tuỳ ý và các hệ số ai là tham số chưa biết mà ta phải xác định dựa vào hệ
hàm đã chọn và các điểm quan sát. Sai số giữa trị đo được và trị tính theo (2.38) là:
ei = yi - f(xi) (2.39)
Sai số này có thể âm hay dương tuỳ từng giá trị của yi. Khi dùng phương pháp
bình phương bé nhất ta xét bình phương của sai số tại một điểm:
ei2 yi f ( xi )
2
(2.40)
Rõ ràng S là hàm của các giá trị cần tìm ai và chúng ta sẽ chọn các hệ số ai này
sao cho S đạt giá trị cực tiểu, nghĩa là các đạo hàm S phải bằng không. Ta đi xét một
a i
S
Theo điều kiện đạo hàm 0 ta nhận được hệ phương trình:
a i
n m n n
a m xi a m 1 x m 1
i na 0 yi
i 1 i 1 i 1
n m 1 n n n
m i m 1 i 0 i
m
a x a x a x xi yi
i 1 i 1 i 1 i 1
n m2 n n n
m i m 1 i 0 i
m 1
a x a x a x 2
xi2 yi
i 1 i 1 i 1 i 1 (2.44)
n n n n
am xim 3 am 1 xim 2 a0 xi3 xi3 yi
i 1 i 1 i 1 i 1
n 2m n n n
m i m 1 i 0 i
2 m 1
a x a x a x m
xim yi
i 1 i 1 i 1 i 1
Đây là một hệ phương trình tuyến tính. Giải hệ này ta sẽ nhận được các gía trị
ai. Sau đây là chương trình viết theo thuật toán trên.
42
Chương trình 5-4
//Xap xi da thuc
#include <conio.h>
#include <stdio.h>
#include <ctype.h>
#define max 11
void main()
{
int i,j,k,m,n,p,kp,t;
float a[max],x[max],y[max],y1[max];
float b[max][max];
char ok;
float s,sx,s1,c,d;
clrscr();
printf("PHUONG PHAP BINH PHUONG TOI THIEU");
printf("\n");
printf("Cho bac cua da thuc xap xi m = ");
scanf("%d",&m);
printf("So diem da cho n = ");
scanf("%d",&n);
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
x[0]=1;
printf("\n");
printf("%4cBANG SO LIEU\n",' ');
43
printf("%8cx%30cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%4c%8.4f%20c%8.4f\n",' ',x[i],' ',y[i]);
ok=' ';
t=1;
flushall();
while (t)
{
printf("Co sua so lieu khong(c/k): ");
scanf("%c",&ok);
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
flushall();
}
if (toupper(ok)!='C')
t=0;
}
//for (i=0;i<=n;i++)
//a[i]=0.0;
printf("\n");
printf("CAC GIA TRI DA CHO");
printf("\n");
printf("X = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',x[i]);
44
printf("\n");
printf("Y = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',y[i]);
printf("\n");
for (p=0;p<=m;p++)
{
y1[p]=0.0;
for (i=1;i<=n;i++)
{
sx=1.0;
for (j=1;j<=p;j++)
sx*=x[i];
y1[p]+=y[i]*sx;
}
}
for (p=0;p<=m;p++)
for (k=0;k<=m;k++)
{
kp=k+p;
b[p][k]=0.0;
for (i=1;i<=n;i++)
{
sx=1.0;
for (j=1;j<=kp;j++)
sx*=x[i];
b[p][k]+=sx;
}
}
for (i=0;i<=m-1;i++)
{
c=1.0/b[i][i];
45
for (k=i+1;k<=m;k++)
{
d=b[i][k];
for (j=i+1;j<=m;j++)
b[k][j]-=b[i][j]*c*d;
y1[k]-=y1[i]*c*d;
b[i][k]*=c;
}
y1[i]*=c;
}
y1[m]/=b[m][m];
for (i=m-1;i>=0;i--)
for (j=i+1;j<=m;j++)
y1[i]-=b[i][j]*y1[j];
printf("\n");
printf("CAC HE SO CUA DA THUC CAN TIM");
printf("\n");
for (i=0;i<=m;i++)
printf("a[%d] = %10.5f\n",i,y1[i]);
getch();
}
Ví dụ. Với đa thức được chọn có dạng cụ thể là: y = a + bx + cx2
Ta có: yi - a - bxi – cxi2 = i , với i = 1, 2,.., n ở đây i sai số tại xi.
Do đó: S = ( yi a bxi cxi2 ) 2 là tổng các bình phương của các sai số.
S phụ thuộc a và b, còn xi, yi ta đã biết rồi.
Mục đích của phương pháp bình phương cực tiểu là xác định a, b và c sao cho
sai số nhỏ nhất: S Smin.
S S S
Như vậy: 0, 0 và 0
a b c
Ta có được hệ phương trình:
46
na b xi c xi 2 yi
a xi b xi c xi xi yi
2 3
(2.45)
x i2i yi
3 4
2
a xi b xi c xi
c
i 1
xi n ln A
i 1
ln yi
n n n
(2.47)
c x 2 ln A x x ln y
i 1
i
i 1
i
i 1
i i
47
Giải hệ phương trình này ta có các hệ số A và c:
Chương trình 5-5
//xap_xi_e_mu;
#include <conio.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#define max 11
void main()
{
int i,n,t;
float x[max],y[max];
char ok;
float a,b,c,d,e,f,d1,d2,d3;
clrscr();
printf("PHUONG PHAP BINH PHUONG TOI THIEU");
printf("\n");
printf("So diem da cho n = ");
scanf("%d",&n);
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
x[0]=1.0;
printf("%4cBANG SO LIEU\n",' ');
printf("%8cx%30cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%4c%8.4f%23c%8.4f\n",' ',x[i],' ',y[i]);
48
ok=' ';
t=1;
while (t)
{
printf("Co sua so lieu khong(c/k): ");
scanf("%c",&ok);
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
if (toupper(ok)!='C')
t=0;
}
printf("CAC GIA TRI DA CHO");
printf("\n");
printf("X = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',x[i]);
printf("\n");
printf("Y = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',y[i]);
printf("\n");
a=0.0;
for (i=1;i<=n;i++)
a+=x[i];
49
b=n;
c=0.0;
for (i=1;i<=n;i++)
c+=log(y[i]);
d=0.0;
for (i=1;i<=n;i++)
d+=x[i]*x[i];
e=0.0;
for (i=1;i<=n;i++)
e+=x[i]*log(y[i]);
d1=a*a-d*b;
d2=c*a-e*b;
d3=a*e-c*d;
c=d2/d1;
a=d3/d1;
printf("\n");
printf("He so A = %8.4f",exp(a));
printf(" va so mu c = %8.4",c);
printf("\n");
printf("\nBANG CAC GIA TRI TINH TOAN");
printf("\n");
printf("%5cx%28cy\n",' ',' ');
for (i=1;i<=n;i++)
{
printf("%8.4f%21c%8.4f\n",x[i],' ',exp(a)*exp(c*x[i]));
}
getch();
x 0 2 4 6 8 10 12
i
q ln x n ln A ln yi
i 1 i 1
n n n
(2.49)
q ln 2 x ln A ln x ln x ln y
i 1
i
i 1
i i 1
i i
void main()
{
int i,n,t;
float x[max],y[max];
char ok;
float a,b,c,d,e,f,d1,d2,d3;
clrscr();
printf("PHUONG PHAP BINH PHUONG TOI THIEU");
printf("\n");
printf("So diem da cho n = ");
scanf("%d",&n);
51
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
x[0]=1.0;
printf("%4cBANG SO LIEU\n",' ');
printf("%8cx%30cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%4c%8.4f%23c%8.4f\n",' ',x[i],' ',y[i]);
ok=' ';
flushall();
t=1;
while (t)
{
printf("Co sua so lieu khong(c/k): ");
scanf("%c",&ok);
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
printf("x[",i,"] = ");
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
if (toupper(ok)!='C')
t=0;
}
52
printf("\n");
printf("\nCAC GIA TRI DA CHO");
printf("\n");
printf("X = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',x[i]);
printf("\n");
printf("Y = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',y[i]);
printf("\n");
a=0.0;
for (i=1;i<=n;i++)
a+=log(x[i]);
b=n;
c=0.0;
for (i=1;i<=n;i++)
c+=log(y[i]);
d=0.0;
for (i=1;i<=n;i++)
d+=log(x[i])*log(x[i]);
e=0.;
for (i=1;i<=n;i++)
e+=log(x[i])*log(y[i]);
d1=a*a-d*b;
d2=c*a-e*b;
d3=a*e-c*d;
c=d2/d1;
a=d3/d1;
printf("\n");
printf("He so A = %8.4f",exp(a));
printf(" va so mu q = %8.4f\n",c);
53
printf("\n");
printf("\nBANG CAC GIA TRI TINH TOAN\n");
printf("%5cx%27cy\n",' ',' ');
for (i=1;i<=n;i++)
{
printf("%8.4f%20c%8.4f\n",x[i],' ',exp(a)*exp(c*log(x[i])));
}
getch();
}
Áp dụng. Với các giá trị x,y khảo sát cho ở bảng sau:
x 1 2 4 5 6
y 7.1 27.8 62.1 110 161
Trường hợp quan hệ y = f(x) có dạng hàm tuần hoàn, ta nên dùng hàm xấp xỉ là
tổ hợp tuyến tính của các hàm sin và cosin có dạng:
n n
y = f ( x) a 0 a i 1
i cos(ix) bi sin(ix)
i 1
(2.50)
Đạo hàm E triệt tiêu theo các biến a0, a1, b1 ta có:
n
cos x sin x a
0 y
cos x .a 1 y cos x
2
cos x cos x sin x
(2.53)
sin x cos x sin x sin x b y sin x
2
Do :
54
sin x 0 ;
cos x 0
n n
sin 2 x
1
;
cos 2 x
1
n 2 n 2
cos x sin x sin x 2
0
n
Nên hệ phương trình (2.53) có dạng đơn giản:
n 0 0
a 0 y
0 n
0.a1 y cos x
2
y sin x
(2.54)
n
b
0 0
2
y 2 2
a0
n
; a1
n
y cos x ; b1
n
y sin x ;
Tương tự cho trường hợp tổng quát:
y 2 2
a0
n
; ai
n
y cos ix ; bi
n
y sin ix ;
Chương trình tìm các hệ số ai và bi được viết như sau:
Chương trình 5-7
//xap_xi_sin_cos;
#include <conio.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#define max 11
#define pi 3.15159
void main()
{
int i,j,m,n,t;
55
float x[max],y[max],a[max],b[max];
char ok;
float omg,t1;
clrscr();
printf("PHUONG PHAP BINH PHUONG TOI THIEU");
printf("\n");
printf("Cho so so hang sin-cos m = ");
scanf("%d",&m);
printf("Cho chu ki T = ");
scanf("%f",&t1);
printf("So diem da cho n = ");
scanf("%d",&n);
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
x[0]=1.0;
printf("%4cBANG SO LIEU\n",' ');
printf("%8cx%30cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%4c%8.4f%23c%8.4f\n",' ',x[i],' ',y[i]);
ok=' ';
t=1;
flushall();
while (t)
{
printf("Co sua so lieu khong(c/k): ");
scanf("%c",&ok);
56
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
flushall();
}
if (toupper(ok)!='C')
t=0;
}
printf("\nCAC GIA TRI DA CHO\n");
printf("\n");
printf(" X Y\n");
for (i=1;i<=n;i++)
printf("%c%8.3f%c%8.3f\n",' ',x[i],' ',y[i]);
printf("\n");
a[0]=0.0;
omg=2*pi/t1;
for (i=1;i<=n;i++)
a[0]+=y[i];
a[0]/=n;
for (j=1;j<=m;j++)
{
a[j]=0.0;
for (i=1;i<=n;i++)
a[j]+=y[i]*cos(j*omg*x[i]);
a[j]=2*a[j]/n;
57
}
for (j=1;j<=m;j++)
{
b[j]=0.0;
for (i=1;i<=n;i++)
b[j]+=y[i]*sin(j*omg*x[i]);
b[j]=2*b[j]/n;
}
printf("\n");
printf("TAN SO GOC OMEGA = %10.5f\n",omg);
printf("HE SO HANG\n");
printf("a[0] = %8.4f\n",a[0]);
printf("CAC HE SO BAC CAO\n");
printf("%5ccos%25csin\n",' ',' ');
for (i=1;i<=m;i++)
printf("%8.4f%21c%6.4f\n",a[i],' ',b[i]);
getch();
}
Áp dụng. Với hàm cho ở bảng số như sau:
58
1 b1 1
(2.56)
y ax a
Và từ đó tính được a và b.
Chương trình viết theo thuật toán ở trên được cho như sau:
Chương trình 5-8
//xap xi huu_ty;
#include <conio.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#define k 11
void main()
{
float x[k],y[k];
float a,b,a1,b1,c,d,e;
int i,n,t;
char ok;
clrscr();
printf("PHUONG PHAP BINH PHUONG TOI THIEU");
printf("\n");
printf("So diem da cho n = ");
scanf("%d",&n);
for (i=1;i<=n;i++)
{
59
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
}
printf("%4cBANG SO LIEU\n",' ');
printf("%8cx%30cy\n",' ',' ');
for (i=1;i<=n;i++)
printf("%4c%8.4f%23c%8.4f\n",' ',x[i],' ',y[i]);
ok=' ';
t=1;
flushall();
while (t)
{
printf("Co sua so lieu khong(c/k): ");
scanf("%c",&ok);
if (toupper(ok)=='C')
{
printf("Chi so cua phan tu can sua i = ");
scanf("%d",&i);
printf("Gia tri moi : ");
printf("x[%d] = ",i);
scanf("%f",&x[i]);
printf("y[%d] = ",i);
scanf("%f",&y[i]);
flushall();
}
if (toupper(ok)!='C')
t=0;
}
printf("CAC GIA TRI DA CHO\n");
printf("\n");
60
printf("X = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ',x[i]);
printf("\n");
printf("Y = ");
for (i=1;i<=n;i++)
printf("%c%8.3f",' ' ,y[i]);
printf("\n");
a=n;
b=0.0;
c=0.0;
d=0.0;
e=0.0;
for (i=1;i<=n;i++)
{
b+=1/x[i];
c+=1/y[i];
d+=1/(x[i]*x[i]);
e+=1/(x[i]*y[i]);
}
a1=(c*d-b*e)/(a*d-b*b);
b1=(a*e-b*c)/(a*d-b*b);
a=1/a1;
b=b1*a;
printf("\n");
printf("Cac he so cua ham huu ty\n");
printf("a = %10.5f b = %10.5f",a,b);
getch();
}
61
Áp dụng. Với dãy số liệu cho như sau:
x 1 2 3 4 5
y 0.3333333 0.5 0.6 0.66666 0.7142857
Câu hỏi:
1) Ưu nhược điểm của các phương pháp nội suy Lagrange, Newton, Spline,
Hermite ?
2) Hãy chỉ ra những trường hợp cụ thể và cách chọn phương pháp nội suy nào
thích hợp nhất ?
3) Phương pháp bình phương cực tiểu thường được áp dụng khi nào? Tại sao
người ta nói phương pháp này mang tính chủ quan của người sử dụng tính toán?
Một cách chính xác có gọi phương pháp này là nội suy được không ?
ài tập:
y 1 3 2 5
2) Cho bảng giá trị của hàm số y = f(x)
x 321.0 322.8 324.2 325.0
y 0 3 5 4 1
62
4) Hãy đánh giá sai số nhận được khi xấp xỉ hàm số y = sinx bằng đa thức nội suy
Lagrange bậc 5: L5(x), biết rằng đa thức này trùng với hàm số đã cho tại các giá trị x
bằng: 00, 50, 100, 150, 200, 250. Xác định giá trị của sai số khi x = 12030’.
5) Tìm đa thức nội suy bậc 2 của hàm y = 3x trên đoạn 1,1 , từ đó suy ra giá trị
x0 = 1 f(x0) = 0
x1 = 4 f(x1) = 1,386294
x2 = 6 f(x0) = 1,791760
Đáp số:
62 3 13
1) 1+ x + x3 - x2
15 10 6
2) 2,50987
1 4
3) f(x)= ( x 26 x 3 220 x 2 664 x 640)
32
1 5
4) sin( x) L5 ( x) x( x )( x )( x )( x )( x ) , khi x=12030’
6! 36 18 12 9 36
5) Để được đa thức nội suy bậc 2 thì cần 3 mốc: Ở đây ta chọn x0 = -1, 0, 1 thì
y 3 -6 39 822 1611
a) Xây dựng đa thức nội suy Newton tiến xuất phát từ nút x0 = -1 của hàm số
63
y = f(x).
b) Dùng đa thức nội suy nhận được, tính gần đúng f(-0.25).
2) Cho bảng giá trị của hàm số y = sinx
x 0,1 0,2 0,3 0,4
Ta tính giá trị của hàm tại 0.14 bằng đa thức nội suy Newton với các mốc cách
đều h = 0.1.
6) Cho các giá trị dưới đây ước tính giá trị ln2 dùng nội suy đa thức Newton bậc 3:
x0 = 1 f(x0) = 0
x1 = 4 f(x1) = 1,386294
x2 = 6 f(x0) = 1,791760
Đáp số:
1) a) x4 - 3x3 + 5x2 - 6
b) -5,6367188
64
2) a) sin(0,14) 0,1395434
b) sin(0,46) 0,4439446
3) f(x) 0,3989423 - 0,0000500x - 0,0000199x(x - 2,5069)
0,47 t (t 1)(t 2) t (t 1)(t 2)(t 3)
4) y = 4303,52+60,59t+ t(t-1)-0,01 +0,03 -
2! 3! 4!
t (t 1)(t 2)(t 3)(t 4)
- 0,06
5!
x 58
Trong đó: t = ; y(x = 58,17) = 4333,75779688
0,34
5) y = 0,13954
6) f3(x) = 0,462098(x-1) – 0,05187311(x-1)(x-4) + 0,007865529(x-1)(x-4)(x-6)
f3(2) = 0,6287656
x f(x) f’(x)
x f(x) f’(x)
2) a) Sử dụng các giá trị và số làm tròn có năm chữ số sau để xây dựng
đa thức nội suy Hermite xấp xỉ sin0,34.
65
x sinx Dxsinx = cosx
b) Xác định sai số giới hạn cho xấp xỉ ở phần (a) và so sánh với sai số
hiện tại.
c) Thêm sin0.33 = 0.32404 và cos0.33 = 0.94604 dữ liệu và lặp lại tính toán
3) Theo bảng dữ liệu cho hàm được mô tả bởi f x e0.1x . Xấp xỉ f(1.25) bằng
2
x1 = 2 1.491824698 0.5967298792
x2 = 3 2.459603111 1.475761867
Tốc độ (m/s) 85 87 90 85 82
66
a) Sử dụng đa thức Hermite để dự đoán vị trí của xe và tốc độ của xe khi
t = 12s.
b) Sử dụng đạo hàm của đa thức Hermite để xác định liệu xem xe có vượt
quá giới hạn tốc độ giới hạn 60 km / h trên đường. Nếu vậy, khi nào
chiếc xe vượt quá tốc độ này lần đầu?
c) Tốc độ tối đa được dự đoán cho xe là bao nhiêu ?
d)
suy ra 3 3 .
2) Cho hàm số y = sinx trên đoạn 0; . Hãy lập hàm spline bậc 3 để xấp xỉ
hàm sinx trên đoạn đã cho, với các mốc nội suy x0 = 0, ,.
2
3) Cho hàm dưới dạng bảng:
x 1 2 3 4 5
y 0 1 0 1 0
y 2,5 1 ? 2,5
Tìm y = f(x) theo phương pháp nội suy spline bậc 3 và tính y(5) = ?
67
Hãy tìm công thức thực nghiệm có dạng y = a + bx.
6) Cho bảng giá trị:
x 0,78 1,56 2,34 3,12 3,81
68
Chương 3 TÍNH GẦN ĐÚNG ĐẠO HÀM
VÀ TÍCH PHÂN
NUMERICAL DIFFERENTIATION
AND INTEGRATION
Trong nhiều bài toán kỹ thuật, ví dụ khi cần tính tích phân trong phương phương
số phần tử hữu hạn, phần tử biên… thường chúng không được nhận được kết quả bởi giải
tích; lúc đó người ta hay sử dụng các phương pháp tính gần đúng.
3.1. Tính gần đúng đạo hàm
Ta biểu diễn hàm f(x) bằng đa thức nội suy: f(x) = P(x), với P(x) là đa thức nội
suy (đa thức nội suy tiện lợi là spline bậc 3); Tiếp theo ta tính gần đúng đạo hàm f ’(x) ở
đa thức này:
f’(x) = P’(x)
Ta cũng có thể áp dụng khai triển Taylor:
h2
f(x + h) = f(x) + h f’(x) + f”(c), với c = x + h, 0 < < 1
2!
f (x h) f (x)
Từ đó ta tính được: f’(x)
h
3.1.1. Đạo hàm ROMBERG
Đạo hàm ROMBERG là một phương pháp ngoại suy để xác định đạo hàm với độ
chính xác cao theo mong muốn.
Để nhận được đạo hàm theo phương pháp này, ta sử dụng khai triển Taylor hàm
f(x) tại (x + h) và (x – h):
h 2 '' h3 h 4 ''
f ( x h) f ( x) h. f ' ( x) f ( x) f ' ' ' ( x) f ( x) ... (3.1)
2! 3! 4!
h 2 '' h3 h 4 ''
f ( x h) f ( x) h. f ' ( x) f ( x) f ' ' ' ( x) f ( x) ... (3.2)
2! 3! 4!
Trừ (3.1) cho (3.2), ta được:
h3 h 5 (v)
f ( x h) f ( x h) 2h. f ' ( x) 2 f ' ' ' ( x) 2 f ( x) ... (3.3)
3! 5!
Từ (3.3) ta rút ra f ’(x):
69
f ( x h ) f ( x h) h2 h 4 (v)
f ' ( x) f ' ' ' ( x) f ( x) ... (3.4)
2h 3! 5!
Hay ta có thể viết lại:
1
f ' ( x) [ f ( x h) f ( x h)] a 2 h 2 a4 h 4 a6 h 6 ... (3.5)
2h
Trong biểu thức (3.5), các hệ số ai phụ thuộc vào f và x.
Ta đặt :
1
(h) [ f ( x h) f ( x h)] (3.6)
2h
Như vậy, từ (3.5) và (3.6) ta được :
D(1,1) (h) f ' ( x) a2 h 2 a4 h 4 a6 h 6 ... (3.7)
Để tạo ra sai phân có độ chính xác cao hơn, ta lấy D(1,1) – 4.D(2,1), được :
h 3 15
(h) 4 ( ) 3 f '( x) a4 h4 a6 h6 ... (3.10)
2 4 16
Chia hai vế của (3.10) cho -3, ta được:
4 D(2,1) D(1,1) 1 5
D(2, 2) f '( x) a4 h4 a6 h6 ... (3.11)
3 4 16
Đối chiếu các biểu thức (3.7), (3.8), (3.9) với biểu thức (3.11), ta nhận thấy:
D(i, 1) sai khác với f ’(x) bậc h2, trong khi D(2, 2) sai khác với f ‘(x) bậc 0(h)4.
Bây giờ, nếu chia đôi bức h, ta sẽ nhận được:
4 6
1 h 5 h
D(3, 2) f '( x) a4 a6 ... (3.12)
4 2 16 2
70
16 D(3, 2) D(2, 2) 1
D(3,3) f '( x) a6 h6 ... (3.14)
15 64
Với (3.14), ta thấy sai số bậc 0(h)6.
Nếu ta tiếp tục chia đôi bức h và tính D(4, 4) thì sai số của đạo hàm f ’(x) là bậc
0(h)8.
Một cách truy hồi, ta có sơ đồ tính đạo hàm theo phương pháp ROMBERG như
sau:
D(1,1)
D(2,1) D(2,2)
D(3,1) D(3,2) D(3,3)
D(4,1) D(4,2) D(4,3) D(4,4)
………………………………………….....
D(n,1) D(n,2) D(n,3) D(n,4) ........ D(n,n)
Trong đó, mỗi giá trị sau có được bằng cách ngoại suy các giá trị trước nó ở hàng
trên.
Với : 2 ≤ j ≤ i ≤ n ; ta có công thức tổng quát:
4 j 1 D(i, j 1) D(i 1, j 1)
D(i, j ) (3.15)
4 j 1 1
Với hi = h / 2i-1
Như vậy phương pháp ROMBERG có thể cho phép tính đạo hàm với độ chính xác
tùy ý; trong thực hành khi hai lần tính đạo hàm liên tiếp, nếu sai số nhỏ hơn sai số cho
phép, thì chương trình tính sẽ dừng lại.
Ví dụ. Tìm đạo hàm của hàm f(x) = x2 + arctan(x) tại x = 2 với bước tính h = 0.5.
Trị chính xác của đạo hàm là 4.2
1
D(1,1) [ f (2.5) f (1.5)] 4.207496266
2 0.5
1
D(2,1) [ f (2.25) f (1.75)] 4.201843569
2 0.25
71
1
D(3,1) [ f (2.125) f (1.875)] 4.200458976
2 0.125
4 D(2,1) D(1,1)
D(2, 2) 4.19995935
4 1
4 D(3,1) D(2,1)
D(3, 2) 4.200458976
4 1
42 D(3, 2) D(2, 2)
D(3,3) 4.200492284
42 1
Chương trình tính đạo hàm như dưới đây. Dùng chương trình tính đạo hàm của
hàm cho trong function với bước h = 0.25 tại xo = 0 ta nhận được giá trị đạo hàm là
1.000000001.
Ứng dụng lập trình
(i) Dùng C++
//Daoham_Romberg;
#include <conio.h>
#include <stdio.h>
#include <math.h>
#define max 11
float h;
void main()
{
float d[max];
int j,k,n;
float x,p;
float y(float),dy(float);
clrscr();
printf("Cho diem can tim dao ham x = ");
scanf("%f",&x);
printf("Tinh dao ham theo phuong phap Romberg\n");
printf("cua ham f(x) = th(x) tai x = %4.2f\n",x);
n=10;
72
h=0.2;
d[0]=dy(x);
for (k=2;k<=n;k++)
{
h=h/2;
d[k]=dy(x);
p=1.0;
for (j=k-1;j>=1;j--)
{
p=4*p;
d[j]=(p*d[j+1]-d[j])/(p-1);
}
}
printf("y'= %10.5f\n",d[1]);
getch();
}
float y(float x)
{
float a=(exp(x)-exp(-x))/(exp(x)+exp(-x));
return(a);
}
float dy(float x)
{
float b=(y(x+h)-y(x-h))/(2*h);
return(b);
}
73
(ii) Dùng Matlab
Xây dựng hàm:
function df = diffromberg(f, x, h, maxiter, tol)
%Tinh dao ham bang phuong phap Romberg
D(1, 1) = (feval(f,x+h) - feval(f, x-h))/(2*h);
for i = 1:maxiter
h = h/2;
D(i + 1, 1) = (feval(f,x+h) - feval(f, x-h))/(2*h);
for j = 1:i
D(i + 1, j + 1) = (4^j*D(i + 1, j) - D(i, j))/(4^j - 1);
end
if (abs( D(i + 1, i + 1) - D(i, i) ) < tol)
df = D(i+1, i+1);
break;
elseif ( i == maxiter )
error( 'Ngoai suy Richardson khong hoi tu' );
end
end
Áp dụng. Tìm đạo hàm của hàm f ( x) x2 2 xe x 1 tại x = 2 với bước tính h = 0.5.
Kết quả tính đạo hàm là 48.334.
Để tính đạo hàm của hàm cho trước ta dùng chương trình:
clear all, clc
format long;
f = inline('x^2 + 2*x*exp(x) + 1');
x = 2;
h = 0.5;
tol = 1e-6;
maxiter = 10;
df = diffromberg(f, x, h, maxiter, tol)
74
3.2. Tính gần đúng tích phân xác định
3.2.1. Công thức hình thang
Trong từng khoảng chia (i, i+1), đường cong Mi, Mi+1 được xấp xỉ thành đường
thẳng.
Đối với tích phân thứ (i + 1), ta có:
f(x)
x i 1 f(b)
y yi 1 y1
xi
f ( x )dx h i
2
f(a)
y0
b a
Với xi = a + ih, h = ,
n
i = 1, 2, . . . . . , n; a = x0 , b = xn x0 x1 x
b x1 x2 xn
IT
h
y 0 y1 (y1 y 2 ) ....... (y n1 y n )
2
(3.18)
y yn
I T h 0 y1 y 2 ....... y n1
2
M 2
Sai số: I - IT h ( b a) , với M = max f”(x), a x b
12
Ví dụ. Dùng công thức hình thang tổng quát với n=10 để tính gần đúng:
1
dx
I= 1 x
0
Đánh giá những sai số của những giá trị gần đúng nhận được.
Giải:
1 0
Ta có: h= = 0,1
10
Kết quả tính toán trong bảng sau:
75
i xi yi
0 0 1,00000
1 0,1 0,90909
2 0,2 0,83333
3 0,3 0,76923
4 0,4 0,71429
5 0,5 0,66667
6 0,6 0,62500
7 0,7 0,58824
8 0,8 0,55556
9 0,9 0,52632
10 1,0 0,50000
6,18773
1
f(x) = =(1+x)-1
1 x
f ' ( x) = -(1+x)-2
2
f '' ( x) = (-1)(-2)(1+x)-3 = Trong (0, 1) M = max f x'' = 2
(1 x) 3
2.(0,1) 2
R (1 0) 0, 00167 (3.20)
12
76
Ứng dụng lập trình
(i) Dùng C++
//tinh tich phan bang phuong phap hinh_thang;
#include <conio.h>
#include <stdio.h>
#include <math.h>
float f(float x)
{
float a=exp(-x)*sin(x);
return(a);
};
void main()
{
int i,n;
float a,b,x,y,h,s,tp;
clrscr();
printf("Tinh tich phan theo phuong phap hinh thang\n");
printf("Cho can duoi a = ");
scanf("%f",&a);
printf("Cho can tren b = ");
scanf("%f",&b);
printf("Cho so buoc n = ");
scanf("%d",&n);
h=(b-a)/n;
x=a;
s=(f(a)+f(b))/2;
for (i=1;i<=n;i++)
{
x=x+h;
77
s=s+f(x);
}
tp=s*h;
printf("Gia tri cua tich phan la : %10.6f\n",tp);
getch();
}
(ii) Dùng Matlab
Xây dựng hàm:
function J = trapezoid(f, a, b, maxiter, tol)
% Quy tac hinh thang lap.
% Cu phap: J = trapezoid(f, a, b, k)
fa = feval(f, a);
fb = feval(f, b);
J1 = (fa + fb)*(b - a)/2;
for k = 2:maxiter
n = 2^(k -2 ); % so diem moi
h = (b - a)/n ; % khoang chia moi
x = a + h/2.0; % toa do diem moi thu nhat
sum = 0.0;
for i = 1:n
fx = feval(f, x);
sum = sum + fx;
x = x + h;
end
J = (J1 + h*sum)/2;
if abs(J1 - J) < tol
break;
end
J1 = J;
end
78
Áp dụng. Tính tích phân
1
J x 3 1 sin xdx
0
t ( t 1) 2
x2 x2 2
f ( x ) dx p 2 ( x ) dx h( y 0 t y 0
2
y 0 ) dt
(3.21)
x0 x0 0
x2
h
x0
f ( x)dx
3
( y 0 4 y1 y 2 ) (3.22)
Tổng quát:
x2 i 2
h
x2 i
f ( x)dx
3
( y2i 4 y2i 1 y2i 2 ) (3.23)
Vậy:
79
h
[( y0 4 y1 y2 ) ( y2 4 y3 y4 ) .... ( y2 n 2 4 y2 n 1 y2 n )]
3
(3.24)
h
I [( y0 y2 n ) 4( y1 y3 ... y2 n 1 ) 2( y2 y4 ... y2 n 2 )]
3
Sai số:
h4
I IS M (b a) (3.25)
180
float y(float x)
{
float a=4/(1+x*x);
return(a);
}
void main()
{
int i,n;
float a,b,e,x,h,x2,y2,x4,y4,tp;
clrscr();
printf("Tinh tich phan theo phuong phap Simpson\n");
printf("Cho can duoi a = ");
scanf("%f",&a);
printf("Cho can tren b = ");
80
scanf("%f",&b);
printf("Cho so diem tinh n = ");
scanf("%d",&n);
h=(b-a)/n;
x2=a+h;
x4=a+h/2;
y4=y(x4);
y2=y(x2);
for (i=1;i<=n-2;i++)
{
x2+=h;
x4+=h;
y4+=y(x4);
y2+=y(x2);
}
y2=2*y2;
y4=4*(y4+y(x4+h));
tp=h*(y4+y2+y(a)+y(b))/6;
printf("Gia tri cua tich phan la : %10.8f\n",tp);
getch();
}
(ii) Dùng Matlab
Xây dựng hàm:
function s = simpson(f, a, b, n)
%n so khoang chia
%neu f chua trong mot file dung ki hieu @ de goi
% s = simpson(@f, a, b, n).
%neu f la ham inline
% s = simpson(f, a, b, n).
if mod(n, 2) ~= 0
81
n=n+1
end
h = (b - a)/(2*n);
s1 = 0;
s2 = 0;
for k = 1:n
x = a + h*(2*k-1);
s1 = s1+ f(x);
end
for k = 1:(n-1)
x = a + h*2*k;
s2 = s2 + f(x);
end
s = h*(f(a) + f(b) + 4*s1 + 2*s2)/3;
clc
Áp dụng. Tính tích phân
1
J e xsin xdx
0
Đánh giá những sai số của những giá trị gần đúng nhận được.
82
3.2.3. Công thức của Gauss
a. Liên hệ giữa các hệ toạ độ tổng thể và hệ toạ độ địa phương
Trong nhiều trường hợp ta cần tính tích phân số với độ chính xác rất cao, như trong
phương pháp phần tử hữu hạn (PTHH), miền tính toán được chia nhỏ thành nhiều miền
con, phương pháp biến phân trọng số xây dựng trên các miền con này. Do đó dẫn đến tích
phân hàm dạng trên miền con.
3
x N i xi N1 x1 N 2 x 2 N 3 x3
i 1
Nếu tích phân hàm dạng bậc cao với sử dụng hệ toạ độ tổng thể (x,y,z, global
coordinate) thì thông thường sẽ xuất hiện các biểu thức đại số rất phức tạp khi phần tử là
hai, ba chiều (Irons and Ahmad, 1980).
Thay vào đó nếu chúng ta thực hiện chúng trong hệ toạ độ địa phương (, , ,
local coordinate) hay còn gọi là toạ độ chuẩn hay toạ độ tự nhiên (normal coordinate hay
natural coordinate) thì sẽ đơn giản hơn rất nhiều Taig, 1961; bởi lẽ nó thuận lợi trong
việc xây dựng hàm nội suy, tích phân số dùng được cách thiết lập của Gauss-Legendre
(phổ biến nhất).
Phần tử chiếu Phần tử thực
y xj
τ e
3
0,1
1 xi Ve
1 2 xj
3 xk xi
vr xk
1 2
0,0 1,0 x
83
Ở đây Ni, Nj là hàm dạng hay còn gọi là hàm nội suy (shape function hay
interpolation function).
3
y N j y j N1 y1 N 2 y2 N3 y3 (3.26)
j 1
x
1
Hay: J (3.28)
y
Ở đây J là ma trận Jacobian biến đổi toạ độ. Định thức của ma trận này, det J ,
cũng phải được ước lượng bởi lẽ nó được dùng trong các tích phân biến đổi như sau:
Cho phần tử tứ giác tuyến tính:
1 1
dxdy det J d d
1 1
(3.29)
e
3 2
3
4 4
1 1
84
Trong một số trường hợp, ví dụ như ở Hình 3.1, phần tử tứ giác có 4 điểm nút, nếu
dạng hình học như vậy, ma trận Jacobian trở nên không xác định; để nó có giá trị tốt, các
hình dạng phần tử như cạnh và góc của nó cần phải đều đặn hơn (ví dụ tam giác đều, tứ
giác đều hình vuông, đây là các dạng phần tử lý tưởng).
2)*gamma(n+alfa+1)*gamma(n+beta+1)*(2^(2*n+alfa+beta+1))*factorial(n);
den = (n + alfa + beta + 1)*gamma(n+alfa+beta+1)*polyval(dv,...
x(i))*polyval(pn1, x(i));
w(i) = num/den;
end
Áp dụng. Tính tích phân J e xsin xdx .
0
b. Tích phân số
Một số tích phân của các loại bài toán hai chiều (2D), ba chiều (3D), theo phương
pháp PTHH có thể được ước lượng bằng giải tích, nhưng nó không thực dụng cho các
hàm số phức tạp, đặc biệt trong trường hợp tổng quát khi , là toạ độ cong. Trong thực
86
hành (3.29), (3.30) được ước lượng bằng số, gọi là tích phân số (numerical integration
hay còn gọi là numerical quadrature). Dùng tích phân số của Gauss, với phần tử tứ giác,
miền hai chiều ta có:
f , dd wi w j f i , j
1 1 n n
1 1 i 1 j 1
(3.31)
f , dd
1 n
2 i 1
wi f i , i (3.32)
0 0
Với phần tử tứ giác thì wi, wj là hệ số trọng số và i , j là các vị trí toạ độ bên
trong phần tử, cho ở Bảng 3.2 (Xem Kopal 1961); còn với phần tử tam giác, tương tự như
phần tử tứ giác, nhưng các điểm tích phân là các điểm mẫu (Sampling Points), Bảng 3.1.
Thông thường người ta muốn các tích phân số đạt độ chính xác cao, nhưng có
những trường hợp đặc biệt lại không cần thiết. Ở tích phân Gauss (3.31), với n = 2, sẽ
chính xác khi hàm f là cubic (bậc 3), còn ở tích phân (3.32), n = 1, sẽ chính xác khi đa
thức f bậc nhất, còn n = 3, sẽ chính xác khi đa thức f bậc hai.
Bảng 3.1: Điểm tích phân cho phần tử tam giác theo công thức (3.32)
n i i wi
1 1/ 3 1/ 3 1
1/ 2 1/ 2 1/ 3
3 1/ 2 0 1/ 3
0 1/ 2 1/ 3
87
Bảng 3.2: Trọng số và điểm tích phân Gauss – Legendre theo công thức (3.31)
1
Giải:
n = 3 tra bảng ta được:
a1 = 0,774 W1 ≡ H1 = 0,555
a2 = -0,774 W2 ≡ H2 = + 0,555
a3 = 0,000 W3 ≡ H3 = 0,888
1
I= f ( )d
1
=H1f(a1) + H2f(a2) + H3f(a3)
I=0,555 3 0,774 2(0,774)2 +0,555 3 0,774 2(0,774)2 +0,888 3 0,000 2(0,000)2 =1,113
88
Ví dụ 2. Dùng chương trình matlab
1
Tính tích phân: e x sin xdx
0
J = intglegendre(f, a, b, n)
Câu hỏi:
1) Khi nào đạo hàm được tính gần đúng được chấp nhận (sai số nằm trong phạm vi
cho phép), khi nào nó không được chấp nhận. Cho vài ví dụ ?
2) Tại sao tích phân gần đúng Gauss tốt hơn tích phân gần đúng Simpson và Tp gần
đúng Simpson tốt hơn Tp gần đúng hình thang ?
3) Tại sao tích phân số (gần đúng) của Gauss càng chính xác khi điểm tích phân càng
nhiều ?
Bài tập:
1) Tính gần đúng y’(55), y’(60) của hàm y = lgx dựa vào bảng giá trị đ cho sau:
x 50 55 60
Simpson mở rộng. Với đoạn 0;1 chia thành 10 đoạn bằng nhau.
1
8) Tính I sinxdx bằng công thức Simpson. Với đoạn 0;1 chia thành 10 đoạn
0
bằng nhau.
1
9) Tính gần đúng tích phân I= 1 x 2 dx bằng công thức Simpson tổng quát sao
0
(x 2 y )dxdy
2
I=
1 1
90
Đáp số:
1) y’(55) 0,00792; y’(60) 0,0072
Giá trị đúng y’(55) = 0,0079862; y’(60) = 0,0072382
2) y’(1) -0,4400275.
3) D(3, 3) = 4,2
4) I I * =1,218; I I * 0,02 .
5) I = 1,6405
6) Công thức hình thang: I I * =1,4672; I I * 0,0136 .
91
Chương 4 GIẢI GẦN ĐÚNG PHƯƠNG TRÌNH
VÀ HỆ PHƯƠNG TRÌNH PHI TUYẾN
ROOTS OF NONLINEAR EQUATIONS
92
xn = g(xn-1) (4.3)
Với n = 1, 2, 3,....
Hàm g(x) được gọi là hàm lặp. Nếu dãy xn khi n thì ta nói phép lặp
(4.3) hội tụ.
y y
x1 xo x xo x1 x
y
Hình 4.1: Minh họa phép lặp theo phương pháp lặp đơn
Ta có định lí: Xét phương pháp lặp (4.3), giả sử:
- [a, b] là khoảng phân li nghiệm của phương trình (4.1) tức là của (4.2);
- Mọi xn tính theo (4.3) đều thuộc [a, b].
- g(x) có đạo hàm thoả mãn:
g ( x) q 1 ,a x b (4.4)
Trong đó q là một hằng số thì phương pháp lặp (4.3) hội tụ.
Ta có thể minh hoạ phép lặp bằng hình vẽ 4.1.
Cách đưa phương trình f(x) = 0 về dạng x = g(x) được thực hiện như sau:
ta thấy f(x) = 0 có thể biến đổi thành x = x + f(x) với 0. Sau đó đặt x + f(x) =
g(x) sao cho điều kiện (4.4) được thoả mãn.
Ví dụ. Xét phương trình
x3 + x - 1000 = 0
Sau bước giải sơ bộ ta có nghiệm x1 (9, 10)
Nếu đưa phương trình về dạng:
x = 1000 - x3 = g(x)
Dễ dàng thấy |g'(x)| >1 trong khoảng (9,10), nên không thoả mãn điều kiện (4.4)
Chúng ta đưa phương trình về dạng:
x 3 1000 x
Thì ta thấy điều kiện (4.4) được thoả mãn. Xây dựng dãy xấp xỉ:
93
x n 1 3 1000 x n
và chương trình giải bài toán bằng phương pháp lặp với sai số cho trước
94
Chương trình 4-2
//lap don
#include <conio.h>
#include <stdio.h>
#include <math.h>
void main()
{
int i;
float epsi,x,x0,y;
float f(float);
clrscr();
printf("Cho sai so epsilon = ");
scanf("%f",&epsi);
printf("Cho gia tri ban dau cua nghiem x0 = ");
scanf("%f",&x0);
x=x0;
y=f(x);
if (abs(y-x)>epsi)
{
x=y;
y=f(x);
}
printf("Nghiem cua phuong trinh la %.6f",y);
getch();
}
float f(float x)
{
float a=exp((1./3.)*log(1000-x));
return(a);
}
95
Cho giá trị đầu xo = 1.Kết quả tính toán x = 9.966555
4.1.2. Phương pháp dây cung
Thay cung AB của y = f(x) bởi dây cung AB, lấy x1 tại giao điểm P của dây
cung với trục hoành làm giá trị gần đúng của nghiệm chính xác . Phương trình dây
cung AB:
y
Y f (a) X a
f (b) f (a) b a B
f(x1)=f(1,18254)=-0,06252
f ( x1 )( x1 1,4) (0,06252)(1,18254 1,4)
x 2 = x 1- =1,18254- 1,19709
f ( x1 ) f (1,4) 0,06252 0,872
96
#include <conio.h>
#include <stdio.h>
#include <math.h>
#define epsi 0.00001
void main()
{
float a,b,fa,fb,dx,x;
float f(float);
clrscr();
printf("Tim nghiem cua phuong trinh phi tuyen\n");
printf("bang phuong phap day cung\n");
printf("Cho cac gia tri a,b\n");
printf("Cho gia tri cua a = ");
scanf("%f",&a);
printf("Cho gia tri cua b = ");
scanf("%f",&b);
fa=f(a);
fb=f(b);
dx=fa*(b-a)/(fa-fb);
while (fabs(dx)>epsi)
{
x=a+dx;
fa=f(x);
if((fa*fb)<=0)
a=x;
else
b=x;
fa=f(a);
fb=f(b);
dx=fa*(b-a)/(fa-fb);
97
}
printf("Nghiem x = %.3f",x);
getch();
}
float f(float x)
{
float e=x*x*x*x+2*x*x*x-x-1;
return(e);
}
Áp dụng. Để tìm nghiệm của hàm f(x) = tg( -x) - x ta dùng chương trình :
clear all, clc
f = inline('tan(pi - x) - x');
[x, ss, xx] = falsp(f, 1.7, 3, 1e-4, 50)
Kết quả: x0 = 2.0289
99
f (x 0 )
Gọi x1 là nghiệm của (4.5), ta có: x1 = x0 -
f ' (x 0 )
f (x1 ) f (x n )
Tương tự: x2 = x1 - ,…, xn + 1 = xn - , với x0 [a, b]
f ' ( x1 ) f ' (x n )
Vì (4.5) dùng thay cho phương trình f(x) = 0, nó tuyến tính đối với x nên
phương pháp Newton cũng gọi là phương pháp tuyến tính hóa, f’(x0) chính là hệ số
góc của y = f(x) tại x0 .
Tại B(x0, f(x0)).
Y - f(x0) = f’(x0).(X - x0) ,
Tại P: x = x1, Y = 0 đó chính là phương trình (4.5)
Hội tụ và sai số y
Người ta sẽ áp dụng phương B
pháp lặp Newton nếu nghiệm y
xn khi n của phương trình:
f(x) = 0, f có đạo hàm f, f” với f’ liên tục
trên [a,b], f’ và f” không đổi dấu trên (a, b).
a M
Xấp xỉ đầu x0 chọn là a hay b sao cho
f(x0) cùng dấu với f”. Khi đó O p b x
α
xn khi n . Cụ thể hơn xn A
đơn điệu tăng tới nếu f’.f” < 0, và xn đơn điệu giảm tới nếu f’.f” > 0 .
f (x n )
Sai số: xn <
,
, với: 0 < m < f ( xn ) và x b
m
Trường Hợp Lặp Newton - Raphson Không Có Hiệu Quả (hàm 1 biến)
f(x) f(x)
xo
x2 x1 x x1
x0 x
O x2
O
100
f(x) f(x)
O x0 x4 x2 x3 x1 x O
X0 X1 X
-X e x x i
i
Giải: Ta có f’(x) = - e - 1, xi + 1 = xi -
ex 1
i
void main()
{
101
float t,x0;
float x[n];
int i;
float f(float);
float daoham(float);
clrscr();
printf("Tim nghiem cua phuong trinh phi tuyen\n");
printf("bang phuong phap lap Newton\n");
printf("Cho gia tri cua x0 = ");
scanf("%f",&x0);
i=1;
x[i]=x0;
do
{
x[i+1] = x[i]-f(x[i])/daoham(x[i]);
t = fabs(x[i+1]-x[i]);
x[i]=x[i+1];
i=i+1;
if (i>100)
{
printf("Bai toan khong hoi tu\n");
getch();
exit(1);
}
else
;
}
while (t>=epsi);
printf("Nghiem x = %.5f",x[i]);
getch();
}
102
float f(float x)
{
float a=x*x-x-2;
return(a);
}
float daoham(float x)
{
float d=2*x-1;
return(d);
}
103
end
xx(1) = x0;
fx = feval(f,x0);
for k = 1: maxiter
if ~isnumeric(df)
dfdx = feval(df, xx(k)); %dao ham cua ham
else
dfdx = (feval(f, xx(k) + h)-feval(f, xx(k) - h))/h2; %dao ham so
end
dx = -fx/dfdx;
xx(k+1) = xx(k) + dx; %pt.(3)
fx = feval(f, xx(k + 1));
if abs(fx)<tolf | abs(dx) < tolx,
break;
end
end
x = xx(k + 1);
if k == maxiter
fprintf('Khong hoi tu sau %d lan lap\n', maxiter)
else
fprintf('Hoi tu sau %d lan lap\n', k)
end
104
trong đoạn [a, b] bằng một đường cong bậc 2 mà ta hoàn toàn có thể tìm nghiêm chính
xác của nó. Gọi các điểm đó có hoành độ lần lượt là a = x2, b = x1 và ta chọn thêm một
điểm x0 nằm trong đoạn [x2, x1]. Gọi
h1 = x1 - x0
h2 = x0 - x2
v = x - x0
f(x0) = f0
f(x1) = f1
f(x2) = f2
h2
h1
Qua 3 điểm này ta có một đường parabol:
y = av2 + bv + c
Ta tìm các hệ số a,b,c từ các giá trị đã biết v:
v 0( x x0 ) a(0) 2 b(0) c f 0
v h1 ( x x1 ) ah12 bh1 c f1
v h2 ( x x2 ) ah22 bh2 c f 2
Từ đó ta có:
f1 f 0 (1 ) f 2
a
h12 (1 )
f1 f 0 ah12
b
h1
c f0
void main()
{
106
float x0,x1,x2,h1,h2,eps;
float a,b,c,gamma,n1,n2,xr;
int dem;
float f(float);
clrscr();
printf("PHUONG PHAP MULLER\n");
printf("\n");
printf("Cho khoang can tim nghiem [a,b]\n");
printf("Cho gia tri duoi a = ");
scanf("%f",&x2);
printf("Cho gia tri tren b = ");
scanf("%f",&x1);
if (f(x1)*f(x2)>0)
{
printf("\n");
printf("Nghiem khong nam trong doan nay\n");
getch();
exit(1);
}
eps=1e-5;
x0=(x1+x2)/2;
dem=0;
do
{
dem=dem+1;
h1=x1-x0;
h2=x0-x2;
gamma=h2/h1;
a=(gamma*f(x1)-
f(x0)*(1+gamma)+f(x2))/(gamma*(h1*h1)*(1+gamma));
b=(f(x1)-f(x0)-a*(h1*h1))/h1;
107
c=f(x0);
if ((a==0)&&(b!=0))
{
n1=-c/b;
n2=n1;
}
if ((a!=0)&&(b==0))
{
n1=(-sqrt(-c/a));
n2=(sqrt(-c/a));
}
if ((a!=0)&&(b!=0))
{
n1=x0-2*c/(b+(sqrt(b*b-4*a*c)));
n2=x0-2*c/(b-(sqrt(b*b-4*a*c)));
}
if (fabs(n1-x0)>fabs(n2-x0))
xr=n2;
else
xr=n1;
if (xr>x0)
{
x2=x0;
x0=xr;
}
else
{
x1=x0;
x0=xr;
}
}
while (fabs(f(xr))>=eps);
108
printf("\n");
printf("Phuong trinh co nghiem x = %.5f sau %d lan lap",xr,dem);
getch();
}
float f(float x)
{
float a=sin(x)-x/2;
return(a);
}
4.1.5. Phương pháp lặp Bernoulli
Có nhiều phương pháp để tìm nghiệm của một đa thức. Ta xét phương trình:
aoxn + a1xn-1 + + an = 0
Nghiệm của phương trình trên thoả mãn định lí: Nếu max{|a1|, |a2|,...,|an|} = A
thì các nghiệm của phương trình thoả mãn điều kiện |x| < 1 + A/ |a0|.
Phương pháp Bernoulli cho phép tính toán nghiệm lớn nhất của một đa thức
Pn(x) có n nghiệm thực phân biệt. Sau khi tìm được nghiệm lớn nhất ta chia đa thức
Pn(x) cho (x - ) và nhận được đa thức mới Qn-1(x). Tiếp tục dùng phương pháp
Bernoulli để tìm nghiệm lớn nhất của Qn-1(x).
Sau đó lại tiếp tục các bước trên cho đến khi tìm hết các nghiệm của Pn(x).
Chúng ta khảo sát phương trình sai phân có dạng như sau:
= aoyk+n + a1yk+n-1 +.....+ anyk = 0 (4.6)
Đây là một phương trình sai phân tuyến tính hệ số hằng. Khi cho trước các giá
trị đầu yo, y1,..yn-1 ta tìm được các giá trị yn, yn+1,.. Chúng được gọi là nghiệm của
phương trình sai phân tuyến tính (4.6).
Đa thức: Pn(x) = a0xn + a1xn-1 +..+an-1x + an (4.7)
Với cùng một hệ số ai như (4.6) được gọi là đa thức đặc tính của phương trình
sai phân tuyến tính (4.6). Nếu (4.7) có n nghiệm phân biệt x1, x2,.., xn thì (4.6) có các
nghiệm riêng là:
yi xik
Nếu yi là các nghiệm của phương trình sai phân là tuyến tính (4.6),thì
109
yk c1 x1k c2 x2k cn xnk (4.8)
Với các hệ số ci bất kì cũng là nghiệm của phương trình sai phân tuyến tính có
hệ số là hằng số (4.6).
Nếu các nghiệm cần sao cho:
|x1| |x | ...|xn|
c x k
Vậy yk c x 1 1 2
k
1 1
c2 x1
c x k 1
Và yk 1 c x k 1
1 1 1 1 2
c2 x1
c x k 1
1 1 2
c2 x1
x1
yk 1
Do đó
yk c x k
1 1 2
c2 x1
Do x1 > x2 >...> xn
k k 1
x2 x
Nên , 2 0 khi k
x1 x1
y k 1
Vậy 0 khi k
yk
yk 1
Nghĩa là lim x1
k yk
Nếu phương trình vi phân gồm n + 1 hệ số, một nghiệm riêng yk có thể được
xác định từ n giá trị yk-1, yk-2,...,yn-1. Điều cho phép tính toán bằng cách truy hồi các
nghiệm riêng của phương trình vi phân.
Để tính nghiệm lớn nhất của đa thức, ta xuất phát từ các nghiệm riêng y1 = 0,
y2 = 0,.., yn =1 để tính yn+1. Cách tính này được tiếp tục để tính yn+2 xuất phát từ
y1 = 0, y2 = 0,.., yn+1 và tiếp tục cho đến khi yk+1 / yk không biến đổi nữa. Trị số của
yk+n được tính theo công thức truy hồi:
yk n
1
a1 yk n1 an yk (4.9)
a0
Ví dụ. Tính nghiệm của đa thức Pn(x) = P3(x) = x3 - 10x2 + 31x - 30.
Như vậy ao = 1, a1 = -10, a2 = 31 và a3 = -30.
110
Phương trình sai phân tương ứng là:
yk+3 -10yk+2 + 31yk+1 - 30yk = 0
Ta cho trước các giá trị y1 = 0; y2 = 0 và y3 = 1. Theo (4.9) ta tính được:
y4 = - (-10y3 + 31y2 - 30y1) = 10
y5 = - (-10y4 + 31y3 - 30y2) = 69
y6 = - (-10y5 + 31y5 - 30y3) = 410
y7 = - (-10y6 + 31y5 - 30y4) = 2261
y8 = - (-10y7 + 31y6 - 30y5) = 11970
y9 = - (-10y8 + 31y7 - 30y6) = 61909
y10 = - (-10y9 + 31y8 - 30y8) = 315850
y11 = - (-10y10 + 31y9 - 30y8) = 1598421
y12 = - (-10y11 + 31y10 - 30y9) = 8050130
y13 = - (-10y12 + 31y11 - 30y10) = 40425749
y14 = - (-10y13 + 31y12 - 30y11) = 202656090
y15 = - (-10y14 + 31y13 - 30y12) = 1014866581
y16 = - (-10y15 + 31y14 - 30y13) = 5079099490
y17 = - (-10y16 + 31y15 - 30y14) = 24409813589
y18 = - (-10y17 + 31y16 - 30y15) = 127092049130
y19 = - (-10y18 + 31y17 - 30y16) = 635589254740
Tỉ số các số yk+1 / yk lập thành dãy:
10 ; 6.9 ; 5.942 ; 5.5146 ; 5.2941 ; 5.172 ; 5.1018 ; 5.0607 ; 5.0363 ; 5.0218 ;
5.013 ; 5.0078 ; 5.0047 ; 5.0028 ; 5.0017 ; 5.001
Nghĩa là chúng sẽ hội tụ tới nghiệm lớn nhất là 5 của đa thức.
Chương trình 4-4
//phuong phap Bernoulli
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max 50
void main()
111
{
float a[max],y[max];
int k,j,i,n,l;
float s,e1,e2,x0,x1,x;
clrscr();
printf("Cho bac cua da thuc can tim nghiem n = ");
scanf("%d",&n);
e1=1e-5;
printf("Cho cac he so cua da thuc can tim nghiem\n");
for (i=0;i<=n;i++)
{
printf("a[%d] = ",i);
scanf("%f",&a[i]);
}
for (k=0;k<=n;k++)
a[k]=a[k]/a[0];
tt: x1=0;
for (k=2;k<=n;k++)
y[k]=0;
y[1]=1;
l=0;
do
{
l=l+1;
s=0;
for (k=1;k<=n;k++)
s=s+y[k]*a[k];
y[0]=-s;
x=y[0]/y[1];
e2=fabs(x1 - x);
x1=x;
112
for (k=n;k>=1;k--)
y[k]=y[k-1];
}
while((l<=50)||(e2>=e1));
if(e2>=e1)
{
printf("Khong hoi tu");
getch();
exit(1);
}
else
printf("Nghiem x = %.4f\n",x);
n=n-1;
if (n!=0)
{
a[1]=a[1]+x;
for (k=2;k<=n;k++)
a[k]=a[k]+x*a[k-1];
goto tt;
}
getch();
}
Kết quả nghiệm của đa thức x3 - 10x2 + 31x - 30 là: 5, 3 và 2
4.1.6. Phương pháp lặp Birge - Viette
Các nghiệm thực, đơn giản của một đa thức Pn(x) được tính toán khi sử dụng
phương pháp Newton:
Pn ( xi )
xi 1 xi (4.10)
Pn( xi )
Để bắt đầu tính toán cần chọn một giá trị ban đầu xo. Chúng ta có thể chọn một
giá trị xo nào đó, ví dụ :
an
x0
an 1
113
Và tính tiếp các giá trị sau:
Pn ( x0 )
x1 x0
Pn( x0 )
Pn ( x1 )
x2 x1
Pn( x1 )
Tiếp theo có thể đánh giá Pn(xi) theo thuật toán Horner:
P 0 = a0
P1 = P0xi + a1 (4.11)
P2 = P1xi + a2
P3 = P2xi + a3
..................
P(xi) = Pn = Pn-1xi + an
Mặt khác khi chia đa thức Pn(x) cho một nhị thức (x - xi) ta được :
Pn(x) = (x - xi)Pn-1(x) + bn (4.12)
Với bn = Pn(xi). Đa thức Pn-1(x) có dạng:
Pn-1(x) = boxn-1 + b1xn-2 + p3xn-3 +..+ bn-2x + bn-1 (4.13)
Để xác định các hệ số của đa thức (4.13) ta thay (4.13) vào (4.12) và cân bằng
các hệ số với đa thức cần tìm nghiệm Pn(x) mà các hệ số ai đã cho:
(x - xi)( boxn-1 + b1xn-2+b3xn-3 +..+ bn-2x + bn-1 ) + bn
= aoxn + a1xn-1 + a2xn-2 +...+ an-1x + a (4.14)
Từ (4.14) rút ra :
bo = ao
b1 = a1 + boxi (4.15)
b2 = a2 + b1xi
......
bk = ak + bk-1xi
.......
bn = an + bn-1xi = Pn(xi)
Đạo hàm (4.12) ta được :
Pn( x) ( x xi ) Pn1 ( x) Pn 1 ( x)
114
Như vậy với một giá trị xi nào đó theo (4.11) ta tính được Pn(xi) và kết hợp
(4.15) với (4.16) tính được Pn(xi). Thay các kết quả này vào (4.10) ta tính được giá trị
xi+1. Quá trình được tiếp tục cho đến khi | xi+1 - xi | < hay Pn(xi+1) 0 nên 1 xi+1 là
một nghiệm của đa thức.
Phép chia Pn(x) cho (x - 1) cho ta Pn-1(x) và một nghiệm mới khác được tìm
theo cách trên khi chọn một giá trị xo mới hay chọn chính xo = 1. Khi bậc của đa thức
giảm xuống còn bằng 2 ta dùng các công thức tìm nghiệm của tam thức để tìm các
nghiệm còn lại.
Ví dụ. Tìm nghiệm của đa thức P3(x) = x3 - x2 -16x + 24
ao = 1 a1 = -1 a2 = -16 a3 = 24
Chọn xo = 3.5 ta có:
Po = ao = 1
P1 = a1 + pox0 = -1 + 3.5*1 = 2.5
P2 = a2 + p1x0 = -16 + 3.5*2.5 = -7.25
P3 = a3 + p2x0 = 24 + 3.5*(-7.25) = - 1.375
b0 = a0 = 1;
b1 = a1 + box0 = -1 + 3.5*1 = 2.5
b2 = a2 + b1x0 = -16 + 3.5*2.5 = -7.25
P2(3.5) = b0x2 + b1x + b2 = 13.75
Pn ( x0 ) 1.375
x1 x0 3.5 3.6
Pn( x0 ) 13.75
115
Quá trình cứ thế tiếp tục cho đến khi sai số chấp nhận được. Chương trình dưới
đây mô tả thuật tính trên.
Chương trình 4-5
//phuong phap Birge-Viette
#include <conio.h>
#include <stdio.h>
#include <math.h>
#define max 20
void main()
{
float a[max],p[max],d[max],x[max];
int k,j,i,n;
float e1,e2,x0,x1;
clrscr();
printf("Cho bac cua da thuc n = ");
scanf("%d",&n);
e1=0.0001;
printf("Cho cac he so cua da thuc can tim nghiem\n");
for (i=0;i<=n;i++)
{
printf("a[%d] = ",i);
scanf("%f",&a[i]);
}
x0=a[0];
for (i=0;i<=n;i++)
a[i]=a[i]/x0;
printf("Nghiem cua phuong trinh : \n");
tt:x0=-a[n]/a[n-1];
j=0;
do
116
{
j=j+1;
p[1]=x0+a[1];
d[1]=1.0;
for (k=2;k<=n;k++)
{
p[k]=p[k-1]*x0+a[k];
d[k]=d[k-1]*x0+p[k-1];
}
x1=x0-p[n]/d[n];
e2=fabs(x1-x0);
if (e2>e1)
x0=x1;
}
while((j<=50)||(e2>=e1));
if (e2>=e1)
printf("Khong hoi tu");
else
printf(" x = %.4f\n",x1);
n=n-1;
if (n!=0)
{
for (k=1;k<=n;k++)
a[k]=p[k];
goto tt;
}
getch();
}
Dùng chương trình trên để tìm nghiệm của đa thức x4 + 2x3 - 13x2 - 14x + 24 ta
được các nghiệm là: -4, 3, -2 và 1.
4.1.7. Phương pháp ngoại suy Aitken
Xét phương pháp lặp:
117
x = f(x) (4.17)
Với f(x) thoả mãn điều kiện hội tụ của phép lặp, nghĩa là với mọi x [a, b] ta
có:
| f’(x) | q < 1 (4.18)
Như vậy:
xn+1 = f(xn) (4.19)
xn = f(xn-1) (4.20)
Trừ (4.19) cho (4.20) và áp dụng định lí Lagrange cho vế phải với c [a, b] ta
có:
xn+1- xn = f(xn) - f(xn-1) = (xn - xn-1)f’(c) (4.21)
Vì phép lặp (4.17) nên :
| xn+1- xn | q | xn - xn-1 | (4.22)
Do (4.22) đúng với mọi n nên cho n = 1, 2, 3 , . . . ta có:
| x2 - x1 | q | x1 - xo |
| x3 - x2 | q | x2 - x1 |
...................
| xn+1 - xn | q | xn - xn-1 |
Điều này có nghĩa là dãy xi+1 - xi, một cách gần đúng, là một cấp số nhân. Ta
cũng coi rằng dãy xn - y với y là nghiệm đúng của (4.17), gần đúng như một cấp số
nhân có công sai q . Như vậy:
x n 1 y
q 1 (4.23)
xn y
x n x n 1
2
y xn (4.27)
x n 2x n1 x n1
118
Công thức (4.27) được gọi là công thức ngoại suy Adam. Như vậy theo (4.27)
trước hết ta dùng phương pháp lặp để tính giá trị gần đúng xn+2, xn+1, xn của nghiệm và
sau đó theo (4.27) tìm được nghiệm với sai số nhỏ hơn.
Để làm ví dụ chúng ta xét phương trình:
lnx - x2 + 3 = 0
Ta đưa về dạng lặp:
x ln(x) 3
1
f(x)
2x ln x 3
Phép lặp hội tụ trong đoạn [0.3, ]. Ta cho x1 = 1 thì tính được:
x2 = 1,7320508076
x3 = 1.883960229
x4 = 1.90614167
y = 1.909934347
Để giảm sai số ta có thể lặp nhiều lần.
Chương trinh 4-6
//phuong phap Aitken
#include <conio.h>
#include <stdio.h>
#include <math.h>
#define m 5
void main()
{
float x[m];
float epsi,n,y;
int i,z;
float f(float);
clrscr();
printf("Cho tri so ban dau x[1] = ");
119
scanf("%f",&x[1]);
printf("Cho tri so sai so epsilon = ");
scanf("%f",&epsi);
printf("\n");
printf( "Ngoai suy Aitken cua ham\n");
z=0;
while (z<=20)
{
for (i=2;i<=4;i++)
x[i]=f(x[i-1]);
n=x[4]-2*x[3]+x[2];
if ((fabs(n)<1e-09)||(fabs(x[1]-x[2])<epsi*fabs(x[1])))
z=20;
else
{
y=x[2]-(x[3]-x[2])*(x[3]-x[2])/n;
if (z>20)
printf("Khong hoi tu sau hai muoi lan lap\n");
x[1]=y;
}
z=z+1;
}
printf("Nghiem cua phuong trinh y = %.6f",y);
getch();
}
float f(float x)
{
float s=sqrt(log(x)+3);
return(s);
}
120
4.1.8. Phương pháp Bairtow
Nguyên tắc của phương pháp Bairstow là trích từ đa thức Pn(x) một tam thức
Q2(x) = x2 - sx + p mà ta có thể tính nghiệm thực hay nghiệm phức của nó một cách
đơn giản bằng các phương pháp đã biết.
Việc chia đa thức Pn(x) cho tam thức Q2(x) đưa tới kết quả:
Pn(x) = Q2(x).Pn-2(x) + R1(x)
Với Pn(x) = aoxn + a1xn-1 + a2xn-2 +...+ an
Q2(x) = x2 - sx + p
Pn-2(x) = boxn-2 + b1xn-3 + b2xn-4 +...+ bn-2
R1(x) = x +
Để có được một thương đúng, cần tìm các giá trị của s và p sao cho R1(x) = 0
(nghĩa là và triệt tiêu). Với s và p đã cho, các hệ số b của đa thức Pn-2(x) và các hệ
số và được tính bằng phương pháp truy hồi. Các công thức nhận được khi khai
triển biểu thức Pn(x) = Q2(x).Pn-2(x) + R1(x) và sắp xếp lại các số hạng cùng bậc:
aoxn + a1xn-1 + a2xn-2 +...+ an = (x2 - sx + p)( boxn-2 + b1xn-3 + b2xn-4 +...+ bn-2)
Số hạng bậc Hệ số của Pn(x) Hệ số của Q2(x).Pn-2(x)
xn ao bo
xn-1 a1 b1 - sbo
xn-2 a2 b2 - sb1 + pbo
...... ...... .....
xn-k ak bk - sbk-1 + pbk-2
x an-1 - sbn-2 + pbn-3
xo an + pbn-2
Như vậy:
bo = a o
b1 = a1 + sbo
b2 = a2 + sb1 - pbo
.................. (4.28)
bk = ak + sbk-1 - pbk-2
= an-1 + sbn-2 - pbn-3
= an - pb-2
121
Chúng ta nhận thấy rằng được tính toán xuất phát từ cùng một công thức truy
hồi như các hệ số bk và tương ứng với hệ số bn-1.
bn-1 = an-1 + sbn-2 - pbn-3 =
Hệ số bn là:
bn = an + sbn-1 - pbn-2 = sbn-1 +
Và cuối cùng :
R1(x) = x + = b+-1(x - s) + bn
Ngoài ra các hệ số bi phụ thuộc vào s và p và bây giờ chúng ta cần phải tìm các
giá trị đặc biệt s* và p* để cho bn-1 và bn triệt tiêu. Khi đó r1(x) = 0 và nghiệm của tam
thức x2 - s*x + p*x sẽ là nghiệm của đa thức Pn(x). Ta biết rằng bn-1 và bn là hàm của s
và p:
bn-1 = f(s, p)
bn = g(s, p)
Việc tìm s* và p* đưa đến việc giải hệ phương trình phi tuyến:
f ( s, p)0
g ( s, p)0
Phương trình này có thể giải dễ dàng nhờ phương pháp Newton. Thật vậy với
một phương trình phi tuyến ta có công thức lặp:
xi+1 = xi - f(xi)/f'(xi)
Hay f'(xi)(xi+1 - xi) = -f(xi)
Với một hệ có hai phương trình, công thức lặp trở thành:
J(Xi)(Xi+1 - Xi) = -F(Xi)
Với Xi = {si, pi}T và Xi+1 = {si+1, pi+1}T
f ( si , pi )
F ( X i )
g ( si , pi )
f f
s p
J (Xi )
g g
s p
Quan hệ: J(Xi)X = -F(Xi) với X = {si+1 - si,pi+1 - pi}T tương ứng với một hệ
phương trình tuyến tính hai ẩn số s = si+1 - si và p = pi+1 - pi :
122
f f
s s p p f ( si , pi )
g s g p g ( s , p )
s p
i i
b1 = a1 + sbo nên:
b1 b1
b0 0
s p
bn 1cn 2 bn cn 3
s (4.30)
cn 1cn 3 cn2 2
bn 1cn 1 bn cn 2
p (4.31)
cn 1cn 3 cn2 2
Sau khi phân tích xong Pn(x) ta tiếp tục phân tích Pn-2(x) theo phương pháp
trên. Các bước tính toán gồm:
- Chọn các giá trị ban đầu bất kì s0 và p0
- Tính các giá trị bo, .., bn theo (4.28)
- Tính các giá trị co,...,cn theo (4.29)
- Tính so và po theo (4.30) và (4.31)
- Tính s1 = s0 + so và p1 = po+ po
- Lặp lại bước 1 cho đến khi pi+1 = pi = p và si+1 = si = s
- Giải phương trình x2 - sx + p để tìm 2 nghiệm của đa thức
- Bắt đầu quá trình trên cho đa thức Pn-2(x)
Ví dụ. Tìm nghiệm của đa thức P4(x) = x4 - 1.1x3 + 2.3x2 + 0.5x2 + 3.3.
Với lần lặp ban đầu ta chọn s = -1 và p =1, nghĩa là tam thức có dạng: x2+x+1
124
a0 a1 a2 a3 a4
1 -1.1 2.3 0.5 3.3
sbi -1 2.1 -3.4 0.8
-pbi-1 -1 2.1 -3.4
bi 1 -2.1 3.4 -0.8 = bn-1 0.7=bn
sbi -1.0 3.1 -5.5
0.8 3.1
0.7 5.5
s 0.11
5.5 3.1
3.2 5.5
5.5 0.8
3.2 0.7
p 0.06
5.5 3.1
3.2 5.5
s* = -1 + 0.11 = -0.89
p* = 1 + 0.06 = 1.06
Tiếp tục lặp lần 2 với s1 = s* và p1 = p* ta có:
a0 a1 a2 a3 a4
1 -1.1 2.3 0.5 3.3
sbi -0.89 1.77 -2.68 0.06
-pbi-1 -1.06 2.11 -3.17
bi 1 -1.99 3.01 -0.07 = bn-1 0.17=bn
sbi -0.89 2.56 -4.01
-pbi-1 -1.0 3.1
ci 1 -2.88 4.51 -1.03
0.07 2.88
0.7 5.5
s 0.01
4.51 2.88
1.03 4.51
125
4.51 0.07
1.03 0.17
p 0.04
4.51 2.88
1.03 4.51
void main()
{
float a[m],b[m],c[m];
int i,n,v;
float s,e1,t,p,q,r,p1,q1;
clrscr();
printf("Cho bac cua da thuc n = ");
scanf("%d",&n);
printf("Cho cac he so cua da thuc can tim nghiem\n");
for (i=n;i>=0;i--)
{
printf("a[%d] = ",n-i);
scanf("%f",&a[i]);
126
}
printf("\n");
e1=0.0001;
if (n<=2)
if (n==1)
{
printf("Nghiem cua he\n");
printf("%.8f",(a[0]/(-a[1])));
getch();
exit(1);
}
do
{
v=0;
p=1;
q=-1;
b[n]=a[n];
c[n]=a[n];
do
{
b[n-1]=b[n]*p+a[n-1];
c[n-1]=b[n-1]+b[n]*p;
for (i=n-2;i>=0;i--)
{
b[i]=b[i+2]*q+b[i+1]*p+a[i];
c[i]=c[i+2]*q+c[i+1]*p+b[i];
}
r=c[2]*c[2]-c[1]*c[3];
p1=p-(b[1]*c[2]-b[0]*c[3])/r;
q1=q-(b[0]*c[2]-b[1]*c[1])/r;
if ((fabs(b[0])<e1)&&(fabs(b[1])<e1))
goto tt;
127
v=v+1;
p=p1;
q=q1;
}
while (v<=40);
if(v>40)
{
printf("Khong hoi tu sau 40 lan lap");
getch();
exit(1);
}
tt:s=p1/2;
t=p1*p1+4*q1;
if(t<0)
{
printf("Nghiem phuc\n");
printf("%.8f+%.8fj\n",s,(sqrt(-t)/2));
printf("%.8f-%.8fj\n",s,(sqrt(-t)/2));
printf("\n");
}
else
{
printf("Nghiem thuc\n");
printf("%.8f\n",(s+sqrt(t)/2));
printf("%.8f\n",(s-sqrt(t)/2));
printf("\n");
}
for (i=2;i<=n;i++)
a[i-2]=b[i];
n=n-2;
}
while ((n>2)&(r!=0.0));
128
s=-a[1]/(2*a[2]);
t=a[1]*a[1]-4*a[2]*a[0];
if (t<0)
{
printf("Nghiem phuc\n");
printf("%.8f+%.8fj\n",s,(sqrt(-t)/(2*a[2])));
printf("%.8f-%.8fj\n",s,(sqrt(-t)/(2*a[2])));
printf("\n");
}
else
{
printf("Nghiem thuc\n");
printf("%.8f\n",(s-sqrt(t)/(2*a[2])));
printf("%.8f\n",(s-sqrt(t)/(2*a[2])));
printf("\n");
}
getch();
}
Áp dụng. Dùng chương trình trên để xác định nghiệm của đa thức:
x6 - 2x5 - 4x4 + 13x3 - 24x2 + 18x - 4 = 0
Ta nhận được các nghiệm:
x1 = 2.61903399
x2 = -2.73205081
x3 = 0.732050755
x4 = 0.381966055
x5 = 0.500011056 + i*1.3228881
x6 = 0.500011056 - i*1.3228881
4.2. Giải hệ phương trình phi tuyến
Ở đây ta đi giải hệ phương trình phi tuyến theo phương pháp lặp Newton-
Raphson
Từ khai triển Taylor cho bài toán một biến:
129
f " ()
f(xi + 1) = f(xi) + f’(xi)(xi + 1- xi) + ( x i1 x i ) 2
2!
f ( xi )
xi 1 xi vì f(xi + 1) = 0
f '( xi )
Mẫu số của (4.33) và (4.34) gọi là định thức Jacobien (detJ), của hệ thống:
ui ui
x y
detJ det
v i v i
x y
130
Ứng dụng lập trình
a. Dùng C++
//giai he pt phi tuyen
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define n 4
float a[n+1][n+2];
float x[n+1],y[n+1];
int i,j,k,l,z,r;
float e,s,t;
void main()
{
void doc();
clrscr();
printf("Cho cac gia tri nghiem ban dau\n");
for (i=1;i<=n;i++)
{
printf("x[%d] = ",i);
scanf("%f",&x[i]);
}
e=1e-6;
z=30;
for (r=1;r<=z;r++)
{
doc();
for (k=1;k<=n-1;k++)
{
s=0 ;
131
for (i=k;i<=n;i++)
{
t=fabs(a[i][k]);
if (s<=t)
{
s=t;
l=i;
}
}
for (j=k;j<=n+1;j++)
{
s=a[k][j];
a[k][j]=a[l][j];
a[l][j]=s;
}
if (a[1][1]==0)
{
printf("Cac phan tu duong cheo cua ma tran bang khong");
getch();
exit(1);
}
else
{
if (fabs(a[k][k]/a[1][1])<(1e-08))
{
printf("Ma tran suy bien");
goto mot;
}
}
for (i=k+1;i<=n;i++)
{
if (a[k][k]==0)
132
{
printf("Cac phan tu duong cheo cua ma tran bang khong\n");
goto mot;
}
s=a[i][k]/a[k][k];
a[i][k]=0;
for (j=k+1;j<=n+1;j++)
a[i][j]=a[i][j]-s*a[k][j];
}
y[n]=a[n][n+1]/a[n][n];
for (i=n-1;i>=1;i--)
{
s=a[i][n+1];
for (j=i+1;j<=n;j++)
s=s-a[i][j]*y[j];
if (a[i][i]==0)
{
printf("Cac phan tu duong cheo cua ma tran bang khong\n");
goto mot;
}
y[i]=s/a[i][i];
}
}
if (r!=1)
for (i=1;i<=n;i++)
{
if (fabs(y[i])<e*fabs(x[i]))
goto ba;
}
for (i=1;i<=n;i++)
x[i]=x[i]-y[i];
printf("\n");
133
}
printf("Khong hoi tu sau %d lan lap\n",z);
goto mot;
clrscr();
ba:printf("Vec to nghiem\n");
for (i=1;i<=n;i++)
printf("%.5f\n",(x[i]-y[i]));
printf("\n");
printf("Do chinh xac cua nghiem la %.5f: \n", e);
printf("\n");
printf("Vec to tri so du :\n");
for (i=1;i<=n;i++)
printf("%.5f\n",(a[i][n+1]));
mot:printf("\n");
getch();
}
void doc()
{
a[1][1]=3*x[1]*x[1]-3*x[2]*x[4];
a[1][2]=-3*x[2]*x[2]-3*x[1]*x[4];
a[1][3]=0;
a[1][4]=-3*x[1]*x[2];
a[1][5]=x[1]*x[1]*x[1]-x[2]*x[2]*x[2]-3*x[1]*x[2]*x[4]-8;
a[2][1]=1;
a[2][2]=1;
a[2][3]=1;
a[2][4]=1;
a[2][5]=x[1]+x[2]+x[3]+x[4]-5;
a[3][1]=-x[1]/sqrt(25-x[1]*x[1]);
134
a[3][2]=0;
a[3][3]=8;
a[3][4]=0;
a[3][5]=sqrt(25-x[1]*x[1])+8*x[3]+4;
a[4][1]=2*x[2]*x[3];
a[4][2]=2*x[1]*x[3];
a[4][3]=2*x[1]*x[2];
a[4][4]=-1;
a[4][5]=2*x[1]*x[2]*x[3]-x[4]+8;
b. Dùng Matlab
Xây dựng hàm :
function [P, iter, err] = new4sys(f, jf, P, max1)
%vao -F la he pt luu trong M-file f.m
% -JF la ma tran jacobi luu trong M-file jf.m
% -P vec to nghiem ban dau
% -max1 so lan lap cuc dai
%ra -P la ve to nghiem
% -iter so lan lap thuc te
% -err sai so
Y = f(P);
for k = 1:max1
J = jf(P);
Q = P - (J\Y')';
Z = f(Q);
err = norm(Q - P);
relerr = err/(norm(Q) + eps);
P = Q;
Y = Z;
135
iter = k;
if (err<eps)|(relerr<eps)|(abs(Y)<eps)
break
end
end
2 x x x x 8 0
1 2 3 4
Ma trận này được chương trình đọc vào nhờ thủ tục doc.Trong thủ tục này,các
hệ số a[i, 5] là các hàm fi(x). Vectơ nghiệm ban đầu được chọn là {0,-1,-1,1}T. Kết
quả tính cho ta: x = {0.01328676, -1.94647929, -1.12499779, 8.05819031}T với độ
chính xác 0.000001. Vectơ số dư r = {0.00000536, -0.00000011, -0.00000001, -
0.00000006}T.
Ví dụ 2. Hãy tính lặp theo phương pháp Newton- Raphson hệ phương trình:
u ( x, y) x xy 10 0
2
Tiếp tục các phần xấp xỉ bị dư, lời giải sẽ tiến dần đến nghiệm chính xác:
(x = 2 , y = 3)
Câu hỏi:
1) Phương trình (hoặc hệ phương trình) phi tuyến thông thường có nhiều nghiệm;
để giải nó (hoặc chúng nó), bước đầu tiên ta phải làm gì?
2) Trình bày cách giải hệ phương trình phi tuyến theo công thức lặp Newton-
Raphson?
3) Tại sao phương pháp lặp Newton – Raphson còn được gọi là phương pháp tiếp
tuyến?
4) Ưu nhược điểm của các phương pháp lặp để giải phương trình phi tuyến ?
Bài tập:
1) Dùng phương pháp dây cung, tìm nghiệm gần đúng với độ chính xác 10-2 của:
a) x3 + 3x + 5=0
b) x 4 -3x +1=0
2) p dụng hai lần phương pháp đây cung, tìm nghiệm thực gần đúng của phương
trình x3-10x+5 trong khoảng phân ly(0, 0.6). Đánh giá sai số của nghệm gần
đúng x2.
3) Cho phương trình x = sin3x, có khoảng phân ly nghiệm là( , ). Tìm nghiệm
6 3
gần đúng trong khoảng đã cho bằng phương pháp dây cung, tính đến phép lặp
thứ 3 là x3.
4) Tìm nghiệm gần đúng của hệ:
x 2 xy y 0
3 2
2
x 2x y 2 0
Bằng phương pháp Newton, cho x0=0.7, y0=1.0.
137
5) Tìm nghiệm dương nhỏ nhất của phương trình f(x) = 2x - 4x. Bằng phương
pháp Newton – Raphson với 3 lần lặp (cho x0 = 0.3)
6) Tìm nghiệm dương nhỏ nhất của phương trình x3 - 10x2 + 5 = 0. Bằng phương
pháp Newton – Raphson với 2 lần lặp (cho x0 = 0.7)
7) Tìm nghiệm gần đúng của hệ bằng phương pháp lặp Newton.
Sinx y 1,32
x cos y 0.85
Với xấp xỉ đầu(x0, y0)=(1.80, -0.33).
8) Tìm nghiệm gần đúng của hệ bằng phương pháp lặp Newton.
2 x 2 y 4 x 1 0
2 3
4
x 4 y 4 y 4 0
4
Đáp số:
2) 0.51
3) x3 0.75649
4) , (0.704402,1.087387)
5) x3 0.3099
6) x2 0.73460
7) , (1.79,0.34)
138
Chương 5 CÁC PHƯƠNG PHÁP SỐ
CỦA ĐẠI SỐ TUYẾN TÍNH
NUMERICAL METHODS FOR LINEAR ALGEBRA
Các phương pháp số gắn liền với việc ứng dụng trên máy tính số. Ma trận được
ứng dụng rất thích hợp ở đây, như giải hệ phương trình vi phân, biểu diễn các vectơ ở
dạng ma trận.
Khi giải hệ đại tuyến A.X = B, ma trận A có thể là ma trận đầy hoặc thưa hoặc
có dạng 3, 5 đường chéo hoặc nhiều đường chéo (dạng BAND). Khi A là ma trận
thưa, đã có thuật toán để lưu trữ, tiết kiệm bộ nhớ và thời gian tính như lưu trữ dạng
BAND bình thường hoặc dạng BAND ép lại, hay kỹ thuật lưu trử Skyline (frontal
method), với nhiều thuật giải trực tiếp hay lặp rất hiệu quả; đặc biệt khi ma trận có
dạng 3, 5 đường chéo có những thuật toán giải riêng để tiết kiệm bộ nhớ và thời gian
tính.
5.1. Ma trận
5.1.1. Các định nghĩa
Ma trận là tập hợp gồm m n phần tử, chia thành m hàng và n cột.
a11 a12 ......a1n
a a ....a
Kí hiệu: A m,n = ai , j m,n 21 22 2n
...............
am1 am 2 ....amn
Có thể coi ma trận hàng (cột) là biểu diễn đại số của một vectơ (hình học).
Vết (trace) của ma trận A được tính: Tr(A) = a11 + a22 +.....+ ann
5.1.2. Định thức của ma trận
Mỗi một ma trận vuông A đều được gắn với một số, kí hiệu det(A) hoặc A ,
được gọi là định thức. Ma trận A được gọi là suy biến nếu det(A) = 0 và ngược lại là
không suy biến.
Để tìm định thức của ma trận vuông nxn, trước hết chúng ta nhắc lại một số tính
chất quan trọng của định thức:
- Nếu nhân tất cả các phần tử của một hàng (hay cột) với k thì định thức được
nhân với k.
139
- Định thức không đổi nếu ta cộng thêm vào một hàng tổ hợp tuyến tính của các
hàng còn lại.
Ta sẽ áp dụng các tính chất này để tính định thức của một ma trận cấp 4 như sau
(phương pháp này có thể mở rộng cho một ma trận cấp n) bằng phương pháp trụ:
a11 a12 a13 a14
a a22 a23 a24
A 21
a a32 a33 a34
31
a a44
41 a42 a43
Lấy giá trị trụ là p1 = a11.Ta chia các phần tử của hàng thứ nhất cho p1 = a11 thì
định thức sẽ là D/p1 (theo tính chất 1) và ma trận còn lại là:
1 a12
a13
a14
a21 a22 a23 a24
a a32 a33 a34
31
a a44
41 a42 a43
Lấy hàng 2 trừ đi hàng 1 đã nhân với a21, lấy hàng 3 trừ đi hàng 1 đã nhân với
a31 và lấy hàng 4 trừ đi hàng 1 đã nhân với a41 (thay hàng bằng tổ hợp tuyến tính của
các hàng còn lại) thì định thức vẫn là D/p1 và ma trận là:
1
a12
a13
a14
0
a22
a23
a24
0
a32
a33
a34
0
a42 a43 a44
. Ta chia các phần tử của hàng thứ hai cho p2 thì định
Lấy giá trị trụ là p2 a22
thức sẽ là D/(p1p2) và ma trận còn lại là:
1 a12
a13
a14
0 1
a23
a24
0 a
a33
a34
32
0 a
42 a43 a44
trận là:
1 0
a13
a14
0 1
a23
a24
0 0
a33
a34
0
0 a43 a44
140
Tiếp tục lấy hàng 3 rồi hàng 4 làm trụ thì ma trận sẽ là:
1 0 0 0
0 1 0 0
0 0 1 0
0 1
0 0
a33
Định thức của ma trận này là D/(p1p2p3p4) = D/( a11a22 a44
) = 1 nên định thức
void main()
{
int i,j,k,n,ok1,ok2,t;
float d,c,e,f,g,h;
float a[50][50];
char tl;
clrscr();
printf("** TINH DINH THUC CAP n **");
printf("\n");
printf("\n");
printf("Cho cap cua dinh thuc n = ");
scanf("%d",&n);
printf("Nhap ma tran a\n");
for (i=1;i<=n;i++)
{
printf("Dong %d:\n",i);
for (j=1;j<=n;j++)
141
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
}
printf("\n");
printf("Ma tran a ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%.5f\t",a[i][j]);
printf("\n");
}
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i,j]);
}
if (toupper(tl)=='K')
142
t=0;
}
printf("Ma tran a ban dau\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%.5f\t",a[i][j]);
printf("\n");
}
printf("\n");
d=1;
i=1;
ok2=1;
while ((ok2)&&(i<=n))
{
if (a[i][i]==0)
{
ok1=1;
k=k+1;
while ((ok1)&&(k<=n))
if (a[k,i]!=0)
{
for (j=i;j<=n;j++)
{
c=a[i][j];
a[i][j]=a[k][j];
a[k][j]=c;
}
d=-d;
ok1=0;
}
143
else
k=k+1;
if (k>n)
{
printf("\n");
printf("** MA TRAN SUY BIEN **");
ok2=0;
d=0;
}
}
if (a[i][i]!=0)
{
c=a[i][i];
for (j=i+1;j<=n;j++)
a[i][j]=a[i][j]/c;
for (k=i+1;k<=n;k++)
{
c=a[k][i];
for (j=i+1;j<=n;j++)
a[k][j]=a[k][j]-a[i][j]*c;
}
}
i=i+1;
}
if (ok2)
{
for (i=1;i<=n;i++)
d=d*a[i][i];
printf("\n");
printf("** GIA TRI DINH THUC D **");
printf("\n");
printf("%.3f",d);
144
}
getch();
}
5.1.3. Nghịch đảo ma trận
Gọi A-1 là ma trận nghịch đảo của một ma trận A bậc n ta có AA-1 = E; trong
biểu thức này E là ma trận đơn vị (ma trận vuông có các phần tử trên đường chéo
chính bằng 1). Dạng của ma trận E, ví dụ cấp 4 là:
1 0 0 0
0 1 0 0
E
0 0 1 0
0 1
0 0
Phương pháp khử để nhận được ma trận nghịch đảo A-1 được thực hiện qua
nhiều giai đoạn (n), mỗi một giai đoạn gồm hai bước. Đối với giai đoạn thứ k:
- Chuẩn hoá phần tử akk bằng cách nhân hàng với nghịch đảo của nó.
- Làm cho bằng không các phần tử phía trên và phía dưới đường chéo cho đến
cột thứ k. Khi k = n thì A(k) sẽ trở thành ma trận đơn vị và E trở thành A-.1
Qua thuật toán tính ma trận nghịch đảo ở trên, ta thấy rằng nếu ma trận không
có tính chất trội thì khi nghịch đảo có khả năng gây sai số lớn, do đó trong cách giải hệ
đại tuyến, các phương pháp giải thông dụng đều tránh sử dụng nghịch đảo ma trận.
Ví dụ. Tính ma trận nghịch đảo của ma trận.
2 1 1
A 1 2 1
1 1 2
Ta viết lại ma trận A và ma trận đơn vị tương ứng với nó:
2 1 1 1 0 0
A 1 2 1 E 0 1 0
1 1 2 0 0 1
Giai đoạn 1:
Bước a: Nhân hàng 1 với 1/a11, nghĩa là a,1j = a1j/a11 đối với dòng thứ nhất,
a,ij = aij đối với các dòng khác.
1 1 2 1 2 1 2 0 0
A 1 2 1 E 0 1 0
1 1 2 0 0 1
145
Bước b: Trừ hàng 3 và hàng 2 cho hàng 1, nghĩa là a(1)1j = aij - ai1aij đối với i 1
1 1 2 1 2 1 2 0 0
A 0 3 2 1 2 E 1 2 1 0
0 1 2 3 2 1 2 0 1
Giai đoạn 2:
Bước a: Lấy hàng 2 làm chuẩn, nhân hàng 2 với 2/3, để nguyên các hàng khác.
1 1 2 1 2 12 0 0
A 0 1 1 3 E 1 3 2 3 0
0 1 2 3 2 1 2 0 1
Bước b: Lấy hàng 1 trừ đi hàng 2 nhân 1/2 và lấy hàng 3 trừ đi hàng 2 nhân 1/2
1 0 1 3 2 3 1 3 0
A 0 1 1 3 E 1 3 2 3 0
0 0 4 3 1 3 1 3 1
Giai đoạn 3:
Bước a: Lấy hàng 3 làm chuẩn, nhân hàng 3 với 3/4, để nguyên các hàng khác.
1 0 1 3 2 3 1 3 0
A 0 1 1 3 E 1 3 2 3 0
0 0 1 1 4 1 4 3 4
Bước b: Lấy hàng 1 trừ đi hàng 3 nhân 1/3 và lấy hàng 2 trừ đi hàng 3 nhân 1/3
1 0 0 3 4 1 4 1 4
A 0 1 0 E 1 4 3 4 1 4
0 0 1 1 4 1 4 3 4
Như vậy A-1 là:
3 / 4 1/ 4 1/ 4
A1 1 / 4 3 / 4 1 / 4
1/ 4 1/ 4 3 / 4
Áp dụng phương pháp này chúng ta có chương trình sau:
Chương trình 5-2
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
146
void main()
{
int i,j,k,n,t,t1;
float c,a[50][50],b[50][50];
char tl;
clrscr();
printf(" **MA TRAN NGHICH DAO** \n");
printf("Cho bac cua ma tran n = ");
scanf("%d",&n);
printf("Vao ma tran ban dau a\n");
for (i=1;i<=n;i++)
{
printf("Vao hang thu %d :\n",i);
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
}
printf("\n");
printf("Ma tran ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%.5f\t",a[i][j]);
printf("\n");
}
t=1;
147
flushall();
while (t)
{
printf("\nCo sua ma tran khong(c/k)?");
scanf("%c",&tl);
if(toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("\nMa tran ban dau\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%.5f\t",a[i][j]);
printf("\n");
}
printf("\n");
for (i=1;i<=n;i++)
for (j=n+1;j<=2*n;j++)
{
if (j==i+n)
a[i][j]=1;
else
148
a[i][j]=0;
}
i=1;
t1=1;
while (t1&&(i<=n))
{
if (a[i][i]==0)
{
t=1;
k=i+1;
while (t&&(k<=n))
if (a[k][i]!=0)
{
for (j=1;j<=2*n;j++)
{
c=a[i][j];
a[i][j]=a[k][j];
a[k][j]=c;
}
t=0;
}
else
k=k+1;
if (k==n+1)
{
if (a[i][k-1]==0)
{
printf("MA TRAN SUY BIEN\n ");
t1=0;
}
}
}
149
if (a[i][i]!=0)
{
c=a[i][i];
for (j=i;j<=2*n;j++)
a[i][j]=a[i][j]/c;
}
for (k=1;k<=n;k++)
{
if (k!=i)
{
c=a[k][i];
for (j=i;j<=2*n;j++)
a[k][j]=a[k][j]-a[i][j]*c;
}
}
i=i+1;
}
if (t1)
{
printf("\n");
printf("\nMA TRAN KET QUA\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=n+1;j<=2*n;j++)
printf("%.4f\t\t",a[i][j]);
printf("\n");
}
printf("\n");
}
getch();
}
150
Dùng chương trình tính nghịch đảo của ma trận:
9 9 8 1 2 1
9 8 7 cho ta kết quả 2 10 9
8 6 1 9 9
7
5.1.4. Tích hai ma trận
Giả sử ta có ma trận Amn và ma trận Bnp. Tích của Amn và Bnp là ma trận Cmp
n
trong đó mỗi phần tử của Cmp là: c ij a ik b kj
k 1
Chương trình dưới đây thực hiện nhân hai ma trận với nhau.
Chương trình 5-3
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#define max 50
void main()
{
int n,l,m,i,j,k,t;
float a[max][max],b[max][max],c[max][max];
char tl;
clrscr();
printf("Cho so hang cua ma tran a : ");
scanf("%d",&n);
printf("Cho so cot cua ma tran a : ");
scanf("%d",&l);
printf("Cho so cot cua ma tran b : ");
scanf("%d",&m);
151
printf("\nNHAP MA TRAN A\n");
for (i=1;i<=n;i++)
for (j=1;j<=l;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran a ma ban da nhap\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=l;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
flushall();
t=1;
while (t)
{
printf("Co sua ma tran khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
152
}
printf("Ma tran a ban dau");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=l;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
printf("\n");
153
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("b[%d][%d] = ",i,j);
scanf("%f",&b[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran b ban dau");
printf("\n");
for (i=1;i<=l;i++)
{
for (j=1;j<=m;j++)
printf("%10.5f",b[i][j]);
printf("\n");
}
printf("\n");
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{
c[i][j]=0;
for (k=1;k<=l;k++)
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}
printf("Ma tran tich c :\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
154
printf("%10.5f",c[i][j]);
printf("\n");
}
getch();
}
Ví dụ. Dùng chương trình tính tính hai ma trận ở trên ta nhận được kết quả:
2 1 5 0 1
1 3 1 2 2 8 14 11
1 0 3 4 3 1 2 2
5 3 14 2 1
5.1.5. Phép biến đổi tuyến tính trong không gian n chiều
Giữa ma trận và các phép biến đổi tuyến tính trong không gian (đại số) có một
mối liên hệ mật thiết. Một phần tử của không gian n chiều có thể được mô tả bằng một
vectơ, hay viết dưới dạng ma trận cột.
155
e1 1,0,0,.........0T
e2 0,1,0,.........0
T
............................
e 0,0,0,.........1T
1
T
X = x .x
d = x y ( x y) T .(x y)
xT.y = x . y . cos
Hai vectơ x, y được gọi là trực giao với nhau nếu: xT.y = 0
Một tập hợp các vectơ trực giao với nhau từng đôi một được gọi là một hệ trực
giao. Một ma trận trực giao sẽ có các hàng và các cột là các vectơ trực giao.
Định lý: Các vectơ của một hệ trực giao là độc lập tuyến tính.
Chuẩn của vectơ, ký hiệu là X , được định nghĩa là một số không âm, thỏa
Có 3 chuẩn sau đây hay sử dụng trong các bài toán ứng dụng:
n
- X 2 = x 21 x 2 2 ... x 2 n = x
i 1
2
i gọi là chuẩn Euclide
156
- X = maxi x i gọi là chuẩn cực đại
Mở rộng khái niệm cho chuẩn các ma trận. Chuẩn của các ma trận A và B ký
hiệu là A và B , được định nghĩa là các số không âm thõa mãn các điều kiện sau:
- AB A + B
- A B A B
- A 2 = a
i, j
2
ij gọi là chuẩn Euclide.
Chuẩn của ma trận là khái niệm hết sức quan trọng đối với các phương pháp số.
Chúng hay sử dụng khi xét tính hội tụ của các phương pháp lặp hoặc khi xét sự ổn
định của các hệ phương trình vi phân.
Liên hệ chuẩn của ma trận và vectơ:
Trong không gian n chiều Vn chuẩn của ma trận tương ứng với chuẩn của vectơ
nếu:
A.X A . X với mọi A và X thuộc Vn.
157
Chú ý một số tính chất: A.B B.A
(AT)T = A , (k.A)T = k.AT
(A+B)T = AT+BT , (A.B)T = BT.AT
(A-1)-1 = A , (A.B)-1 = B-1.A-1
(AT)-1 = (A-1)T , det(A.B) = det(A).det(B)
det(A) = det(AT)
1
a11 0 0 1 / a 11 0 0
0 a 0
22 0 = 0 1 / a 22
0 0 a33 0 0 1 / a 33
Ma trận A là suy biến, det (A) = 0 thì các hàng hoặc các cột của nó là các
vectơ phụ thuộc tuyến tính.
Hạng của ma trận vuông A là số lớn nhất các hàng (hoặc các cột) độc lập
tuyến tính với nhau.
Ma trận B có được từ ma trận A bằng cách đổi chỗ hai hàng cho nhau
thì:
det(B) = - det(A).
Nếu A, B là các ma trận vuông trực giao thì AT, A-1, A.B cũng là các ma
trận trực giao.
Nếu A, B là các ma trận vuông đối xứng thì A, A + B cũng là những
ma trận vuông đối xứng. Nếu A không suy biến thì A-1 cũng đối xứng.
Cần chú ý rằng: Tích của hai ma trận đối xứng nói chung không phải là ma
trận đối xứng.
n
Nếu A = [aij] là ma trận vuông cấp n thoả a kk a ks , với s k, k = 1...n ,
s 1
thì det(A) 0. Ma trận A được gọi là có phần tử trên đường chéo chính aii trội. Hơn
nữa nếu akk > 0, k = 1 ,2,.., n thì det(A)>0 định thức xác định dương.
Sau đây là một số chương trình thực hiện các phép tính ma trận
a. Nghịch đảo ma trận
Gọi A-1 là ma trận nghịch đảo của một ma trận A bậc n ta có AA-1 = E (trong
biểu thức này E là một ma trận vuông có các phần tử trên đường chéo chính bằng 1).
Dạng của ma trận E, ví dụ cấp 4 là:
158
1 0 0 0
0 1 0 0
E
0 0 1 0
0 1
0 0
Phương pháp khử để nhận được ma trận nghịch đảo A-1 được thực hiện qua
nhiều giai đoạn (n), mỗi một giai đoạn gồm hai bước. Đối với giai đoạn thứ k:
- Chuẩn hoá phần tử akk bằng cách nhân hàng với nghịch đảo của nó.
- Làm cho bằng không các phần tử phía trên và phía dưới đường chéo cho đến
cột thứ k. Khi k = n thì A(k) sẽ trở thành ma trận đơn vị và E trở thành A-1.
Ví dụ. Tính ma trận nghịch đảo của ma trận.
2 1 1
A 1 2 1
1 1 2
Ta viết lại ma trận A và ma trận đơn vị tương ứng với nó:
2 1 1 1 0 0
A 1 2 1 E 0 1 0
1 1 2 0 0 1
Giai đoạn 1:
Bước a: Nhân hàng 1 với 1/a11, nghĩa là a,1j = a1j/a11 đối với dòng thứ nhất,
a,ij = aij đối với các dòng khác.
1 1 2 1 2 1 2 0 0
A 1 2 1 E 0 1 0
1 1 2 0 0 1
Bước b: Trừ hàng 3 và hàng 2 cho hàng 1, nghĩa là a(1)1j = aij- ai1aij đối với i 1.
1 1 2 1 2 1 2 0 0
A 0 3 2 1 2 E 1 2 1 0
0 1 2 3 2 1 2 0 1
Giai đoạn 2:
Bước a: Lấy hàng 2 làm chuẩn, nhân hàng 2 với 2/3, để nguyên các hàng khác.
1 1 2 1 2 12 0 0
A 0 1 1 3 E 1 3 2 3 0
0 1 2 3 2 1 2 0 1
Bước b: Lấy hàng 1 trừ đi hàng 2 nhân 1/2 và lấy hàng 3 trừ đi hàng 2 nhân ½.
159
1 0 1 3 2 3 1 3 0
A 0 1 1 3 E 1 3 2 3 0
0 0 4 3 1 3 1 3 1
Giai đoạn 3:
Bước a: Lấy hàng 3 làm chuẩn, nhân hàng 3 với 3/4, để nguyên các hàng khác.
1 0 1 3 2 3 1 3 0
A 0 1 1 3 E 1 3 2 3 0
0 0 1 1 4 1 4 3 4
Bước b: Lấy hàng 1 trừ đi hàng 3 nhân 1/3 và lấy hàng 2 trừ đi hàng 3 nhân 1/3
1 0 0 3 4 1 4 1 4
A 0 1 0 E 1 4 3 4 1 4
0 0 1 1 4 1 4 3 4
Như vậy A-1 là:
3 / 4 1/ 4 1/ 4
1
A 1/ 4 3 / 4 1/ 4
1/ 4 1/ 4 3 / 4
Áp dụng phương pháp này chúng ta có chương trình sau:
Chương trình 5-4
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
void main()
{
int i,j,k,n,t,t1;
float c,a[50][50],b[50][50];
char tl;
clrscr();
printf(" **MA TRAN NGHICH DAO** \n");
printf("Cho bac cua ma tran n = ");
160
scanf("%d",&n);
printf("Vao ma tran ban dau a\n");
for (i=1;i<=n;i++)
{
printf("Vao hang thu %d :\n",i);
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
}
printf("\n");
printf("Ma tran ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%.5f\t",a[i][j]);
printf("\n");
}
t=1;
flushall();
while (t)
{
printf("\nCo sua ma tran khong(c/k)?");
scanf("%c",&tl);
if(toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
161
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("\nMa tran ban dau\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%.5f\t",a[i][j]);
printf("\n");
}
printf("\n");
for (i=1;i<=n;i++)
for (j=n+1;j<=2*n;j++)
{
if (j==i+n)
a[i][j]=1;
else
a[i][j]=0;
}
i=1;
t1=1;
while (t1&&(i<=n))
{
if (a[i][i]==0)
{
t=1;
k=i+1;
162
while (t&&(k<=n))
if (a[k][i]!=0)
{
for (j=1;j<=2*n;j++)
{
c=a[i][j];
a[i][j]=a[k][j];
a[k][j]=c;
}
t=0;
}
else
k=k+1;
if (k==n+1)
{
if (a[i][k-1]==0)
{
printf("MA TRAN SUY BIEN\n ");
t1=0;
}
}
}
if (a[i][i]!=0)
{
c=a[i][i];
for (j=i;j<=2*n;j++)
a[i][j]=a[i][j]/c;
}
for (k=1;k<=n;k++)
{
if (k!=i)
{
163
c=a[k][i];
for (j=i;j<=2*n;j++)
a[k][j]=a[k][j]-a[i][j]*c;
}
}
i=i+1;
}
if (t1)
{
printf("\n");
printf("\nMA TRAN KET QUA\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=n+1;j<=2*n;j++)
printf("%.4f\t\t",a[i][j]);
printf("\n");
}
printf("\n");
}
getch();
}
b. Nhân hai ma trận
Giả sử ta có ma trận Amn và ma trận Bnp. Tích của Amn và Bnp là ma trận Cmp
n
trong đó mỗi phần tử của Cmp là: c ij a ik b kj
k 1
Chương trình dưới đây thực hiện nhân hai ma trận với nhau.
Chương trình 5-5
#include <conio.h>
#include <stdio.h>
#include <math.h>
164
#include <stdlib.h>
#include <ctype.h>
#define max 50
void main()
{
int n,l,m,i,j,k,t;
float a[max][max],b[max][max],c[max][max];
char tl;
clrscr();
printf("Cho so hang cua ma tran a : ");
scanf("%d",&n);
printf("Cho so cot cua ma tran a : ");
scanf("%d",&l);
printf("Cho so cot cua ma tran b : ");
scanf("%d",&m);
printf("\nNHAP MA TRAN A\n");
for (i=1;i<=n;i++)
for (j=1;j<=l;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran a ma ban da nhap\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=l;j++)
printf("%10.5f",a[i][j]);
printf("\n");
165
}
flushall();
t=1;
while (t)
{
printf("Co sua ma tran khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran a ban dau");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=l;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
printf("\n");
166
{
printf("b[%d][%d] = ",i,j);
scanf("%f",&b[i][j]);
}
printf("\n");
printf("Ma tran b ban da nhap\n");
for (i=1;i<=l;i++)
{
for (j=1;j<=m;j++)
printf("%10.5f",b[i][j]);
printf("\n");
}
flushall();
t=1;
while (t)
{
printf("Co sua ma tran khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("b[%d][%d] = ",i,j);
scanf("%f",&b[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran b ban dau");
printf("\n");
167
for (i=1;i<=l;i++)
{
for (j=1;j<=m;j++)
printf("%10.5f",b[i][j]);
printf("\n");
}
printf("\n");
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{
c[i][j]=0;
for (k=1;k<=l;k++)
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}
printf("Ma tran tich c :\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=m;j++)
printf("%10.5f",c[i][j]);
printf("\n");
}
getch();
}
5.1.7. Vectơ riêng, trị riêng và các dạng toàn phương của ma trận
Cho A là ma trận vuông cấp n, số được gọi là trị riêng và vectơ khác không
X gọi là vectơ riêng của A nếu chúng thỏa mãn điều kiện:
A.X = .X hay (A- E).X = 0 => A .E =0 (5.1)
Giải phương trình (5.1), ta sẽ tìm được phương trình bậc n cho , sao cho:
f( ) = 0.
168
f( ) được gọi là đa thức đặc trưng của A, nó có n trị riêng 1, 2,.., n. Tập
hợp các giá trị riêng 1, 2,.., n này được gọi là phổ và maxi ( i ) là bán kính phổ
của ma trận A.
Với mỗi i có vô số Xi. Các vectơ riêng cùng tương ứng với một i rõ ràng là
phụ thuộc tuyến tính và chỉ khác nhau một hằng số . Do đó ta có thể chọn một vectơ
duy nhất làm cơ sở. Tập hợp n vectơ riêng, ứng với n trị riêng khác nhau tạo thành một
hệ vectơ độc lập tuyến tính. Ma trận gồm các cột là các vectơ riêng của ma trận A, gọi
là ma trận dạng riêng của A.
Định lý:
Nếu A là ma trận thực, đối xứng thì các trị riêng là thực. Các vectơ riêng ứng
với các trị riêng khác nhau là các vectơ thực trực giao và độc lập tuyến tính.
Nếu A là ma trận xác định dương thì các giá trị riêng là những số dương.
Định lý Sylvester:
Nếu định thức A và tất cả các tử thức nằm trên đường chéo chính đều là
Như vậy do (5.2) là hệ phương trình tuyến tính thuần nhất nên điều kiện cần và
đủ để là giá trị riêng của ma trận trên là định thức của nó bằng không:
det(A - E) = 0 (5.4)
169
Phương trình (5.4) được gọi là phương trình đặc trưng của ma trận A. Định thức
det(A - E) được gọi là định thức đặc trưng của ma trận A. Định thức của ma trận trên,
ký hiệu PA(), được gọi là đa thức đặc trưng của ma trận vuông A.
Ví dụ. Tìm vec tơ riêng và trị riêng của ma trận:
3 1 3
3 1 1
2 2 0
Trước hết ta tính đa thức đặc trưng của ma trận A:
3 1 3
PA ( ) 3 1 1 (4 )(2 4)
2 2
Ta nhận được các giá trị của , chúng tạo thành vec tơ riêng ứng với .
Như vậy khi khai triển định thức ta có một đa thức bậc n có dạng:
Pn() = n - p1n-1 - p2n-2 - ··· - pn = 0
Muốn xác định các hệ số của đa thức đặc trưng này ta dùng phương pháp
Fadeev-Leverrier. Ta xét ma trận A:
a11 a12 a1n
a a22 a2 n
A 21
a ann
n1 an 2
Ta gọi vết của ma trận A là số:
vet(A) = a11 + a22 + ··· + ann
Khi đó tham số pi của Pn() được xác định như sau:
p1 = vet(B1) với B1 = A
p2 = (1/2)vet(B2) với B2 = A(B1-p1E)
p3 = (1/3)vet(B3) với B3 = A(B2-p2E)
......
Chương trình tính các hệ số pi như sau:
170
Chương trình 5-6
// Faddeev_Leverrier;
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#define max 50
void main()
{
int i,j,k,m,n,k1,t;
float vet,c1,d;
char tl;
float p[max];
float a[max][max],b[max][max],c[max][max],b1[max][max];
clrscr();
printf("Cho bac cua ma tran n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j );
scanf("%f",&a[i][j]);
}
printf("\n");
clrscr();
printf("Ma tran ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
171
{
for (j=1;j<=n;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
t=1;
flushall();
while (t)
{
printf("\n");
printf("Co sua ma tran khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
flushall();
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran ban dau");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%10.5f",a[i][j]);
printf("\n");
172
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
b[i][j]=a[i][j];
for (k=1;k<=n-1;k++)
{
vet=0.0;
for (i=1;i<=n;i++)
vet+=b[i][i];
p[k]=vet/k;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
if (j!=i)
c[i][j]=b[i][j];
if (j==i)
c[i][j]=b[i][j]-p[k];
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
b[i][j]=0.0;
for (k1=1;k1<=n;k1++)
b[i][j]+=a[i][k1]*c[k1][j];
}
}
vet=0.0;
for (i=1;i<=n;i++)
vet+=b[i][i];
p[n]=vet/n;
printf("\n");
printf("Cac he so cua da thuc dac trung\n");
173
printf("\n");
d=1.0;
printf("%6.2f",d);
for (i=1;i<=n;i++)
{
c1=-p[i];
printf("%5c%6.2f",' ',c1);
}
getch();
}
Phương pháp Mises
Thuật toán Mises tìm giá trị riêng lớn nhất của một ma trận A. Nếu ma trận A
là thực và mỗi trị riêng bội k có đủ k vec tơ riêng độc lập tuyến tính thì việc tính toán
sẽ cho ta giá trị riêng lớn nhất.
Một vectơ V bất kì có thể được viết dưới dạng:
n
V v1 X 1 v2 X 2 vn X n vi X i (5.5)
i 1
Trong đó X1, X2,.., Xn là các véc tơ riêng tương ứng với các giá trị riêng 1, 2,
3,.., n và v1, v2, v3,..., vn là các hằng số.
Khi nhân A với V ta có:
AV = Av1X1 + Av2X2 +....+ AvnXn
Do: Av1X1 = v1AX1 = v11X1 ; Av2X2 = v2AX2 = v22X2 v.v.
Nên: AV = v11X1 + v22X2 +...+ vnnXn
n n
AV vi Ai X i vi i X i
i 1 i 1
174
2
p
3
p
n
p
A V v1 X 1 v2 X 2 v3 X 3 vn X n
p p
1 1 1
1
Tương tự ta có:
2
p 1
3
p 1
n
p 1
A V
p 1 p 1
v1 X 1 v2 X 2 v3 X 3 vn X n
1 1 1
1
Do đó: A p 1V 1 A pV
Hay:
A A pV 1 A pV
Như vậy A pV là véc tơ riêng của A ứng với 1 còn giá trị riêng 1 sẽ là:
A p 1V
lim 1
p A pV
Trong thực tế để tránh vượt quá dung lượng bộ nhớ khi 1 khá lớn, các vectơ Vk
được chuẩn hoá sau mỗi bước bằng cách chia các phần tử của nó cho phần tử lớn nhất
mk và nhận được vectơ V’k
Như vậy các bước tính sẽ là:
- Cho một vec tơ V bất kì (có thể là V = { 1, 1, 1,..., 1}T)
- Tính V1 = AV và nhận được phần tử lớn nhất là m1j từ đó tính tiếp
V1 = V1/m1j
Một cách tổng quát, tại lần lặp thứ p ta nhận được vectơ Vp và phần tử lớn nhất
mpj thì V’p = Vp/ mpj.
Tính V p 1 AV p với vp+1,j là phần tử thứ j của Vp+1. Ta có:
lim V p X 1
p
lim v p 1, j 1
p
175
Ví dụ. Tìm giá trị riêng lớn nhất và vec tơ riêng tương ứng của ma trận:
17 24 30 17
8 13 20 7
A
2 10 8 6
23 43 54 26
Chọn V= {1, 1, 1, 1}T ta tính được:
V V1 = AV V’1 V2 = V’2
AV’1
1 88 -0.6027 -6.4801 -0.5578
1 48 -0.3288 -5.6580 -0.4870
1 26 -0.1781 0.0818 0.0070
1 -146 1 11.6179 1
11.6179
V3 = V’3 V4 = AV’3 V’4 V5 =
AV’2 AV’4
-3.9594 -0.5358 -3.6823 -0.5218 -3.5718
-3.6526 -0.4942 -3.5196 -0.4987 -3.4791
0.0707 0.0096 0.0630 0.0089 0.0408
7.3902 1 7.0573 1 6.9638
7.3902 7.0573 6.9638
Ta xây dựng chương trình theo thuật toán trên như sau:
176
Chương trình 5-7
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#define max 50
void main()
{
int i,j,k,n,t;
char tl;
float t0,t1,epsi,s;
float a[max][max];
float x0[max],x1[max];
clrscr();
printf("Phuong phap lap luy thua tim tri rieng lon nhat\n");
printf("Cho so hang va cot cua ma tran n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
177
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
flushall();
t=1;
while (t)
{
printf("\nCo sua ma tran khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
epsi=1e-5;
printf("\nMa tran ban dau\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
178
for (i=1;i<=n;i++)
x0[i]=1;
k=1;
t=0;
t1=0;
do
{
t0=t1;
for (i=1;i<=n;i++)
{
x1[i]=0;
for (j=1;j<=n;j++)
x1[i]=x1[i]+a[i][j]*x0[j];
}
s=0;
j=0;
for (i=1;i<=n;i++)
if (s<fabs(x1[i]))
{
j=i;
s=fabs(x1[i]);
}
t1=x1[j];
for (i=1;i<=n;i++)
x1[i]=x1[i]/t1;
if (fabs(t1-t0)<epsi)
{
printf("Da thuc hien %d buoc lap\n",k);
printf("Gia tri rieng lon nhat Vmax = %15.5f\n",t1);
printf("Vec to rieng tuong ung\n");
for (i=1;i<=n;i++)
printf("%.5f\n",x1[i]);
179
t=1;
}
if (fabs(t1-t0)>epsi)
{
for (i=1;i<=n;i++)
x0[i]=x1[i];
k=k+1;
}
if (k>max)
t=1;
}
while(t==0);
getch();
}
Áp dụng. Dùng chương trình này tính gía trị riêng và vectơ riêng của ma trận:
2 1 0
9 4 6
8 0 3
Ta nhận được giá trị riêng là 3.0000 và vec tơ riêng là x = {-0.75, 0.75, 1}T
Như chúng ta đã nói trước đây, phương pháp Mises (hay còn gọi là phương
pháp lặp lũy thừa) chỉ cho phép tìm giá trị riêng lớn nhất và vectơ riêng tương ứng của
ma trận. Để xác định các giá trị riêng khác, ma trận A được biến đổi thành một ma trận
khác A1 mà các giá trị riêng là 2 > 3 >... Phương pháp này gọi là phương pháp
xuống thang. Sau đây là phương pháp biến đổi ma trận:
Giả sử X1 là vec tơ riêng của ma trận A tương ứng với giá trị riêng 1 và W1 là
vec tơ riêng của ma trận AT tương ứng với giá trị riêng 1. Từ định nghĩa AX1 = 1X1
ta viết:
(A - E)X1 = 0
Ta tạo ma trận A1 dạng:
(5.7)
AA 1 T
1 T XW
1 1
W X1 1
180
Ta chú ý là X1W1T là một ma trận còn W 1T X 1 là một con số. Khi nhân hai vế của
biểu thức (5.7) với X1 và chý ý đến tính kết hợp của tích các ma trận, ta có:
1
A1 X 1 AX 1 T X 1W 1T X 1
W1 X 1
W T X1
AX 11 X 1 1 (5.8)
W 1T X 1
AX 11 X 1
0
AX X W X
2 1 1
1
T
2
W X 1 1
void main()
{
float a[max][max],vv[max][max],at[max][max];
float x[max],y[max],vd[max];
int i,j,k,n,l,t;
float vp,v1,z,epsi,va,ps;
char tl;
clrscr();
epsi=0.000001;
printf("Cho bac cua ma tran n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
clrscr();
printf("Ma tran ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
183
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
t=1;
flushall();
while (t)
{
printf("\n");
printf("Co sua ma tran khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
for (l=1;l<=n;l++)
{
for (i=1;i<=n;i++)
x[i]=1;
vp=1.23456789;
k=0;
for (k=1;k<=40;k++)
{
184
for (i=1;i<=n;i++)
{
y[i]=0;
for (j=1;j<=n;j++)
y[i]=y[i]+a[i][j]*x[j];
}
v1=y[1]/x[1];
z=0;
for (i=1;i<=n;i++)
if (fabs(y[i])>z)
z=y[i];
for (i=1;i<=n;i++)
x[i]=y[i]/z;
if (fabs(vp-v1)<epsi)
break;
vp=v1;
}
{
printf("Gia tri rieng : %9.6f\n",v1);
printf("Vec to rieng : \n");
for (i=1;i<=n;i++)
printf("%.5f\n",x[i]);
printf("\n");
getch();
}
vd[l]=v1;
va=v1;
for (i=1;i<=n;i++)
vv[l][i]=x[i];
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
at[i][j]=a[j][i];
185
for (i=1;i<=n;i++)
x[i]=1;
vp=1.23456;
k=0;
for (k=1;k<=40;k++)
{
for (i=1;i<=n;i++)
{
y[i]=0;
for (j=1;j<=n;j++)
y[i]=y[i]+at[i][j]*x[j];
}
v1=y[1]/x[1];
z=0;
for (i=1;i<=n;i++)
if (fabs(y[i])>z)
z=y[i];
for (i=1;i<=n;i++)
x[i]=y[i]/z;
if (fabs(vp-v1)<epsi)
break;
vp=v1;
}
if (fabs(vp-v1)>epsi)
{
printf("Khong hoi tu sau 40 lan lap\n");
getch();
exit(1);
}
if (fabs(va-v1)>3*epsi)
{
printf("Co loi\n");
186
getch();
exit(1);
}
ps=0;
for (i=1;i<=n;i++)
ps=ps+x[i]*vv[l][i];
ps=v1/ps;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
a[i][j]=a[i][j]-ps*vv[l][i]*x[j];
}
}
Ví dụ. Dùng chương trình này tìm giá trị riêng của ma trận:
23 4 16
40 5 32
20 4 13
Ta nhận được kết quả:
Giá trị riêng 3.00000 vec tơ riêng
0.529411
1.000000
-0.411765
Giá trị riêng 3.000000 vec tơ riêng
-0.833336
-0.166678
1.000000
Giá trị riêng -1.000000 vec tơ riêng
0.500000
1.000000
-0.500000
5.2. Giải hệ đại tuyến
Bài toán cơ bản:
187
Cho hệ gồm n phương trình đại số tuyến tính với n ẩn:
a11x1+ a12x2+...+ a1nxn = b1
a21x1+ a22x2+...+ a2nxn = b2
... ... ...
an1x1+ an2x2+...+ annxn = bn
Viết dưới dạng matrix:
A.X = B
Giả thiết det(A) 0: Hệ này có nghiệm duy nhất.
Ta có thể tìm nghiệm theo quy tắc CRAMER hoặc sử dụng ma trận nghịch đảo
nhưng cách này đòi hỏi phép tính khá lớn và không thuận lợi khi ma trận A xấu.
Chúng ta chỉ nghiên cứu các phương pháp triển khai hữu hiệu trên máy tính. Có
thể phân loại chúng thành hai nhóm chính:
- Các phương pháp trực tiếp: Gauss, Gauss Jordan, phân tích LU,...
- Các phương pháp lặp: Lặp đơn, Gauss - Seidel, lặp Gradient liên hợp…
5.2.1. Phương pháp giải trực tiếp
a. Phương pháp khử Gauss
Chúng ta biết rằng các nghiệm của hệ đại tuyến không đổi nếu ta thay một hàng
bằng tổ hợp tuyến tính của các hàng khác. Như vậy bằng một loạt các biến đổi ta có
thể đưa hệ đại tuyến ban đầu về dạng tam giác. Đó chính là nội dung của phương pháp
khử Gauss. Chúng ta đi xét hệ phương trình:
a11x1 a12 x2 a13 x3 b1
a21x1 a22 x2 a23 x3 b2
a x a x a x b
31 1 32 2 33 3 3
Số hạng đầu của phương trình bằng số hạng đầu của hàng thứ hai trong hệ
phương trình ban đầu. Khi trừ hàng một đã được biến đổi cho hàng 2 ta nhận được
hàng 2 mới:
a a a
0 x1 a22 21 a12 x2 a23 21 a13 x3 b2 21 b1
a11 a11 a11
Ta tiếp tục cách này để loại trừ x1 ra khỏi hàng thứ 3. Phương trình trở thành:
188
a12
a11 x1 b1
a13
0 a22 x2 b2
a23
0 a
32
x3 b3
a33
Với a,11 = a11, a,12 = a12, a,13 = a13, a,13 = a13, b,1 = b1
a21 a21 a31
a22
a22 a12 a23
a23 a13 a32
a32 a12
a11 a11 a11
Ta loại trừ số hạng chứa x3 trong dòng thứ 3 bằng cách tương tự. Ta nhân hàng
thứ 2 trong hệ A'X = B' với a,32/a,22 và đem trừ đi hàng thứ 3 trong hệ mới. Như vậy số
hạng chứa x3 biến mất và ta nhận được ma trận tam giác trên.
a12
a11 x1 b1
a13
0 a22 x2 b2
a23
0
0 x3 b3
a33
Với a11
a11 a12
a12 a13
a13 b1 b1 a22
a22 a23
a23
a32
a33
b2 b2 a33
a33 a b3 b3 b
23
a22 2
a22
Các phép tính này chỉ thực hiện được khi a11 0 và a,11 0.
Với một hệ có n phương trình, thuật tính hoàn toàn tương tự. Sau đây là chương
trình giải hệ phương trình n ẩn số bằng phương pháp khử Gauss.
Chương trình 5-9
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <ctype.h>
#define max 10
void main()
{
float b[max],x[max];
float a[max][max];
int i,j,k,n,t;
189
float c,s,d;
char tl;
clrscr();
printf("Cho so phuong trinh n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a :\n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran a ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
190
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran a ban dau\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
printf("Cho cac phan tu cua ma tran b : \n");
for (i=1;i<=n;i++)
{
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
printf("\n");
printf("Ma tran b ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %15.5f\n",i,b[i]);
printf("\n");
flushall();
t=1;
191
while (t)
{
printf("Co sua ma tran b khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%f",&i);
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
if (toupper(tl)=='K')
t=0;
}
printf("\n");
printf("Ma tran b\n");
for (i=1;i<=n;i++)
printf("b[%d] = %15.5f\n",i,b[i]);
printf("\n");
for (k=1;k<=n-1;k++)
{
for (i=k+1;i<=n;i++)
{
b[i]=b[i]-b[k]*a[i][k]/a[k][k];
for (j=k+1;j<=n;j++)
a[i][j]=a[i][j]-a[k][j]*a[i][k]/a[k][k];
}
}
{
if (a[n][n]==0)
if (b[n]==0)
192
printf("He da cho vo nghiem");
else
{
printf("He da cho co vo so nghiem");
x[n]=c;
}
else
x[n]=b[n]/a[n][n];
for (i=n-1;i>=1;i--)
{
s=0;
for (k=i+1;k<=n;k++)
s=s+a[i][k]*x[k];
x[i]=(b[i]-s)/a[i][i];
}
printf("\n");
printf("Nghiem cua he da cho la\n");
printf("\n");
for (i=1;i<=n;i++)
printf("x[%d] = %15.5f\n",i,x[i]);
getch();
}
}
b. Phương pháp Gauss – Jordan
Xét hệ phương trình AX = B. Khi giải hệ bằng phương pháp Gauss ta đưa nó về
dạng ma trận tam giác sau một loạt biến đổi. Phương pháp khử Gauss-Jordan cải tiến
khử Gauss bằng cách đưa hệ về dạng:
EX = B*
Và khi đó nghiệm của hệ chính là B*. Trong phương pháp Gauss-Jordan mỗi
bước tính phải tính nhiều hơn phương pháp Gauss nhưng lại không phải tính nghiệm.
Để đưa ma trận A về dạng ma trận E tại bước thứ i ta phải có aii = 1 và aij = 0. Như vậy
tại lần khử thứ i ta biến đổi:
193
1.aij = aij/aii (j = i + 1, i + 2,..., n)
2.k = 1, 2,..., n
akj = akj - aijaki (j = i + 1, i + 2,..., n)
bk = bk - biaki
Ví dụ. Cho hệ phương trình
8 4 2 0 x1 24
4 10 5 4 x2 32
2 5 6.5 4 x3 26
0 4 4 9 x4 21
Biến đổi lần 1: Ta chia hàng 1 cho a11 = 8, nhân hàng 1 vừa nhận được với 4 và
lấy hàng 2 trừ đi, nhân hàng 1 vừa nhận được với 2 và lấy hàng 3 trừ đi, giữ nguyên
hàng 4 vì phần tử đầu tiên đã bằng 0 ta có:
1 0.5 0.25 0 x1 3
0 8 4 4 x2 20
0 4 6 4 x3 20
0 4 9 x4 21
4
Biến đổi lần 2: Ta chia hàng 2 cho a22 = 8, nhân hàng 2 vừa nhận được với 0.5
và lấy hàng 1 trừ đi, nhân hàng 2 vừa nhận được với 4 và lấy hàng 3 trừ đi, nhân hàng
2 vừa nhận được với 4 và lấy hàng 4 trừ đi ta có:
1 0 0 0.25 x1 1.75
0 1 0.5 0.5 x2 2.5
0 0 4 2 x3 10
0 0 2 7 x4 11
Biến đổi lần 3: Ta chia hàng 3 cho a33 = 4, giữ nguyên hàng 1, nhân hàng 3 vừa
nhận được với 0.5 và lấy hàng 2 trừ đi, nhân hàng 3 vừa nhận được với 2 và lấy hàng 4
trừ đi ta có:
1 0 0 0.25 x1 1.75
0 1 0 0.25 x2 1.25
0 0 1 0.5 x3 2.5
0 6 x4 6
0 0
Biến đổi lần 4: Ta chia hàng 4 cho a44 = 6, nhân hàng 4 vừa nhận được với
- 0.25 và lấy hàng 1 trừ đi, nhân hàng 4 vừa nhận được với 0.25 và lấy hàng 2 trừ đi,
nhân hàng 4 vừa nhận được với 0.5 và lấy hàng 3 trừ đi ta có:
194
1 0 0 0 x1 2
0 1 0 0 x2 1
0 0 1 0 x3 2
0 1 x4 1
0 0
void main()
{
float a[spt][2*spt];
float b[spt];
int i,j,k,n,m,t;
float max,c;
char tl;
clrscr();
printf("Cho so phuong trinh n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a :\n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
195
printf("Ma tran a ma ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran a\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
196
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
printf("Cho cac phan tu cua ma tran b : \n");
for (i=1;i<=n;i++)
{
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
printf("\n");
printf("Ma tran b ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %15.5f\n",i,b[i]);
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran b khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
if (toupper(tl)=='K')
t=0;
}
197
printf("\n");
printf("Ma tran b\n");
printf("\n");
for (i=1;i<=n;i++)
printf("%15.5f\n",b[i]);
printf("\n");
t=1;
flushall();
i=1;
while (t)
{
if (a[i][i]==0)
{
max=0;
m=i;
for (k=i+1;k<=n;k++)
if (max<fabs(a[k][i]))
{
m=k;
max=fabs(a[i][i]);
}
if (m!=i)
{
for (j=i;j<=n;j++)
{
c=a[i][j];
a[i][j]=a[m][j];
a[m][j]=c;
}
c=b[i];
b[i]=b[m];
b[m]=c;
198
}
if (m==i)
{
t=0;
printf("MA TRAN SUY BIEN");
}
}
if (a[i][i]!=0)
{
c=1/a[i][i];
for (j=i;j<=n;j++)
a[i][j]=a[i][j]*c;
b[i]=b[i]*c;
for (k=1;k<=n;k++)
if (k!=i)
{
c=a[k][i];
for (j=i;j<=n;j++)
a[k][j]=a[k][j]-a[i][j]*c;
b[k]=b[k]-b[i]*c;
}
}
i=i+1;
if (i==(n+1))
t=0;
}
if (i==(n+1))
{
printf("NGHIEM CUA HE");
printf("\n");
for (i=1;i<=n;i++)
printf("x[%d] = %15.5f\n",i,b[i]);
199
}
getch();
}
200
a11 a12 a13 b11 b12 b13 c11 c12 c13
A a21 a22 a23 B b21 b22 b23 C c21 c22 c23
a a33 b c c33
31 a32 31 b32 c33 31 c32
Với: c11 = a11b11 + a12b21 + a13b31
c12 = a11b12 + a12b22 + a13b32
c13 = a11b13 + a12b23 + a13b33
c21 = a21b11 + a22b21 + a23b31
Tổng quát :
n
c ij a ik b kj
k 1
Dùng quy tắc này cho hai ma trận L và U và cho đồng nhất các hệ số của chúng
với ma trận A, ta có:
1 0 0 r11 r12 r13 a11 a12 a13
l21 1 0 0 r22 r23 a21 a22 a23
l r33 a a33
31 l321 1 0 0 31 a32
a11 = 1. r11 + 0.0 + 0.0 = r11
a12 = r12 ; a13 = r13
a21 = l21r11
a22 = l21r12 + r22 ; a23 = l31r11
a31 = l31r11 ; a32 = l31r12
a33 = l31r13 + l32r23 + r33
Một cách tổng quát ta có:
Với j > i : lij = rji = 0
Với i = 1 : r1j = a1j (j = 1 tới n)
lj1 = aj1/r11 (j = 1 tới n)
Với i = 2 tới n
i 1
rij aij lik rkj ( j = i tới n)
k 1
i 1
a ji l jk rki
l ji k 1
(j = i tới n)
rii
201
Chương trình 5-11
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max 6
void main()
{
float a[max][max],r[max][max],l[max][max];
int i,j,k,n;
float tr,tl;
clrscr();
printf("Cho bac cua ma tran n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran can phan tich a\n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
l[i][j]=0.0;
r[i][j]=0.0;
}
for (i=1;i<=n;i++)
{
r[1][i]=a[1][i];
l[i][i]=1.0;
202
l[i][1]=a[i][1]/a[1][1];
}
for (k=2;k<=n;k++)
{
for (j=k;j<=n;j++)
{
tr=0.0;
for (i=1;i<=k;i++)
tr=tr+l[k][i]*r[i][j];
r[k][j]=a[k][j]-tr;
}
if (k!=n)
{
for (i=1;i<=n;i++)
{
tl=0.0;
for (j=1;j<=k-1;j++)
tl=tl+l[i][j]*r[j][k];
l[i][k]=(a[i][k]-tl)/r[k][k];
}
}
else
printf("\n");
}
printf("Ma tran l :\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",l[i][j]);
printf("\n");
}
printf("Ma tran r :\n");
203
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",r[i][j]);
printf("\n");
}
getch();
}
Áp dụng. Dùng chương trình này phân tích ma trận ta được:
2 1 2 1 0 0 2 1 2
A 3 1 1 L 1.5 1 0 R 0 2.5 4
7 5 3 3.5 6 1 0 6.4
0
(ii). Phương pháp phân tích Cholesky: Phương pháp Cholesky dùng để phân
tích một ma trận đối xứng sao cho A = UTU với U là một ma trận tam giác trên. Cách
phân tích cũng tương tự như phương pháp Crout . Ta xét các ma trận A và U bậc 3 như
sau :
a11 a12 a13 r11 r12 r13
A a21 a22 a23 U 0 r22 r23
a a33 0 0 r
31 a32 33
i 1
aij rki rkj
rij k 1
, i j
rii
rij = 0 (i > j )
Dưới đây là chương trình:
Chương trình 5-12
#include <conio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max 6
void main()
{
float a[max][max],r[max][max],b[max][max];
int i,j,k,n,l;
clrscr();
printf("Cho bac cua ma tran n : ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran can phan tich a :\n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
for (i=1;i<=n;i++)
205
for (j=1;j<=n;j++)
r[i][j]=0.0;
for (i=1;i<=n;i++)
{
if (a[i][i]<0.0)
{
printf("Ma tran khong duong");
getch();
exit(1);
}
else
{
r[i][i]=sqrt(a[i][i]);
for (j=1+i;j<=n;j++)
r[i][j]=a[i][j]/r[i][i];
for (k=i+1;k<=n;k++)
for (l=k;l<=n;l++)
a[k][l]=a[k][l]-r[i][k]*r[i][l];
}
}
printf("\n");
printf("Ma tran chuyen vi cua r\n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
b[j][i]=r[i][j];
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",b[i][j]);
printf("\n");
}
printf("\n");
206
printf("Ma tran r\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",r[i][j]);
printf("\n");
}
getch();
}
Ví dụ 1. Dùng chương trình này để phân tích ma trận:
10 7 8 7 6
7 5 6 5 4
8 6 10 9 6
7 5 9 10 7
6 4 6 7 9
Ta có :
3.162278 2.213594 2.529822 2.213594 1.897367
0 0.316228 1.264911 0.316228 0.631456
U 0 0 1.414214 2.121320 1.414214
0 0 0 0.707107 0
1.732052
0 0 0 0
1 0 0 3 0,1 0, 2
U 0, 0333333 1 0 , U 0 7, 00333 0, 293333
0,100000 0, 0271300 1 0 0 10, 0120
Phân tích LY = b
1 0 0 y1 7,85
0, 0333333 y 19,3
1 0 2
0,100000 0, 0271300 1 y3 71, 4
207
Khai triển ra ta có:
y1 = 7,85
0,0333333y1 + y2 = -19,3
0,100000y1 – 0,0271300y2 + y3 = -19,3
Giải ra ta được:
7,85
Y 19,5617
70, 0843
Áp dụng phương trình UX = Y
3 0,1 0, 2 x1 7,85
0 7, 00333 0, 293333 x 19,5617
2
0 0 10, 0120 x3 71, 0843
3
Giải ra ta được: X 2,5
7, 00003
Chương trình giải hệ đại tuyến theo thuật toán Crout
void main()
{
float b[max],x[max],y[max];
float a[max][max],r[max][max],l[max][max];
int i,j,k,n,t;
float c,tr,tl,s;
char tloi;
208
clrscr();
printf("Cho so phuong trinh n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran a ma ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tloi);
if (toupper(tloi)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
209
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
flushall();
}
if (toupper(tloi)=='K')
t=0;
}
printf("Ma tran a\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
printf("\n");
printf("Cho cac phan tu cua ma tran b : \n");
for (i=1;i<=n;i++)
{
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
printf("\n");
printf("Ma tran b ma ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %10.5f\n",i,b[i]);
printf("\n");
t=1;
flushall();
while (t)
{
210
printf("Co sua ma tran b khong(c/k)?");
scanf("%c",&tloi);
if (toupper(tloi)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("b[%d] = ",i);
scanf("%f",&b[i]);
flushall();
}
if (toupper(tloi)=='K')
t=0;
}
printf("\n");
printf("Ma tran b\n");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %10.5f\n",i,b[i]);
printf("\n");
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
r[i][j]=0.0;
l[i][j]=0.0;
}
for (i=1;i<=n;i++)
{
r[1][i]=a[1][i];
l[i][i]=1.0;
l[i][1]=a[i][1]/a[1][1];
}
for (k=2;k<=n;k++)
211
{
for (j=k;j<=n;j++)
{
tr=0.0;
for (i=1;i<=k;i++)
tr=tr+l[k][i]*r[i][j];
r[k][j]=a[k][j]-tr;
}
if (k!=n)
{
for (i=1;i<=n;i++)
{
tl=0.0;
for (j=1;j<=k-1;j++)
tl=tl+l[i][j]*r[j][k];
l[i][k]=(a[i][k]-tl)/r[k][k];
}
}
else
printf("\n");
}
if (l[1][1]==0.0)
if (b[1]==0.0)
printf("He da cho vo nghiem\n");
else
{
printf("He da cho co vo so nghiem\n");
y[n]=c;
}
else
y[1]=b[1]/l[1][1];
for (i=2;i<=n;i++)
212
{
s=0.0;
for (k=1;k<=i-1;k++)
s=s+l[i][k]*y[k];
y[i]=(b[i]-s)/l[i][i];
}
if (r[n][n]==0.0)
if (y[n]==0.0)
printf("He da cho vo nghiem\n");
else
{
printf("He da cho co vo so nghiem\n");
x[n]=c;
}
else
x[n]=y[n]/r[n][n];
for (i=n-1;i>=1;i--)
{
s=0.0;
for (k=i+1;k<=n;k++)
s+=r[i][k]*x[k];
x[i]=(y[i]-s)/r[i][i];
}
printf("\n");
printf("Nghiem cua he da cho la\n");
printf("\n");
for (i=1;i<=n;i++)
printf("x[%d] = %15.5f\n",i,x[i]);
getch();
}
213
(iii) Chương trình giải hệ đại tuyến theo phương pháp Choleski
Trong phương pháp Cholesky một ma trận đối xứng A được phân tích thành
dạng A = UTU trong đó U là một ma trận tam giác trên. Hệ phương trình lúc đó
chuyển thành AX = UTUX = B. Như vậy trước hết ta phân tích ma trận A thành tích
hai ma trận. Sau đó giải hệ phương trình UTY = B và cuối cùng là hệ UX = Y. Chương
trình mô tả thuật toán này được cho dưới đây:
void main()
{
float a[max][max],r[max][max];
float b[max],x[max],y[max];
int i,j,k,l,n,t;
float s;
char tl;
clrscr();
printf("Cho so phuong trinh n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
214
}
printf("\n");
printf("Ma tran a ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
flushall();
t=1;
while (t)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[",i,",",j,"] = ");
scanf("%f",&a[i][j]);
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran a\n");
printf("\n");
for (i=1;i<=n;i++)
215
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
printf("Cho cac phan tu cua ma tran b : \n");
for (i=1;i<=n;i++)
{
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
printf("\n");
printf("Ma tran b ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %15.5f\n",i,b[i]);
printf("\n");
flushall();
t=1;
while (t)
{
printf("Co sua ma tran b khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("b[%d] = ",i);
scanf("%f",&b[i]);
}
if (toupper(tl)=='K')
216
t=0;
}
printf("\n");
printf("Ma tran b\n");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %15.5f\n",i,b[i]);
printf("\n");
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
r[i][j]=0.0;
for (i=1;i<=n;i++)
{
if (a[i][i]>=0)
{
r[i][i]=sqrt(a[i][i]);
for (j=1+i;j<=n;j++)
r[i][j]=a[i][j]/r[i][i];
for (k=i+1;k<=n;k++)
for (l=k;l<=n;l++)
a[k][l]=a[k][l]-r[i][k]*r[i][l];
}
}
for (k=1;k<=n;k++)
{
s=b[k];
if (k!=1)
for (i=1;i<=k-1;i++)
s=s+r[i][k]*y[i];
y[k]=-s/r[k][k];
}
for (i=n;i>=1;i--)
217
{
s=-y[i];
if (i!=n)
for (k=i+1;k<=n;k++)
s=s-r[i][k]*x[k];
x[i]=s/r[i][i];
}
printf("Nghiem cua he phuong trinh la\n ");
for (i=1;i<=n;i++)
printf("x[%d] = %10.5f\n",i,x[i]);
getch();
}
5.2.2. Phương pháp lặp giải hệ phương trình
Phương pháp Gauss thuộc loại phương pháp đúng hay còn gọi là phương pháp
trực tiếp. Ngoài ra còn có 1 loại phương pháp khác là phương pháp lặp, trong mục này
ta lần lượt xét một số phương pháp lặp thông dụng.
a. Phương pháp lặp đơn giải hệ phương trình
Phương pháp lặp đơn, hệ phương trình cho ở dạng vector: Ax = f
Ta chuyển hệ này về dạng tương đương: x = Bx + g
b11 b12 b1n
b 21 b 22 b 2n
Giả sử: B=
b n1 b n 2 b nn
Sau đó ta xây dựng công thức tính lặp:
x ( m ) Bx ( m1) g
( 0) (5.13)
x
n
Phương pháp tính theo (5.13) gọi là phương pháp lặp đơn.
218
Sự hội tụ:
Giả sử = (1 , 2 , . . . . ., n)T là nghiệm của hệ x = Bx + g , nếu xi(m) i
khi m , với i = 1, 2, 3 , . . . , n thì ta nói phương pháp lặp (5.13) hội tụ.
Ta đưa vào các ký hiệu: z = ( z1 , z2 , . . . , zn )T thì mỗi đại lượng sau:
z0 max z i
z1 z1 z 2 zn
z2 z12 z 22 z 2n
Gọi là độ dài mở rộng của vector z, người ta còn gọi nó là chuẩn của z.
n
0 r max
i
b ij
j1
n
r1 max b ij
Đối với ma trận B = ( bi j), ta đặt:
j
i 1
n n
r2 . b ij
i 1 j1
Người ta chứng minh được định lý sau đây về điều kiện hội tụ:
- Nếu r0 < 1 hoặc r1 < 1 hoặc r2 < 1 thì phương pháp lặp (5.13) hội tụ với bất
kỳ xấp xỉ ban đầu x(0) nào, đồng thời ta có sai số đánh giá:
rPm
x (m)
x (1) x ( 0)
P 1 rP P
rPm
x (m)
x ( m ) x ( m 1)
1 rP P
P
219
1 1
x1 5 x2 10 x3 1
1 1 6
x2 x1 x3
10 5 5
1 1 4
x3 10 x1 10 x2 5
Như vậy :
1 1
0 5 10 1
B
1
0
1 5
và G
10 5 6
4
1 1 0
10 10 5
void main()
{
float a[max][max];
float f[max],x0[max],x1[max];
int i,j,k,n,l,t;
float s,c,epsi;
char tl;
clrscr();
printf("Cho so phuong trinh n = ");
scanf("%d",&n);
220
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran a ma ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
flushall();
221
}
if (toupper(tl)=='K')
t=0;
}
printf("Ma tran a\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
printf("\n");
printf("Cho cac phan tu cua ma tran f : \n");
for (i=1;i<=n;i++)
{
printf("f[%d] = ",i);
scanf("%f",&f[i]);
}
printf("\n");
printf("Ma tran f ma ban da nhap");
printf("\n");
for (i=1;i<=n;i++)
printf("f[%d] = %10.5f\n",i,f[i]);
printf("\n");
t=1;
flushall();
while (t)
{
printf("Co sua ma tran f khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
222
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("f[%d] = ",i);
scanf("%f",&f[i]);
flushall();
}
if (toupper(tl)=='K')
t=0;
}
printf("\n");
printf("Ma tran f");
printf("\n");
for (i=1;i<=n;i++)
printf("f[%d] = %10.5f\n",i,f[i]);
printf("\n");
for (i=1;i<=n;i++)
x0[i]=0.0;
x0[1]=1.0;
printf("Cho so lan lap l = ");
scanf("%d",&l);
epsi=1e-5;
for (i=1;i<=n;i++)
{
c=1.0/a[i][i];
for (j=1;j<=n;j++)
if (j!=i)
a[i][j]*=c;
f[i]*=c;
a[i][i]=0.0;
}
k=1;
223
t=0;
do
{
for (i=1;i<=n;i++)
{
x1[i]=f[i];
for (j=1;j<=n;j++)
x1[i]=x1[i]-a[i][j]*x0[j];
}
s=0.0;
for (i=1;i<=n;i++)
s=s+fabs(x1[i]-x0[i]);
if (s>=epsi)
for (i=1;i<=n;i++)
x0[i]=x1[i];
if (s<epsi)
{
t=1;
printf("\n");
printf("Phep lap hoi tu sau %d buoc tinh",k);
printf("\n");
printf("NGHIEM CUA HE");
printf("\n");
for (i=1;i<=n;i++)
printf("x[%d] = %10.5f\n",i,x1[i]);
}
k=k+1;
if (k>l)
{
t=1;
printf("Phep lap khong hoi tu sau %d buoc tinh",k-1);
}
224
}
while (t==0);
getch();
}
x1 1 1 j x (jk )
j 1
( k 1) n
Chọn lớp nghiệm gần đúng ban đầu: x1(o) = 1.2, x2(o) = 0, x3(o) = 0.
Sử dụng phương pháp lặp Seidel, ta có:
225
Lần lặp thứ 1:
x11 1.2 0.1 0 0.1 0 1.2
1
x2 1.3 0.2 1.2 0.1 0 1.06
1
x3 1.4 0.2 1.2 0.2 1.06 0.948
Lần lặp thứ 2:
x12 1.2 0.11.06 0.1 0.948 0.9992
2
x2 1.3 0.2 0.9992 0.1 0.948 1.00536
1
x3 1.4 0.2 0.9992 0.2 1.00536 0.999098
Và cứ thế tiếp tục cho lần lặp thứ 3, 4,…cho đến khi thỏa mãn sai số cho phép.
Ví dụ 2. Tìm nghiệm gần đúng của hệ phương trình sau bằng phương pháp lặp đơn.
4 x1 0,24 x 2 0,08 x3 8
0,09 x1 3x 2 0,15 x3 9
0,04 x 0,08 x 4 x 20
1 2 3
Giải:
Hệ phương trình đã cho có dạng đường chéo trội, dễ dàng đưa về dạng
X= X . Trong đó:
0 0,06 0,02 2
0,03 0
0,05 ; 3
0,01 0,02 0 5
x
0,08 1 quá trình lặp hội tụ.
void main()
{
float b[max],x[max];
float a[max][max];
int i,j,k,n,dem,t1;
float t,s,d,w,epsi;
char tl;
clrscr();
printf("Cho so an so n = ");
scanf("%d",&n);
printf("Cho cac phan tu cua ma tran a : \n");
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Ma tran a ma ban da nhap\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%10.5f",a[i][j]);
printf("\n");
}
printf("\n");
227
t1=1;
flushall();
while (t1)
{
printf("Co sua ma tran a khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("Cho chi so cot can sua : ");
scanf("%d",&j);
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
flushall();
}
if (toupper(tl)=='K')
t1=0;
}
printf("Ma tran a\n");
printf("\n");
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
printf("%15.5f",a[i][j]);
printf("\n");
}
printf("\n");
printf("Cho cac phan tu cua ma tran b : \n");
for (i=1;i<=n;i++)
{
printf("b[%d] = ",i);
228
scanf("%f",&b[i]);
}
printf("\n");
printf("Ma tran b");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %10.5f\n",i,b[i]);
printf("\n");
t1=1;
flushall();
while (t1)
{
printf("Co sua ma tran b khong(c/k)?");
scanf("%c",&tl);
if (toupper(tl)=='C')
{
printf("Cho chi so hang can sua : ");
scanf("%d",&i);
printf("b[%d] = ",i);
scanf("%f",&b[i]);
flushall();
}
if (toupper(tl)=='K')
t1=0;
}
printf("\n");
printf("Ma tran b");
printf("\n");
for (i=1;i<=n;i++)
printf("b[%d] = %10.5f\n",i,b[i]);
printf("\n");
printf("Cho so lan lap k : ");
229
scanf("%d",&k);
printf("\n");
w=1;
epsi=1e-8;
for (i=1;i<=n;i++)
x[i]=0.0;
dem = 0;
do
{
dem=dem+1;
for (i=1;i<=n;i++)
{
s=0.0;
for (j=1;j<=n;j++)
s=s+a[i][j]*x[j];
d=x[i];
x[i]=(1-w)*d+w*(-s+a[i][i]*d+b[i])/a[i][i];
t=fabs(d-x[i]);
}
}
while ((dem<=k)&&(t>epsi*fabs(x[n])));
if (t<epsi*fabs(x[n]))
{
printf("Nghiem sau %d lan lap la :\n",dem);
for (i=1;i<=n;i++)
printf("x[%d] = %12.8f\n",i,x[i]);
}
else
{
printf("Khong dat do chinh xac sau %d lan lap\n",k);
printf("Nghiem cua lan lap cuoi cung la : \n");
230
for (i=1;i<=n;i++)
printf("x[%d] = %12.8f\n",i,x[i]);
}
getch();
}
Dùng Matlab
Xây dựng hàm:
function x = gausseidel(a, b, x0, kmax)
%Tim nghiem cua he AX = B bang cach lap Gauss–Seidel.
if nargin < 4
kmax = 100;
end
if nargin < 3
x0 = zeros(size(b));
kmax = 100;
end
na = size(a,1);
x = x0;
for k = 1: kmax
x(1, :) = (b(1, :) - a(1, 2:na)*x(2: na, :))/a(1,1);
for m = 2:na-1
tmp = b(m, :) - a(m, 1:m-1)*x(1: m - 1, :) - a(m, m + 1:na)*x(m + 1:na,:);
x(m, :) = tmp/a(m, m);
end
x(na, :) = (b(na,:) - a(na,1:na - 1)*x(1:na - 1,:))/a(na, na);
err = sqrt(x - x0)'*(x - x0);
if err < eps
break;
end
x0 = x;
end
if k == kmax
231
fprintf('Khong hoi tu sau %d lan lap',kmax);
else
fprintf('Hoi tu sau %d lan lap',k);
end
c. Phương pháp lặp với hệ số giảm dư SOR
Phương pháp SOR tương tự như các phương pháp Jacobi và Gauss-Seidel,
nhưng nó sử dụng hệ số tỉ lệ làm giảm nhanh chóng các sai số xấp xỉ. Ngược lại với
các phương pháp cổ điển đã được thảo luận trong phần trước, kỹ thuật SOR là một
sự cải tiến gần đây hơn.
Kỹ thuật SOR là một trong lớp các phương pháp giảm dư để tính toán xấp xỉ
x(k) theo công thức:
i 1 i
xi( k ) 1 xi( k 1) bi aij x j aij x j
(k ) ( k 1)
aii j 1 j i 1
Với ω là hệ số tỷ lệ.
Khi ω = 1, chúng ta có phương pháp Gauss-Seidel. Khi 0 < ω < 1, kỹ thuật này
được gọi là phương pháp giảm dư dưới và có thể được sử dụng để nhận được hội tụ
của một số hệ thống khi chúng không hội tụ theo phương pháp Gauss-Seidel.
Khi 1 < ω, các kỹ thuật này được gọi là các phương pháp giảm dư trên, được sử
dụng để gia tăng sự hội tụ cho các hệ thống sử dụng kỹ thuật lặp Gauss-Seidel. Những
phương pháp này được viết tắt là SOR (Successive Over-Relaxation) và được sử dụng
để tìm lời giải số của hệ đại tuyến.
Để xác định dạng ma trận của phương pháp SOR, chúng ta viết lại phương trình
trước đó như sau:
i 1 i
aii xi( k ) aij x(jk ) 1 aii xi( k 1) aij x(jk 1) bi
j 1 j i 1
Câu hỏi đặt ra là giá trị thích hợp của ω được chọn như thế nào. Mặc dù không
có câu trả lời đầy đủ cho câu hỏi này trong trường hợp tổng quát với hệ tuyến tính n×n,
kết quả sau đây có thể được sử dụng trong các tình huống nhất định.
Nếu A là một ma trận xác định dương và 0 < ω < 2, thì phương pháp SOR hội
tụ cho bất kỳ lựa chọn lời giải xấp xỉ ban đầu nào [vector x(0)].
233
Thêm vào, nếu A là ma trận 3 đường chéo, thì ρ(Tg) = [ρ(Tj )]2 < 1, và sự lựa
chọn tối ưu của ω cho phương pháp SOR là:
2
1 1 [ T j ]2
Điều này giải thích sự hội tụ nhanh chóng thu được trong ví dụ 1 bằng cách sử
dụng ω = 1.25.
d. Phương pháp gradient liên hợp (Conjugate gradient method)
Phương pháp gradient liên hợp của Hestenes và Stiefel [HS] đã được phát triển
như là một phương pháp nhằm thiết kế để giải hệ đại tuyến xác định dương (n x n)
phương trình.
Phương pháp này thường kém hơn phương pháp ước lượng Gauss, từ chỗ cả
hai phương pháp đều yêu cầu n bước chính để xác định lời giải và các bước của
phương pháp gradient liên hợp đòi hỏi nhiều phép tính hơn so với phương pháp ước
lượng Gauss.
Tuy nhiên, phương pháp gradient liên hợp là rất hữu ích khi sử dụng như là
phương pháp xấp xỉ để giải hệ ma trận thưa lớn và nó càng hiệu quả hơn nữa, nếu bài
234
toán là không dừng. Những bài toán này thường gặp ở các bài toán giá trị biên, ví dụ:
bài toán dự báo ngập lũ ở một vùng nào đó, hay bài toán tính kết cấu chịu tải trọng
động...
Để giải hệ phương trình: P(I, J) F(J) = G(I)
Giá trị ban đầu ước lượng là: F0(J), gây ra phần dư U(I), ta biểu diễn:
U(I) = G(I) - P(I, J) F
O (J) .
235
5.2.3. Hệ phương trình số phức
Giả sử ta có một hệ phương trình số phức có dạng AX = B, trong đó A = C + jD
, B = E + jF và X = Y + jZ . Ta viết lại phương trình dưới dạng sau:
(C + jD)(Y + jZ) = (E + jF)
Nhân biểu thức vế trái và cân bằng phần thực với phần thực và phần ảo với
phần ảo ta nhận được hệ mới:
CY - DZ = E
DY CZ = F
Như vậy chúng ta nhận được một hệ gồm 2n phương trình số thực. Giải hệ này
và kết hợp các phần thực và phần ảo ta nhận được nghiệm của hệ phương trình ban
đầu. Chương trình giải hệ phương trình số phức được xây dựng như sau:
void main()
{
int i,j,k,l,n,m;
float s,t,a[max][max],b[max][max],x[max];
clrscr();
printf("Cho so an so cua phuong trinh n = ");
scanf("%d",&n);
printf("Cho phan thuc cua cac he so,ke ca ve phai\n");
for (i=1;i<=n;i++)
for (j=1;j<=n+1;j++)
{
236
printf("a[%d][%d] = ",i,j);
scanf("%f",&a[i][j]);
}
printf("\n");
printf("Cho phan ao cua cac he so,ke ca ve phai\n");
for (i=1;i<=n;i++)
for (j=1;j<=n+1;j++)
{
printf("b[%d][%d] = ",i,j);
scanf("%f",&b[i][j]);
}
for (i=1;i<=n;i++)
a[i][2*n+1]=a[i][n+1];
for (i=n+1;i<=2*n;i++)
a[i][2*n+1]=b[i-n][n+1];
for (i=n+1;i<=2*n;i++)
for (j=1;j<=n;j++)
a[i][j]=b[i-n][j];
for (i=1;i<=n;i++)
for (j=n+1;j<=2*n;j++)
a[i][j]=-b[i][j-n];
for (i=n+1;i<=2*n;i++)
for (j=n+1;j<=2*n;j++)
a[i][j]=a[i-n][j-n];
m=2*n;
for (k=1;k<=m-1;k++)
{
s=0.0;
for (i=k;i<=m;i++)
{
t=fabs(a[i][k]);
if (s<=t)
237
{
s=t;
l=i;
}
}
for (j=k;j<=m+1;j++)
{
s=a[k][j];
a[k][j]=a[l][j];
a[l][j]=s;
}
if (fabs(a[k][k]/a[1][1])<=1e-08)
{
printf("Ma tran suy bien\n");
getch();
exit(1);
}
for (i=k+1;i<=m;i++)
{
s=a[i][k]/a[k][k];
a[i][k]=0.0;
for (j=k+1;j<=m+1;j++)
a[i][j]-=s*a[k][j];
}
}
x[m]=a[m][m+1]/a[m][m];
for (i=m-1;i>=1;i--)
{
s=a[i][m+1];
for (j=i+1;j<=m;j++)
s-=a[i][j]*x[j];
x[i]=s/a[i][i];
238
}
printf("\n");
printf("Nghiem phuc cua he\n");
for (i=1;i<=n;i++)
if (x[i+n]<0)
printf("%10.5f-%10.5fj\n",x[i],fabs(x[i+n]));
else
printf("%10.5f+%10.5fj\n",x[i],x[i+n]);
getch();
}
Áp dụng. Dùng chương trình này giải hệ phương trình:
(3 7 j ) x (2 4 j ) y (1 3 j ) z (4 2 j )r 8 36 j
(5 6 j ) x (2 5 j ) z (3 j )r 4 10 j
(4 5 j ) x (1 2 j ) y (5 j ) z 6r 13 3 j
(2 4 j ) x (1 j ) y (2 3 j )r 10 6 j
Câu hỏi:
1) Hãy cho ví dụ về bài toán nào đó trong thực tế kỹ thuật có ma trận thưa (dạng
BAND hay dạng bất kỳ) ?
2) Hãy trình bày một thuật toán lưu trữ tiết kiệm bộ nhớ trong máy tính và giải nó
khi ma trận thưa ?
3) Hãy cho một ví dụ cụ thể về ma trận A xác định dương ?
4) Hãy nêu ưu nhược điểm của các phương pháp giải hệ đại tuyến (trực tiếp và
lặp) ?
Bài tập:
1) Dùng phân tích LU để giải phương trình:
239
10 2 1 x1 27
3 6 2 x 61,5
2
1 1 5 x3 21,5
4) Giải hệ phương trình sau bằng phương pháp lặp đơn sao cho :
X k X k 1 là số đã cho trước.
10 x1 x2 x3 12
2 x1 10 x2 x3 13
2 x 2 x 10 x 14
1 2 3
Giải hệ phương trình bằng phương pháp lặp Gauss-Seidel. Cho biết nghiệm
đúng của hệ là (1, 1, 1).
6) Cho hệ phương trình :
240
Giải hệ phương trình bằng phương pháp lặp Gauss-Seidel. Cho biết nghiệm
đúng của hệ là (3, -2.5, 7).
7) Dùng phương pháp lặp Gauss-Seidel tìm nghiệm gần đúng của hệ phương
trình với sai số: 0, 05
10 x1 2 x2 1x3 27
3x1 6 x2 2 x3 6,15
x x 5 x 21,5
1 2 3
8) Tìm hai lần lặp đầu tiên theo phương pháp SOR với ω = 1.1 cho những hệ
tuyến tính, bằng cách sử dụng x(0) = 0:
3x1 x2 x3 1
a. 3x1 6 x2 2 x3 0
3x 3x 7 x 4
1 2 3
4 x1 x2 x3 x5 6
x 3x x x 6
1 2 3 4
b. 2 x1 x2 5 x3 x4 x5 6
x x x 4 x 6
1 2 3 4
2 x2 x3 x4 4 x5 6
4 x1 1x2 x3 12
1x1 4 x2 2 x3 1
x 2x 4x 5
1 2 3
Giải hệ phương trình bằng phương pháp gradient liên hợp. Biết nghiệm đúng
của hệ là (3, 1, 1).
Đáp số:
x1 0,9618359
2) a) x 2 3,9448436
x 2,9398827
3
x1 0,9922021
b) x 2 3,9937418
x 2,9964857
3
241
x1 0,9444
x 2 1,1743 X k X k 1 0,5.10
-4
3)
x 1,1775
3
4) X = (2.0, 2.5, 3)
x1 0,9992
5) x2 1, 00536
x 0.999098
3
x1 2,99997
6) x2 0,99999
x 0.99999
3
242
Chương 6 NGHIỆM GẦN ĐÚNG CỦA HỆ
PHƯƠNG TRÌNH VI PHÂN THƯỜNG
SOLVING THE ORDINARY DIFFERENTIAL EQUATIONS
6.1. Mở đầu
Nhiều bài toán khoa học kỹ thuật có phương trình chỉ đạo là (hệ) phương trình vi
phân thường cùng với điều kiện biên và điều kiện ban đầu. Nghiệm đúng của chúng
thường chỉ áp dụng cho một số lớp bài toán rất hạn chế; đa số các bài toán là phải tìm
nghiệm gần đúng.
Có hai loại bài toán là:
(i) Bài toán Cauchy hay còn gọi là bài toán giá trị ban đầu, bao gồm (hệ) phương
trình vi phân và điền kiện ban đầu của bài toán.
(ii) Bài toán biên, bao gồm (hệ) phương trình vi phân và điều kiện biên để giải gần
đúng các bài toán này có hai phương pháp là:
- Phương pháp giải tích: Tìm nghiệm gần đúng dưới dạng biểu thức như
phương pháp xấp xỉ liên tiếp Picard, phương pháp chuỗi nguyên, phương
pháp tham số bé,…
- Phương pháp số: Tìm nghiệm gần đúng bằng số tại các điểm rời rạc; nó còn
chia ra phương pháp một bước (như phương pháp Euler, Runghe-Kutta,…)
và phương pháp đa bước (Adams,…). Với phương pháp một bước tính
nghiệm gần đúng yi thông qua yi-1 còn với phương pháp đa bước yi tính được
thông qua nhiều bước trước đó: yi-1, yi-2, yi-3,…
6.2. Nghiệm gần đúng của bài toán Cauchy đối với phương trình vi phân thường
y ' f ( x, y )
Giả sử ta cần giải bài toán Cauchy: (6.1)
y ( x0 ) y0
Giả sử rằng trong miền ta xét, hàm f(x, y) có các đạo hàm riêng liên tục đến cấp n,
khi đó nghiệm cần tìm sẽ có các đạo hàm riêng liên tục đến cấp n + 1, và do đó ta có thể
viết:
243
y0 y ( x0 ) y0 ( x x0 ) y ,o
( x x0 )2 ( x x0 ) n 1 ( n 1) n 1
y "0 ...... y0 ( x x0 ) (6.2)
2! (n 1)!
Ký hiệu x - x0 = h, với h đủ bé ta có thể bỏ qua 0(x – x0n+1).
Từ (6.2) ta có:
( x x0 ) n1
h2 h n 1 ( n 1)
y0 = y(x0+h) - y0 + hy’0 + y" .......... y0 (6.3)
(n 1)!
0
2!
Để tính (6.3) ta lần lượt tính từ (6.1):
f 0 f
y’0 = f(x0, y0) = f0 , y”0 = f0 0 ,
x y
m
n
mu
Nói chung ta có: f u Cm f
K K
x y K 0 x m K y K
n
hK
Vậy ta tính được: y(x) y
K 0
(K )
( x0 )
K!
Trong thực tế cách tính này ít dùng vì cồng kềnh, ta sẽ xét các phương pháp giải
khác đơn giản hơn.
f
Giả sử f(x, y) là hàm liên tục theo x, y và < K.
y
Để tìm xấp xỉ liên tiếp, trong (6.4) thay y bằng y0, ta có xấp xỉ thứ nhất:
244
x
y1 y0 f (t , y0 )dt ,
x0
lim y n ( x ) y( x )
n
M ( KC ) n
Sai số: yn ( x) y( x) , trong đó f (x, y ) = M
K .n!
b
Với: x x 0 < a , y y 0 < b , thì C = min a ,
M
Ta có:
f
(i) > 0 và f(x, y0) > 0 thì: y0 < y1 < y2 < . . . < yn < y(x)
y
f
(ii) > 0 và f(x, y0) < 0 thì: y0 > y1 > y2 > . . . > yn > y(x)
y
Trong hai trường hợp này ta có dãy xấp xỉ 1 phía.
f
(iii) < 0 các xấp xỉ Pica lập thành các xấp xỉ 2 phía.
y
Ứng dụng lập trình
Dùng Matlab
Xây dựng hàm:
function g = picard(f, y0, maxiter)
syms x y
g = subs(f, y0);
245
g = int(g, x);
for i = 1:maxiter
g = subs(f, g);
g = int(g, x);
end
g = sort(g);
Ví dụ. Tìm 2 nghiệm xấp xỉ liên tiếp theo phương pháp Pica của phương trình vi phân:
y’ = x 2 + y2 cho y(0) = 0
6.2.2. Phương pháp Euler
y
y=f(x)
A3
A2
A1
` Ao
x
O xo x1 x2 x3
y(ci )
y(x) y(xi ) y(x i ).(x - x i ) ( x xi ) 2
2!
Với: ci = xi + (x - xi), 0 < < 1
Thay x = xi+1 = xi + h, và y’(xi) = f(xi, y(xi))
y (ci )
Ta có: y(xi 1 ) y(xi ) h.f(x i , y(xi )) h .
2
2!
246
Khi bước chia h khá bé, số hạng cuối 0, khi thay y(xi) bằng ui ta được:
ui+1 = ui + hi.f(xi,ui)
Biểu thức này cho phép tính ui+1 khi biết ui, với điều kiện ban đầu được cho là: uo =
Đánh giá sai số:
f
Định lý: Giả sử L và y '' K , trong đó L, K là những hằng số, khi đó phương
y
pháp Euler hội tụ và sai số là ei = ui - y(xi) có đánh giá:
ei ui y ( xi ) M ( e0 h)
K
M e L ( xi x 0 ) ,
2
Ứng dụng lập trình
(i) Dùng C++
//pp_Euler;
#include <conio.h>
#include <stdio.h>
#include <math.h>
void main()
{
int i,n;
float a,b,t,z,h,x0,y0,c1,c2;
float x[100],y[100];
247
clrscr();
printf("Cho can duoi a = ");
scanf("%f",&a);
printf("Cho can tren b = ");
scanf("%f",&b);
printf("Cho so buoc tinh n = ");
scanf("%d",&n);
printf("Cho so kien x0 = ");
scanf("%f",&x0);
printf("Cho so kien y0 = ");
scanf("%f",&y0);
printf("\n");
printf("Bang ket qua\n");
printf("\n");
printf("Phuong phap Euler\n");
h=(b-a)/n;
x[1]=x0;
y[1]=y0;
printf(" x y");
printf("\n");
for (i=1;i<=n+1;i++)
{
x[i+1]=x[i]+h;
y[i+1]=y[i]+h*f(x[i],y[i]);
printf("%3.2f%16.3f",x[i],y[i]);
printf("\n");
}
printf("\n");
getch();
printf("Phuong phap Euler cai tien\n");
248
printf(" x y");
printf("\n");
for (i=1;i<=n+1;i++)
{
x[i+1]=x[i]+h;
c1=h*f(x[i],y[i]);
c2=h*f(x[i]+h,y[i]+c1);
y[i+1]=y[i]+(c1+c2)/2;
printf("%3.2f%15.5f",x[i],y[i]);
printf("\n");
}
getch();
}
function dy = f1(t, y)
dy = zeros(3, 1);
dy(1) = y(2) * y(3);
dy(2) = -y(1) * y(3);
dy(3) = -0.51 * y(1) * y(2);
250
6.2.3. Phương pháp Runghe - Kutta bậc 4
Xét bài toán Cauchy (6.1). Giả sử ta đã tìm được giá trị gần đúng yi của y(xi) và
muốn tính yi+1 của y(xi+1). Trước hết ta viết công thức Taylor:
h2 hm ( m) hm 1 ( m 1)
y( xi 1 ) y( xi ) hy( xi ) y( xi ) y ( xi ) y (c ) (6.5)
2 m! m!
Với c (xi, xi+1) và:
y( xi ) f xi , y( xi )
d k 1
y ( k ) ( xi ) f xi , y ( xi )
dx k 1
Ta viết lại (6.5) dưới dạng:
h2 hm ( m) hm 1 ( m 1)
yi 1 yi hy( xi ) y( xi ) y ( xi ) y (c ) (6.6)
2 m! m!
Ta đã kéo dài khai triển Taylor để kết quả chính xác hơn. Để tính yi, yi v.v… ta
có thể dùng phương pháp Runge-Kutta bằng cách đặt:
yi 1 yi r1k1(i ) r2k2(i ) r3k3(i ) r4k4(i ) (6.7)
Trong đó:
k1(i ) hf ( xi , yi )
(i )
k2 hf ( xi ah, yi k1 )
(i )
(i ) (6.8)
k3 hf ( xi bh, yi k1 k2 )
(i ) (i )
.......
Và ta cần xác định các hệ số a, b,..; , , ,...; r1, r2,.. sao cho vế phải của (6.7) khác
với vế phải của (6.6) một vô cùng bé cấp cao nhất có thể có đối với h.
Khi dùng công thức Runge-Kutta bậc hai ta có:
k1 hf ( xi , yi )
(i )
(i ) (6.9)
k2 hf ( xi ah, yi k1 )
(i )
................
251
Do đó vế phải của (6.6) là:
hf ( xi , yi )
h2
2
f x( xi , yi ) f y( xi , yi ) y( x) (6.11)
Bây giờ cho (6.11) và (6.12) khác nhau một vô cùng bé cấp O(h3) ta tìm được các
hệ số chưa biết khi cân bằng các số hạng chứa h và chứa h2:
r1 + r2 = 1
a.r1 = 1/ 2
.r2 = 1
Như vậy: = a, r1 = (2a - 1)/ 2a, r2 = 1/ 2a với a được chọn bất kì.
Nếu a = 1/2 thì r1 = 0 và r2 = 1. Lúc này ta nhận được công thức Euler. Nếu a = 1
thì r1 = 1/2 và r2 = 1/2. Lúc này ta nhận được công thức Euler cải tiến.
Một cách tương tự chúng ta nhận được công thức Runge-Kutta bậc 4. Công thức
này hay được dùng trong tính toán thực tế vì độ chính xác cao và thuật toán không phức
tạp:
k1 = h.f(xi, yi)
k2 = h.f(xi+h/ 2, yi + k1/ 2)
k3 = h.f(xi+h/ 2, yi + k2/ 2)
k4 = h.f(xi+h, yi + k3)
yi+1 = yi + (k1 + 2k2 + 2k3 + k4) / 6
Ví dụ 1. Cho phương trình vi phân
y
y’ = y 2
x
y(1) = 1, h = 0.2. Tính trong khoảng [1, 1.4] Runge- Kuta.
y
f(x, y) = y2
x
252
i x y k=hf(x,y) y
0 1 1 0 0
1,1 1 -0,018 -0,036
1,1 0,991 -0,0186 -0,162
1,2 0,984 -0,039 -0,079
1
y1 = y0 + (k1+2k2 +2k3+k4)
6
1
= 1+ (0+2(-0.018)+2(-0,081)-0,079 = 0,954
6
i x y k=hf(x,y) y
1
y2 = y1 + (k1+2k2 +2k3+k4)
6
1
= 0,954+ (-0,058+2(-0,02)+2(-0,032)+(-0,042)
6
Ứng dụng lập trình
(i) Bằng C++
//Phuong phap Runge_Kutta;
#include <conio.h>
#include <stdio.h>
#include <math.h>
#define k 10
void main()
{
float a,b,k1,k2,k3,k4;
int i,n;
float x0,y0,h,e;
float x[k],y[k];
clrscr();
printf("Phuong phap Runge - Kutta\n");
printf("Cho can duoi a = ");
scanf("%f",&a);
printf("Cho can tren b = ");
scanf("%f",&b);
printf("Cho so kien y0 = ");
scanf("%f",&y[0]);
printf("Cho buoc tinh h = ");
scanf("%f",&h);
n=(int)((b-a)/h);
printf(" x y\n");
for (i=0;i<=n+1;i++)
{
x[i]=a+i*h;
k1=h*f(x[i],y[i]);
k2=h*f((x[i]+h/2),(y[i]+k1/2));
k3=h*f((x[i]+h/2),(y[i]+k2/2));
k4=h*f((x[i]+h),(y[i]+k3));
y[i+1]=y[i]+(k1+2*k2+2*k3+k4)/6;
printf("%12.1f%16.4f\n",x[i],y[i]);
254
}
getch();
}
255
for k = 1:n
f1 = h*feval(f, x(k));
f1 = f1(:)';
f2 = h*feval(f, x(k) + h/2);
f2 = f2(:)';
f3 = h*feval(f, x(k) + h/2);
f3 = f3(:)';
f4 = h*feval(f, x(k) + h);
f4 = f4(:)';
y(k+1, :) = y(k, :) + (f1 + 2*(f2 + f3) + f4)/6;
end
end
Áp dụng. Giải phương trình y’= x + y 0 x 1 , y(0) = 0.5, h = 0.1
Bằng phương pháp Runghe - Kutta
Ta dùng chương trình :
clear all, clc
a = 0;
b = 1;
y = inline('x + y');
ya = 0.5;
n = 10;%so lan tinh chi n = 10
[x, y] = rungekutta(y, a, b, ya, n)
plot(x, y);
6.2.4. Phương pháp Adam
Giả sử cần giải phương trình vi phân:
Y’ = f(x, y), với điều kiện ban đầu: y(x0) = y0
Cho biến số thay đổi bởi bước h nào đó, xuất phát từ điều kiện ban đầu Y(x0) = Y0
bằng phương pháp nào đó (ví dụ: phương pháp Runghe-Kutta bậc 4), ta tìm được 3 giá
trị tiếp theo của hàm cần tìm y(x): Y1 = Y(x1) = Y(x0+h), Y2 = Y(x0+2h), Y3 = Y(x0 + 3h).
Nhờ các giá trị x0, x1, x2, x3 và Y0, Y1, Y2, Y3 ta tính được q0, q1, q2, q3.
256
Trong đó: q0 = h.Y0’ = h.f(x0, y0), q1 = h.f(x1, y1), q2 = h.f(x2, y2), q3 = h.f(x3 , y3),
sau đó ta lập bảng sai phân hữu hạn của các đại lượng y và q
Biết các số ở đường chéo dưới, ta tìm y3 theo công thức Adam như sau:
1 5 3
y3 q3 .q2 .2 q1 .3 .q0
2 12 8
Tiếp đó ta có:
Y4 = Y3 + Y3 q4 = h.f(x4, Y4)
Sau đó viết đường chéo tiếp theo như sau:
q3 = q4 - q3 , 2q2= q3 - q2 , 3q1 = 2.q2 - 2.q
Đường chéo mới cho phép ta tính Y4 :
Y4 = q4 + 1/2q3 + 5/122q2 + 3/83q1
Vì vậy ta có: Y5 = Y4 + Y4 . . . . .
Ví dụ. Giải lại ví dụ 1 bằng phương pháp Adam
. Tìm x4 = 1,8 y4 =?
x5 = 2,0 y5 = ?
257
x y y q q 2 q 3q
1 1 0
-0,016 -0,030
1,2 0,984 -0,030 0,016
-0,038 -0,014 -0,008
1,4 0,946 -0,044 0,008
-0,046 -0,006 -0,001
1,6 0,900 -0,05 0,007
-0,053 0,001 0,388
1,8 0,847 -0,049 0,395
-0,02 0,396
2 0,827 0,347
1 5 3
y3 =q3 + q2 + 2 q1 + 3q0 =-0,050+1/2.(-0,006)+5/12.(0,008)+3/8.(-0,008)
2 12 8
1 5 3
y4 =q4 + q3 + 2 q2 + 3q1 =-0,049+1/2.0,001+5/12.0,07+3/8.(-0,001)= -0,02
2 12 8
Câu hỏi:
1) Hãy cho ví dụ cụ thể về bài toán phương trình vi phân thường: Bài toán Cauchy
(hay còn gọi là bài toán giá trị ban đầu) và bài toán biên ?
2) Tại sao phương pháp Pica được gọi là phương pháp giải tích gần đúng ?
3) Tại sao phương pháp Euler cho sai số lớn, nhưng các sách về phương pháp tính
đều phải đưa phương pháp này vào ?
4) Tại sao các sách về phương pháp tính thường trình bày phương pháp Runghe –
Kutta bậc 4 để giải phương trình vi phân thường mà không trình bày phương pháp
này có bậc cao hơn hoặc thấp hơn (bậc 3, bậc 5… ) ?
5) Tại sao phương pháp Adam được gọi là phương pháp đa bước ?
258
Bài tập:
1) Tìm nghiệm gần đúng của phương trình y’ = x + y2 thỏa mãn điều kiện ban đầu
y(0) =1, bằng phương pháp xấp xỉ liên tiếp pica (đến xấp xỉ thứ hai)
2) Tìm nghiệm đúng của bài toán vi phân y’ = x + y, y(0) = 0 trên miền x 0 bằng
phương pháp dãy pica.
3) Tìm nghiệm gần đúng của phương trình y’ = 2xycos(x2) thỏa mãn điều kiện
y(0) = 1 bằng phương pháp dãy pica.
4) Bằng phương pháp ơle (công thức ơle), tìm nghiệm gần đúng của bài toán côsi
y’(y + x) = y – x, y’(0) =1, lấy h = 0.1 (tìm bốn giá trị đầu tiên của y).
5) Tìm nghiệm gần đúng của bài toán côsi
( x y )(1 xy )
y’ y(0) =1 trên [0, 1] bằng công thức ơle, lấy h = 0.2.
x 2y
y(0) =1 bằng công thức dạng Runghe-Kutta bậc 4 trên đoạn [0, 1] với h = 0.2 (Tính hai
giá trị y1 = y(0,2), y2 = y(0.4). So sánh với nghiệm đúng y = 2 x 1 .
8) Bằng phương pháp Runghe-Kutta bặc 4 tìm nghiệm gần đúng của bài toán côsi.
x
y’ = + 0.5y, y(0) = 1 lấy với h = 0.1; Tính y(0.5).
y
259
Đáp số:
1) Chọn xấp xỉ đầu y0 = y(0) = 1
x2
Xấp xỉ thứ nhất y1 = 1 + x +
2
3 2 2 3 1 4 1 5
Xấp xỉ thứ 2 y2 = 1 + x + x + x + x + x
2 3 4 20
2) Chọn xấp xỉ đầu y0 = y(0) = 0, được dãy pica. Dãy đó hội tụ tới nghiệm đúng
n
x k 1
của bài toán: y = ex – x - 1 và yn(x) =
k 1 ( k 1)!
n
sin k ( x 2 )
3) yn(x) =
2
; nghiệm đúng y(x) = e sin(x ) .
k 1 k!
7) x 0 0,2 0,4
260
Chương 7 GIẢI GẦN ĐÚNG PHƯƠNG TRÌNH ĐẠO HÀM RIÊNG
BẰNG PHƯƠNG PHÁP SỐ
NUMERICAL METHOD FOR PARTIAL DIFFERENTIAL EQUATIONS
Các hiện tượng vật lý trong tự nhiên thường rất phức tạp, nên thường phải mô
tả bằng các phương trình đạo hàm riêng. Mỗi loại phương trình đạo hàm riêng (PDF)
thường đòi hỏi các điều kiện biên tương ứng để bài toán có nghiệm tốt, phù hợp với
hiện tượng vật lý quan sát.
7.1. Phân loại phương trình đạo hàm riêng bậc 2
Xét một phương trình đạo hàm riêng (PDE) bậc 2 với hai biến độc lập x, y
2u 2u 2u u u
A 2 B C 2 D E Fu g ( x, y)
x xy y x y
Chuyển tất cả các số hạng khác đạo hàm bậc hai về vế trái, ta có:
Au,xx + Bu,xy + Cu,yy = Ƒ (7.1)
Ở đây dấu ',' chỉ số dưới chỉ đạo hàm riêng. Dạng tuyến tính hoặc phi tuyến
của phương trình (7.1) phụ thuộc vào các hệ số A, B, C, và Ƒ.
Phương trình tuyến tính:
Nếu A, B, C là các hàm số chỉ của x và y, và Ƒ là một hàm tuyến tính theo u,
u, x, u,y, khi đó phương trình (7.1) được gọi là phương trình tuyến tính. Trong trường
hợp này, phương trình (7.1) có thể được viết như sau:
Au,xx + Bu,xy + Cu,yy = -Du,x - Eu,y - Fu + g (7.2)
Trong đó A, B, C, D, E, F và g là các hàm theo biến x và y
Phương trình phi tuyến: Tùy thuộc vào các dạng của A, B, C và Ƒ, Eq. (7.1)
có thể được phân loại thêm để chỉ ra bậc phi tuyến.
- Á tuyến tính: Nếu A, B và C là các hàm chỉ của x và y, và Ƒ là hàm (có thể
không phải là một hàm tuyến tính) của x, y, u, u,x, u,y như Ƒ = Ƒ (x, y, u , u,x , u y),
phương trình (7.1) được gọi là phương trình á tuyến tính hoặc phương trình nửa tuyến
tính.
- Tựa tuyến tính: Nếu A, B, C và d là các hàm của x, y, u, u,x, u,y, thì phương
trình (7.1) được gọi là phương trình tựa tuyến tính.
Phi tuyến (hoàn toàn): Nếu phương trình (7.1) khác hơn so với phương trình
tuyến tính, á tuyến tính hoặc tựa tuyến tính, nó được gọi là phương trình phi tuyến.
261
7.1.1. Phân loại phương trình đạo hàm riêng bậc 2 tuyến tính
Ở đây, chúng ta chỉ thảo luận việc phân loại phương trình đạo hàm riêng bậc 2
tuyến tính với hai biến độc lập. Chúng ta muốn nghiên cứu phân loại phương trình đạo
hàm riêng, bởi vì:
- Có một số khác biệt cơ bản trong các lời giải của từng loại khác nhau của các
phương trình.
- Tùy thuộc vào loại phương trình, chỉ có một số dạng bài toán (như loại có giá
trị ban đầu, các loại giá trị biên, hoặc các loại giá trị biên - ban đầu) có thể có các giải
pháp hay cách đặt bài toán tốt.
- Nó cũng giúp chuyển đổi một phương trình đạo hàm riêng tuyến tính bậc 2
(với hai biến độc lập) về các dạng chính tắc, điều này rất tiện lợi trong phương pháp
giải số.
Từ dạng tổng quát:
2u 2u 2u u u
A B C D E Fu g ( x, y) (7.3)
x 2
xy y 2
x y
Phân loại với chú ý các đạo hàm bậc cao, khi đó (7.3) được viết lại:
2u 2u 2u
A B C f u x , u y , u, x, y (7.4)
x 2 xy y 2
Đơn giản (7.4) bằng cách đổi biến số: = (x, y) , = (x, y)
Đặt: = x + y , = x + y
u u u u u
Hay: x x
x x x y
Tương tự cho các đạo hàm khác ta được:
u 2u u
( A C B ) [2 A 2C B( )]
2 2
( A 2 C 2 B ) = f (7.5)
Một cách đơn giản để tìm lời giải của phương trình này, là chọn , sao cho số
hạng thứ nhất và thứ ba trong phương trình (7.5) triệt tiêu:
A B C 0
2 2
2
A B C 0
2
262
Giả sử: 0, 0 ta có:
A(/)2 + B(/) + C = 0, A(/)2 + B(/) + C = 0 (7.6)
1
2 A ( B B 4 AC )
2
1 ( B B 2 4 AC )
2 A
- Trường hợp 2
263
2 u2 2 u2
x 2 y 2 0
u2 x, 0 0 y ≥ 0,−∞ < x < ∞ (7.8)
u
2 x, 0 sin nx
y x
Hai bài toán trên có u1 ≡ 0 và u2 = sin(nx) sinh (ny) / n2 là lời giải tương ứng.
Những lời giải này có thể dễ dàng được kiểm tra bởi một sự thay thế trực tiếp vào PDE
tương ứng và các điều kiện ban đầu. Với n rất lớn, các điều kiện ban đầu của bài toán
thứ hai chỉ khác chút ít so với điều kiện ban đầu của bài toán thứ nhất, nhưng các lời
giải của hai bài toán có sự khác nhau khá nhiều, nghĩa là các lời giải của hai bài toán
này là không tốt.
c. Phương trình Parabol (B2 - 4AC = 0)
2u u
Phương trình nhiệt 1 chiều 2 (còn gọi là phương trình khuếch tán) là
x t
một ví dụ điển hình của PDE parabol.
7.1.2. Những lưu ý về phương trình đạo hàm riêng
Cần lưu ý, việc phân loại các PDE chỉ là một cách phân loại cục bộ. Chúng ta
xem xét, như là một ví dụ, phương trình Tricomi.
2 u2 2 u2
y 0 (7.9)
x 2 y 2
264
Trong lĩnh vực kỹ thuật có ba bài toán biên: bài toán biên Dirichlet, bài toán biên
Neumann, bài toán biên hổn hợp.
u = f(v)
u
f ( v)
n
Nếu f(v) = 0 ta có bài toán Neumann thuần nhất. Để cho bài toán Neumann có
nghiệm duy nhất ta phải đặt thêm điều kiện g(1) nào đó. Điều kiện biên Neumann còn
gọi là điều kiện biên tự nhiên (natural boundary conditions).
0
Với bài toán hổn hợp (mixed boundary conditions)
Trong thực tế kỹ thuật, người ta thường hay gặp điều kiện biên hỗn hợp này.
Trên thực tế việc tìm nghiệm chính xác của các bài toán biên nói trên là vô cùng
khó khăn, toán học hiện nay chỉ cho phép giải các bài toán đó trong một số trường hợp
thật đơn giản, còn phần lớn là phải giải theo các phương pháp gần đúng khác nhau.
Tư tưởng của các phương pháp gần đúng (approximation methods) là xấp xỉ
không gian vô hạn chiều của nghiệm bằng một không gian con hữu hạn chiều.
a0
u ( x) (an cos nx bn sin nx)
2 n 1
u ( x) an .n ( x)
n 0
Nghiệm chính xác của bài toán có thể biểu diễn bằng các dạng sau:
u(x) = a0 + a1x + a2x2 + a3x3 +.. ..+ anxn +.. .. (7.10)
Rõ ràng nghiệm chính xác u(x) có thể xem như là một hàm của vô hạn các hệ số:
Trong khi đó giải theo các phương pháp gần đúng ta chỉ có thể tìm được
nghiệm uh của nó như là hàm của một dãy hữu hạn các hệ số a0, a1, a2, .. ..,an nào đó
mà thôi.
Trong chương này ta sẽ nghiên cứu một số phương pháp số mạnh, thường sử
dụng để giải các bài toán cơ học:
266
7.4. Phương pháp đặc trưng
Nội dung của phương pháp đặc trưng là biến đổi phương trình vi phân đạo hàm
riêng về hệ phương trình vi phân thường, và tìm lời giải bài toán ở hệ phương trình vi
phân thường này, từ đó ta dễ dàng thấy được bản chất vật lý của hiện tượng nghiên
cứu.
2u 1 2u
Ví dụ. Xét phương trình truyền sóng : (7.11)
x 2 c 2 t 2
v u 2v 2u
Ta đặt hàm v(x, t) sao cho: (7.12)
x t xt t 2
v u
Vì :
t x t t
1 2u 2u 1 2v 2u
Từ (7.11) ta có: 0 2 0
c 2 t 2 x 2 c tx x 2
1 v u
Và đặt: f (t)
c 2 t x
Đi đến hệ thống:
v u v v
x t 0 1 0 x 0 1 0
u 1 t
1 v u
c 2 0 u
f (t)
0 1
c 2 t x x t f (t )
1 0 0 1
Đặt A= , B= 1
0 1 c 2 0
Phương trình đặc trưng được suy từ:
1 1 1
det(A - B) = 0 1
0 2 = 2
c2
c c
dx x ct a
Từ đó ta có đường cong đặc trưng: c
dt x ct b
7.5. Phương pháp sai phân
Dựa trên khai triển Taylor, một cách gần đúng ta thay các tỉ vi phân bằng tỉ sai
phân.
c
Ví dụ. Tìm đạo hàm
x x
267
c x 2 2 c
Ta có: C(x + x) = C(x) + x .....
2! x 2 x
(7.13)
x x
C C( x x ) C( x ) x 2 C
......
x x x 2 x 2 x
c x c
2 2
c C( x x ) C( x x ) x 3 3C
......
x x 2x 3! x 3 x
Có thể khai triển:
c x 2 C
2
2C C ( x x) 2C ( x) C ( x x)
0(x 2 ) (7.16)
x x
2
x 2
2 2
Áp dụng các sai phân này vào giải phương trình Laplace: 0
x 2 y 2
x i X
Chọn : (7.17)
y i Y
Thay (7.16) vào (7.17), được:
i1, j 2ij i1, j i , j1 2ij 1, j1
0
X 2 Y 2
268
t i,j+1 i+1,j+1
yj+
∆y
1
yj
yj-1
i,j ∆x i+1,j
xi-1 xi xi-1 x
7.5.1. Sơ đồ hiện – Sơ đồ ẩn
(Explicit - Implicit Scheme)
2 2 S
Time
Xét phương trình:
x 2 y 2 T t
K 1 K t+1 k 1i , j
Sai phân tiến: t t t .K t
K K 1 t k i ,j
Sai phân lùi: t t t .K t y
Ở đây (t)K = t = const t-1 k 1i , j
x
T= (t ) j ,
K t K.t
K
- Sai phân tiến theo thời gian t của phương trình trên, ta được:
iK1, j 2iK, j iK1, j iK, j1 2iK, j iK, j1 S iK, j1 iK, j
(x )2 (y )2 T t
Từ phương trình này ta tìm được ngay iK, j1 khi biết các iK1, j ,
iK, j iK j , j iK, j 1 iK, j 1 nên gọi là sơ đồ hiện.
269
t
k+1
∆x ∆x x
iK1,1j 2iK, j1 iK1,1j iK, j11 2iK, j1 iK, j11 S i , j i , j
K 1 K
.
(x)2 (y) 2 T t
Phương trình trên có 5 ẩn số trong 1 phương trình nên phải thiết lập các phương
trình cho tất cả các nút khác bên trong miền bài toán và giải đồng thời các hệ phương
trình này, thì mới tìm được các ẩn của bài toán ở bước thời gian (t + 1), nên ta gọi sơ
đồ này là sơ đồ ẩn.
k+1
∆x ∆x x
Phương trình (còn gọi là lược đồ) (7.19) nhận được từ khai triển Taylor của
(7.18) hoặc bằng một lược đồ khác, ta thử xem lược đồ (7.19) có nhất quán với
phương trình vi phân (7.18) hay không ?
Từ khai triển Taylor ta được:
z 2 z t 2 3z t 3
z z t 2
n 1 n
...... t
t t 2! t 3 3!
j j
Đặt r
z (x ) 2 z x 2 3z x 3 x
z j 1 z j
n n
2 3 ......
x 1! x 2! x 3!
Thay tất cả vào (7.19), ta được:
z 2 z t 2 3 z t 3 z x 2 z x 2
z t 2
n
... (1 r ) z j r ( z j
n n
... (7.20)
t t 2! t 3 3! x 1! x 2 2!
j
x 1
Nhân 2 vế của (7.20) với rồi chuyển vế, rồi nhân tiếp 2 vế với ta được:
t t
z z 2z t 2z x
2 ...... 2 ... (7.21)
t x t 2! x 2!
Khi x, t 0, vế phải của (7.21) 0, do đó ta thấy phương trình (7.21)
(7.18)
Ta nói: “Một lược đồ sai phân được gọi là ổn định, nếu tập hợp vô hạn các
nghiệm tính được là bị chặn đều, ngược lại gọi là không ổn định”.
Như vậy sự ổn định của lược đồ sai phân không liên quan đến phương trình vi
phân (chỉ là riêng của lược đồ).
271
Vậy thì: znj1 A zn B zn ( A B). zn znj
D = 0,0.6 0,0.3 biết giá trị của hàm u(x, y) trên biên là u(x, y) = x + 3y với bước
272
Ta cần tính giá trị của hàm u tại 4 điểm là (1, 1), (1, 2), (2, 1), (2, 2). Hàm
f(x, y) = xy2 nên f11 = 0.002, f12 = 0.008, f21=0.004, f22 = 0.016. Ta có hệ 4 phương
trình đại số tuyến tính là:
u 21 2u11 u 01 u12 2u11 u10
0,002
0,2 2 0,12
2u u i 1, j 2u i , j u i 1, j
2
x i , j h2
u ui , j 1 ui , j
(Sai phân tiến)
t i , j l
Thế vào phương trình đạo hàm riêng ta áp dụng sai phân tiến sơ đồ hiện:
ui , j 1 ui , j ui1, j 2ui , j ui1, j
l h2
Đặt l / h 2 thế vào trên ta có phương trình:
ui , j 1 (1 2 )ui , j (ui1, j ui1, j )
1
(Điều kiện lược đồ sai phân ổn định khi 0 )
2
273
1
Với h = 0.1 và l = 0.005 thì ta có
2
ui1, j ui 1, j
Thế vào ta có ui , j 1
2
x
j 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
t
0 0 0 0.343 0.672 0.970 1.214 1.375 1.423 1.326 1.060 0.615 0
1 0.005 0 0.336 0.657 0.943 1.173 1.318 1.350 1.242 0.971 0.530 0
2 0.01 0 0.328 0.640 0.915 1.131 1.261 1.280 1.161 0.886 0.485 0
3 0.015 0 0.320 0.621 0.885 1.088 1.205 1.211 1.083 0.823 0.443 0
4 0.02 0 0.311 0.602 0.855 1.045 1.150 1.144 1.017 0.763 0.411 0
Ví dụ 3. Giải gần đúng phương trình đạo hàm riêng dạng Hyperbolic.
2u 2 u
2
a
x 2 t 2
Thế đạo hàm phương trình đạo hàm riêng bằng tỷ sai phân:
ui 1, j 2ui , j ui 1, j ui , j 1 2ui , j ui , j 1
2
a2
h l2
2
2
2
2 1
2
Thế = l/h =1/2 và a =1, u’t(x, 0) = 0 vào phương trình (7.24) ta được:
3 1
ui ,1 ui ,0 (ui 1,0 ui 1,0 ) (7.25)
4 8
Với phương pháp biến phân người ta tìm lời giải xấp xỉ trên toàn miền bài toán,
do đó hàm xấp xỉ trên toàn miền bài toán thường là rất khó xây dựng, phương pháp
phần tử hữu hạn (PTHH - The finite element method) khắc phục nhược điểm này là
chia miền bài toán thành nhiều miền con và tìm hàm xấp xỉ trên miền con, còn gọi là
phần tử (element) với thỏa mãn điều kiện cân bằng và liên tục giữa các phần tử. Trong
phương pháp PTHH thường dựa trên các phương pháp biến phân RAYLEIGH –
RITZ và GALERKIN.
275
7.6.1. Phương pháp biến phân RAYLEIGH - RITZ
Bài toán [phương trình đạo hàm riêng] Bài toán [biến phân]
Với cực tiểu phiếm hàm và thoả mãn điều kiện trên biên F = G(s).
Giả sử ta có F(x, y) đi tìm I(F) cực trị, ta biểu diển hàm F(x, y) như sau:
n
Các Ci phải xác định sao cho I(Fn) đạt cực trị.
Hàm i (x, y) được chọn trước sao cho thỏa điều kiện biên. Như vậy:
Các hệ số Ci được xác định từ 0 , i = 1, 2, 3, . . ., n.
ci
7.6.2. Phương pháp biến phân GALERKIN
Nếu hàm không tồn tại phiếm hàm, người ta sử dụng phương pháp biến phân
Galerkin như sau:
276
n
D L(U ) M j dD 0 hay D
L
P 1
N P .
U P
M j dD 0
Trong trường hợp U p là hằng số, và j N p , ta được phương pháp
GALERKIN.
Tóm lại, phương pháp Galerkin được thiết lập có dạng:
n
D
L
P 1
N p .
U P
M N p dD 0
hay N
D
p .R.dD 0, với p=1,2,…,n (7.30)
Với N eP gọi là hàm tọa độ được chọn trong miền con De sao cho thoả mãn
một số tính chất nào đó (xem chương 8), ta có được Phương pháp phần tử hữu hạn.
q F G k+1
0 (7.32)
t x y
C
Áp dụng phương pháp miền con k
277
D
.q j ,k F .y Gx 0
d
(7.35)
dt A
FAB =
1
Fj,k1 Fj,k , GAB = 1 G j,k1 G j,k
2 2
Tương tự cho yBC, yCD, yDA, . . .
Nếu không phụ thuộc thời gian t và xi = yi = const, ta được:
d F j 1,k F j 1,k G j ,k 1 G j ,k 1
q j ,k
dt 2x 2y
7.8. Phương pháp phần tử biên
Với phương pháp phần tử biên, như tên gọi của nó, 2
việc chia phần tử chỉ ở biên của bài toán.
Xét ví dụ bài toán mô tả dòng chảy thế hai chiều
(2 Dimensions): 1
n
2 = 0 (7.38)
Trong miền ta có:
+ Điều kiện biên chủ yếu: trên biên 1 (đk biên Dirichlet)
+ Điều kiện biên tự nhiên: q = q trên biên 2 (điều kiện biên
n n
Neumann)
Với = 1 + 2
Dạng biến phân trọng số dư
Định nghĩa:
Gọi các phần dư:
~
R=
2
R1 =
R2 = q - q
~ ~
R. .d R .q .d R
~ .d
=> 1 2
1 2
278
Dùng tích phân từng phần hai lần liên tiếp, ta có:
~ ~ ~
( ) .d q . .d q. .d q~. .d q~. . d
2
2 2 2 1
~
2 ( x x ) 0 (7.41)
Với là hàm Dirac.
~ 1 1
. ln( ) , với r = x 2 y 2 (7.42)
2 r
Với những điểm x nằm bên trong , cách thành lập theo phương pháp phần
tử biên cho bài toán biểu diễn bởi phương trình Laplace là:
~
( x ) . q~.d .q.d
Với những điểm x nằm trên biên , phương trình viết cho bài toán trở thành:
~
c. ( x ) . q~.d .q.d (7.43)
với c = (thông thường c = 1/2)
2.
Ta đi rời rạc hóa biên của miền D, dùng phần tử bậc 2 ta được:
n n
~
(c. ) i . q~.d .q.d (7.43)
j 1 j j 1 j
1
Hàm dạng được biểu diễn: ( ) [ N1 N 2 N 3 ] 2 [ N ] ,
3
q( )=[N]. q
279
3
0
1
1 2
1
1 1
N1( ) = ( 1) , N2 ( ) = (1 )(1 ) , N3( ) = ( 1)
2 2
Với [ 1,1]
Thiết lập cho một phần tử trên biên, ta có:
1 1
. q .d [ N1 N 2 N 3 ]. q .2 .d [h1 h2 h3 ].2
~ ~
3
3
j j
q1 q1
~ ~
. q.d [ N1 N 2 N 3 ] .q2 .d [ g1 g 2 g 3 ].q2
q3 q
3
j j
~
Ở đây: ~
hk= N k q d
j
và gk = N k d , k 1,2,3
j
dx dy
2 2 h2
d , d G .d
d d
h2
1 j+
hk = N k ( ). q
~.d
N K ( ) q~. G d ho 1
j
1
~
1
~ j
gk =
j
N k ( ). .d N K ( ) . G d
1
h1
Cuối cùng thế vào phương trình đã rời rạc hoá, ta có:
1
q1
2
(c ) i H i1 H i 2 ..... H in ] [Gi1 Gi 2 .... Gi 2 N ] q 2 (7.44)
... q
2N
n
280
Với H ij là tổng của số hạng h1 của phần tử j + 1 và h2 của phần tử j.
Nếu đặt:
ˆ
H ij , i j N 2N
H ij
ˆ
H ij c, i j thì ta viết lại: H
i 1
ij . j Gij .q j
j 1
Câu hỏi:
1) Trình bày ý nghĩa vật lý của các phương trình loại Hyperbol, Parabol, Ellip?
Trong thực tế có những phương trình lưỡng tính, nhất là trong cơ học lưu chất,
hãy cho vài ví dụ và giải thích ?
2) Từ sự mô tả bản chất vật lý của bài toán của mỗi loại phương trình mô tả, nên
số và loại điều kiện biên phải đáp ứng, hãy cho mỗi loại phương trình vài ví dụ?
3) Phương pháp đặc trưng đóng một vai trò quan trọng trong việc hiểu rõ bản chất
vật lý của bài toán, vì sao?
4) Phương pháp sai phân là phương pháp không bảo toàn, vì sao?
5) Nêu các điều kiện để sơ đồ sai phân được chấp nhận?
6) Ưu nhược điểm của sai phân hiện và sai phân ẩn?
7) Hãy nêu sự giống nhau và khác nhau của các phương pháp Sai phân, Phần tử
hữu hạn, Thể tích hữu hạn, Phần tử biên; ưu nhược điểm của chúng?
Bài tập :
Bằng phương pháp sai phân giải các phương trình sau:
2u 2u
2 2 , 0 x 2, u x,0 x 2 x
2
t x
1)
u 0, t u 2, t sin t , u 1 0,1.k .
. 2 x
t t 0
281
u 2 u
2 , 0 x 1, t 0
t x
2) u x,0 4 0,1.k 1 x
u 0, t u 1, t 0
282
q0
0
x x y y D
283
Chương 8 PHƯƠNG PHÁP PHẦN TỬ HỮU HẠN
Như đã phân tích ở mục 7.6, chương 7, một bài toán có miền hình học phức tạp,
có thể xem như là tập hợp của nhiều dạng hình học đơn giản (gọi là miền con hay phần tử
–element), để việc xây dựng hàm xấp xỉ (hay còn gọi là hàm nội suy - interpolation
function) trên miền con này được dễ dàng, hàm xấp xỉ được xây dựng một cách hệ thống
cho hầu hết dạng hình học, hàm xấp xỉ này chỉ phụ thuộc vào phương trình vi phân, từ đó
hình thành phương pháp phần tử hữu hạn.
Với phương pháp phần tử hữu hạn, miền tính toán được xem như là tập hợp nhiều
miền con hữu hạn (finite element) có dạng hình học đơn giản (simple shape-element).
Trên mỗi miền con này, phương trình chủ đạo (governing equation) được thiết lập với sử
dụng một phương pháp biến phân nào đó. Các phần tử được liên kết với nhau và phải thoả
mãn điều kiện cân bằng và liên tục của các biến phụ thuộc qua biên của các phần tử.
284
Tuyến tính (4) Bậc hai (8) Bậc ba (12)
Ở đây j là hàm nội suy (interpolation functions) và hj là ẩn của bài toán tại nút
của phần tử.
Ta cũng có thể mô tả hình dạng của phần tử bằng cách dùng các toạ độ của mỗi nút
trong phần tử (xem Hình 8.1).
285
n
x( p ) S
j 1
j ( p ).x j (8.2)
n
y ( p) S
j 1
j ( p ). y j (8.3)
n
z ( p) S
j 1
j ( p ).z j (8.4)
Vì rằng hàm nội suy Sj được dùng xác định hình dạng của phần tử, nên thường
được gọi là hàm dạng (shape functions).
h(e)(x)=Ni(e)(x)hi + Nj(e)(x)hj
h(e)(x)
x(P)=Si(e)(x)xi(e)+Sj(e)(x)xj(e)
hi
Hàm dạng
xi(e) xi(e)
x
286
Hàm nội suy bậc hai, hàm dạng tuyến tính
hk
h(e)(x)=Ni(e)(x)hi + Nj(e)(x)hj+ Nk(e)(x)hk
hj
Hàm nội suy
h(e)(x)
x(P)=Si(e)(x)xi(e)+Sj(e)(x)xk(e)
hi
Hàm dạng
xi(e) xj(e) xk(e)
x
Hình 8.1: Hàm nội suy và hàm dạng của phần tử một chiều
Bậc của đa thức dùng để nội suy và các hàm dạng bên trong phần tử có thể là khác
nhau, người ta phân ra ba loại như sau: Phần tử dưới tham số (subparametric elements)
khi bậc đa thức hàm dạng nhỏ hơn bậc đa thức nội suy. Phần tử đẳng tham số
(isoparametric elements) khi bậc đa thức hàm dạng bằng bậc đa thức nội suy. Phần tử trên
tham số (superparametric elements) khi bậc đa thức hàm dạng lớn hơn bậc đa thức nội
suy (xem Hình 8.2).
Đa số các bài toán trong thực tế dùng phần tử đẳng tham số và hàm dạng đồng nhất
với hàm nội suy.
hk
hj Hàm nội suy bậc hai(nút i, j, k)
h(x)
hi Hàm dạng tuyến tính (nút i và nút k)
hj
Hàm nội suy tuyến tính (nút i và j)
h(x)
Hàm dạng tuyến tính (nút i và j)
hi
xi(e) x xj(e)
287
Phần tử tham số Hàm dạng bậc 2(nút i, j,k)
(e) (e)
(xk(e) , yk(e))
hk (xj , yj )
h(x)
(xi(e) , yi(e))
hi
Hàm nội suy tuyến tính (nút i và j)
x xm
N k ( x) (8.5)
m 0 xk xm
k m
Với: m là số nút.
xm là toạ độ nút thứ m.
Tính chất của hàm nội suy:
Hàm nội suy có các tính chất sau:
Tính chất 1: Hàm nội suy có giá trị bằng 1 tại nút đó và bằng 0 tại các nút
khác.
Tính chất 2: Các hàm nội suy thoả biểu thức sau:
n
N ( ).P ( ) P ( ), j 1,2,....n
i 1
i j i j (8.6)
288
(nội suy bậc cao ở các bài toán hai hoặc ba chiều) phải sử dụng hàm nội suy trong toạ độ
địa phương.
8.2.1. Hàm nội suy cho bài toán một chiều
a. Nội suy tuyến tính trong hệ toạ độ tổng thể:
N N1 N2 (8.7)
xB x x xA
Với N1 N2
xB xA xB xA
b. Nội suy dạng Lagrange bậc hai trong hệ toạ độ tổng thể:
N N1 N 2 N 3 (8.8)
ie xie x ke x ke x ej
2 2
ie x ej x ke
2 2
Trong đó:
ie x ej x ke ,
3
D e ie
i 1
Ni
N 1 2 1
1
N1 N2 (8.10)
1.0 N 1 1
2 2
-1 0
1
d. Nội suy bậc hai dạng Lagrange trong hệ toạ độ địa phương: N N1 N2 N3
u1 u2 u3 u1 u2 u3
1 2 3 1 2 3
x1 x3 x
-1 0 1 x1 x2 x3
2
1 1
nd = 3 x1 x x3
vr n=3
v er
289
e. Nội suy bậc ba dạng Lagrange trong hệ toạ độ địa phương:
N N1 N2 N3 N4
u1 u2 u3 u4 u1 u2 u3 u4
1
1 2 3 4 1 2 3 4
2 x1 x 4 2 x1 x 4
-1 1/ 3 0 1/ 3 1 x1 x2 x3 x2
3 3
1 1 x1 x x2
nd = 4
vr n=4 v er
9 1 1
N1 16 1 3 3
27 1
N 2 1 1
16 3
(8.11)
N 27 1 1 1
3
16 3
N 9 1 1 1
4
16 3 3
8.2.2. Hàm nội suy cho bài toán hai chiều
a. Nội suy tuyến tính trong hệ toạ độ tổng thể cho phần tử tam giác:
N N1 N2 N3 (8.12)
Ở đây: N1
1
2A
ie ie x ie y (8.13)
b. Nội suy tuyến tính trong hệ toạ độ địa phương cho phần tử tam giác:
N N1 N 2 N 3 (8.14)
290
y
u3
3 2 u2
u3 3
t n
1
u1
1 2
u1 u2 x
vr ve
n 3 n3 nd 3
Với:
N1 1 , N 2 , N 3
Nếu điểm gốc toạ độ địa phương được chọn khác như hình sau, thì hàm nội suy
cho phần tử tam giác cũng sẽ thay đổi theo:
1
1 N1 ( )
2
1
N 2 (1 ) (8.15)
2
1
-1 N 3 (1 )
2
- 1
1
c. Nội suy bậc hai trong hệ toạ độ địa phương cho phần tử tam giác:
y
u5 n
t
5 u4
u5
5 4 u3
3
u4 u6 6 2
u6 6 4 u2
1
1 2 3 u1
u1 u2 u3 x
n6 nd 6
291
N 1 1 2 , N 4 4
N 2 4 , N 5 1 2
(8.16)
N 3 1 2 , N 6 4
Với: 1
d. Nội suy tuyến tính trong hệ toạ độ địa phương cho phần tử tứ giác:
Hàm dạng: N N1 N 2 N 3 N 4 (8.17)
N1
1
1 1 , N3
1
1 1
4 4
N 2 1 1 , N 4 1 1
1 1
4 4
y
u4 u3 u3
4 3 3
u4
4
2 u2
1
u1
1 2 ve
u1 u2
n4 x
v r n4 nd 4
e. Nội suy bậc hai trong hệ toạ độ địa phương cho phần tử tứ giác:
5
x1 x3
1
6 4 x2
3 2
7 6 5 7 9 etc
8 2
-1 8 4 1 …
9 1
1 2 3
-1 x
nd 9
e
v
r
v n 9
292
3 1 1 , 4 1 1
1 1
4 4
5 1 2 1 , 6 11 2
1 1
2 2 (8.18)
7 1 2 1 , 8 11 2
1 1
2 2
9 1 2 1 2
z
u4
4
u4 1 3 u3
4 u1 2
u1 3 u2
1 u3 y
2
u2 x ve
vr n4 nd 4
N1 1 , N3
N2 , N4 (8.19)
b. Nội suy bậc hai trong hệ toạ độ địa phương cho phần tử hình chóp:
N 1 1 2
1
70 N 2 4
9 N 3 1 2
8 6 (8.20)
N 4 4
1
5 N 5 1 2
2
4 N 6 4
3
293
N 7 4 , N 8 4
với: 1
N 9 4 , N10 1 2
c. Nội suy tuyến tính trong hệ toạ độ địa phương cho phần tử ba chiều hình trụ đáy tam
giác:
z
6
0
4 6 0 3
3
5 1 0 4
1 0
2
1
1 y
1
3
ve
2 vr x
n6
nd 6
N1 a , N 4 b
N 2 a , N 5 b (8.21)
N 3 a , N 6 b
1 1
Với: 1 , a , b
2 2
d. Nội suy tuyến tính trong hệ toạ độ địa phương cho phần tử ba chiều hình trụ có đáy tứ
giác:
z 8
1 1 7
6
5 1 1 5
1 1 6
4 3
1
4 2
1
3 y
2
vr n8 n8 nd 8 ve
x
294
N1
1
a2 b2 c2 , N 2 1 a1 b2 c2 , N 3 1 a1 b1 c2
c c c
N4
1
a2 b1 c1 , N 5 1 a2 b2 c1 , N 6 1 a1 b2 c1
c c c
N7
1
a1 b1 c1 , N8
1
a2 b1 c1 (8.22)
c c
a1 1 , a 2 1
Với : b1 1 , b2 1
c1 1 , c 2 1
Với cách chia miền tính toán V bằng tổng các miền con V(e) , mô hình thực tế được
thay bằng mô hình tính toán với ne phần tử hữu hạn được liên kết với nhau bởi các điểm
nút và tại mỗi điểm nút tồn tại các đại lượng thể hiện sự tác động qua lại của các phần tử
kề nhau, như vậy bài toán hệ liên tục có bậc tự do vô hạn được thay bằng bài toán tính
hệ có bậc tự do hữu hạn đơn giản hơn nhiều.
295
Một chiều:
Mưa
Nút
Lớp không thấm
Phần tử
Hai chiều:
Mặt đất
Mực nước
ngầm
Phần tử
Ba chiều:
Phần tử
Phương pháp phần tử hữu hạn áp dụng ở đây thường là phương pháp Galerkin- gọi
tắt là phương pháp phần tử hữu hạn Galerkin.
Để tìm được nghiệm trên các miền con điều quan trọng là phải chọn hàm toạ độ
Np(e) (hay còn gọi là hàm nội suy, hàm dạng) đảm bảo sự liên tục của các đại lượng cần
tìm giữa các phần tử trong miền D.
296
Miền V được chia thành ne phần tử (miền con V(e)) bởi R điểm nút. Tại một nút có
s bậc tự do, thì số bậc tự do của cả hệ là: n = R.s
Gọi q là véc-tơ ẩn của toàn hệ, q e là véc tơ ẩn của mỗi phần tử, giả sử mỗi
phần tử có r nút, thì số bậc tự do của mỗi phần tử là: r s
Ta có liên hệ : q e = Le q (8.24)
(ne1) = (nen) x (n 1)
Với Le được gọi là ma trận định vị.
Ứng với mỗi phần tử, ta có phương trình ma trận:
Ke q e = Ce (8.25)
[K]e ma trận phần tử , {C}e vectơ vế phải phần tử.
{q}e là tập hợp các giá trị cần tìm tại các nút của phần tử.
e 1
Ke q e =
e 1
Ce
C C
ne ne
e 1
e =
e 1
LeTCe
K- Ma trận tổng thể.
q - Vectơ tập hợp tổng các ẩn cần tìm tại các nút (tổng bậc tự do tại các nút).
C Vectơ các số hạng tổng thể ở vế phải.
Như vậy việc sử dụng ma trận định vị Le để tính K và C , thực chất là sắp
xếp các phần tử Ke , Ce vào vị trí của nó ở trong K và C . Tuy nhiên trong thực
hành người ta không dùng cách này.
Sau đây, sẽ giới thiệu một cách ghép nối trực tiếp để thiết lập ma trận tổng thể và
vectơ vế phải tổng thể mà không cần xử dụng ma trận định vị Le .
Giả sử xét bài toán thấm có áp trong miền (A B C D E F), miền được chia thành
8 phần tử tam giác (ne = 8), có 9 điểm nút (R = 9), tại mỗi điểm nút có s bậc tự do (số ẩn
297
số tại nút ), ở đây s =1 là cột nước thấm, mỗi phần tử tam giác có 3 điểm nút (r = 3), thì số
bậc tự do của mỗi phần tử là: r s = 31 = 3 (xem Hình 8.3).
y(m)
Vn = 0
F E D k
3 9
6
4 8
3 7
2 8 i
2 5 6 j
1 4 5
1 7
A B C x(m)
Vn = 0
Nếu cũng với phần tử tam giác có ba điểm nút này r = 3, tại mỗi nút có ba ẩn h, u,
v như bài toán dòng chảy hở hai chiều ngang s = 3, thì số bậc tự do của mỗi phần tử là r.
s = 3x3 = 9, ta sẽ được ma trận phần tử (9, 9). Để đơn giản ta xét phần tử tam giác tại mỗi
nút có một bậc tự do. Mỗi phần tử (ở đây là tam giác) được đánh số các nút (i, j, k) theo
chiều được qui ước (chẳng hạn ngược chiều kim đồng hồ) nút i được qui ước là nút ở bên
trái và thấp nhất. Với mỗi phần tử bất kỳ ne ta có ma trận phần tử Ke và véc tơ vế phải
Ce như sau:
K iie K ije K ike cie
K e
K eji K ejj K ejk
, Ce
= c ej
K kie K kje K kke c e
k
Với cách đánh số nút và phần tử như trên ta có 8 phần tử với các nút tương ứng (i,
j, k) như sau: e1(1, 4, 5), e2(1, 5, 2), e3(2, 5, 6), e4(2, 6, 3), e5(4, 7, 8), e6(4, 8, 5), e7(5, 8,
9), e8(5, 9, 6) .
Ví dụ phần tử: e4(i, j, k) e4 (2, 6)
K 22
4 4
K 26 4
K 23 c 24
4
Ke=4 = K 624 4
K 66 K 63 , và Ce=4 = c 64
K 32
4 4
K 36 4
K 33 c 4
3
298
Mỗi hệ số Kije : e chỉ số trên, chỉ số này thuộc ma trận phần tử, i là hàng nào
trong ma trận tổng thể, j là cột nào trong ma trận tổng thể. Ví dụ đây là hệ số của ma
trận phần tử e = 4, nằm trong hàng 6 cột 2 của ma trận tổng thể. Và ma trận tổng thể:
ne 8
K = K
e 1
e = K e
e 1
= [X]
1 2 3 4 5 6 7 8 9
1 1 2
k 11 +k 11 k 212 k 141 1
k 15 +k 152
2 k 2 k 2 +k3 +k 4 k 423 k 225 +k 325 k 326 +k 426
21 22 22 22
3 4
k 32 k 433 k 436
4 k1 k144 +k544 +k644 k145 +k 645 k547 k548 +k 648
= 1 2
41
[X] 5 k 51 +k 51 k 52 +k 52 k 59 +k 59 (8.27)
2 3
k154 +k 654 k155 +k 255 +k 355 +k 655 +k 755 +k 855 k 356 +k 856 k 658 +k758 7 8
6 k362 +k 462 k 463 k365 +k 865 k 366 +k 466 +k 866 k 869
7 k574 k577 k578
8 k584 +k684 k685 +k785 k587 k588 +k 688 +k 788 k 789
9
k795 +k895 k896 k798 k799 +k 899
Cộng một cách tương tự cho vectơ vế phải C , với chú ý phép cộng này giống
cộng các số hạng trên đường chéo chính của ma trận tổng thể K :
ne
C = e 1
Ce (8.28)
Ta thấy ở ma trận tổng thể các phần tử khác không có dạng đường chéo (hay còn
gọi là dạng Band). Để tiết kiệm bộ nhớ và thời gian tính của máy tính, người ta chỉ lưu
trữ các phần tử khác không này và thuật toán cũng chỉ tính toán với các phần tử khác
không.
Người ta phải lưu trữ cả ma trận dạng Band này khi ma trận Band có chiều rộng
Band hẹp (liên quan đến cách đánh số nút của các phần tử), không đối xứng (Hình 8.4).
Chỉ cần lưu trữ một nữa Band khi ma trận đối xứng. Khi chiều rộng Band lớn và trong các
hàng của Band còn nhiều phần tử bằng không, người ta có thể dồn ma trận lại thành ma
trận Band hẹp hơn, như vậy sẽ cần thêm ma trận định vị nữa. Tuy nhiên với cách lưu trữ
ma trận Band dù theo kiểu nào, thì trong Band vẫn còn một số hệ số phần tử bằng không,
299
do đó để loại bỏ các phần tử bằng không ở trong Band, người ta còn có cách lưu trữ các
phần tử khác không này ở dạng vectơ gọi là kỹ thuật frontal method.
Thiết lập ma trận tổng thể của bài toán ở dạng ma trận Band
Ở đây ma trận tổng thể được lưu trữ ở dạng Band, ví dụ ma trận tổng thể không đối
xứng, nên lưu trữ cả hai Band (KIJ K J I).
b
b
[VK] KII
n
[K]= KII
n 2b+1
1111
Hình 8.4: Cách lưu trữ ma trận dạng Band
Ta có : KIJ = V Ki j (8.29)
Với : i = I
j = J - I + 1 + b
(Nếu ma trận đối xứng chỉ cần lưu trữ một Band, lúc đó j = J - I + 1)
Sau đây là thuật toán theo phương pháp khử Gauss, viết cho ma trận Band đối
xứng, chỉ lưu trữ một Band có chiều rộng b:
Ước lượng thuận Thế ngược
bn
Do k = 1, n = 1 bn
an ,1
nbk = min(n-k+1, b)
do i = k+1, nbk+k+-1 Do ii = 1, n =1
i1 = i - k+1 i = n – ii
c = ak, i1/ak,1 nbi = min(n-1+1, b)
do j = I, nbk +k – 1 sum = 0
j1 = j-i+1 Do j = 2, nbi
j2 = j-k+1 Sum = sum + ai, jbi+j-1
ai, j1 = ai, j1 – cak, j2 bi sum
bi
bi = bi - cbk ai ,1
300
Bước 5: Áp đặt các điều kiện biên của bài toán ta sẽ nhận được hệ phương trình
để giải như sau:
1
b
1
[VK] =
n
n
[K]=
n 2b+1
Krj = 0 nếu j r
Kir = 0 nếu i r (8.31)
Krr = 1
Vectơ vế phải của hệ thống sẽ là:
c1 k1r i
c k
2 2r i
C = (8.32)
i
c n k n r i
301
Cũng có thể đưa điều kiện biên vào bằng cách nhân hệ số trên đường chéo chính
của ma trận [VK] với một số rất lớn (từ 108 - 1015) khi ma trận [K] có tính chất trội hoặc
không xấu (các hệ số kii là không quá bé so với các hệ số khác).
Bước 6: Giải hệ phương trình đại số.
K q C
* * *
(8.33)
Cách giải hệ phương trình ở dạng ma trận (8.33) này tuỳ theo từng loại bài toán
(dừng hoặc không dừng) tính chất của ma trận lưu trữ, cách lưu trữ ma trận tổng thể mà
chọn cách giải thích hợp; chẳng hạn khử Gauss trực tiếp, phép tách LU hay Cholexski
hoặc giải lặp Gauss-seidel có hệ số giảm dư hay lặp theo phương pháp gradient liên
hợp,… (xem N.T. Hùng, 2000)
Ví dụ. Áp dụng phương pháp PTHH Galerkin
d 2T
Giải phương trình f ( x) với chiều dài thanh l = 10cm với điều kiện biên
dx 2
T(0, t) = 50, T(10, t) = 100 và hàm phân bố nhiệt độ f(x) = 20, theo phương pháp phần tử
hữu hạn Galerkin.
Giải:
Bước 1: Rời rạc hoá miền khảo sát.
Rời rạc hóa thanh thành 5 phần tử tương ứng với 6 nút như hình vẽ
302
Chọn hàm xấp xỉ T N1T1 N 2T2 , ở đây :
+ N1, N2 là hàm nội suy tuyến tính trong hệ toạ độ tổng thể :
N N1 N 2 ,
x2 x x x1
N1 ; N2
x2 x1 x2 x1
x2 d 2T x2
x1 dx 2
N i dx f ( x)N i dx
x1
(8.34)
x2 d 2T
Ta tích phân từng phần vế trái :
x1 dx 2
N i dx
dN i ( x)
u N i ( x) du dx
Với: 2 dx ta được
dv d T dx v dT
dx 2 dx
x2
x2 d 2T dT x2 dT dN ( x)i
x1 dx 2
Ni dx Ni ( x)
dx x1
x1 dx dx
dx
x2 d 2T dT ( x2 ) dT ( x1 ) x2 dT dN i
x1 dx 2
N i dx N i ( x2 )
dx
N i ( x1 )
dx
x1 dx dx
dx (8.35)
x2 x
Với: x = x2 thì N1(x2) = 0 ( N1 ).
x2 x1
x2 x
x = x1 thì N1(x1) = 1 ( N1 ).
x2 x1
x2 x
N2 suy ra N 2 ( x 2 ) 1 , N2 ( x1) 0
x2 x1
dT dN1 dN 2
Với T1 T2 (8.38)
dx dx dx
Và nội suy tuyến tính trong hệ toạ độ tổng thể : N N1 N 2 với
dN1 1 x x dN 2 1 x x1
với ( N1 2 ); với ( N 2 )
dx x2 x1 x2 x1 dx x2 x1 x2 x1
dT dN i
Cùng các giá trị : ; đã tính ở trên và
dx dx
Khi i = 1, ta có:
dT dN 1 x 2 (T T ) T T2
x2
dx 2 1
dx 1 (8.39)
x1 dx dx x1 ( x x )
2 1
2
x 2 x1
Khi i = 2, ta có:
x2 dT dN 2 x2 T T T T
x1 dx dx
dx 2 1
x1 ( x x )
2 1
2
dx 1 2
x2 x1
(8.40)
Kết hợp các phương trình (8.36), (8.37), (8.39) và (8.40) biểu diễn ở dạng ma trận:
dT ( x1 ) x2
f ( x) N1 ( x)dx
1 1 1 T1 dx x1
x2 x1 1
1 T2 dT ( x ) x2
dx f ( x) N 2 ( x)dx
2
x1
Trong đó :
304
x2 x
x2 x2 2
x1
f ( x) N 1 ( x)dx 20
x1
x 2 x1
dx 10(2 x)dx 20 , với x2 = 2, x1 = 0
0
x x1
x2 x2 2
x1
f ( x) N 2 ( x)dx 20
x1
x2 x1
dx 10 xdx 20 , với x2 = 2, x1 = 0
0
Ke T e = Ce
e 1 e 1
k 1 k 1 0,5 0,5
K 1
111 121
k 21 k 22 0,5 0,5
e
305
5
Đưa các ma trận phần tử vào ma trận tổng thể : K total K
1 e
k11
1 1
k12
1 0,5 0,5
k 21
1
k 22 k 22
2 2
k 23 0,5 1 0,5
2 2
k 33
3 3
0,5 1 0,5
K k 32 k 33 k 34
3
k 43 3
k 33 k 44
4 4
k 45 0,5 1 0,5
5 0,5 1 0,5
4
k 54 4
k 55 k 55
5
k 56
0,5 0,5
5
k 65 k 66
5
Các véc tơ vế phải tương ứng với từng phần tử như sau:
dT ( x1 ) x2 dT ( x2 ) x3
f ( x) N1 ( x)dx f ( x) N 2 ( x)dx
dx x1 dx x2
C1 x2 C2 x3
dT ( x2 ) dT ( x3 )
dx f ( x) N 2 ( x)dx dx f ( x) N 3 ( x)dx
x1 x2
dT ( x3 ) x4 dT ( x4 ) x5
f ( x) N 3 ( x)dx f ( x) N 4 ( x)dx
dx x3 dx x4
C3 x4 C4 x5
dT ( x4 ) dT ( x5 )
dx f ( x) N 4 ( x)dx dx f ( x) N 5 ( x)dx
x3 x4
dT ( x5 ) x6
f ( x) N 5 ( x)dx
dx x5
C5 x6
dT ( x6 )
dx f ( x) N 6 ( x)dx
x5
306
dT ( x1 ) x2
f ( x) N1 ( x)dx
dx x1
x2 x3
f ( x) N ( x)dx f ( x) N ( x)dx
2 2
dT ( x1 ) 20
x1 x2
dx
x4 x4
40
5 x3
f ( x ) N 3 ( x ) dx x f ( x ) N 3 ( x ) dx
40
Ce x
3
x5
40
5
e 1
f ( x) N 4 ( x)dx f ( x) N 4 ( x)dx 40
x4 x4
x6 x3 dT ( x6 ) 20
f ( x) N 5 ( x)dx f ( x) N 5 ( x)dx dx
x5 x2
dT ( x6 ) 6
x
dx f ( x) N 6 ( x)dx
x5
dT
0,5T1 0,5T2
dx
( x) 20
0,5T1 T2 0,5T3 40
0,5T2 T3 0,5T4 40
0,5T3 T4 0,5T5 40
0,5T4 T5 0,5T6 40
0,5T5 0,5T6
dT
( x) 20
dx
307
dT
dx ( x) 0,5T2 5
T2 0,5T3 65
0,5T2 T3 0,5T4 40
0,5T3 T4 0,5T5 40
0,5T4 T5 90
0,5T5
dT
( x) 30
dx
1 0,5 dT ( x1 ) / dx 5
1 0,5 T2
65
0,5 1 0,5 T3
40
0,5 1 0,5 T4 40
0,5 1 0,5 T5 90
0,5 1
dT ( x6 ) / dx
30
T
350
310 320
300
250 250
220
200
150
100 100
50 50
0
L
0 2 4 6 8 10
Nhận xét:
Qua đồ thị trên ta thấy :
+ Kết quả tính toán bằng phương pháp PTHH cho nghiệm gần đúng với nghiệm
của phương pháp giải tích.
+ Nếu miền tính toán của bài toán nêu trên được chia thành các phần tử có kích
thước càng nhỏ thì độ chính xác của nghiệm càng cao (càng tiến gần đến nghiệm giải
tích).
Phụ lục tính toán bằng phần mền Maple 9
> K:=array([[1,-0.5,0,0,0,0],[0,1,-0.5,0,0,0],[0,-0.5,1,-0.5,0,0],[0,0,-0.5,1,-0.5,0],[0,0,0,-
0.5,1,0],[0,0,0,0,-0.5,-1]]);
309
1 5 0 0 0 0
0 1 5 0 0 0
0 5 1 5 0 0
K :
0 0 5 1 5 0
0 0 0 5 1 0
0 0 0 0 5 1
> F:=vector([-5,65,40,40,90,-30]);
F : 5, 65, 40, 40, 90, 30
> linsolve(K,F);
F 104.9999999, 219.9999998, 309.9999997, 319.9999998, 249.9999999, 95.000000
> A:=array([[1,-0.5,0,0,0,0],[0,1,-0.5,0,0,0],[0,-0.5,1,-0.5,0,0],[0,0,-0.5,1,-0.5,0],[0,0,0,-
0.5,1,0],[0,0,0,0,-0.5,-1]]);
1 5 0 0 0 0
0 1 5 0 0 0
0 5 1 5 0 0
A :
0 0 5 1 5 0
0 0 0 5 1 0
0 0 0 0 5 1
> F:=vector([-5,65,40,40,90,-30]);
F : 5, 65, 40, 40, 90, 30
> linsolve(K,F);
8.5. Phương pháp phần tử hữu hạn trong Cơ học vật rắn
Phương pháp PTHH là một phương pháp số có hiệu quả để giải các bài toán ứng
dụng có điều kiện biên.
Xấp xỉ ẩn trên miền con Ve (phần tử), Ve = V (miền tính toán). Các phần tử nối
kết lại các điểm nút. Tại nút chứa ẩn bài toán (còn gọi là bậc tự do).
Phương pháp này là chủ đạo trong các bài toán cơ học vật rắn, đặc biệt thích hợp
cho bài toán có miền xác định phức tạp, điều kiện biên khác nhau. Lập trình, tự động,
tính toán dễ dàng và trở nên thông dụng nhờ sự phát triển của máy tính điện tử.
Với bài toán cơ học VẬT RẮN biến dạng & CƠ KẾT CẤU dùng 3 mô hình:
310
+ Mô hình tương thích : Xem chuyển vị là đại lượng cần tìm trước.
+ Mô hình cân bằng : Xấp xỉ ứng suất trên từng phần tử, đi tìm ứng suất.
+ Mô hình hỗn hợp : Xem chuyển vị & ứng suất là hai yếu tố độc lập.
Hàm xấp xỉ biểu diễn gần đúng dạng phân bố của chuyển vị và ứng suất.
Đối với các bài toán trong cơ học chất lỏng, thường thiết lập bài toán theo dạng
yếu Galerkin - trên từng phần tử (Xem sách chuyên khảo của cùng Tác giả).
Bài toán biên (Bài toán có điều kiện biên)
Trạng thái ban đầu G, biên của thể tích V là S.
Sau khi có ngoại lực tác dụng nó biến đổi thành trạng thái G’ .
Hãy tính tại mọi điểm I(x1, x2) những thông số trạng thái như: Chuyển vị u, biến
dạng , ứng suất ,...
u
Biết liên hệ: [] = [
x ] tại 1 điểm.
[] = [E] x [], với E: Tính chất của vật liệu.
x2
= s
I
x2 u (S)
(V)
u=o G
G'
o x1 x1
311
x2
(S)
(V)
2+d 2
12
dx2 1 I 1+d 1
2
O
dx1 x1
Xây dựng phương trình cân bằng cho một vi phân diện tích [dx1, dx2] bao quanh
điểm I bất kỳ.
D{[u], [E]} = 0: Gọi là phương trình vi phân.
Cộng thêm các điều kiện ràng buộc cho trước trên biên (u = 0, = s).
Trong “Phương pháp sai phân”, sử dụng phương trình cân bằng theo cách này
(để giải người ta chuyển dạng VI PHÂN về dạng SAI PHÂN).
(ii) Cách thứ 2: “ Nguyên lý biến phân - cực tiểu phiếm hàm’’.
Dùng lý thuyết biến phân để xây dựng phương trình cân bằng cho cả vùng (V), kể
cả biên (S), gọi: Phương trình tích phân và tìm cực tiểu phiếm hàm ở dạng tích phân này
d = 0; đây chính là”Phương pháp cân bằng”. Giải phương trình này sẽ cho ta lời đáp số
của bài toán.
Trong kết cấu hàm gọi thế năng và ở đây sử dụng biến phân về chuyển vị.
b. Các phương trình cơ bản
(i) Chuyển vị - biến dạng và ứng suất trong phần tử
Ma trận độ cứng phần tử và vectơ tải phần tử
Ta có: {u}e = [N]{q}e (8.42)
Với {q}e chuyển vị nút phần tử.
Từ liên hệ giữa chuyển vị {u}e và biến dạng { }e ta có:
{ }e = [ ]{ u} e [ ][ N]{ q} e [ B]{ q} e (8.43)
Trong đó: [B] = [ ][N]
312
Khi vật liệu tuân theo định luật Hooke ta có:
{}e = [D]({ }e-{ 0}e)+{0}e (8.44)
Trong đó: {0}e, { o }e là ứng suất và biến dạng ban đầu của phần tử.
Mang (8.43) vào (8.44) được: {}e = [D][B]{q}e - [D]{ o }e+{0}e (8.45)
Hay: {}e = [T]{q }e - [D]{ o }e + {0}e (8.46)
Trong đó: [T] = [D][B] gọi là ma trận tính ứng suất phần tử.
Từ (8.42), (8.43), (8.45) cho ta biểu diễn chuyển vị, biến dạng và ứng suất
trong phần tử theo vectơ chuyển vị nút phần tử {q}e.
Thế năng toàn phần của phần tử:
1
e ({ u} e ) 2{ } .{ } e dV - {g}T {u}e dV - { P} .{ u} e dS
T T
e (8.47)
Ve Ve Se
1
1
-( {g} {u}e dV +
T
{P}T .{u}e dS + { o }Te .[ D][ B])dV - { o }Te .B.dV ){q}e
Ve Se Ve
2 Ve
2
1
Hay: e ({q}e ) = {q}e T [ K ]e {q}e {q}e T .{P}e (8.48)
2
1 1
{P}e [ N]T {g}e dV + {N} {P}e dS + [ B T ].[ D].{ o }e )dV - [ B]T .{ o }e dV
T
Ve Se Ve
2 Ve
2
Miền V được chia thành ne phần tử (miền con Ve ) bởi R điểm nút. Tại 1 nút có S
bậc tự do, thì số bậc tự do cả hệ: n = R.S
Gọi { q } là vectơ chuyển vị nút tổng thể. Giả sử mỗi phần tử có r nút, thì số bậc
tự do của mỗi phần tử là: ne = r.S
313
Ta có liên hệ: {q}e = [L]e . { q } (8.50)
(ne.1) (ne.n ) (n.1)
Với [L]e gọi là ma trận định vị.
Sử dụng (8.50) và (8.48) ta có thế năng toàn phần của hệ:
ne ne
1
e1
e [ { q} T [ L ] Te .[K ] e[ L ] e{ q} { P} Te .[L ] e{ q} T ]
e1 2
(8.51)
Áp dụng nguyên lý thế năng toàn phần dừng (nguyên lý Lagrange) ta sẽ có điều
kiện cân bằng của toàn hệ tại các điểm nút:
0
q1
0
q 2
0 .
hay ở dạng ma trận: 0
. {q }
0
q n
ne ne
Viết lại: [ K ]. { q} { P} { 0} (8.52)
ne
ne
{ P} [ L ] Te .{P} e gọi là vectơ tải tổng thể.
e1
Ghi chú: Việc sử dụng ma trận định vị [L]e để tính [ K ] và {P} , thực chất là sắp
xếp các phần tử [K ]e , {P}e vào vị trí của nó trong [ K ] và {P} . Tuy nhiên trong thực
hành ta không dùng cách này.
314
Phép chuyển trục tọa độ
Ở trên đây đã xây dựng [N], [Ke], {P}e trong hệ tọa độ thích hợp của mỗi phần tử,
gọi là hệ tọa độ địa phương (và do đó các bậc tự do của phần tử cũng lấy theo hệ tọa độ
này).
Tuy nhiên trong thực tế, thường gặp các kết cấu mà các phần tử khác nhau thì có
các hệ tọa độ địa phương khác nhau và do đó các bậc tự do của phần tử cũng khác nhau
về phương.
Do vậy cần thiết có hệ tọa độ chung cho toàn hệ.
Gọi (x, y, z) là hệ tọa độ địa phương tương ứng {q}e, {P}e, [K]e
(x’, y’, z’) là hệ tọa độ tổng thể tương ứng {q’}e, {P’}e, [K’]e
Ta có quan hệ: {q}e = [T]e{q’}e (8.53)
{P}e = [T]e.{P’}e (8.54)
[T]e là ma trận biến đổi tọa độ từ (x’, y’, z’) về ( x, y, z).
1
Mặt khác: ∏e = {q}Te[K]e {q}e - {P}Te{q’}e. Thế (8.53) vào đây ta được:
2
1
∏e = {q’}Te[T]Te[K]e[T]e {q’}e - {P}Te[T]e {q’}e (8.55)
2
1
Hay ∏e = {q’}Te[K’]e{q’}e - {P’}Te[T]e {q’}e
2
Trong đó: [K’]e = [T]Te[K]e[T]e và {P’}e = [T]e {P}e (8.56)
So sánh (8.54) và (8.56) ta thấy [T]Te [T]e = [E]: Ma trận đơn vị.
Khi Te là ma trận vuông thì TeT = Te-1, Te là ma trận trực giao.
Tương tự khi áp dụng nguyên lý thế năng toàn phần dùng cho toàn hệ ta được :
'
ne
P P P '
'
e (8.58)
e1 n
Ở đây số hạng thứ 2: P ' trong (8.58) là vectơ tải trọng tập trung đặt tại các nút
n
tác dụng theo các phương tương ứng của các thành phần trong véc tơ chuyển vị nút kết
cấu {q’}e, gọi vectơ tải trọng nút.
315
Ghép nối phần tử hay sử dụng ma trận chỉ số để xây dựng
Ma trận độ cứng tổng thể và vectơ tải tổng thể.
Để xác định sự tương ứng của mỗi phần tử thuộc qe trong đó q (hoặc qe
trong q). Người ta lập ma trận chỉ số b (còn gọi là ma trận liên hệ Boolean) mà giá trị
của mỗi thành phần bij chính là chỉ số tổng thể tương ứng bậc tự do thứ j của phần tử thứ
i. Ma trận chỉ số b có số hàng bằng số phần tử của hệ, số cột bằng số bậc tự do của một
phần tử.
Ví dụ.
q1 q3 q5 q7
1 2 3
q2 q4 q6 q8
i j
1 1 2 3 4
e
q2 q4
2 3 4 5 6
3 5 6 7 8
Mỗi thành phần K eij của ma trận phần tử [K]e sẽ phải gộp thêm vào phần tử
K m,n của ma trận tổng thể [ K ] với m = bei, n = bej (nhớ là bei, bej là các giá trị của phần tử
316
[b] = e (hàng)
i j
(Cột)
Ví dụ. Tính toán hệ thanh:
+ Phần tử thanh chịu biến dạng dọc trục
Đi biểu diễn chuyển vị dọc thanh: y
U(x) = [N].{q}e
q1
q i ui q
Trong đó: {q}e = 1
q j e u j e L=a
{ } { x }
{ } { x }
d
Ký hiệu: [ ]
dx
, q3
x
317
x x
(1 ) L (1 )
L .p(x ).dx L .q.dx q.L 1 q.a 1
L L
1 1 1 1
EF EF
[K] (1 1) 1 2 1
a a
=
sym 1 sym 1
R
Véc tơ tải trọng nút: P 0 ,
n
0
qa
1 R 2 R
qa
Vectơ tải tổng thể: P
1 1 0 qa
2 qa
1 0
2
Ta có hệ phương trình: K q P được tính cụ thể như sau:
qa
1 1 0 q1 ( 2 R )
EF
q qa
a
2 1 2
sym
1 q qa
3 2
2
q 3 . qa
2 2 EF
Giải hệ này ta được:
4 qa 2
3
q
2 EF
318
2qa
FEM
3qa/2
Chính xác Chính xác
FEM
3qa2/2EF u
N
2
4qa /2EF
qa/2
du 1 1 0 2 3qa
N1 = EF. EF . 3 qa
dx 1 a a
2 EF
2
3qa2
du 1 1 2EF qa
EF . 2
a 4 qa 2
N2 = EF.
dx 2 a
2 EF
+ Phần tử thanh trong dàn phẳng
y
vi' =q'2j
i
x
u2 =q2
y'
vi' =ri'
i i
uj' =q'2j-1
j
u1 =q1
e
q'2i-1 = ui'
o x'
319
Trong dàn phẳng xem mỗi mắt dàn là một đỉnh nút, mỗi thanh dàn là một phần tử
chiụ biến dạng dọc trục:
q1 = q’2i-1lij + q’2i-1mij
q2 = q’2j-1lij + q’2j-1mij
Trong đó: lij, mij là cosine chỉ phương của trục phần tử (trục x) đối với hệ trục tổng
thể x’o’y’.
{q’}e u i , vi , u j , v j
' ' '
q
' T '
2i 1 , q ' 2i , q ' 2 j 1 , q ' 2 j
T
l ij2 l ij m ij l ij2 l ij m ij
m ij2 l ij m ij m ij2
EF
[K’]e = l ij2 l ij m ij
L
sym y' m ij2
Chú ý: y
x
x j xi
' '
mij = cos(x, y ) = ’ i
L
1 1 l ij 0 EF
m ij
m ij 0
[Se ] = EF. l ij m ij
'
. = l ij
L L 0 0 l ij m ij L
'
[Se ] =
EF
cos sin cos sin
L
+ Khung phẳng
y y
v2 ≡ q3 x
v1 ≡ q1 2 x
2 ≡ q4
1
1≡ q2 L,EJ o z
y
dv/dx
y dv/dx
A
B'
v
A
y
B x
u=-y.dv/dx
321
Ta có vectơ chuyển vị nút phần tử:
dv
Với góc xoay:
dx
Quan hệ giữa chuyển vị dọc trục u và độ võng v là:
dv
U = -y.
dx
Trong đó: y là khoảng cách từ điểm xét tới trục trung hòa.
Khi đó biến dạng dọc trục:
du d2v
x y. 2 , với v = [N].{q}e
dx dx
Với: [N] là ma trận hàm dạng
[N] = [N1 N2 N3 N4]
x2 x3 x x2
Với: N1(x) = 1-3 2 2 3 , N2(x) = x.(1-2 2 )
L L L L
x2 x3 x x2
N3(x) = 3. 2 , N4(x) = x.( 2)
L2 L3 L L
d2N d2
Viết lại: x y. 2 {q}e [B]{q}e , trong đó [B] = -y 2 [ N]
dx dx
6 x 4 x 6 12 x 2 6 x
Hay: [B] = -y ( 12 3 )( 6 2 )( 2 3 )( 2 )
L L L
2
L L L L L
Ứng suất tại mọi điểm của dầm chịu uốn: x E. x , biểu diễn dạng ma trận:
{} = [D].{ } , ở đây: [D] = [E]
Ma trận phần tử của dầm chịu uốn: [K]e = [ B] T [ D][ B]dV E [ B] T [ B]dF.dX
Ve LF
322
Với Jz = y 2 dF : Momen quán tính của mặt cắt ngang đối với trục z.
F
L L2 12
3a 2 2a3
1
L2 L3
P
1 2a 2 a3
a L 2
{P}e = 2
P
[ N ( a )] .Q Q.
T L
P
3 2 3
3a 2a
P
4 2 3
L L
a a3
L L2
Mômen uốn: y
d2v d2
M = EJ. EJ [ N]{ q} e
dx 2 dx 2 Lực phân bố P3
P1
q
i j P4 x
M EJ [ N '' ]{q}e P2
L
Với: y
P1 Q P3
N dx 2 [ N]
,, d2
o
N ,, [ N ''1 N ''2 N ''3 N '' 4 ] P2 P4 x
a
L
Có lực tập trung Q
323
đặt ở toạ độ xQ = a
M (tai nut 1) M 1
Gọi {M}e = là mômen uốn tại đầu nút phần tử {M}e =
M (tai nut 2) M 2
M e EJ. N '' ( x 0) .{q}e
''
N ( x L)
M e [ S ]e {q}e
[ N " (0)] EJ 6L 4L2 6L 2L2
Vậy: [S]e=EJ " 3
[ N (L )] L 6L 2L
2
6L 4L2
8.6. Phương pháp phần tử hữu hạn trong Cơ học chất lỏng
Khác với chất rắn trong lưu chất các phân tử của nó chuyển động tương đối với
nhau.
Các phương trình cơ bản của cơ học chất lưu được suy diễn từ các định luật bảo
toàn khối lượng, động lượng và năng lượng. Với định luật bảo toàn khối lượng người ta
xây dựng phương trình liên tục, từ định luật bảo toàn động lượng xây dựng phương trình
chuyển động, định luật bảo toàn năng lượng chính là định luật thứ nhất của nhiệt động lực
học.
Người ta dùng khái niệm chất lỏng lý tưởng (ideal liquids) là chất lỏng không có
tính nhớt và không nén được; ngược lại mọi chất lưu thực (real fluids) đều có tính nhớt
hữu hạn và có thể nén được hoặc không nén được. Chất lưu không nhớt (non-viscous
fluids) là chất lưu không có tính nhớt, có thể nén được hoặc không thể nén được. Một chất
lưu nhớt (viscous fluids) được gọi là chất lưu Newton nếu hệ số nhớt của nó không phụ
thuộc vào gradient vận tốc; ngược lại chất lưu phi Newton (non- Newtonian fluids) là chất
lưu có hệ số nhớt của nó phụ thuộc vào gradient vận tốc.
Việc giải các bài toán trong cơ học lưu chất thường phức tạp hơn rất nhiều so với
bài toán trong cơ học vật rắn, bởi lẽ đa số các bài toán trong cơ học lưu chất thường
không thể tìm được phiếm hàm, bậc của các số hạng (terms) trong phương trình thường
có độ lớn khác nhau và phụ thuộc vào tốc độ dòng chảy. Đối với bài toán nhiều chiều,
không dừng, biên của bài toán thay đổi theo thời gian, nên bài toán thường phải biến đổi
hệ phương trình chỉ đạo, và lời giải thường phải ở dạng Galerkin không chuẩn, thậm chí
có trường hợp phải sử dụng các phép tách các phương trình (split) và phải sử dụng những
324
thuật toán có độ chính xác rất cao (CBS, Taylor – Galerkin) để có thể nhận được lời giải
số tốt.
Sau đây, giới thiệu lời giải số một bài toán đơn giản theo phương pháp PTHH
Galerkin cho bài toán một chiều của chất lỏng Newton.
Ví dụ: Xét dòng Poiseuille chảy giữa hai bản phẳng song song cho bởi phương trình:
d 2u 1 dp
y (8.59)
dy 2 dx
aL2 y2
Vậy: u (1 2 )
2 L
aL2
Tại trục y = 0 thì: u
2
Bây giờ ta đi tìm u bằng cách đi giải bài toán theo phương pháp PTHH Galerkin,
áp dụng vào phương trình (8.59):
L
d 2u 1 dp
i .
0 dy
2
dy 0
dx
(8.61)
L
d 2u a
hay 0 i . dy 2 dy 0
Với u xấp xỉ trong từng miền con là đoạn thẳng , ᴪj là hàm trọng số. Với bài toán
này, để đơn giản ta chia làm hai phần tử một chiều có chiều dài L theo phương oy:
325
3
uu y j e y u j e
j 1
Với ( y) thường chọn là hàm nội suy Lagrange, ở đây ta chọn bậc của nó là hai:
e
j
_
_ y 2 y
y 1
e
1
h h
1
_
_
_
y y
2e y 4 1
h h
_
_
_
y 2 y
3 y 1
e
h h
_
1
Với y h và áp dụng tích phân từng phần ta có được phương trình dạng ma trận:
2
K U e f e Q
e e
(8.62)
d e d
e
dp
L L
Với : K i . j dy
e
ij ; fi e ie dy
0
0
dy dy dx
du du
Với : Q1e . ; Q3e .
dy 0 dy h
Với h = 2L, ta có :
7 8 1 u1 1 Q1
1
u q0 L 4 0
8 16 8 2
6L 3 1
1 8 7 u3 1 Q3
Ta thấy lời giải phù hợp với nghiệm chính xác của bài toán là:
q0 L2 y 2
u( y) 1
2 L2
326
Câu hỏi:
1) Trong trường hợp nào hàm dạng đồng nhất với hàm nội suy?
2) Nêu đặc tính của hàm dạng?
3) Trong phương pháp PTHH bước quan trọng nhất là thiết lập phương trình phần tử
(hay còn gọi tính ma trận phần tử), vì sao?
4) Tại sao trong thực hành lập trình tính toán, người ta không sử dụng ma trận định vị để
thiết lập ma trận tổng thể?
Bài tập
1) Hãy trình bày phương pháp Phần tử hữu hạn Galerkin tổng quát và áp dụng cho bài
toán một chiều (one dimension 1D) nào đó, do em tự chọn, có số phần tử ne = 3 ÷ 7,
tự cho các phương trình ma trận phần tử (element matrix equations) [K]e.{X}={c}e .
Hãy thiết lập hệ phương trình ma trận cho toàn hệ: [K]e.{X} = {c}e
d 2T
2) Giải phương trình f ( x) với chiều dài thanh l = 10cm với điều kiện biên
dx 2
T(0, t) = 50, T(10, t) = 100 và hàm phân bố nhiệt độ f(x) = 20, theo phương pháp
phần tử hữu hạn Galerkin.
327
PHẦN PHỤ LỤC
b ( x2 , y 2 , z 2 )
c a b
b
c b
aa
a
i j k
a b 4 0 1 i 10 j 4k 1, 10, 4
2 1 3
328
u v w u v w
a0 0a
a a 0
c a b ca cb
c k a ca ka
c ka ck a
1a a
0a 0
1a a
i . i = 1, j . j = 1, k . k = 1
i . j = 0, j . k = 1, i . k = 1
1 1
V1 = abc, V2 = V1 = abc
6 6
r
x
Adr rotAdsvới r xi y j zk
(L ) ( S)
i j k
CurlA = X A =
X Y z
AX AY AZ
AZ AY A A A A
CurlA = i( - ) + j( X - Z ) + k( Y - X ) = rotA
y z z x x y
A (iA X jA Y kA Z ) i j k A X AY AZ
x y z x y z
d d (.) (.)
u hay u (.)
dt t dt t
330
2 2 2 u u u 2 2 2
2 2 2 , divgrad u = u u = 2
2 2
x y z x y 2 z2
Ví dụ 2. Cho U = 2x + yz – 3y2. Tính U
U = 2i + (z - 6y)j + yk
Ví dụ 3. Cho A = 3xzi + 2xyj – yz2k. Tính A
A = 3z + 2x – 2yz
Ví dụ 4. Cho A = yzi + 3zxj + zk.
CurlA = X A = -3xi + yj + 2zk
Ví dụ 5. Chiếu phương trình Navier- Stocks lên hệ trục tọa độ tự nhiên:
dv 1
F gradp v
dt
Trong đó: F g
v : Trường vận tốc dòng chảy.
v
Hướng d n: VT= v.v
t
à v iv x jv y kv z
v v v
v i j k
x y z
1 p p p 2v 2v 2v
VP= iFx jFy k Fz (i j k ) ( 2 2 2 )
x y z x y z
331
aij có hai chỉ số, nên là Tensor hạng hai
Qui tắc chỉ số
Khi có hai chỉ số giống nhau, iểu thị một tổng:
3
aibi = a1b1+ a2b2+ a3b3 = ai bi
i 1
Hệ thống đối ứng khi aij = aji, phản đối ứng khi aij = -aji
Ví dụ 6.
1 khi i= j
ij
0 khi i j
là một Tensor hạng hai đối ứng.
Tổng các Tensor cùng hạng là một Tensor cùng hạng:
Cijk = aijk bijk (hạng a)
Nh n Tensor: Cijklm= aijk.blm
(mọi tích có thể có của từng thành phần Tensor)
Vô hướng được em như Tensor hạng zero.
Phép cuộn Tensor:
Được thực hiện khi có hai chỉ số ất kỳ trùng nhau:
3
aijkk = aijkk = aij11+ aij22+ aij33 = Cij
k 1
x x 'a , y y' b
x ' x a , y' y b
+ Phép quay:
B B’
W = f(z)
A C A’ C’
y v
o O’ u
x
γ l l’
y g h γ’ g’
v
h’
x0, yo u0, vo
Ϭ
ϕ’
λ ϕ '
λ
'
o
o x u
Đặt U(x i , P) U(x i , P)e dt , hàm U(x i , P) được gọi là phép iến đổi
Pt
. U PU U(x i , P) ,
U(x i , t ) Pt
0 t 0
z
mặt nước
mặt nước 1
(x,y,t)
O
0 ,
h(x,y) đáy
đáy x,y -1
Tọa độ
Tọa độ z
334
D. MỘT VÀI ỨNG DỤNG CỦA GIẢI TÍCH HÀM
1. Không gian mêtrix
Định nghĩa: ột tập hợp X được gọi là một không gian etri , nếu ứng với
mỗi cặp phần tử , y X có một số thực (x, y) 0, gọi là khoảng cách giữa & y,
thỏa điều kiện sau:
(x, y) = 0 khi và chỉ khi x = y, (x, y) = (y, x)
(x, y) (x, z) + (z, y), x, y, z X ( ất đẳng thức tam giác).
2. Không gian tuyến tính định chuẩn
Tập hợp X được gọi là không gian tuyến tính nếu trên tập hợp đó ác định hai
phép tính: Cộng các phần tử và nh n phần tử với một số đ ng thời thỏa các tiên đề:
x+y =y+x , (x + y) + z = x + (y + z ),
(x + y) = x + y , ( + )x = x + x , (x) = ()x
T n tại phần tử X, gọi là phần tử không, sao cho 0. = , x X
Không gian tuyến tính được gọi là định chuẩn, nếu ứng với mỗi X ta ác
định được một số thực gọi là chuẩn của và ký hiệu x đ ng thời số thực đó thỏa
x . x , R, xX
335
Không gian tuyến tính mà trong đó có ác định tích vô hướng được gọi là
không gian Euclic.
Không gian Euclic đủ, vô hạn chiều được gọi là không gian Hil ert.
4. Toán Tử Tuyến Tính - Phiếm Hàm Tuyến Tính
Giả sử X, Y là hai không gian Topo tuyến tính
Toán tử (hay ánh ạ):
A: X Y (y = Ax , x X , y Y) được gọi là tuyến tính nếu ta có:
A(x1 + x2 ) = Ax1 + Ax2
Tập hợp tất cả các gía trị X mà tại đó A ác định, được gọi là miền ác
định của toán tử A và ký hiệu D(A). iền giá trị của A được ký hiệu R(A) Y.
Trong trường hợp Y = R1 (trường số thực), thì toán tử tuyến tính A được gọi là
phiếm hàm tuyến tính.
Câu hỏi:
1) Nêu ý nghĩa vật lý và trình ày công thức tính của các toán tử Haminton
(GradU, DivA, RotA)? Sự ích lợi của nó ?
2) Hãy nêu những ưu nhược điểm của phép tính toán tử so với phép tính tensor ?
3) Hãy nêu vài ứng dụng của công thức Stockes và công thức O trograski–Gauss?
4) Hãy nêu vài ứng dụng của các phép iến đổi (Laplace, iến hình ảo giác,
Sigma) ?
Bài tập :
1) Chứng minh: divgradu 2u
rot(u.a) gradu a urota với: a là vectơ, u = u( , y, z)
Hãy viết nó ở dạng chiếu lên các trục tọa độ o , oy, oz.
336
5) Viết các thành phần hình chiếu lên các trục o , oy, oz của các phương trình sau:
ui
div (kT ) ij
de
.
dt x j
Với:
u u
ij p ij i j ij divV
x
j xi
337
TÀI LIỆU THAM KHẢO
1. Phạm Kỳ Anh, Giải tích số, Nhà xuất bản Đại học Quốc Gia, Hà Nội 1996
2. Đào Huy Bích - Nguyễn Đăng Bích, Cơ học môi trường liên tục, Nhà xuất bản
Xây Dựng, Hà Nội 2002
3. Phan Đăng Cầu & Phan Thị Hà, Giáo trình phương pháp số, Nhà xuất bản
Bưu Điện 2007
4. Tạ Văn Đĩnh, Phương pháp tính, Nhà xuất bản giáo dục, 1997
5. Phạm Hồng Giang, Phương pháp phần tử biên, NXB Khoa học và kỹ thuật,
Hà Nội 2002.
6. Phan Văn Hạp và các tác giả khác, Cơ sở phương pháp tính, Nhà xuất bản Đại
học - Trung học chuyên nghiệp, Hà Nội 1970
7. Nguyễn Thế Hùng, Giáo trình Phương pháp số, Đại học Đà Nẵng 1996
8. Nguyễn Thế Hùng, Phương pháp phần tử hữu hạn trong chất lỏng, Nhà xuất
bản Xây Dựng, Hà Nội 2004
9. Đặng Quốc Lương, Phương pháp tính trong kỹ thuật, Nhà xuất bản Xây Dựng,
Hà Nội 2001
10. Đinh Văn Phong, Phương pháp số trong cơ học, Nhà xuất bản Khoa học và Kỹ
thuật, Hà Nội 1999
11. Lê Đình Thịnh, Phương pháp tính, Nhà xuất bản Khoa học và Kỹ thuật, Hà
Nội 1995
12. Lê Trọng Vinh, Giải tích số, Nhà xuất bản Khoa học và Kỹ thuật, Hà Nội 2000