Giúp chuyển bảng dữ liệu (x>0) thành bảng dữ liệu mới sau khi Loga nê pe các phần tử! (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Bảng tính mà còn bày đặt merge cells chỉ tổ gặp rắc rối sau này.
Bỏ merge cells đi thì mới có hứng code.

Gợi ý:
1. dùng Record Macro để chọn nguyên vùng nguồn
2. dùng Record Macro để chọn nguyên vùng đích, gõ công thức vào ô đầu và Ctrl+Enter để nó cóp công thức sang các ô còn lại.
3. chỉnh macro. Hàm Log tự nhiên trong VBA là Log(số). Hàm log theo hệ là Log(số)/Log(hệ)
 
Lần chỉnh sửa cuối:
Upvote 0
Vâng bác! Vậy Log trong VBA là Logarit cơ số e luôn.
Trừ phi bạn muốn làm con tính theo chuỗi khai triển Taylor. (Tính theo chuỗi Taylor cũng xứng đáng làm một bài tập viết code)

Cóp từ quép sai chỉ dẫn của Microsoft:

1622547373268.png

Dịch:
Hàm trả về một trị Double là Log tự nhiên của một số.

Ngữ pháp:
Log(số)
Số là tham bắt buộc, kiểu biến Double hoặc bất kỳ biểu thức số lớn hơn 0.
Chú của riêng tôi: VBA có tậ ép kiểu, chỉ cần cho nó tham là số thì nó tự đọng ép ra Double. Vả lại, Double là kiểu cao nhất của số cho nên hầu như bất cứ số nào cũng có thể ép thành Double tư. Tuy nhiên, nếu gọi hàm này với hằng thì nên thêm # sau hằng để trình dịch khỏi phải ép kiểu
Log(15#)

Chú thích:
Log tự nhiên là log với hệ e. Hằng số e có giá trị khoảng 2,718282.
 
Upvote 0
Bảng tính mà còn bày đặt merge cells chỉ tổ gặp rắc rối sau này.
Bỏ merge cells đi thì mới có hứng code.
Bài 1 minh họa cho câu hỏi để các bác có để ý đến thì dễ hiểu bác ạ!
1. dùng Record Macro để chọn nguyên vùng nguồn
2. dùng Record Macro để chọn nguyên vùng đích, gõ công thức vào ô đầu và Ctrl+Enter để nó cóp công thức sang các ô còn lại.
3. chỉnh macro. Hàm Log tự nhiên trong VBA là Log(số). Hàm log theo hệ là Log(số)/Log(hệ)
Bảng tạo Đích tạo ra là bảng có giá trị sau khi Log(x) là được ạ, không phải là tham chiếu Formula
Chỗ này dùng vòng lặp lồng vào nhau, thử hoài không được.
Bác và các bác cho em xin code bài này với!
Em cảm ơn các bác!
Bài đã được tự động gộp:

Trừ phi bạn muốn làm con tính theo chuỗi khai triển Taylor. (Tính theo chuỗi Taylor cũng xứng đáng làm một bài tập viết code)

Cóp từ quép sai chỉ dẫn của Microsoft:

View attachment 259856

Dịch:
Hàm trả về một trị Double là Log tự nhiên của một số.

Ngữ pháp:
Log(số)
Số là tham bắt buộc, kiểu biến Double hoặc bất kỳ biểu thức số lớn hơn 0.
Chú của riêng tôi: VBA có tậ ép kiểu, chỉ cần cho nó tham là số thì nó tự đọng ép ra Double. Vả lại, Double là kiểu cao nhất của số cho nên hầu như bất cứ số nào cũng có thể ép thành Double tư. Tuy nhiên, nếu gọi hàm này với hằng thì nên thêm # sau hằng để trình dịch khỏi phải ép kiểu
Log(15#)

Chú thích:
Log tự nhiên là log với hệ e. Hằng số e có giá trị khoảng 2,718282.
Do dính dáng đến hồi quy phi tuyến nên Loga nê pe 2 vế đưa về tuyến tính.Nên Loga nê pê bảng dữ liệu đầu vào để hồi quy phi tuyến theo tuyến tính.
Dữ liệu là số Double và dương, chuyển bảng hiện có qua Loga nê pe là được ạ!
 
Lần chỉnh sửa cuối:
Upvote 0
Sub t()
Const RGNGU = "c3" ' từ đây xác định vùng sử dụng của đầu vào
Const RGNGUOFFSET = 2 ' vùng sử dụng sẽ chứa 2 dòng title, dữ liệu cầnn thiết thì phải nhảy 2 dòng
Const RGDIT = "i3" ' ô bắt đầu dữ liệu cho đầu ra
Dim a As Variant, i As Long, j As Long, ia As Long, ja As Long
a = Range(RGNGU).CurrentRegion.Offset(RGNGUOFFSET, 0).Value
ia = UBound(a) - RGNGUOFFSET ' mảng dữ liệu thật ra nhỏ hơn vùng sử dụng 2 dòng
ja = UBound(a, 2)
For i = 1 To ia
For j = 1 To ja
If a(i, j) > 0 Then
a(i, j) = Log(a(i, j))
Else
a(i, j) = "#NUM!"
End If
Next j
Next i
Range(RGDIT).Resize(ia, ja).Value = a
End Sub

Có ai muốn thử viết code cho hàm Log hôn?
 
Upvote 0
Sub t()
Const RGNGU = "c3" ' từ đây xác định vùng sử dụng của đầu vào
Const RGNGUOFFSET = 2 ' vùng sử dụng sẽ chứa 2 dòng title, dữ liệu cầnn thiết thì phải nhảy 2 dòng
Const RGDIT = "i3" ' ô bắt đầu dữ liệu cho đầu ra
Dim a As Variant, i As Long, j As Long, ia As Long, ja As Long
a = Range(RGNGU).CurrentRegion.Offset(RGNGUOFFSET, 0).Value
ia = UBound(a) - RGNGUOFFSET ' mảng dữ liệu thật ra nhỏ hơn vùng sử dụng 2 dòng
ja = UBound(a, 2)
For i = 1 To ia
For j = 1 To ja
If a(i, j) > 0 Then
a(i, j) = Log(a(i, j))
Else
a(i, j) = "#NUM!"
End If
Next j
Next i
Range(RGDIT).Resize(ia, ja).Value = a
End Sub

Có ai muốn thử viết code cho hàm Log hôn?
Có cái nội suy đa thức sự phiền các bác không dám đưa lên.
 
Upvote 0
Tôi hỏi có ai hứng thử viết hàm triển khai Taylor của Log hay không bởi vì dạng bài này khá phổ biến với bài tập về lập trình.
Bài tập này được những người viết sách và dạy dùng để thử thách tư duy lô gic và vòng lặp của học sinh. Bình thường thì người ta dùng hàm Cosine bởi vì hàm này khá dễ khai triển. Hàm Log thử thách cao hơn một chút bởi vì nó có tới 3 dạng:

1622596935665.png

Hàm Cos chỉ có mọt dạng (vì vậy có thể dùng đệ quy thay cho vòng lặp cũng được)

1622597038328.png

(các hình trên cóp từ quép sai efunda chấm cơm)
 
Upvote 0
Tôi hỏi có ai hứng thử viết hàm triển khai Taylor của Log hay không bởi vì dạng bài này khá phổ biến với bài tập về lập trình.
Bài tập này được những người viết sách và dạy dùng để thử thách tư duy lô gic và vòng lặp của học sinh. Bình thường thì người ta dùng hàm Cosine bởi vì hàm này khá dễ khai triển. Hàm Log thử thách cao hơn một chút bởi vì nó có tới 3 dạng:

View attachment 259878

Hàm Cos chỉ có mọt dạng (vì vậy có thể dùng đệ quy thay cho vòng lặp cũng được)

View attachment 259879

(các hình trên cóp từ quép sai efunda chấm cơm)
Mình cứ thế nghiệm giả định vào e^ làm căn cứ tìm nghiệm gần đúng
 
Upvote 0
Mình cứ thế nghiệm giả định vào e^ làm căn cứ tìm nghiệm gần đúng
Nó xoay thành bài toán: bạn dùng phương pháp trâu bò, đoán từ điểm thấp nhất trở đi hay dùng phép nhị phân, đoán 2 điểm?
Vả lại, dùng phép tính mò như thế bạn phải đoán trước bước tăng đi của từng lượt vòng lặp.
Công thức Taylor chỉ xét lô gic, không cần phải đoán bước. Chỉ cần bạn tự đặt giới hạn "độ gần đúng"
 
Upvote 0
Nó xoay thành bài toán: bạn dùng phương pháp trâu bò, đoán từ điểm thấp nhất trở đi hay dùng phép nhị phân, đoán 2 điểm?
Vả lại, dùng phép tính mò như thế bạn phải đoán trước bước tăng đi của từng lượt vòng lặp.
Công thức Taylor chỉ xét lô gic, không cần phải đoán bước. Chỉ cần bạn tự đặt giới hạn "độ gần đúng"
Bắt đầu 0 -> x ngẫu nhiên hoặc cho cố định ví dụ 10, thế vào e^ và so sánh kết quả: Nếu "gần đúng" thoát , Không bằng: Bước kế nếu lớn hơn là x/2 -> x ngược lại là x -> 2*x ...
 
Upvote 0
Hàm Log:

Lô gic thứ nhất:
Trong ba công thức, cái công thức đại trà x > 0 là rắc rối nhất.
Tuy nhiên nếu ta sử dụng hai congn thức còn lại, 0 < x <=2, và x >= 1/2 thì không cần đến x > 0 nữa.

Như vậy, xét con toán điều kiện x <= 2 là nhẹ nhất:
Logn (x) = (x-1) - (x-1)^2/2 + (x-1)^3/3 = SIGMA( (x-1) ... (+/-)(x-1)^n/n ) : với (+) nếu n lẻ, và - nếu n chẵn.

Code:
Const SORATNHO = 0.000001 ' một phần triệu, dùng để xét giới hạn triển khai
Dim i As Long, soHang As Double
IF x - 0 < SORATNHO Then
LogN = "#NUM!"
ElseIf x > 0. And x <= 2. Then
For i = 1 To 1000 ' trong vòng 1000 số hạng thôi, không nên đi xa quá
soHang = ((x - 1)^n)/n
If abs(soHang) < SORATNHO Then Exit For ' đạt giới hạn
LogN = LogN + IIF(n And 1, soHang, -soHang) ' n And 1 là con toán tét số chẵn lẻ.
Next i
Else ' lớn hơn 2 tức là phải lớn hơn 1/2, không cần phải xét
' code tương tự như trên
End If

Xét thuật toán, ta thấy trị (x - 1) được tính nhiều lần. Như vậy không tối ưu. Đồng thời, bình thường thì con toán luỹ thữa cũng tốn nhiều năng lượng hơn toán nhân. Và đây là điểm mà loại bài tập chuỗi Taylor này được dùng để tét khả năng thuật toán của học sinh ở bước mở đầu. (*1)
Chỉnh như sau:

Dim hatNhan As Double, soHang As Double, soHangN As Double
hatNhan = x - 1.
soHang = 1.
For i = 1 to 1000 ' trong vòng 1000 số hạng thôi, không nên đi xa quá
soHang = soHang * hatNhan
soHangN = soHang / i
If abs(soHangN) < SORATNHO Then Exit For ' đạt giới hạn
LogN = LogN + IIF(n And 1, soHangN, -soHangN) ' n And 1 là con toán tét số chẵn lẻ.
soHang = soHang
Next i

(*1) Cách tính nghiệm, và dùng thuật toán nhị phân như bài #9 là loại tính nằm trong bài học về thuật toán lập trình.
 
Upvote 0
(*1) Cách tính nghiệm, và dùng thuật toán nhị phân như bài #9 là loại tính nằm trong bài học về thuật toán lập trình.
Tôi không hiểu lắm. Bài #9 là thay vì tính log thì tính lũy thừa của e. Nếu thế thì tính luôn log thôi chứ tính lũy thừa của e thì cũng là con toán "khó như nhau". Tôi hiểu là ở đây tìm cách tính gần đúng log. Tức cách tính chỉ dùng các phép toán cộng trừ nhân chia. Phép tính lũy thừa bậc số tự nhiên có thể trình bầy bằng phép toán nhân.

Tóm lại là tính log bằng phương pháp "tờ giấy và bút chì". Còn nếu đã cho là có thể gọi hàm có sẵn - lũy thừa của e, hoặc "bấm máy" thì gọi hàm có sẵn - bấm luôn log đi chứ sao lại bấm lũy thừa của e?
 
Upvote 0
Code hoàn chỉnh.
Mã:
Function myLN(ByVal x As Double) As Double
Const saiso = 0.000000000000001
Dim k As Long, base As Double, base2 As Double, p As Double, result As Double
    If x <= 0 Then Err.Raise xlErrValue
    If x = 1 Then
        myLN = 0
        Exit Function
    End If
    base = (x - 1) / (x + 1)
    p = 1 / base
    base2 = base * base
    For k = 1 To 10000 Step 2
        p = p * base2
        result = result + 2 * p / k
        If 2 * p * base2 / (k + 2) < saiso Then Exit For
    Next
    myLN = result
End Function
 
Upvote 0
Bác Vetmini đã nói là chú ý của riêng, như vậy không có nguồn, ta có thể kiểm chứng, dùng vòng for chạy khoảng 1 triệu lần theo 2 cách rồi so thời gian. Còn cách viết kia thì nhiều ngôn ngữ có, từ khóa Google là literal.
 
Upvote 0
Loga nê pe chính là log cơ số e thì là Ln trong excel.
1623373487728.png
 
Upvote 0
Code hoàn chỉnh.
Mã:
Function myLN(ByVal x As Double) As Double
Const saiso = 0.000000000000001
Dim k As Long, base As Double, base2 As Double, p As Double, result As Double
    If x <= 0 Then Err.Raise xlErrValue
    If x = 1 Then
        myLN = 0
        Exit Function
    End If
    base = (x - 1) / (x + 1)
    p = 1 / base
    base2 = base * base
    For k = 1 To 10000 Step 2
        p = p * base2
        result = result + 2 * p / k
        If 2 * p * base2 / (k + 2) < saiso Then Exit For
    Next
    myLN = result
End Function
Các hàm triển khai Taylor là công thức gần đúng nên có sai số, nhiều khi khá lớn. Ví dụ
1623377168333.png
Đó là lý do có tới 3 công thức, dùng công thức nào phải hiểu nguồn gốc của nó
 
Upvote 0
Tôi thì thích cái Log(15#). Mong được chỉ rõ nguồn. Ngoài VBA thi cách viết đó còn dùng ở ngôn ngữ nào khác? Cảm ơn
Thực ra thì cách kinh điển của hầu hết các ngôn ngữ là gõ thêm một dấu chấm.
Log(15#) hay Log(15.) như nhau.

Về cái dấu hiệu xác định kiểu thì có thể tìm hiểu trong trang docs của Microsoft : VB Type Characters
 
Upvote 0
Theo tôi, là For lặp ít quá. Tôi cho
For k = 1 To 999999999 Step 2
và in k sau khi vòng For thì k=740457257
và KQ khác nhau không quá 10^-7
Với vòng lặp lớn tốc độ rất chậm, vấn đề quan trong hơn là không khống chế được sai số ví dụ sai số cho phép là 10^-8 thì tới lúc nào thỏa và dừng code?
 
Upvote 0
Các hàm triển khai Taylor là công thức gần đúng nên có sai số, nhiều khi khá lớn. Ví dụ
View attachment 260450
Đó là lý do có tới 3 công thức, dùng công thức nào phải hiểu nguồn gốc của nó
Theo tôi, là For lặp ít quá. Tôi cho
For k = 1 To 999999999 Step 2
và in k sau khi vòng For thì k=740457257
và KQ khác nhau không quá 10^-7
Nguồn gốc thì dễ hiểu thôi. Cái lỗi là phải tính sai số theo công thức chứ không phải theo một số hạng nào đó của khai triển. Cái lỗi này không chỉ ở bài #14 mà còn ở bài #12.

Công thức dùng trong bài đúng với mọi x > 0. Vấn đề nằm ở chỗ tính bao nhiêu số hạng thì dừng. Lỗi code là không tính sai số theo công thức mà lại dùng số hạng n làm sai số.

Thực ra sai số được tính theo công thức, và chỉ ngừng tính khi sai số nhỏ hơn cho phép. Không thể có số hạng nào đó nhỏ hơn sai số cho phép thì khẳng định rằng sai số được chứng minh bằng công thức cũng nhỏ hơn sai số cho phép.

Sai số R(n) = f(n)(c)*(x-x0)^n/n!

Trong đó f(n)(c) là giá trị đạo hàm bậc n tại điểm c, với c nằm trong khoảng [x0;x].

Nếu tính điểm dừng dựa vào công thức sai số thì điểm dừng sẽ nằm ở rất xa. Khi đó với k rất lớn như ở bài của bạn haog thì độ chính xác sẽ lớn.
 
Upvote 0
Vì ví dụ của HieuCD sai đến 8 đơn vị nên phải kiểm tra thuật toán. Vì dùng For nên chưa thỏa điều kiện số hạng tổng quát < số epxilon đã chọn (0.00.......0) đã lặp xong 1000 lần, nên tôi sửa để nó lặp thêm nhiều hơn. Thế thôi. CT chạy cũng nhanh lắm. Tất nhiên tôi phải thử thay 1000 bằng 10000, rồi 100000... đến khi in k thấy nó < cận cuối của For (là số sau To của For)

Còn đây không là chuỗi đan dấu, mà là chuỗi dương nên điều kiện kết thúc tính toán chính như Batman1 viết:
R(n) = f(n)(c)*(x-x0)^n/n!

Nhưng mà chúng ta đang xa rời chủ đề của mục này rồi. Cảm ơn mọi người.
 
Upvote 0
Nguồn gốc thì dễ hiểu thôi. Cái lỗi là phải tính sai số theo công thức chứ không phải theo một số hạng nào đó của khai triển. Cái lỗi này không chỉ ở bài #14 mà còn ở bài #12.

Công thức dùng trong bài đúng với mọi x > 0. Vấn đề nằm ở chỗ tính bao nhiêu số hạng thì dừng. Lỗi code là không tính sai số theo công thức mà lại dùng số hạng n làm sai số.

Thực ra sai số được tính theo công thức, và chỉ ngừng tính khi sai số nhỏ hơn cho phép. Không thể có số hạng nào đó nhỏ hơn sai số cho phép thì khẳng định rằng sai số được chứng minh bằng công thức cũng nhỏ hơn sai số cho phép.

Sai số R(n) = f(n)(c)*(x-x0)^n/n!

Trong đó f(n)(c) là giá trị đạo hàm bậc n tại điểm c, với c nằm trong khoảng [x0;x].

Nếu tính điểm dừng dựa vào công thức sai số thì điểm dừng sẽ nằm ở rất xa. Khi đó với k rất lớn như ở bài của bạn haog thì độ chính xác sẽ lớn.
Khi dùng dãy số rời rạc tính một hàm nào đó thường kèm theo công thức xác định sai số, dãy rời rạc khác nhau sẽ có công thức tính sai số khác nhau và công thức nầy phải tính được, chưa hình dung nguồn gốc và cách tính Sai số R(n) = f(n)(c)*(x-x0)^n/n! như thế nào
Nếu chỉ án chừng For k = 1 To 999999999 Step 2 như bạn haog cũng không chuẩn vì còn lệ thuộc vào giá trị cần tính log, với con số khá lớn như trong thiên văn học mình e rằng sai số sẽ tăng nhiều
Phương pháp nhị phân kiểm soát được sai số và số vòng lặp thấp hơn nhiều, lũy thừa chỉ là phép nhân nhiều lần
 
Upvote 0
hùi rài hay đọc các bài viết về số e , mình thấy nó là 1 con số rất là khó , không hiểu cách người ta xây dựng công thức để tính toán với nó thế nào nhỉ , hoặc bản thân số e đã có 1 quy luật tính toán sẵn rồi , trước đi học cứ ráp công thức là xong , mặc dù mình ko giỏi toán lém @@
 
Upvote 0
Sai số R(n) = f(n)(c)*(x-x0)^n/n! như thế nào
Khi học về định lý, công thức, khai triển Taylor thầy và sách có đưa ra mà. Tất nhiên người ta phải chứng minh được thì mới đưa ra.

Phương pháp nhị phân kiểm soát được sai số và số vòng lặp thấp hơn nhiều
Thực ra rỗi hơi thì làm tiêu khiển thôi. Nếu bạn muốn bạn có thể tự viết từ A đến Z rồi đưa lên cho những ai cần mà. Tôi không cần. Còn người khác có thể có người chưa chắc viết được code trên cơ sở vài từ chung chung của bạn. Muốn thì làm từ A đến Z rồi đưa lên thôi.
--------------
Chẳng qua là thử viết code cho khai triển Taylor mà bác VetMini đưa ra ở bài #8 thôi. Tôi không bàn về các thuật toán có thể có. Càng không phán thuật toán nào tối ưu.
 
Lần chỉnh sửa cuối:
Upvote 0
Các hàm triển khai Taylor là công thức gần đúng nên có sai số, nhiều khi khá lớn. Ví dụ
View attachment 260450
Đó là lý do có tới 3 công thức, dùng công thức nào phải hiểu nguồn gốc của nó
Theo bạn nghĩ thì chính máy tính (và/hoặc các ứng dụng) làm cách nào để tính các hàm như Log, hàm lượng giác?

Trả lời luôn: máy tính dùng CORDIC (COordinate Rotation DIgital Computer), hoặc đa thức Cherbyshev, hoặc máy xưa thì dùng chuỗi Taylor.
 
Upvote 0

Bài viết mới nhất

Back
Top Bottom