Đố vui về VBA!

Liên hệ QC

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,905
Nhằm cũng cố kiến thức về VBA cho các bạn mới bắt đầu và cả những bạn đang ứng dụng mà chưa hiểu nhiều về nó, tôi mở topic này với mong mõi qua những câu hỏi vui, các bạn sẽ nhận định lại sự hiểu biết cũa mình... (Kễ cã chính tôi cũng đang tập tành nên có rất nhiều cái chưa biết)
Mong rằng topic sẽ mang đến cho các bạn những khám phá thú vị với những cái tưỡng chừng như đã biết
Mong nhận dc bài viết về câu đố cũa các cao thủ! Còn các bạn mới thì đừng ngại khi đưa ra ý kiến cũa mình.. Có sai có sữa sẽ hoàn thiện!
Tôi xin mỡ màn trước bằng 1 câu hỏi đơn giãn
ANH TUẤN

CÂU HỎI 1: Tại sao biến K ko hoạt động?
Tôi muốn khi nhấn vào 1 button thì cell A1 sẽ tăng lên 1 đơn vị... Tôi đã làm như sau:
-Tạo 1 Command Button (nút nhấn thuộc thanh Control Toolbox), click phải chuột lên nút nhấn, chọn View code, rồi gõ vào đoạn code sau:
PHP:
Private Sub CommandButton1_Click()
   K = K + 1
   Range("A1").Value = K
End Sub
Ban đầu K chưa có gì, xem như =0, nhấn nút lần thứ nhất thì K dc tăng thêm 1, vậy K hiện tại sẽ bằng 1, và gán K vào cell A1 thì đương nhiên A1 sẽ =1... Nhấn nút lần 2, K lại dc tăng thêm 1 nên hiện tại K sẽ =2 và cell A1 cũng sẽ =2... vân vân.. từ đó diễn tiến tiếp...
Hi.. hi.. Điều này nghe qua có vẽ rất hợp lý, ấy thế mà khi nhấn nút nó chỉ hoạt động dc duy nhất 1 lần (A1 = 1) rồi thôi ko nhút nhít nữa...
Các bạn có thể giãi thích tại sao lại như thế ko? Tại sao những lần nhấn nút sau đó K lại ko tăng thêm tí nào (vì thực tế A1 vẫn cứ = 1 hoài) ?
ANH TUẤN
 
Các bạn xem thử với cái vụ SNT này ta dùng Step 6 thì có nhanh thêm ko?
PHP:
Function SoNT(So As Single) As Boolean
    Dim i As Long
    If So < 2 Or (So <> 2 And So Mod 2 = 0) Or So <> Int(So) Then Exit Function
    If So = 3 Or So = 2 Then SoNT = True: Exit Function
    Select Case So Mod 6
         Case 1, 5
         For i = 5 To Sqr(So) Step 6
             If So Mod i = 0 Or So Mod i + 2 = 0 Then Exit Function
         Next i
    Case Else
        Exit Function
    End Select
    SoNT = True
End Function
Trong trường hợp Step 2, nó chỉ ngưng lại đễ xét 1 d/k, còn ở đây tuy Step 6, nhưng khi ngưng lại nó phải xét 2 d/k... Chã biết có nhanh ko nữa... Xin các cao thủ test dùm
ANH TUẤN
 
Upvote 0
CÂU HỎI 1: Tại sao biến K ko hoạt động?
Tôi muốn khi nhấn vào 1 button thì cell A1 sẽ tăng lên 1 đơn vị... Tôi đã làm như sau:
-Tạo 1 Command Button (nút nhấn thuộc thanh Control Toolbox), click phải chuột lên nút nhấn, chọn View code, rồi gõ vào đoạn code sau:
PHP:
Private Sub CommandButton1_Click()
   K = K + 1
   Range("A1").Value = K
End Sub
Ban đầu K chưa có gì, xem như =0, nhấn nút lần thứ nhất thì K dc tăng thêm 1, vậy K hiện tại sẽ bằng 1, và gán K vào cell A1 thì đương nhiên A1 sẽ =1... Nhấn nút lần 2, K lại dc tăng thêm 1 nên hiện tại K sẽ =2 và cell A1 cũng sẽ =2... vân vân.. từ đó diễn tiến tiếp...
Hi.. hi.. Điều này nghe qua có vẽ rất hợp lý, ấy thế mà khi nhấn nút nó chỉ hoạt động dc duy nhất 1 lần (A1 = 1) rồi thôi ko nhút nhít nữa...
Các bạn có thể giãi thích tại sao lại như thế ko? Tại sao những lần nhấn nút sau đó K lại ko tăng thêm tí nào (vì thực tế A1 vẫn cứ = 1 hoài) ?
ANH TUẤN
về mặt lý thuyết là vậy, nhưng khai báo như trên các lần nhấn nút đều ở trạng thái 1, giá trị K khởi tạo đều bắt đầu là 0.
 
Upvote 0
New member cũng muốn đóng góp ý kiến cho câu 1. Ngoài các cách đã nêu ta còn có thể dùng cách sau:
Mã:
Sub Command1_Click()
Static k As Integer
k=k+1
...
End sub
Tuy nhiên cách này chỉ lưu được lại k trong lúc run-time, nếu đóng form lại và chạy lại code thì k sẽ đếm lại từ đầu.
 
Upvote 0
ANHTUAN1066, mình giải thích thế này có đúng không:
cái biến k bạn khai trong sub Cmd...click() vây nó là biến cục bộ của Sub đó. Kết thúc sự kiện click thì biến đó mất. Khi nhấn tiếp thì nó khởi động từ đầu.
Để được như bạn lập luận phải khai ở những dòng đầu tiên trong Module khi chưa có khai báo sub .
 
Upvote 0
ANHTUAN1066, mình giải thích thế này có đúng không:
cái biến k bạn khai trong sub Cmd...click() vây nó là biến cục bộ của Sub đó. Kết thúc sự kiện click thì biến đó mất. Khi nhấn tiếp thì nó khởi động từ đầu.
Để được như bạn lập luận phải khai ở những dòng đầu tiên trong Module khi chưa có khai báo sub .
Chắc là vậy!
Nếu ta không biết vụ khai báo Public cho biến K thì có thể làm theo cách củ chuối: Lưu biến K vào 1 Name (Trước khi chạy code, đặt name K, refer to = 1)
PHP:
Private Sub CommandButton1_Click()
   ActiveWorkbook.Names("K").Delete
   ActiveWorkbook.Names.Add Name:="K", RefersToR1C1:="=" & ([A1] + 1)
   [A1] = Evaluate("K")
End Sub
Cách này xem ra còn "ngầu" hơn khai báo Public ở chổ: Đóng file rồi mở ra, giá trị K vẩn được bảo toàn
 
Lần chỉnh sửa cuối:
Upvote 0
Các bạn ơi giúp mình chuyển lại hay viết lại cái code mã hóa từ tiếng việt thành con số này qua bên VBA của word với:
Function Gen(ByVal s As String) As String
Dim rs As String
Dim uniBytes As Byte() = Encoding.Unicode.GetBytes(s)
For i As Integer = 0 To uniBytes.Length - 1
rs &= uniBytes(i).ToString()
Next
Return rs
End Function
Cái này mình viết bên VB2005
Mong các bạn giúp đỡ.
 
Upvote 0
CÂU HỎI 2: Sub và Private Sub?
Sau khi hoàn tất câu hõi 1, giờ tôi sữa code 1 chút, đặt code vào 1 module rồi dùng Command Button đễ gọi Sub thông qua lệnh Call
PHP:
Sub Add()
     Cho code vào đây!
End Sub
Private Sub CommandButton1_Click()
     Call Add
End Sub
Hoàn toàn ko có vấn đề gì về cách viết này.. và các bạn cũng thấy các cao thủ đã từng viết kiểu như vậy!
Cho hỏi: Cách viết trong câu hỏi 1 là gọi trực tiếp code bằng Button, còn cách viết thứ 2 này thì gọi code thông qua lệnh Call... Vậy có gì khác nhau giữa 2 cách viết và tại sao đôi khi ta lại cần làm như vậy? Sao ko cho code trực tiếp vào mà lại thông qua Call Add chi cho mất công thế?
ANH TUẤN
Cách gọi Sub có các ưu điểm sau:
-Khi Copy sheet, dung lượng code không tăng lên bao nhiêu
-Muốn sửa code chỉ sửa ở 1 chổ
-Khi dùng pass để lock project, ta để sub vào module và copy sheet sang workbook khác thì không thể xem được code mà thấy như sau:
PHP:
Private Sub CommandButton1_Click()
     Call Add
End Sub
nhưng dùng trực tiếp, khi copy sheet sang workbook khác có thể xem được code
 
Lần chỉnh sửa cuối:
Upvote 0
Các bạn ơi giúp mình chuyển lại hay viết lại cái code mã hóa từ tiếng việt thành con số này qua bên VBA của word với:
Function Gen(ByVal s As String) As String
Dim rs As String
Dim uniBytes As Byte() = Encoding.Unicode.GetBytes(s)
For i As Integer = 0 To uniBytes.Length - 1
rs &= uniBytes(i).ToString()
Next
Return rs
End Function
Cái này mình viết bên VB2005
Mong các bạn giúp đỡ.
Hy vọng cái này có thể giúp bạn

http://www.giaiphapexcel.com/forum/showthread.php?p=113616#post113616
 
Upvote 0
Chào tất cả các bác, lâu quá không gặp không biết các bác vẩn khỏe hết chứ! Em có 1 vấn đề muốn hỏi về số nguyên tố nhưng vẫn chưa biết phải viết code như thế nào. Mong các bác chỉ giúp nha! Vấn đề là cần tìm tiệm cận trên, tiệm cận dưới của 1 số mà là số nguyên tố. Ví dụ: Nếu nhập vào công thức: =CTSNT(10)=11 =CDSNT(10)=7 Nếu có thể thì xin ít dùng vòng lặp thôi! Càng ít càng tốt. Ví khi tìm 1 số lớn thì sẽ rất lâu đó bác ơi. À, còn 1 điều nữa em nhận thấy rằng tất cả số nguyên tố điều là số lẻ (ngoại trừ số 2) nên không biết có thể giúp ít được không? Xin cảm ơn mọi người trước nha! Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo sự hướng dẫn tận tình của bác ndu96081631 em đã làm được với bộ công thức như sau:
PHP:
Private Function SoNT(So As Single) As Boolean     Dim i As Single     If So < 2 Or (So  2 And So Mod 2 = 0) Or So  Int(So) Then Exit Function     If So = 3 Or So = 2 Then SoNT = True: Exit Function     Select Case So Mod 6          Case 1, 5          For i = 5 To Sqr(So) Step 6              If So Mod i = 0 Or So Mod i + 2 = 0 Then Exit Function          Next i     Case Else         Exit Function     End Select     SoNT = True End Function
PHP:
 Function CDSNT(CheckNum As Single) As Single   Dim Temp As Single   For Temp = CheckNum To 2 Step -1     If SoNT(Temp) Then Exit For   Next   CDSNT = Temp End Function
PHP:
 Function CTSNT(CheckNum As Single) As Single   Dim Temp As Single   For Temp = CheckNum To 10 ^ Val(Len(CheckNum) + 1)     If SoNT(Temp) Then Exit For   Next   CTSNT = Temp End Function
Lúc đầu em dùng biến là Long nhưng đọc trong sách "Lập trình VBA trong Excel" thấy có biến Single với giá trị lưu trữ lớn hơn rất nhiều từ 1.401298E-45 đến 3.40282338 (Sách Lập trình VBA trong Excel trang 102) Nhưng khi áp dụng vào thì code không chạy mà đứng trơ ra không hiểu nguyên do? Không có vị sư phụ nào am hiểu vấn đề có thể trình bày cho em được rõ không ạ? Xin chân thành cảm ơn. Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Lúc đầu em dùng biến là Long nhưng đọc trong sách "Lập trình VBA trong Excel" thấy có biến Single với giá trị lưu trữ lớn hơn rất nhiều từ 1.401298E-45 đến 3.40282338 (Sách Lập trình VBA trong Excel trang 102)


Theo mình thì trong VB (VBA) dạng biến chứa dữ liệu số lớn nhất là Double
 
Upvote 0
Cái này em không chắc lắm, vì em toàn học lóm cả! Còn chính xác như thế nào mời các cao thủ bình luận thêm nha. Và nhất là tác giả sách là bác Phan Tự Hướng sẽ cho bác biết chính xát hơn em. Đây là nội dung bảng kiểu giá trị trong VB mà bác Hướng đã viết.
Kiểu giá trị | Mô tả Byte | Lưu giữ số nguyên dương nhỏ, từ 0 đến 255
Boolean | Lưu giữ kết quả Logic, True hoặc False
Integer | Lưu giữ giá trị nguyên, từ -32,768 đến 32,767 Long | Lưu giữ giá trị nguyên, từ -2,147,483,648 to 2,147,483,647 Single | Lưu giữ giá trị số, từ -3.402823E38 đến -1.401298E-45; từ 1.401298E-45 đến 3.402823E38 Currency | Lưu giữ số liệu kiểu tiền tệ, áp dụng cho lĩnh vực tài chính, kế toán. Từ -922337203685477.5808 đến 922337203685477.5807 Date | Lưu giữ số liệu kiểu thời gian, từ January 1, 100 tới December 31,9999. Dữ liệu kiểu Date phải có dấu # ở hai đầu. Object | Chứa tham khảo đến bất kỳ đối tượng nào. String | Lưu giữ dưới dạng chuỗi, dài của chuỗi từ 0 đến 65535 ký tự, giá trị chuỗi được đặt trong dấu "" Variant | Lưu mọi dữ liệu thuộc kiểu định sẵn như: Date, String, Double, Integer... Nếu bạn không khai báo kiểu rõ ràng cho biến thì được hiểu là Variant. VBA sẽ chuyển đổi dữ liệu thuộc kiểu Variant thành một kiểu dữ liệu khác cho phù hợp trong quá trình tính toán.​
Thân.​
 
Lần chỉnh sửa cuối:
Upvote 0
Biến Single và Double là số nguyên và phân, không phải số nguyên đơn thuần như Integer và Long. Thế mà For ...next nó đòi nguyên mới chịu cơ! Nó không nhảy đỏng lên hoặc đứng ì ra là may đấy!
 
Upvote 0
Dùng Single thì không nguyên đúng không? Mà For... next muốn nguyên. Vậy ta có thể khắc phục bằng cách thêm INT vào để lấy số đầu thôi cho lệnh For... next, vậy là ổn 1 cái. Nhưng em chỉ có thể dùng đến số 16777218 thôi. Lớn hơn thì nó đứng ì ra. Và công thức lấy cận trên thì lại sai và luôn lấy số cuối cùng mà mình nhập vào. Còn cận dưới thì rơi vào số 1677213. Cũng tình huống trên nhưng dùng biến Long thì số tận cùng là 2147483647. Và nó là số nguyên tố cuối cùng luôn. Tức là cận trên hay cận dưới điều là nó cả. Và biến Integer thì là số 32767. Vậy xét thấy biến Long Integer đã làm đúng trách nhiệm của mình là đã hoàn thành chỉ số cho phép còn biến Single thì tại sao lại không đúng vậy? Xin chỉ giáo thêm.
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu tôi không nhầm thì toán tử MOD bạn dùng ở đây có chút vấn đề với số lớn. Bạn thử thay thế toán tử MOD bằng phương pháp khác xem sao.
 
Upvote 0
Hàm MOD chia được số lớn nhất là 402,653,183. Vậy là do hàm MOD không đáp ứng được số quá lớn. =MOD(402653183,3) Nhưng nếu dùng công thức khác để thay thế thì sao? Ví dụ như:
PHP:
Function ModTay(so1 As Variant, so2 As Variant) As Variant ModTay = so1 - Int(so1 / so2) * so2 End Function
Với ModTay thì tính đến số 1E+307 luôn nhưng hình như không chính xác nhỉ? =ModTay(1E+307,3)= 1.2474E+291 (À sao em nhập số này rồi Enter thì Excel tự tắt vậy? Không biết các bác có bị giống em không?) =ModTay(1E+16,3) đến ModTay(1E+306,3) điều ra = 0 cả. Các số 1E+15 trở xuống thì tính mới đúng. Vậy là sao ta? Vậy ta chuyển qua dùng Round thay INT xem sao nha!
PHP:
Function ModTay(so1 As Variant, so2 As Variant) As Variant ModTay = so1 - WorksheetFunction.Round((so1 / so2), 0) * so2 End Function
=ModTay(1E+307,3)|= 9.9792E+291 =modtay(1E+306,3)|= 1.0915E+291 =modtay(1E+305,3)|= 9.7453E+289 =modtay(1E+304,3)|= 9.7453E+288 =modtay(1E+303,3)|= 9.1362E+287 =modtay(1E+302,3)|= 1.142E+287 =modtay(1E+301,3)|= 1.0707E+286 =modtay(1E+300,3)|= 1.0409E+285 =modtay(1E+299,3)|= 1.1153E+284 =modtay(1E+298,3)|= 9.2939E+282 =modtay(1E+297,3)|= 1.1617E+282 =modtay(1E+296,3)|= 9.076E+280 =modtay(1E+295,3)|= 9.076E+279 =modtay(1E+294,3)|= 1.1345E+279 =modtay(1E+293,3)|= 8.8633E+277 =modtay(1E+292,3)|= 8.8633E+276 =modtay(1E+291,3)|= 9.6942E+275
(Và gõ các số lớn này vào cũng gây Exit Excel luôn) Đến =modtay(1E+15,3) nó mới đúng. Và Excel luôn khống chế 1 số lớn hơn 1E+307, tứ là 1E+308 thì sẽ báo lỗi và sẽ hiện giá trị là -1 vào đó. Vậy ta không bao giờ tính được các số lớn hơn 1E+306 sao? Nhưng sao khi đưa vào công thức thì vẫn bị khống chế không chạy là sao ta? Mọi người ơi giúp em tý nữa nha! Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi đã gặp vấn đề này 1 lần mà giờ không nhớ ở bài nào. Nhưng chắc chắn là không dùng INT hay ROUND được. Trong bài đó hình như tôi dùng hàm Floor của WorksheetFunction, bạn thử lại với hàm Floor này xem sao
Mã:
  PhanDu = So1 - WorksheetFunction.Floor(So1/So2,1)*So2
 
Upvote 0
Rất tiết hàm Floor báo lỗi #Value! toàn bộ không tính được bất kỳ số nào? Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Rất tiết hàm Floor báo lỗi #Value! toàn bộ không tính được bất kỳ số nào?
Thân.
Lỗi #VALUE bạn thừa biết là sai kiểu tham số truyền vào mà. Bạn thử kiểm tra lại xem, tôi vừa thử viết 1 hàm và nó chạy tốt mà.
Mã:
Function BigMod(So1 As Double, So2 As Double) As Double
    BigMod = So1 - Application.WorksheetFunction.Floor(So1 / So2, 1) * So2
End Function
 
Upvote 0
À thì ra lúc em dùng Floor đặt thông số cuối là 0 nên nó báo #Value! Và không phải là biến sai đâu bác vì em dùng biến Variant mà. Và nếu dùng công thức trên thì số cũng đâu có vượt ra khỏi 1E+307 đâu. Và kết quả vẫn sai ý như vậy thôi! Đâu có gì thay đổi đâu bác! Em cần tìm số cực lớn và thoát khỏi 16777218 luôn. Mà các hàm Mod tự tạo chỉ cho phép dùng đến 15 chữ số thôi. Còn qua công thức xác định cận số nguyên tố thì chỉ còn có 8 số thôi! Vậy phải làm sao để lấy được số nguyên tố cực lớn hả bác. Mong mọi người tìm thêm cách giúp em với! Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom