Xin giúp đỡ đổi "Function" thành "Sub"

Liên hệ QC

Cô Bé Dễ Thương

Thành viên thường trực
Tham gia
30/9/16
Bài viết
223
Được thích
48
Giới tính
Nữ
Bài toán như sau:
Ví dụ:
39014
2915
106
16
7
- Lần lượt lấy 3+9, rồi lấy 9+0, tiếp 0+1, tiếp 1+4.Nếu lớn 10 thì chỉ lấy hàng đơn vị. Được số mới là: 2915
- Và lại liên tiếp 2+9=11 lấy hàng đơn vị được 1, tiếp 9+1=10 lấy 0,tiếp 1+5=6.Ta được số mới: 106
- Tiếp tục: 1+0=1, 0+6=6 Được số mớ là 16
- Tiếp tục: 1+6=7

Được sự giúp đỡ của bác haonlh có Function (kết quả ok),như sau:
Chép hàm sau vào code của bảng tính
Function SPascal(ss$) As Long
' Tinh tong pascal
Dim lenth&, i&, tam$, s1$, s2$
lenth = Len(ss)
Do While lenth > 1
tam = "": s1 = Left(ss, 1)
For i = 2 To lenth
s2 = Mid(ss, i, 1)
tam = tam & ((Val(s1) + Val(s2)) Mod 10)
s1 = s2
Next
ss = tam
lenth = Len(ss)
Loop
SPascal = ss
End Function

Chú ý đối số trên ô nào đó phải không quá 15 chữ số. Còn nếu hơn thì phải định dạng ô đó là text (hoặc gõ dấu nháy đơn rồi nhập số).

Nay em muốn đổi chương trình này thành Sub. Các anh chị giúp em với. Vốn VBA của em hiện chưa đủ để viết lai chương trình này.
Vậy xin các anh chị có ghé qua đổi Function trên thành Sub giúp em với ạ.
Em cảm ơn chân thành!
 
Function thì nó có cái kết qủa để trả về. Đổi thành Sub thì kết quả bỏ vào đâu?
 
Upvote 0
Bỏ vào A1 chẳng hạn. Ô nào cũng đươc ạ. Bác đổi giúp em với
A1 là ô chứa con số gốc VD: 39014
A2 là ô kết quả
Rich (BB code):
Sub SPascal1()
' Tinh tong pascal
Dim lenth&, i&, tam$, s1$, s2$
Dim ss$
ss = Range("B1")
lenth = Len(ss)
Do While lenth > 1
    tam = "": s1 = Left(ss, 1)
    For i = 2 To lenth
        s2 = Mid(ss, i, 1)
        tam = tam & ((Val(s1) + Val(s2)) Mod 10)
        s1 = s2
    Next
    ss = tam
    lenth = Len(ss)
Loop
Range("A1") = ss
End Sub
 
Upvote 0
A1 là ô chứa con số gốc VD: 39014
A2 là ô kết quả
Rich (BB code):
Sub SPascal1()
' Tinh tong pascal
Dim lenth&, i&, tam$, s1$, s2$
Dim ss$
ss = Range("B1")
lenth = Len(ss)
Do While lenth > 1
    tam = "": s1 = Left(ss, 1)
    For i = 2 To lenth
        s2 = Mid(ss, i, 1)
        tam = tam & ((Val(s1) + Val(s2)) Mod 10)
        s1 = s2
    Next
    ss = tam
    lenth = Len(ss)
Loop
Range("A1") = ss
End Sub
Code chả cải tiến gì thì sửa lại chi vậy?
Chỉ cần đại khái:
Sub DoiTuFunction()
[a2].Value = SPascal([a1].Value)
End Sub

Chú về code: đáng lẽ bài này nên code hàm đệ quy.
 
Upvote 0
Code chả cải tiến gì thì sửa lại chi vậy?
Chỉ cần đại khái:
Sub DoiTuFunction()
[a2].Value = SPascal([a1].Value)
End Sub

Chú về code: đáng lẽ bài này nên code hàm đệ quy.
Bác vội trách! Vì người ta không biết nên phải từng bước. Tôi hồi xưa còn không phân biệt được function và sub khác nhau thế nào mà. Nếu thay Function bằng Sub đâu có biết được ngay là làm thế nào để cho nó hoạt động được.
 
Upvote 0
Bác vội trách! Vì người ta không biết nên phải từng bước. Tôi hồi xưa còn không phân biệt được function và sub khác nhau thế nào mà. Nếu thay Function bằng Sub đâu có biết được ngay là làm thế nào để cho nó hoạt động được.
Tại bạn học đốt mất giai đoạn căn bản của hàm con (nói chung cho function và sub). Bạn không thể nói "từng bước" được vì chính bạn đã từng bỏ mất vài bước ở giữa.
Và phần căn bản của hàm con cũng khuyên rằng (*): nếu đã có một hàm con chạy ra kết quả rồi thì cần thêm thắt gì cứ việc vết thêm cái hàm/sub gọi nó. Cực chẳng đã mới phải sửa.

(*) chính sách "chia để trị" của viết code:
Hầu hết các vị viết code ở đây có khuynh hướng viết một cái hàm/sub tổ bố với một đống options làm đủ thứ việc.
Tôi theo chính sách khác: viết nhiều hàm con; mỗi hàm con có công việc riêng của nó. Cái hàm/sub chung với một đống options gọi những hàm nhỏ này.

(**) Thêm, hàm đệ quy:
Function PatCanDom(so As String) As String
' hàm đệ quy tính trị Pascal của một chuỗi số
If Len(so) <= 1 Then
PatCanDom = so
Exit Function
End If
Dim i As Long, s As String
For i = 1 To Len(so) - 1
s = s & ((Val(Mid(so, i, 1)) + Val(Mid(so, i + 1, 1))) Mod 10) ' chỉ lấy 1 chữ số hàng đơn vị
Next i
PatCanDom = PatCanDom(s)
End Function
 
Upvote 0
Thực ra đệ qui không phải toàn mầu hồng, không phải bao giờ cũng tốt.

Đệ qui cho phép giải quyết nhiều vấn đề theo cách dễ dàng hơn so với những cách "truyền thống". Nhưng có những tình huống không nên sử dụng đệ qui, thậm chí cả khi thuật toán dùng đệ qui có vẻ như đơn giản hơn.

Nên nhớ về các mặt xấu của đệ qui:
- cần nhiều bộ nhớ (memory) trong quá trình tính toán. Cứ mỗi lần gọi đệ qui là một lần phải nhớ một số thông tin (đặt lên stack), cần thiết cho việc tái tạo lại tình trạng trước khi gọi đệ qui (khi return thì lấy lại từ stack). Máy vi tính đôi khi gặp nhiều khó khăn khi tính giá trị của hàm, mặc dù các tham số không hề lớn. Vd. điển hình là tính phần tử thứ n (n = 1, 2, ...) của dãy Fibonacci.

- nhiều khi chương trình dùng đệ qui chạy chậm hơn so với chương trình dùng vòng lặp.

Nếu thuật toán không dùng đệ qui sẽ phức tạp hơn nhiều so với thuật toán dùng đệ qui thì người ta dùng đệ qui. Trong trường hợp ngược lại thì người ta dùng thuật toán không dùng đệ qui.
-----------
1. Ta xét 2 code: dùng và không dùng đệ quy.
Mã:
Function Fibo_dequi(ByVal n As Long) As Double
    If n > 2 Then
        Fibo_dequi = Fibo_dequi(n - 2) + Fibo_dequi(n - 1)
    ElseIf n > 0 Then
        Fibo_dequi = n - 1
    End If
End Function

Function Fibo(ByVal n As Long) As Double
Dim k As Long, f As Double, f1 As Double, f2 As Double
    If n < 3 Then
        If n >= 1 Then Fibo = n - 1
        Exit Function
    End If
    f1 = 0
    f2 = 1
    For k = 1 To n
        If k > 2 Then
            f = f1 + f2
            f1 = f2
            f2 = f
        Else
            f = k - 1
        End If
    Next k
    Fibo = f
End Function

Sub test1()
Dim n As Long, t
    t = Timer
    n = 70
    Debug.Print Fibo(n)
    MsgBox "Fibo: " & Timer - t
End Sub

Sub test2()
Dim n As Long, t
    t = Timer
    n = 70
    Debug.Print Fibo_dequi(n)
    MsgBox "Fibo_dequi: " & Timer - t
End Sub

Sub test1 chạy trong nháy mắt trong khi test2 tôi phải dùng Task Manager để giết

2.
Mã:
Function tong_chuso(ByVal so As String) As Long
Dim length As Long, k As Long, tmp As String, s1 As Long, s2 As Long
    length = Len(so)
    Do While length > 1
        tmp = String(length - 1, "0")
        s1 = Left(so, 1)
        For k = 2 To length
            s2 = Mid(so, k, 1)
            Mid(tmp, k - 1, 1) = (s1 + s2) Mod 10
            s1 = s2
        Next
        so = tmp
        length = Len(so)
    Loop
    tong_chuso = so
End Function

Sub batman1()
Dim s As String, t
    t = Timer
    s = "aaaaaaaaaaaaaaaaaaaa"
    s = Replace(s, "a", "bbbbbbbbbbbbbbbbbbbb")
    s = Replace(s, "b", "12345678901234567895")
   
    MsgBox "batman1: " & tong_chuso(s) & " - " & Timer - t
End Sub
Trên máy tôi sub batman1 chạy hết khoảng 35 s. Code dùng đệ qui chạy bị lỗi tràn bộ nhớ (tràn stack).
Nếu rút ngắn chuỗi s thì code dùng đệ qui không còn lỗi nữa nhưng chạy chậm hơn code không dùng đệ qui.
 
Upvote 0
Thực ra đệ qui không phải toàn mầu hồng, không phải bao giờ cũng tốt.

Đệ qui cho phép giải quyết nhiều vấn đề theo cách dễ dàng hơn so với những cách "truyền thống". Nhưng có những tình huống không nên sử dụng đệ qui, thậm chí cả khi thuật toán dùng đệ qui có vẻ như đơn giản hơn.

Nên nhớ về các mặt xấu của đệ qui:
- cần nhiều bộ nhớ (memory) trong quá trình tính toán. Cứ mỗi lần gọi đệ qui là một lần phải nhớ một số thông tin (đặt lên stack), cần thiết cho việc tái tạo lại tình trạng trước khi gọi đệ qui (khi return thì lấy lại từ stack). Máy vi tính đôi khi gặp nhiều khó khăn khi tính giá trị của hàm, mặc dù các tham số không hề lớn. Vd. điển hình là tính phần tử thứ n (n = 1, 2, ...) của dãy Fibonacci.

- nhiều khi chương trình dùng đệ qui chạy chậm hơn so với chương trình dùng vòng lặp.

Nếu thuật toán không dùng đệ qui sẽ phức tạp hơn nhiều so với thuật toán dùng đệ qui thì người ta dùng đệ qui. Trong trường hợp ngược lại thì người ta dùng thuật toán không dùng đệ qui.
-----------
1. Ta xét 2 code: dùng và không dùng đệ quy.
Mã:
Function Fibo_dequi(ByVal n As Long) As Double
    If n > 2 Then
        Fibo_dequi = Fibo_dequi(n - 2) + Fibo_dequi(n - 1)
    ElseIf n > 0 Then
        Fibo_dequi = n - 1
    End If
End Function

Function Fibo(ByVal n As Long) As Double
Dim k As Long, f As Double, f1 As Double, f2 As Double
    If n < 3 Then
        If n >= 1 Then Fibo = n - 1
        Exit Function
    End If
    f1 = 0
    f2 = 1
    For k = 1 To n
        If k > 2 Then
            f = f1 + f2
            f1 = f2
            f2 = f
        Else
            f = k - 1
        End If
    Next k
    Fibo = f
End Function

Sub test1()
Dim n As Long, t
    t = Timer
    n = 70
    Debug.Print Fibo(n)
    MsgBox "Fibo: " & Timer - t
End Sub

Sub test2()
Dim n As Long, t
    t = Timer
    n = 70
    Debug.Print Fibo_dequi(n)
    MsgBox "Fibo_dequi: " & Timer - t
End Sub

Sub test1 chạy trong nháy mắt trong khi test2 tôi phải dùng Task Manager để giết

2.
Mã:
Function tong_chuso(ByVal so As String) As Long
Dim length As Long, k As Long, tmp As String, s1 As Long, s2 As Long
    length = Len(so)
    Do While length > 1
        tmp = String(length - 1, "0")
        s1 = Left(so, 1)
        For k = 2 To length
            s2 = Mid(so, k, 1)
            Mid(tmp, k - 1, 1) = (s1 + s2) Mod 10
            s1 = s2
        Next
        so = tmp
        length = Len(so)
    Loop
    tong_chuso = so
End Function

Sub batman1()
Dim s As String, t
    t = Timer
    s = "aaaaaaaaaaaaaaaaaaaa"
    s = Replace(s, "a", "bbbbbbbbbbbbbbbbbbbb")
    s = Replace(s, "b", "12345678901234567895")
  
    MsgBox "batman1: " & tong_chuso(s) & " - " & Timer - t
End Sub
Trên máy tôi sub batman1 chạy hết khoảng 35 s. Code dùng đệ qui chạy bị lỗi tràn bộ nhớ (tràn stack).
Nếu rút ngắn chuỗi s thì code dùng đệ qui không còn lỗi nữa nhưng chạy chậm hơn code không dùng đệ qui.
Code đệ qui chạy chậm do cách xử lý không hợp lý khiến số lần gọi lại hàm quá lớn, vấn đề ở lệnh
Fibo_dequi = Fibo_dequi(n - 2) + Fibo_dequi(n - 1)
Trong khi đó code dùng for chỉ chạy n lần vòng
Nếu theo dạng
Fibo_dequi = Fibo_dequi(...)
Tốc độ sẽ khác nhiều

Thử chạy sub Test với cột đầu mảng Res là số lần gọi Function Fibo_dequi
Mã:
Dim q

Sub Test()
  Dim tmp, i&, n&, Res() As Long
 
  n = 20
  ReDim Res(1 To n, 1 To 2)
  For i = 1 To n
    q = 0
    Res(i, 2) = Fibo_dequi(i)
    Res(i, 1) = q
  Next i
  Range("A2").Resize(n, 2) = Res
End Sub

Function Fibo_dequi(ByVal n As Long) As Double
    q = q + 1
    If n > 2 Then
        Fibo_dequi = Fibo_dequi(n - 2) + Fibo_dequi(n - 1)
    ElseIf n > 0 Then
        Fibo_dequi = n - 1
    End If
End Function
 
Upvote 0
Thực ra đệ qui không phải toàn mầu hồng, không phải bao giờ cũng tốt.
...
Bài Pát Can này là bài nhỏ. Tôi chỉ nhân những lúc bài nhỏ để giới thiệu đệ quy thôi.

Chứ theo nguyên tắc "if it ain't broke, don't fix it" thì ở bài #5 tôi đã giải rồi:
Cái hàm của thớt đâu có vấn đề gì. Muốn dùng sub (chả biết để làm gì, để có thể nhấn nút?) thì chỉ việc viết cái sub gọi nó.

Code đệ qui chạy chậm do cách xử lý không hợp lý khiến số lần gọi lại hàm quá lớn, ...
Đệ quy gần như không bao giờ được coi là code có tốc độ.
So với lối cổ điển vòng lặp, đệ quy gần như luôn phải chịu gánh nặng "gọi và nối hàm".
Mỗi lượt gọi và nối hàm lại phải tốn thì giờ và bộ nhớ ngăn xếp.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài Pát Can này là bài nhỏ. Tôi chỉ nhân những lúc bài nhỏ để giới thiệu đệ quy thôi.

Chứ theo nguyên tắc "if it ain't broke, don't fix it" thì ở bài #5 tôi đã giải rồi:
Cái hàm của thớt đâu có vấn đề gì. Muốn dùng sub (chả biết để làm gì, để có thể nhấn nút?) thì chỉ việc viết cái sub gọi nó.


Đệ quy gần như không bao giờ được coi là code có tốc độ.
So với lối cổ điển vòng lặp, đệ quy gần như luôn phải chịu gánh nặng "gọi và nối hàm".
Mỗi lượt gọi và nối hàm lại phải tốn thì giờ và bộ nhớ ngăn xếp.
Dùng Sub đệ quy tốc độ nhanh hơn Functio đệ quy
Mã:
Sub Main()
  Dim i&, n&, Res#, Arr()

  n = 1000
  ReDim Arr(1 To n, 1 To 1)
  For i = 1 To n
    Res = 1
    Call DeQui(Res, 0, i)
    Arr(i, 1) = Res
  Next i
  Range("C2").Resize(n, 1) = Arr
End Sub

Private Sub DeQui(ByRef Res, ByVal Res0#, ByVal n&)
  Dim tmp#

  If n > 2 Then
    tmp = Res
    Res = Res + Res0
    Call DeQui(Res, tmp, n - 1)
  ElseIf n > 0 Then
    If Res = 1 Then Res = n - 1
  End If
End Sub
 
Upvote 0

VetMini cảm ơn anh nhiều. cách của anh giúp nhiều bạn cứng vba chuyển function sang Sud dễ dàng​

Maika8008 cảm ơn anh. đã không tiếc thời gian viết lại cho em thành Sub. Giúp em hiểu thuật toán của function gốc​

batman1 HieuCD cảm ơn các anh đã quan tâm​

Hôm qua em thấy được comment của các bác rồi. Do trục trặc mạng không vào sớm để cảm ơn các bác được. Em chúc các bác mạnh khỏe.
 
Upvote 0
Dùng Sub đệ quy tốc độ nhanh hơn Functio đệ quy
...
Có nhiều yếu tố. Yếu tố quan trọng nhất là ngôn ngữ. Yếu tố thứ hai là cách giảm thiểu công việc nhét và móc ngăn xếp cho chương trình mỗi lượt gọi và kết thúc hàm. Điển hình, byRef nhanh hơn byVal, dùng biến toàn cục (nhất là mảng) để giảm bộ nhớ ngăn xếp, ...

Nó chuyện thêm về Code nhanh:

Bỏ qua cái nguyên tắc "if it ain't broke, don't fix it" (nếu nó chưa hư thì đừng vội sửa) thì code bài #1 rất luộm thuộm. Nó được viết thẳng theo yêu cầu mà không qua phân tích.
Vì vậy, code bị phải liên tục tính lại chuỗi số. Chuỗi mà bị tính lại rất tốn tài nguyên máy.

Theo luật cộng Pascal thì cứ mỗi lượt tính, lượng số đầu ra giảm đi 1 so với đầu vào.
Nếu có thiết kế đầy đủ thì lúc duyệt chuỗi chỉ cần 1 chuỗi và một biến cho biết độ dài hiện sử dụng trong chuỗi.
Mã:
Function PatCanXiCut(ByVal chuoi As String) As Long
' hàm xì cút tính trị pát can của một chuỗi số
If Len(chuoi) <= 1 Then
  PatCanXiCut = Val(chuoi)
  Exit Function
End If
Dim curLen As Long, i As Long, so1 As Long, so2 As Long
For curLen = Len(chuoi) To 2 Step -1
  so1 = Val(Mid(chuoi, 1, 1))
  For i = 2 To curLen
    so2 = Val(Mid(chuoi, i, 1))
    Mid(chuoi, i - 1, 1) = (so1 + so2) Mod 10
    so1 = so2
  Next i
Next curLen
PatCanXiCut = Val(Left(chuoi, 1))
End Function
Giải thutaaj trên vẫn chưa tối ưu vì phải ghi lại kêt quả tạm trong chuỗi số, rồi lại lấy ra để tính tiếp. Nếu chuỗi dài thì có lẽ dùng một mảng tạm hiệu quả hơn
Hiện tại tôi vẫn chưa tìm được cách tính thẳng luôn từ đầu đến cuối.
 
Lần chỉnh sửa cuối:
Upvote 0
Có nhiều yếu tố. Yếu tố quan trọng nhất là ngôn ngữ. Yếu tố thứ hai là cách giảm thiểu công việc nhét và móc ngăn xếp cho chương trình mỗi lượt gọi và kết thúc hàm. Điển hình, byRef nhanh hơn byVal, dùng biến toàn cục (nhất là mảng) để giảm bộ nhớ ngăn xếp, ...

Nó chuyện thêm về Code nhanh:

Bỏ qua cái nguyên tắc "if it ain't broke, don't fix it" (nếu nó chưa hư thì đừng vội sửa) thì code bài #1 rất luộm thuộm. Nó được viết thẳng theo yêu cầu mà không qua phân tích.
Vì vậy, code bị phải liên tục tính lại chuỗi số. Chuỗi mà bị tính lại rất tốn tài nguyên máy.

Theo luật cộng Pascal thì cứ mỗi lượt tính, lượng số đầu ra giảm đi 1 so với đầu vào.
Nếu có thiết kế đầy đủ thì lúc duyệt chuỗi chỉ cần 1 chuỗi và một biến cho biết độ dài hiện sử dụng trong chuỗi.
Mã:
Function PatCanXiCut(ByVal chuoi As String) As Long
' hàm xì cút tính trị pát can của một chuỗi số
If Len(chuoi) <= 1 Then
  PatCanXiCut = Val(chuoi)
  Exit Function
End If
Dim curLen As Long, i As Long, so1 As Long, so2 As Long
For curLen = Len(chuoi) To 2 Step -1
  so1 = Val(Mid(chuoi, 1, 1))
  For i = 2 To curLen
    so2 = Val(Mid(chuoi, i, 1))
    Mid(chuoi, i - 1, 1) = (so1 + so2) Mod 10
    so1 = so2
  Next i
Next curLen
PatCanXiCut = Val(Left(chuoi, 1))
End Function
Giải thutaaj trên vẫn chưa tối ưu vì phải ghi lại kêt quả tạm trong chuỗi số, rồi lại lấy ra để tính tiếp. Nếu chuỗi dài thì có lẽ dùng một mảng tạm hiệu quả hơn
Hiện tại tôi vẫn chưa tìm được cách tính thẳng luôn từ đầu đến cuối.
Giải thuật và code quá hay, khó có cách nào viết hiệu quả hơn /-*+/
 
Upvote 0
Code đệ qui chạy chậm do cách xử lý không hợp lý khiến số lần gọi lại hàm quá lớn, vấn đề ở lệnh
Fibo_dequi = Fibo_dequi(n - 2) + Fibo_dequi(n - 1)
Trong khi đó code dùng for chỉ chạy n lần vòng
Nếu theo dạng
Fibo_dequi = Fibo_dequi(...)
Tốc độ sẽ khác nhiều

Thử chạy sub Test với cột đầu mảng Res là số lần gọi Function Fibo_dequi
Mã:
Dim q

Sub Test()
  Dim tmp, i&, n&, Res() As Long

  n = 20
  ReDim Res(1 To n, 1 To 2)
  For i = 1 To n
    q = 0
    Res(i, 2) = Fibo_dequi(i)
    Res(i, 1) = q
  Next i
  Range("A2").Resize(n, 2) = Res
End Sub

Function Fibo_dequi(ByVal n As Long) As Double
    q = q + 1
    If n > 2 Then
        Fibo_dequi = Fibo_dequi(n - 2) + Fibo_dequi(n - 1)
    ElseIf n > 0 Then
        Fibo_dequi = n - 1
    End If
End Function
Tôi không hiểu ý bạn.

Tôi muốn tính số Fibonacci vd. thứ 70. Tôi không quan tâm tới các số Fibonacci 1, 2, ..., 69, 71, 72, ... nhưng nếu code tính thêm thì cũng chả sao. Để tính số Fibonacci thứ 70 tôi chạy test1 và test2 ở bài #8. Kết quả là test1 chạy trong nháy mắt, còn test2 tôi phải giết vì đợi quá lâu.

Bạn đề nghị code trong bài #9. Bạn đã thử chạy code bài #9 với n = 70 chưa? Tôi không quan tâm tới n = 20 vì quá tầm thường. Với n = 70 bạn thử thấy code chạy hết bao lâu?
 
Upvote 0
Viết như vậy được không ta
PHP:
Function Pascal(iChuoi As String) As Long
  Dim x&
  For x = 1 To Len(iChuoi)
    Pascal = (Pascal + Val(Mid(iChuoi, x, 1))) Mod 10
  Next x
End Function
 
Upvote 0
Dùng Sub đệ quy tốc độ nhanh hơn Functio đệ quy
Mọi nỗ lực hiện thời của bạn là cải thiện tốc độ cho đệ qui. Cái mà tôi muốn trình bầy là so sánh giữa đệ qui và KHÔNG đệ qui cho cùng một n.

1. Với function đệ qui thì dễ rồi. Đó là hàm tổng quát. Tôi có thể gửi cho người khác và họ chỉ cần biết chạy code là tính được số Fibonacci vd. thứ 70. Hoặc nếu họ cần code trong ngôn ngữ khác và họ biết lập trình thì họ chỉ cần dịch ra ngôn ngữ khác. Sub đệ qui khi gửi cho người không biết lập trình mà chỉ biết chạy code thì luôn phải đính kèm code kiểu Main. Vì nếu không có thì "em gà lắm" không biết viết THÊM code như thế nào để tính số Fibonacci vd. thứ 70.

Nhưng mục đích của tôi là so sánh đệ qui và KHÔNG đệ qui.

2. Khi chạy sub đệ qui ở bài #11 với n = 1400, và function KHÔNG đệ qui ở bài #8 cũng với n = 1400 thì code ở bài #8 chạy nhanh hơn.

Mục đích trong bài #8 là so sánh đệ qui và KHÔNG đệ qui trong một vấn đề cụ thể.
 
Upvote 0
Giải thuật và code quá hay, khó có cách nào viết hiệu quả hơn /-*+/
Ngay ở bài #8 tôi đã đưa ra code hàm tong_chuso với code dùng để test là
Mã:
Sub batman1()
Dim s As String, t
    t = Timer
    s = "aaaaaaaaaaaaaaaaaaaa"
    s = Replace(s, "a", "bbbbbbbbbbbbbbbbbbbb")
    s = Replace(s, "b", "12345678901234567895")
    
    MsgBox "batman1: " & tong_chuso(s) & " - " & Timer - t
End Sub

Tôi chạy thử lại thì mất 37,75781 s trên máy tôi.

Tôi cũng chạy code test code PatCanXiCut
Mã:
Sub blabla()
Dim s As String, t
    t = Timer
    s = "aaaaaaaaaaaaaaaaaaaa"
    s = Replace(s, "a", "bbbbbbbbbbbbbbbbbbbb")
    s = Replace(s, "b", "12345678901234567895")
    
    MsgBox "PatCanXiCut: " & PatCanXiCut(s) & " - " & Timer - t
End Sub
Chạy thử mất 46,60156 s. Tôi không quan trọng sự chênh lệch vài giây vì đó có thể là sự dao động của system ở mỗi thời điểm. Nhưng tôi không tin là code ở bài #13 (PatCanXiCut) chạy nhanh vượt trội hơn code ở bài #8 (tong_chuso).

Tôi không phải là loại người thích thi thố tốc độ. Bàn về code, kể cả tốc độ của code thôi chứ không hay thi thố chuyện viết code ngắn nhất, dùng ít FOR, ít Do, chạy cực nhanh. Nhưng riêng bài này tôi muốn trình bầy thêm một code nữa. Chưa suy nghĩ sâu nhưng chắc không sai.
Mã:
Function tong_chuso(ByVal so As String) As Long
Dim length As Long, k As Long, start As Long, chuso() As Long
    length = Len(so)
    ReDim chuso(1 To length)
    For k = 1 To length
        chuso(k) = Mid(so, k, 1)
    Next k
    For k = 1 To length - 1
        For start = 1 To length - k
            chuso(start) = (chuso(start) + chuso(start + 1)) Mod 10
        Next start
    Next
    tong_chuso = chu
Code này có lẽ vô địch thế giới rồi.
 
Upvote 0
Ngay ở bài #8 tôi đã đưa ra code hàm tong_chuso với code dùng để test là
...
tong_chuso dùng phép ép kiểu để đổi chuỗi thành số.
Các code khác dùng hàm Val. Có lẽ (đoán thôi) do hàm này là hàm "lấy số cho đến lúc hết lấy được" cho nên không hiệu quả lắm.
Tôi chỉ chưa hiểu tại sao code tong_chuso gọi hàm String để lập chuỗi (len-1) lần mà không bị mất hiệu quả. Có lẽ hàm String được viết rất tốt cho VBA?
 
Upvote 0
Web KT

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

Back
Top Bottom