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ử!

Liên hệ QC

Thư Sinh Áo Trắng

Thành viên hoạt động
Tham gia
26/3/21
Bài viết
160
Được thích
31
loganepe.jpg
Giúp em code VBA bài này với các bác!
 

File đính kèm

  • loganepe.xlsm
    10.4 KB · Đọc: 6
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
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#)
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
 
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
Web KT
Back
Top Bottom