Đố 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
 
Dựa trên cơ sở gợi ý của bác TigerTiger, tôi có chỉnh lại code viết hàm tìm số nguyên tố của bác BNTT như sau:
PHP:
Public Function SoNguyenTo(So As Double) As Boolean
    Dim i As Integer
    If So <= 0 Or Int(So) <> So Then
        SoNguyenTo = False
    Else
        For i = 2 To Int(Sqr(So))
            If So Mod i = 0 Then
                SoNguyenTo = False
                Exit Function
            End If
        Next
        SoNguyenTo = True
    End If
End Function
Nhờ các bác xem có còn lỗi gì không?
 
Lần chỉnh sửa cuối:
Upvote 0
anhtuan1066 đã viết:
Ko phải là ko chính xác... mà là thừa...
ANH TUẤN
a tuấn bắt bẻ wa nhỉ, híc đúng là thừa thôi, KQ vẫn chuẩn

ĐÚng là Sqr(<...>) -> tigertiger nhầm Sqrt(<...>) là hàm tính căn bậc 2

Sửa 1 chút cho nó dễ hỉu hơn
PHP:
Public Function SoNguyenTo(So As Double) As Boolean
    Dim i As Integer, sNt As Boolean
    sNt = True
    If So <= 0 Or Int(So) <> So Then
        sNt = False
    Else
        For i = 2 To Int(Sqr(So))
            If So Mod i = 0 Then
                sNt = False:    Exit For
            End If:  Next
    End If
    SoNguyenTo = sNt
End Function
 
Upvote 0
Nếu số là 2147483647 +1 thì sao? Lúc này nên khai biến thế nào?
 
Upvote 0
Topic chạy tới đây hình như ko còn mang mục đích là "đố vui" nữa rồi nhỉ? Ý tôi muốn nói đến 1 cái gì đó thật đơn giãn, ta dùng và thấy hàng ngày mà lại ko đễ ý tại sao nó lại như vậy!
ANH TUẤN
 
Upvote 0
Cách giải của tiger chuẩn rồi. Khâm phục!

Tiger trau chuốt thêm một chút để chạy nhanh hơn xem nào? Vẫn còn chưa tối ưu đâu.
 
Upvote 0
workman đã viết:
Cách giải của tiger chuẩn rồi. Khâm phục!

Tiger trau chuốt thêm một chút để chạy nhanh hơn xem nào? Vẫn còn chưa tối ưu đâu.
Đúng thuật toán Tìm nguyên tố có nhiều thuật toán (xem thêm ở phần cuối bài này). Ở đây chúng ta sử dụng thuật toán đơn giản,

Tuy vậy có thể tối ưu thêm 1 chút có thể để ý rằng ngoại trừ 2 còn tất cả những những số nguyên tố đều là số lẻ vì thế
thêm đ/k Nếu so thỏa mãn : (So > 2 And Int(So) Mod 2 = 0) -> là số không là số nguyên tố -> chỉ dùng For ktra khi so đó là số lẻ (ngoại trừ 2)

Và cụ thể như sau:

PHP:
Public Function SoNguyenTo(So As Double) As Boolean
    Dim i As Integer, sNt As Boolean
    sNt = True
    If So <= 0 Or Int(So) <> So Or (So > 2 And Int(So) Mod 2 = 0) Then
        sNt = False
    Else
        For i = 2 To Int(Sqr(So))
            If So Mod i = 0 Then
                sNt = False:    Exit For
            End If:  Next
    End If
    SoNguyenTo = sNt
End Function
Về thuật toán tìm số nguyên tố có nhiều thuật toán - thuật toán tối ưu nhanh - hiện người nói nhiều đến thuật toán Lấy ngẫu nhiên như: Kiểm tra Miller-Rabin và Kiểm tra Solovay-Strassen ; tuy nhiên các thuật toán này khá phức tạp
Xem thêm ở đây


@ThuNghi
ThuNghi đã viết:
Nếu số là 2147483647 +1 thì sao? Lúc này nên khai biến thế nào?
Vấn đề là chúng ta khai báo biến thôi -> đổi i thành Long. Nhưng ở đây đang chú ý là lệnh và thuật toán a ah
còn nếu cần tìm số nguyên tố là số rất lớn thì thuật toán lại khác xem thêm tại đây
 
Lần chỉnh sửa cuối:
Upvote 0
tigertiger đã viết:
a tuấn bắt bẻ wa nhỉ, híc đúng là thừa thôi, KQ vẫn chuẩn

ĐÚng là Sqr(<...>) -> tigertiger nhầm Sqrt(<...>) là hàm tính căn bậc 2

Sửa 1 chút cho nó dễ hỉu hơn
PHP:
Public Function SoNguyenTo(So As Double) As Boolean
    Dim i As Integer, sNt As Boolean
    sNt = True
    If So <= 0 Or Int(So) <> So Then
        sNt = False
    Else
        For i = 2 To Int(Sqr(So))
            If So Mod i = 0 Then
                sNt = False:    Exit For
            End If:  Next
    End If
    SoNguyenTo = sNt
End Function


Có lẽ nên dựa vào số cuối cùng của So sau đó mới kiểm tra If So Mod i = 0
Như vậy sẽ nhanh hơn một xíu (tuy nhiên lại phải thêm mấy dòng code nữa - Không biết hàm Mod và hàm Right thì cái nào nhanh hơn nhỉ ??)
Đây chỉ là một ý tưởng thoáng qua thôi.

Thân!
 
Upvote 0
Vậy 1 có phải snt không nhỉ?
Các hàm trên khi tính cho 1 sẽ sai hoặc báo lỗi, trừ cái nào có if So <=2
 
Lần chỉnh sửa cuối:
Upvote 0
ptm0412 đã viết:
Vậy 1 có phải snt không nhỉ?
Các hàm trên khi tính cho 1 sẽ sai hoặc báo lỗi, trừ cái nào có if So <=2
Theo những gì tôi biết từ trước tới giờ thì:
SỐ NGUYÊN TỐ LÀ SỐ CHỈ CHIA HẾT CHO 1 VÀ CHÍNH NÓ, NHỎ NHẤT LÀ 2
Vậy số 1 hình như không được xem như là số nguyên tố, vì số nguyên tố nhỏ nhất là 2.
Có bác nào có ý kiến khác không ạ ?
 
Upvote 0
BNTT đã viết:
Theo những gì tôi biết từ trước tới giờ thì:
SỐ NGUYÊN TỐ LÀ SỐ CHỈ CHIA HẾT CHO 1 VÀ CHÍNH NÓ, NHỎ NHẤT LÀ 2
Vậy số 1 hình như không được xem như là số nguyên tố, vì số nguyên tố nhỏ nhất là 2.
Có bác nào có ý kiến khác không ạ ?

Số nguyên tốsố tự nhiên lớn hơn 1, chỉ chia hết cho 1 và chia hết cho chính nó.
Ví dụ: 2, 3, 5, 7, 11..

Theo :_http://vi.wikipedia.org

Thân!
 
Upvote 0
Mr Okebab đã viết:
Số nguyên tốsố tự nhiên lớn hơn 1, chỉ chia hết cho 1 và chia hết cho chính nó.
Ví dụ: 2, 3, 5, 7, 11..

Theo :_http://vi.wikipedia.org

Thân!
Oh, đây chỉ là khái niệm thôi,
Nhưng đúng là thường thấy là 1 không phải số nguyên tố cũng lạ nhỉ?

Mr Okebab đã viết:
Có lẽ nên dựa vào số cuối cùng của So sau đó mới kiểm tra If So Mod i = 0
Như vậy sẽ nhanh hơn một xíu (tuy nhiên lại phải thêm mấy dòng code nữa - Không biết hàm Mod và hàm Right thì cái nào nhanh hơn nhỉ ??)
Đây chỉ là một ý tưởng thoáng qua thôi.
Thân!
Oh, nghe có vẻ hợp lý khi lấy chữ số cuối -> để xét nó chia hết 2, 3.. sẽ nhanh hơn:
+ tưởng đúng nhưng chưa bao hết ví dụ số 121 chẳng hạn
+ bên cạnh đó i chạy từ 2 -> những số chia hết cho 2, 3 sẽ bị loại ngay (không thực hiện hết vòng for)-> vẫn nhanh như thường
.
 
Lần chỉnh sửa cuối:
Upvote 0
tigertiger đã viết:
Oh, nghe có vẻ hợp lý khi lấy chữ số cuối -> để xét nó chia hết 2, 3.. sẽ nhanh hơn:
+ tưởng đúng nhưng chưa bao hết ví dụ số 121 chẳng hạn
+ bên cạnh đó i chạy từ 2 -> những số chia hết cho 2, 3 sẽ bị loại ngay (không thực hiện hết vòng for)-> vẫn nhanh như thường
.

Bác hiểu sai ý em rồi : Ta không dựa vào dấu hiệu chia hết!
VD : Số cuối của SO là :
: 1, vậy số cuối của i phải là : 1; 3; 7; 9
: 3, vậy số cuối của i phải là : 1; 3; 7; 9
: 5, vậy số cuối của i phải là : 1; 3; 5; 7; 9
: 7, vậy số cuối của i phải là : 1; 3; 7; 9
: 9, vậy số cuối của i phải là : 1; 3; 7; 9
Cái này ta chỉ xét 1 lần trước khi có vòng For.

Cũng chẳng biết là nhanh hơn không, hình như chậm hơn. Híc híc

Thân!
 
Upvote 0
Tôi thì sẽ làm bài toán nguyên tố này như sau:
1> D/k loại bõ các số chẳn và các số ko nguyên:
Mã:
If So < 2 Or (So <> 2 And So Mod 2 = 0) Or So <> Int(So) Then Exit Function
2> Tiếp theo cho vòng lập For chạy từ 3 đến Sqr(So) Step 2
3> Và vòng lập For như sau:
PHP:
For i = 3 To Sqr(So) Step 2
    If So Mod i = 0 Then Exit Function
Next
Vậy là xong...
Ngoài ra cũng có công thức cho vụ này, tuy đưa vào đây ko hợp lắm nhưng cũng xin góp vui (công thức mãng nha)
Mã:
=OR(A1=2,A1=3,ISNA(MATCH(TRUE,A1/ROW(INDIRECT("2:"&INT(SQRT(A1))))=INT(A1/ROW(INDIRECT("2:"&INT(SQRT(A1))))),0)))
Nói chung công thức hay VBA vẫn cùng 1 nguyên tắc TÌM và XÉT ĐIỀU KIỆN...
Mến
ANH TUẤN

Có lỗi gì đâu bạn... Tôi đang thử đây
SoNT(3) cho kết quã = TRUE
SoNT(5) cho kết quã = TRUE
SoNT(7) cũng cho kết quã = TRUE
Cã UDF và công thức cho cùng 1 kết quã
Hi.. hi... Máy bạn bị sao rồi đại ca ơi
ANH TUẤN
 

File đính kèm

  • SoNT.zip
    6 KB · Đọc: 30
Upvote 0
Tớ sai, vì nghĩ rằmg For i = m to n với m>n sẽ không chạy. Thực ra nó cũng chạy. Lạ thực, nó ra ngoài lý luận thông thường. Ai biết giải thích giùm.
Tớ thử thế này: thử với So=11, Int(Sqr(So)) = 3
Theo mình lý luận thì
- For chạy vòng 1, i = 3, OK
- For chạy vòng 2, i = 3 + 2 = 5 (5>Int(Sqr(So)) ) For phải ngưng.

Thế mà vẫn chạy. Kiểm tra (bằng cách Pause) : i vẫn = 5!!!
Kiểm tra với So=29, Int(So)) = 5, i đạt đến 7 !!!
 
Lần chỉnh sửa cuối:
Upvote 0
ptm0412 đã viết:
Tớ sai, vì nghĩ rằmg For i = m to n với m>n sẽ không chạy. Thực ra nó cũng chạy. Lạ thực, nó ra ngoài lý luận thông thường. Ai biết giải thích giùm.
Nhưng mà tôi đâu thấy phần Help nào nói rằng bắt buộc m phải nhỏ hơn n đâu nhỉ... Thử vào nó chạy tuốt...
ANH TUẤN
 
Upvote 0
tigertiger đã viết:
Vấn đề là chúng ta khai báo biến thôi -> đổi i thành Long. Nhưng ở đây đang chú ý là lệnh và thuật toán a ah
còn nếu cần tìm số nguyên tố là số rất lớn thì thuật toán lại khác xem thêm tại đây

Thuật toán của tiger quá tốt, tôi đâu có ý nghiên cứu toán cao cấp đâu (mà cũng không có khả năng, thông cảm già rồi).

Bạn chú ý nếu số nhập vào là số lớn thì việc chạy nhiều vòng lặp chính là nguyên nhân làm có hàm chạy chậm. Tiger nghiên cứu tiếp làm sao giảm vòng lặp xem sao?

Tôi thấy các bạn có nhiều cao thủ toán lý thuyết và toán tin. Thôi không dám ngo ngoe đố linh tinh nữa.

À, mà các bác có bài nào hay hay post lên để anh em giải trí cho vui.
 
Upvote 0
Nhưng mà tôi đâu thấy phần Help nào nói rằng bắt buộc m phải nhỏ hơn n đâu nhỉ... Thử vào nó chạy tuốt...
Không phải Help, mà là lý luận. For i = m to n step k nghĩa là:
i=m: chạy vòng 1
i=m+1*k: chạy vòng 2
i=m+2*k: chạy vòng 3
. . .

khi m+x*k = n, For dừng lại.

Thế mà nếu So=2, Int(Sqr(So)) = 1
Theo mình lý luận thì với For i=2 to 1 mà không có step âm
hoặc For i = 3 to 1 step 2 thì phải báo lỗi ngay khi tính i lần 2.
 
Upvote 0
Xin phép sửa lại chút xíu, tốc độ sẽ được cải thiện.
PHP:
Public Function SoNguyenTo(So As Double) As Boolean
    Application.Volatile (False)
    Dim i As Integer
    If So <= 1 Or Int(So) <> So Or (So > 2 And Int(So) Mod 2 = 0) Then Exit Function
    SoNguyenTo = True
    If So = 2 Or So = 3 Or So = 5 Or So = 7 Then Exit Function
    For i = 3 To Int(Sqr(So)) Step 2
        If So Mod i = 0 Then SoNguyenTo = False: Exit Function
    Next
End Function


Thân!

 
Upvote 0
Mr. Okebab đã viết:
Xin phép sửa lại chút xíu, tốc độ sẽ được cải thiện.

Thực ra cũng không cải thiện nhiều, vì thực ra ngay những vòng lặp đầu tiên -> Fun... đã xét đến chia 2,3,... như vậy nó sẽ bị loại ngay,
Đôi khi thấy Exit Funtion ta tưởng nhanh hơn -> nhưng nếu ta dùng IF, hay Exit For -> kết thúc lệnh - cũng tương đương nhau
Và trên cả vấn đề ở đây đúng như Workman viết đó là vấn đề khi số đó là số nguyên tố có giá trị lớn -> thuật toán đang dùng mất nhiều vòng lặp ->
khi đó phải dùng thuật toán khác

mạn đàm như vậy thôi, -> tôi nghĩ nên chuyển sang vấn đề khác
 
Upvote 0
tigertiger đã viết:
Thực ra cũng không cải thiện nhiều, vì thực ra ngay những vòng lặp đầu tiên -> Fun... đã xét đến chia 2,3,... như vậy nó sẽ bị loại ngay,
Đôi khi thấy Exit Funtion ta tưởng nhanh hơn -> nhưng nếu ta dùng IF, hay Exit For -> kết thúc lệnh - cũng tương đương nhau
Và trên cả vấn đề ở đây đúng như Workman viết đó là vấn đề khi số đó là số nguyên tố có giá trị lớn -> thuật toán đang dùng mất nhiều vòng lặp ->
khi đó phải dùng thuật toán khác

mạn đàm như vậy thôi, -> tôi nghĩ nên chuyển sang vấn đề khác

Cái nhanh hơn chút xíu là cái step 2, chứ mấy cái kia quan trọng gì.

Nhưng thôi có thể kết ở đây được rồi. Ta chuyển sang đề tài khác vậy.

Thân!
 
Upvote 0
Web KT
Back
Top Bottom