Hàm e mũ trong lập trình viết như thế nào

Trở về Mục lục cuốn sách1. Chiếc máy tính tayPhần cốt lõi của MATLAB là một chiếc máy tính tay. Khi khởi động MATLAB bạn sẽ thấy một cửa sổ có tiêu đề MATLAB trong đó chứa những cửa sổ con có các tiêu đề Current Directory (Thư mục hiện hành), Command History (Nhật ký lệnh) và Command Window (Cửa sổ lệnh). Riêng cửa sổ lệnh dùng để chạy trình thông dịch MATLAB; nó cho phép bạn gõ vào các câu lệnh MATLAB, rồi thực hiện chúng và in ra kết quả.

Ban đầu, cửa sổ lệnh hiện một dòng chữ chào người dùng và thông tin về phiên bản MATLAB đang chạy, tiếp theo là dấu

>>

vốn là dấu nhắc của MATLAB; tức là ký hiệu dùng để nhắc bạn nhập vào một câu lệnh.

Dạng câu lệnh đơn giản nhất là một biểu thức toán học, vốn được hợp thành từ các toán hạng (ví dụ như các số) và các toán tử (như dấu cộng, +).

Nếu bạn gõ vào một biểu thức và ấn Enter (hoặc Return), MATLAB sẽ lượng giá biểu thức và in ra kết quả.

>> 2 + 1
ans = 3

Để nói rõ hơn: trong ví dụ trên, MATLAB tự in ra >>; tôi gõ vào 2 + 1 và ấn Enter, rồi MATLAB lại in ra ans = 3. Khi tôi nói là “in”, điều đó có nghĩa là “hiện lên màn hình”. Điều này có thể làm bạn thoạt đầu thấy dễ lẫn, nhưng đó chính là cách mọi người vẫn nói.

Một biểu thức có thể bao gồm bao nhiêu toán tử và toán hạng cũng được. Bạn không cần phải gõ các dấu cách; một số người gõ và một số người không.

>> 1+2+3+4+5+6+7+8+9
ans = 45

Lại nói về dấu cách, bạn có thể nhận thấy rằng MATLAB chèn vào một số dấu cách giữa ans = và kết quả. Trong các ví dụ tôi sẽ bỏ bớt khoảng cách này để tiết kiệm chỗ.

Các toán tử số học khác cũng giống như bạn đã biết. Phép trừ kí hiệu bởi dấu -; phép nhân bởi một dấu sao, *; phép chia bởi dấu gạch chéo xuôi /.

>> 2*3 - 4/5
ans = 5.2000

Thứ tự thực hiện phép toán cũng giống như trong môn đại số: các phép nhân và chia được thực hiện trước các phép cộng và trừ. Bạn có thể dùng cặp ngoặc đơn để thay đổi thứ tự tính.

>> 2 * (3-4) / 5
ans = -0.4000

Khi thêm vào cặp ngoặc đơn, tôi cũng đồng thời thay đổi độ dãn cách để ta dễ đọc hơn. Đây là một trong những gợi ý về cách trình bày trong cuốn sách, để chương trình được dễ đọc. Bản thân phong cách không làm ảnh hưởng đến tính năng của chương trình; trình thông dịch MATLAB không kiểm tra phong cách. Nhưng người đọc thì có, và quan trọng nhất bạn chính là người đọc thường xuyên nhất các mã lệnh bạn viết ra.

Từ đó dẫn đến định lý thứ nhất về gỡ lỗi chương trình:

Mã lệnh dễ đọc cũng dễ gỡ lỗi.

Thời gian bạn bỏ ra để làm đẹp mã lệnh hoàn toàn xác đáng; điều này sẽ giúp bạn tiết kiệm thời gian gỡ lỗi!

Toán tử thông dụng tiếp đến là lũy thừa, với ký hiệu ^, đôi khi còn được gọi là “dấu mũ”. Số 2 nâng lên lũy thừa 16 là

>> 2^16
ans = 65536

Cũng như trong đại số cơ bản, phép lũy thừa được thực hiện trước các phép nhân và chia, nhưng một lần nữa, bạn có thể dùng cặp ngoặc tròn để thay đổi thứ tự thực hiện phép tính.

2. Các hàm toán học

MATLAB biết cách tính gần như mọi hàm toán học bạn biết đến. Nó biết tất cả các hàm lượng giác; sau đây là cách dùng:

>> sin(1)
ans = 0.8415

Lệnh này là một ví dụ của một lời gọi hàm. Tên của hàm này là sin, vốn là ký hiệu thông dụng của hàm lượng giác sin. Giá trị trong cặp ngoặc tròn được gọi là đối số. Tất cả các hàm lượng giác trong MATLAB đều tính theo ra-đian.

Một số hàm nhận nhiều đối số, khi đó chúng được phân cách bởi cách dấu phẩy. Chẳng hạn, atan2 dùng để tính nghịch đảo của hàm tan, vốn là góc tính theo ra-đian giữa chiều dương trục x và điểm có các tọa độ yx cho trước.

>> atan2(1,1)
ans = 0.7854

Nếu bạn không rành chút kiến thức lượng giác trên thì cũng không nên lo lắng. Đó chỉ là một ví dụ cho thấy hàm có nhiều đối số.

MATLAB cũng có các hàm lũy thừa, như exp, dùng để tính số e nâng lên một số mũ cho trước. Vì vậy exp(1) chính là e.

>> exp(1)
ans = 2.7183

Nghịch đảo của explog, nhằm tính loga cơ số e:

>> log(exp(3))
ans = 3

Ví dụ này cũng cho thấy các lời gọi hàm có thể lồng ghép được; nghĩa là bạn có thể dùng kết quả tính được từ hàm này để làm đối số cho một hàm khác.

Một cách tổng quát hơn, bạn có thể dùng lời gọi một hàm như là toán hạng cho một biểu thức.

>> sqrt(sin(0.5)^2 + cos(0.5)^2)
ans = 1

Như bạn có thể đoán được, sqrt có tác dụng tính căn bậc hai.

Còn có rất nhiều hàm toán học khác, nhưng cuốn sách này không nhằm mục đích là một cuốn sổ tra cứu. Để biết cách dùng các hàm khác, bạn cần phải đọc tài liệu.

3. Tài liệu

MATLAB đi kèm theo hai dạng tài liệu trực tuyến, helpdoc.

Lệnh help hoạt động trong cửa sổ lệnh; bạn chỉ cần gõ help theo sau là tên của lệnh.

>> help sin
 SIN    Sine of argument in radians.
    SIN(X) is the sine of the elements of X.

    See also asin, sind.

    Overloaded functions or methods (ones with the same name in other
       directories) help sym/sin.m

    Reference page in Help browser
       doc sin

Không may là kiểu tài liệu này không thích hợp lắm với người bắt đầu.

Có một chỗ dễ gây lỗi là tên hàm trong thông tin trợ giúp trên xuất hiện là chữ in, nhưng nếu bạn gõ y hệt như thế vào MATLAB, bạn sẽ nhận một lỗi:

>> SIN(1)
??? Undefined command/function 'SIN'.

Một vấn đề khác là có những từ trong thông tin trợ giúp mà bạn vẫn còn chưa biết nghĩa. Chẳng hạn, “the elements of X” (phần tử của X); bạn chỉ hiểu được sau khi đọc đến mục véc-tơ và ma trận sau đây mấy chương.

Các trang doc thường tốt hơn. Nếu bạn gõ doc sin, một trình duyệt sẽ xuất hiện với các thông tin chi tiết về hàm này và cả những ví dụ về cách dùng nó. Những ví dụ này thường có véc-tơ và ma trận, giờ thì bạn chưa hiểu, nhưng có thể sẽ biết qua về những nội dung sắp tới.

4. Biến

Một trong những đặc điểm giúp MATLAB mạnh hơn một máy tính tay là khả năng đặt tên cho một giá trị. Một giá trị sau khi đã đặt tên được gọi là một biến.

MATLAB đi kèm theo một số giá trị định sẵn. Chẳng hạn 1, cái tên pi dùng để chỉ đại lượng π trong toán học, vốn gần bằng

>> pi
ans = 3.1416

Và nếu bạn làm bất cứ phép tính nào với số phức, có thể bạn sẽ thấy tiện khi dùng i hoặc j vốn được định nghĩa sẵn là căn bậc hai của -1.

Bạn có thể dùng một tên biến ở bất cứ chỗ nào viết được một số; chẳng hạn, như toán hạng trong một biểu thức:

>> pi * 3^2
ans = 28.2743

hoặc như đối số cho một hàm:

>> sin(pi/2)
ans = 1

>> exp(i * pi)
ans = -1.0000 + 0.0000i

Như ví dụ thứ hai đã cho thấy, nhiều hàm MATLAB cũng tính được với số phức. Ví dụ này biểu diễn đẳng thức Euler: eiπ=-1.

Mỗi khi lượng giá một biểu thức, MATLAB gán giá trị cho một biến có tên là ans. Bạn có thể dùng ans trong phép tính tiếp theo như một cách viết tắt cho “giá trị của biểu thức liền trước”.

>> 3^2 + 4^2
ans = 25

>> sqrt(ans)
ans = 5

Nhưng nhớ rằng giá trị của ans lại thay đổi mỗi khi bạn lượng giá một biểu thức.

5. Lệnh gán

Bạn có thể tự tạo các biến và cho chúng các giá trị, bằng cách dùng lệnh gán. Toán tử gán là dấu bằng, =.

>> x = 6 * 7
x = 42

Ví dụ này tạo ra một biến mới có tên là x và gán cho nó giá trị của biểu thức 6 * 7. MATLAB trả lời lại với tên biến và giá trị tính được.

Trong mỗi câu lệnh gán, vế trái phải là một tên biến hợp lệ. Vế phải có thể là một biểu thức bất kì, bao gồm cả lời gọi hàm.

Hầu như bất kỳ dãy chữ cái viết thường và viết in nào cũng tạo nên một tên biến hợp lệ. Một số dấu nhất định cũng hợp lệ, nhưng chỉ có dấu gạch thấp, _, là kí hiệu thông dung nhất. Các chữ số cũng được, nhưng không được đặt chúng ở đầu tên biến. Không được dùng các dáu cách. Các tên biến đều có sự phân biệt giữa chữ in và chữ thường, vì vậy xX là các biến khác nhau.

>> fibonacci0 = 1;

>> LENGTH = 10;

>> first_name = 'allen'
first_name = allen

Hai ví dụ đầu cho thấy cách dùng của dấu chấm phẩy, dùng để ngăn không cho in ra kết quả của câu lệnh. Trong trường hợp này MATLAB tạo ra biến và gán nó với giá trị, nhưng không hiển thị gì.

Ví dụ thứ ba cho thấy rằng không phải mọi thứ trong MATLAB đều là con số. Một dãy các ký tự trong cặp dấu nháy đơn được gọi là một chuỗi.

Mặc dù i, jpi đều được định nghĩa sẵn nhưng bạn hoàn toàn có thể gán lại chúng. Việc dùng ij vào mục đích khác cũng thường thấy, song có lẽ sẽ không hay nếu ta đổi giá trị của pi!

6. Tại sao phải dùng biến?

Các lý do chung lý giải cho việc dùng biến là

  • Để tránh việc tính lại một giá trị được dùng lặp lại nhiều lần. Chẳng hạn, nếu bạn thực hiện tính toán liên quan đến e, có thể bạn sẽ muốn tính nó một lần và lưu lại kết quả.
    >> e = exp(1)
    e = 2.7183
    
  • Để làm cho sự gắn kết giữa mã lệnh và cơ sở toán học trở nên rõ ràng hơn. Nếu bạn tính diện tích của một hình tròn, có thể bạn muốn dùng một biến có tên là r:
    >> r = 3
    r = 3
    
    >> area = pi * r^2
    area = 28.2743
    

    Bằng cách này mã lệnh viết ra sẽ giống với công thức quen thuộc πr2.

  • Để chẻ nhỏ một phép tính dài thành một loạt các bước. Chẳng hạn bạn phải lượng giá một biểu thức đồ sộ, gai góc như sau:
    ans = ((x - theta) * sqrt(2 * pi) * sigma) ^ -1 * ...
    exp(-1/2 * (log(x - theta) - zeta)^2 / sigma^2)
    

    Bạn có thể dùng dấu ba chấm để tách một biểu thức thành nhiều dòng. Chỉ việc gõ vào ... ở cuối dòng trên rồi tiếp tục gõ xuống dòng dưới.

    Nhưng cách tốt hơn thường là chia phép tính thành một loạt các bước kế tiếp và gán những kết quả trung gian cho các biến.

    shiftx = x - theta
    denom = shiftx * sqrt(2 * pi) * sigma
    temp = (log(shiftx) - zeta) / sigma
    exponent = -1/2 * temp^2
    ans = exp(exponent) / denom
    

    Tên của các biến trung gian giải thích vai trò của chúng trong phép tính. shiftx là giá trị của x bị dịch chuyển đi theta đơn vị. Cũng dễ hiểu khi đặt exponent là đối số cho hàm exp, và denom thay thế cho mẫu số. Việc chọn những cái tên có nghĩa làm cho mã lệnh dễ đọc và dễ hiểu (xem Định lý thứ nhất về gỡ lỗi).

7. Lỗi

Tuy giờ còn sớm nhưng rất có thể bạn đã bắt đầu mắc lỗi khi lập trình. Mỗi khi học thêm được một đặc điểm mới của MATLAB, bạn cần phải thử để gây ra lỗi, càng nhiều càng tốt, càng sớm càng tốt.

Khi bạn cố ý gây ra lỗi, bạn sẽ thấy các thông báo lỗi trông như thế nào. Sau này, khi bạn vô tình mắc lỗi, bạn sẽ hiểu được những thông báo lỗi khi đó có ý gì.

Một lỗi hay gặp ở người mới lập trình là việc bỏ qua dấu * trong phép nhân.

>> area = pi r^2
??? area = pi r^2
              |
Error: Unexpected MATLAB expression.

Thông báo lỗi chỉ ra rằng, sau khi thấy toán hạng pi, MATLAB “trông đợi” một toán tử, chẳng hạn *. Nhưng thay vào đó, nó nhận được một tên biến, vốn là biểu thức không được mong đợi (“unexpected expression”), được chỉ ra bởi dấu sổ thẳng, | (còn gọi là “pipe”).

Một lỗi hay gặp khác là việc bỏ quên cặp ngoặc tròn bao quanh các đối số của một hàm. Chẳng hạn, trong cách viết toán học, ta thường ghi \sinπ, nhưng trong MATLAB thì không được như vậy.

>> sin pi
??? Function 'sin' is not defined for values of class 'char'.

Vấn đề ở đây là khi bạn bỏ mất cặp ngoặc, MATLAB sẽ coi như đối số là một chuỗi kí tự (thay vì một biểu thức). Trong trường hợp này, hàm sin sẽ gây ra một thông báo lỗi hợp lý; nhưng những lúc khác kế quả có thể sẽ loạn. Chẳng hạn, bạn có thể hiểu được điều gì đang diễn ra ở đây không?

>> abs pi
ans =  112   105

Cái “đặc điểm ngôn ngữ” này có lý do riêng của nó, nhưng thay vì tìm hiểu ngay bây giờ, tôi khuyên bạn nên {luôn luôn} viết cặp ngoặc tròn bao quanh các đối số.

Ví dụ này minh họa cho Định lý thứ hai của việc gỡ lỗi.

Điều duy nhất còn tồi tệ hơn cả việc nhận được thông báo lỗi là việc không nhận được thông báo lỗi nào.

Những người mới bắt đầu lập trình ghét các thông báo lỗi và tìm mọi cách xua đuổi chúng đi. Những người lập trình có kinh nghiệm hiểu rằng thông báo lỗi là người bạn của họ. Chúng có thể khó hiểu, và thậm chí có thể đánh lạc hướng, nhưng công sức bỏ ra đểu hiểu được chúng sẽ được đền bù xứng đáng.

Sau đây là một lỗi thông thường khác của người mới bắt đầu. Nếu bạn chuyển biểu thức toán sau đây sang MATLAB:

1 / 2√π

Bạn có thể muốn viết như sau:

1 / 2 * sqrt(pi)

Nhưng cách này sai. Rất sai.

8. Phép toán số học với những số có phần thập phân

Trong toán học, có một vài loại số: số nguyên, số thực, hữu tỉ, vô tỉ, số ảo, số phức, v.v. MATLAB chỉ có một kiểu số, đó là số có phần thập phân, chính xác hơn là dấu phẩy động.

Bạn có thể đã nhận thấy rằng MATLAB biểu thị các giá trị theo cách viết có phần thập phân. Vì vậy, số hữu tỉ 1/3 chẳng hạn được biểu diễn bởi giá trị phẩy động như sau

>> 1/3
ans = 0.3333

vốn chỉ gần đúng. Thực ra nó không đến nỗi dở như ta có thể hình dung; MATLAB dùng nhiều chữ số hơn là nó biểu diễn (hiển thị) trên màn hình. Bạn có thể thay đổi format (định dạng) để thấy các chữ số còn lại.

>> format long
>> 1/3
ans = 0.33333333333333

Ở bên trong, MATLAB dùng dạng dấu phẩy động IEEE với độ chính xác kép, vốn có khoảng 15 chữ số có nghĩa (theo hệ thập phân). Các chữ số không đứng ở đầu hoặc cuối không được tính là chữ số “có nghĩa”, vì vậy MATLAB có thể biểu diễn cả những số lớn lẫn nhỏ với cùng lượng chữ số có nghĩa như vậy.

Những giá trị rất lớn và rất nhỏ được biểu diễn theo cách viết khoa học.

>> factorial(100)
ans = 9.332621544394410e+157

Kí hiệu e trong cách viết này không phải là hằng số mũ e; nó chỉ là chữ viết tắt của “exponent” (lũy thừa). Vì vậy ở đây, 100! xấp xỉ với 9,33 × 10157. Đáp số chính là một số nguyên gồm 158 chữ số, nhưng ở đây ta chỉ biết được 16 chữ số đầu tiên.

Bạn có thể tự nhập vào các số theo cách viết tương tự.

>> speed_of_light = 3.0e8
speed_of_light = 300000000

Dù MATLAB có thể xử lý được những số lớn, nhưng vẫn có một giới hạn. Các biến được định nghĩa trước, realmaxrealmin, chứa các giá trị số lớn nhất và nhỏ nhất mà MATLAB có thể xử lý2.

>> realmax
ans = 1.797693134862316e+308

>> realmin
ans = 2.225073858507201e-308

Nếu kết quả tính toán quá lớn, MATLAB sẽ “làm tròn lên” thành vô cùng.

>> factorial(170)
ans = 7.257415615307994e+306

>> factorial(171)
ans = Inf

Phép chia cho số không cũng trả lại kết quả Inf, nhưng trong trường hợp này MATLAB sẽ cảnh báo bạn vì phép chia cho không thường được coi là không xác định.

>> 1/0
Warning: Divide by zero.

ans = Inf

Một lời cảnh báo cũng giống như một thông báo lỗi nhưng “vô hại”; việc tính toán vẫn được tiếp tục. Việc để cho Inf tiếp tục lan truyền đi trong phép tính thường không cho kết quả như bạn mong đợi, nhưng nếu bạn cẩn thận khi dùng nó, Inf có thể sẽ hữu ích.

Với những phép tính thực sự không xác định, MATLAB sẽ trả lại NaN, là viết tắt của “not a number” (không phải một con số).

>> 0/0
Warning: Divide by zero.

ans = NaN

9. Lời chú thích

Ngoài những câu lệnh cấu thành chương trình, sẽ rất có ích nếu ta kèm thêm những lời chú thích để đưa thêm thông tin về chương trình. Dấu phần trăm % ngăn cách lời chú thích với mã lệnh.

>> speed_of_light = 3.0e8     % meters per second
speed_of_light = 300000000

Lời chú thích chạy từ dấu phần trăm về cuối dòng. Ở trường hợp trên nó giải thích về đơn vị của giá trị. Bạn có thể tưởng tượng rằng MATLAB sẽ giúp việc theo dõi các đơn vị và thao tác với chúng qua từng phép tính, nhưng thật ra gánh nặng đó được đặt lên vai người lập trình.

Lời chú thích không ảnh hưởng đến việc thực thi chương trình. Chúng chỉ dành cho người đọc. Những lời chú thích hợp lý sẽ làm chương trình dễ đọc hơn, nhưng chú thích dở thì vô dụng hoặc (còn tệ hơn nữa) có thể gây nhầm lẫn.

Hãy tránh việc đặt những lời chú thích thừa:

>> x = 5        % assign the value 5 to x

Những lời chú thích hay phải bổ sung thông tin vốn không có sẵn trong câu lệnh, như ở ví dụ trên, phải nói về ý nghĩa của biến:

>> p = 0         % position from the origin in meters 
>> v = 100       % velocity in meters / second
>> a = -9.8      % acceleration of gravity in meters / second^2

Nếu bạn dùng các tên biến dài thì bạn có thể cũng không cần những lời chú thích như vậy, nhưng điều này lại bất tiện ở chỗ: câu lệnh dài sẽ khó đọc hơn. Ngoài ra, nếu bạn chuyển từ biểu thức toán vốn dùng tên biến ngắn thì chương trình bạn nên thống nhất với công thức toán học.

10. Thuật ngữ

trình thông dịch:Chương trình làm nhiệm vụ đọc và thực thi mã lệnh MATLAB. mã lệnh:Dòng lệnh MATLAB được thực thi bởi trình thông dịch. dấu nhắc:Ký hiệu mà trình thông dịch in ra để chỉ rằng nó đang đợi bạn gõ vào một câu lệnh. toán tử:Một trong các kí hiệu, như *+, để biểu thị cho các phép toán. toán hạng:Một số hoặc một biến xuất hiện trong biểu thức bên cạnh các toán tử. biểu thức:Dãy các toán hạng và toán tử để biểu thị một phép toán và trả lại một giá trị. giá trị:Kết quả số của một phép tính. lượng giá:Tính giá trị của một biểu thức. thứ tự tính toán:Quy tắc chỉ định những phép toán nào trong một biểu thức sẽ được thực hiện trước. hàm:Một phép tính được đặt tên; chẳng hạn log10 là tên hàm dùng để tính loga cơ số 10. gọi:Để hàm được thực thi và tính một kết quả. lời gọi hàm:Dạng câu lệnh để thực thi một hàm. đối số:Biểu thức xuất hiện trong một lời gọi hàm để chỉ định các giá trị mà hàm thao tác với. lời gọi hàm lồng ghép:Biểu thức trong đó dùng kết quả của một lời gọi hàm làm đối số cho một lời gọi hàm khác. biến:Một giá trị được đặt tên. lệnh gán:Lệnh tạo ra một biến mới (nếu cần) và cho nó một giá trị. chuỗi:Giá trị bao gồm một dãy các kí tự (đối ngược với một con số). dấu phẩy động:Kiểu số mà MATLAB sử dụng. Tất cả các số có dấu phẩy động đều biểu diễn được với khoảng 16 chữ số trong phần thập phân (khác với các số nguyên và số thực trong toán học). cách viết khoa học:Một dạng viết và biểu thị các số lớn và nhỏ; chẳng hạn 3.0e8 để biểu thị cho 3,0 × 108 hay 300 000 000. lời chú thích:Phần của chương trình nhằm cung cấp thêm thông tin về chương trình, nhưng không ảnh hưởng đến việc thực thi nó.

11. Bài tập

Hãy viết một biểu thức MATLAB để lượng giá biểu thức toán sau đây. Bạn có thể coi rằng các biến mu, sigmax đều đã tồn tại.

(e-(x-μ)/(σ√2)2) / (σ√2π)

Lưu ý: bạn không thể dùng những chữ cái Hi Lạp trong MATLAB; khi chuyển từ biểu thức toán có chứa chữ cái Hi Lạp, ta thường viết hẳn tên nó (coi như bạn đã biết tên các chữ cái này).