VBA Nâng cao: NOT, OR, XOR và AND toán tử logic tối quan trọng cho tư duy lập trình (1 người xem)

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

Giải pháp
CẬP NHẬT BÀI VIẾT

Các phép toán cộng, trừ, nhân, chia, chia dư và lũy thừa chỉ sử dụng phép toán bitwise, các toán tử dịch chuyển bit bên dưới mã chỉ hoạt động trong TwinBasic.
Để thay thế và sử dụng trong VBA hãy thay thế các vị trí mã chuyển bit << và >>, thành dịch chuyển trái LShift và dịch chuyển phải RShift.


Các đoạn mã bên dưới chỉ là ví dụ để các bạn hiểu cách các phép toán hoạt động như thế nào.

1. Cộng hai số bằng bitwise:

JavaScript:
Function BitwiseAdd(a As Long, b As Long) As Long
    Dim carry As Long
    Do While b <> 0
        carry = a And b
        a = a Xor b
        b = carry << 1
    Loop
    BitwiseAdd = a
End Function


Function BitwiseAddDecimal(a As Currency, b As Currency, Optional precision...
Hôm nay tôi chia sẻ đến các bạn một kiến thức, mà hầu như các Lập trình viên sơ cấp, không được giảng rỏ về 4 toán tử NOT, OR, AND và XOR căn bản trong mọi ngôn ngữ lập trình.

NOT, OR, AND và XOR không phải trả về giá trị đúng sai như các bạn thường vận dụng. Vì chúng là toán tử, chính xác thì chúng là toán tử tính toán chỉ khác cộng, trừ, nhân, chia, ..., chúng tính toán dựa vào phép toán bitwise.
Nhưng ít sách vở căn bản nào giải thích rõ cho các bạn biết bản chất của chúng.

Chính vì vậy mà hôm nay tôi chia sẻ thêm kiến thức tuy căn bản nhưng lại là tiền đề cho những cấu trúc mã Nâng cao sau này. Vì chúng là cơ sở tạo các cấu trúc mã với giải thuật, thuật toán sau rộng hơn trong Lập trình. Vì chúng không chỉ có trong một ngôn ngữ là VBA.

Để bắt đầu chủ đề các bạn cần xem kiến thức cơ bản về các toán tử logic NOT, OR, XOR và AND tại Wikipedia:
(Tiếng Anh) https://en.wikipedia.org/wiki/Bitwise_operation
(Tiếng Việt) https://vi.wikipedia.org/wiki/Phép_toán_thao_tác_bit


Ví dụ:
Ví dụ 1: Cho một hộp đựng có thể chứa Táo, Cam, Chanh, Bưởi, Ổi. Nếu trong hộp đựng đã chứa Táo, Cam, Chanh thì thêm Bưởi và Ổi.

Với mã dưới đây là một giải pháp chứ không phải giải thuật để giải bài toán trên:

JavaScript:
Sub ThemTraiCay1()
  Dim Thung, TraiCay, i, j, b As Border
  Const Tao = 1, Cam = 2, Chanh = 3, Buoi = 4, Oi = 5
  Thung = Array(Tao, Cam, Chanh)
  TraiCay = Array(Tao, Cam, Chanh, Buoi, Oi)
  For j = 0 To UBound(TraiCay)
    b = True
    For i = 0 To UBound(Thung)
      If Thung(i) = TraiCay(j) Then b = False: Exit For
    Next
    If b Then
      ReDim Preserve Thung(1 To UBound(Thung) + 1): Thung(UBound(Thung)) = TraiCay(j)
    End If
  Next
End Sub

Với mã dưới đây là giải thuật để giải bài toán trên nhanh và hiệu quả:
JavaScript:
Sub ThemTraiCay2()
  Dim Thung, TraiCay
  Const Tao = 2 ^ 0, Cam = 2 ^ 1, Chanh = 2 ^ 2, Buoi = 2 ^ 3, Oi = 2 ^ 4
  Thung = Tao + Cam + Chanh
  TraiCay = Tao Or Cam Or Chanh Or Buoi Or Oi
  Thung= Thung Or TraiCay

  Debug.Print "  Tao: "; Tao And Thung
  Debug.Print "  Cam: "; Cam And Thung
  Debug.Print "Chanh: "; Chanh And Thung
  Debug.Print " Buoi: "; Buoi And Thung
  Debug.Print "   Oi: "; Oi And Thung
End Sub


Vì chưa có thời gian để viết bài thêm: nên tạm thời tôi dừng ở đây.
****Bài viết sẽ được tiếp tục cập nhật thêm****
Đang không hiểu thấy chạy thử thì Táo, Cam, Chạy không có cộng thêm bưởi vào! thấy vẫn 1, 2,4 đúng ra phải 25, 26, 28 không biết phải không?
1678096581161.png
 
Upvote 0
Đang không hiểu thấy chạy thử thì Táo, Cam, Chạy không có cộng thêm bưởi vào! thấy vẫn 1, 2,4 đúng ra phải 25, 26, 28 không biết phải không?
Bạn chưa đọc qua Wikipedia về phép toán Bitwise, để hiểu được giải thuật trên. Bitwise không phải toán cộng hay trừ mà là dịch chuyển bit, quay bit.
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn chưa đọc qua Wikipedia về phép toán Bitwise, để hiểu được giải thuật trên. Bitwise không phải toán cộng hay trừ mà là dịch chuyển bit, quay bit.
bác có update mới phiên bản này chưa bác. Thật sự em ko nghĩ là Excel có thế toàn năng như thế. Tks bác đã nâng tầm excel
 
Upvote 0
Đang không hiểu thấy chạy thử thì Táo, Cam, Chạy không có cộng thêm bưởi vào! thấy vẫn 1, 2,4 đúng ra phải 25, 26, 28 không biết phải không?
View attachment 287305
Bạn chuyển hết những số này sang dạng nhị phân, sau đó dùng toán tử OR, AND và NOT và đọc bài viết trên Wikipedia là sẽ hiểu.
AND dùng để kiểm tra một bit cờ nào đó được thiết đặt (1) hay chưa (0), OR dùng để bật/tắt bit cờ, còn OR để đảo ngược bit.
Một ví dụ thường thấy là dùng để lưu trữ giá trị kiểu boolean, thay vì khai báo kiểu boolean tốn mấy byte thì dùng toán tử thao tác bit OR để bật tắt cờ bit (1 - TRUE, 0 - FALSE) tốn có vài bit, giúp tiết kiệm bộ nhớ.
Ngoài ra còn dịch chuyển bit (bit shift), dịch chuyển trái hoặc dịch chuyển phải, rất tiếc là VB/VBA không hỗ trợ toán tử này.
 
Upvote 0
...
Một ví dụ thường thấy là dùng để lưu trữ giá trị kiểu boolean, thay vì khai báo kiểu boolean tốn mấy byte thì dùng toán tử thao tác bit OR để bật tắt cờ bit (1 - TRUE, 0 - FALSE) tốn có vài bit, giúp tiết kiệm bộ nhớ.
...
Thời buổi bi giờ tiết kiệm bộ nhớ không còn là vấn đề quan trọng nữa.
Vấn đề là truy cập có nhanh hay không. Hiện nay, Long là loại truy cập hiệu quả nhất.
Người ta sử dụng phép toán bit với lý do chính là bọn này gần với phép tính căn bản của CPU, rất rất nhanh.
Ví dụ ăn bản nhất là con toán xét chẵn/lẻ. Rất nhiều bạn có thói quen dùng hàm hoặc toán tử Mod để tính. Đó là thói quen ấu trĩ lập trình.
Ta biết số lẻ có bit 1 là 1 và số chẵn có bit này là 0
Phép toán AND 1 hiệu quả nhất để làm việc này.
If (a AND 1) a là số lẻ.
If (a AND 1) = 0 a là số chẵn
Function IsOdd(a as long) as boolean
If (a AND 1) IsOdd = True
End Function
Function IsEven(a as long) as boolean
If (a AND 1)=0 IsEven = True
End Function
Hai hàm này vốn có sẵn trong Excel. Rất tiếc là còn rất nhiều bạn dùng hàm Mod(a, 2) để tính.

Bài toán dựng cờ bit là một ứng dụng khác hoàn toàn. Nó dùng trong một số trường hợp có thể dùng trị nguyên để phân biệt các loại trong một tổng loại. Ví dụ cam táo trên là một trường hợp, tổng loại là trái cây, phân loại là cam táo...

' xét xem có những loại trái cây nào trong thùng
For Each quả trong thùng
Select Case quả
Case cam: qtt = qtt OR cam
Case táo: qtt = qtt OR táo
...
End Select
Next quả
' Code xét xem có bao nhiêu loại quả trong thùng
Cộng số bit của qtt, bao nhiêu bit là bây nhiêu loại quả
' Code thêm vào cho đủ loại quả
For Each loại quả in tổng loại quả
qtt = qtt OR loại quả
Next loại quả

Lưu ý: khi tính các loại quả thì nên cẩn thận với phép cộng. Phép cộng chỉ cộng được một lần, qua lầ thứ hai sẽ ra kết quả sai. Phép OR thì bao nhiêu lần cũng được.
 
Lần chỉnh sửa cuối:
Upvote 0
Thời buổi bi giờ tiết kiệm bộ nhớ không còn là vấn đề quan trọng nữa.
Vấn đề là truy cập có nhanh hay không. Hiện nay, Long là loại truy cập hiệu quả nhất.
Người ta sử dụng phép toán bit với lý do chính là bọn này gần với phép tính căn bản của CPU, rất rất nhanh.
Ví dụ ăn bản nhất là con toán xét chẵn/lẻ. Rất nhiều bạn có thói quen dùng hàm hoặc toán tử Mod để tính. Đó là thói quen ấu trĩ lập trình.
Ta biết số lẻ có bit 1 là 1 và số chẵn có bit này là 0
Phép toán AND 1 hiệu quả nhất để làm việc này.
If (a AND 1) a là số lẻ.
If (a AND 1) = 0 a là số chẵn

Bài toán dựng cờ bit là một ứng dụng khác hoàn toàn. Nó dùng trong một số trường hợp có thể dùng trị nguyên để phân biệt các loại trong một tổng loại. Ví dụ cam táo trên là một trường hợp, tổng loại là trái cây, phân loại là cam táo...

' xét xem có những loại trái cây nào trong thùng
For Each quả trong thùng
Select Case quả
Case cam: qtt = qtt OR cam
Case táo: qtt = qtt OR táo
...
End Select
Next quả
' Code xét xem có bao nhiêu loại quả trong thùng
Cộng số bit của qtt, bao nhiêu bit là bây nhiêu loại quả
' Code thêm vào cho đủ loại quả
For Each loại quả in tổng loại quả
qtt = qtt OR loại quả
Next loại quả

Lưu ý: khi tính các loại quả thì nên cẩn thận với phép cộng. Phép cộng chỉ cộng được một lần, qua lầ thứ hai sẽ ra kết quả sai. Phép OR thì bao nhiêu lần cũng được.
Tiết kiệm bộ nhớ vẫn quan trọng nhé, nhất là khi lập trình nhúng bằng C++ (bộ nhớ RAM hạn chế), viết driver (gpu, thiết bị ngoại vi, v.v,...), v.v., nên cách thức trên vẫn được sử dụng nhiều, các struct của Win32 API vẫn sử dụng cách này để tối ưu sử dụng bộ nhớ nhất có thể, nhiều tham số các hàm cung cấp được đóng gói (pack) vào kiểu DWORD dưới dạng low order 16bit WORD và high order 16bit WORD (những ai lập trình Window desktop chắc không lạ gì tham số wParam, lParam và sử dụng các macro như LOWORD và HIWORD, LOBYTE, HIBYTE thực chất sử dụng những phép dịch chuyển bit trái phải).
Còn vấn đề dùng toán tử thao tác bit thay cho một số phép toán cơ bản thì đôi khi vẫn sử dụng do tốc độ của nó mang lại tốt hơn, vd: Tính căn bậc hai hoặc lũy thừa của một số thì dùng phép dịch chuyển bit trái hoặc phải cho hiệu năng tốt hơn.
 
Upvote 0
CẬP NHẬT BÀI VIẾT

Các phép toán cộng, trừ, nhân, chia, chia dư và lũy thừa chỉ sử dụng phép toán bitwise, các toán tử dịch chuyển bit bên dưới mã chỉ hoạt động trong TwinBasic.
Để thay thế và sử dụng trong VBA hãy thay thế các vị trí mã chuyển bit << và >>, thành dịch chuyển trái LShift và dịch chuyển phải RShift.


Các đoạn mã bên dưới chỉ là ví dụ để các bạn hiểu cách các phép toán hoạt động như thế nào.

1. Cộng hai số bằng bitwise:

JavaScript:
Function BitwiseAdd(a As Long, b As Long) As Long
    Dim carry As Long
    Do While b <> 0
        carry = a And b
        a = a Xor b
        b = carry << 1
    Loop
    BitwiseAdd = a
End Function


Function BitwiseAddDecimal(a As Currency, b As Currency, Optional precision As Long = 5)) As Currency
    Dim scale As Currency
    Dim intA As Currency, intB As Currency, intResult As Currency
    Dim divisor As Currency, quotient As Currency

    ' Chuyển đổi các tham số thành kiểu nguyên với độ chính xác (precision)
    scale = CCur(BitwisePower(CLng(10), precision)) ' Lũy thừa với bitwise, chuyển về Currency
    intA = CCur(BitwiseMultiply(CLng(a), CLng(scale))) ' Nhân sử dụng bitwise, chuyển về Currency
    intB = CCur(BitwiseMultiply(CLng(b), CLng(scale))) ' Nhân sử dụng bitwise, chuyển về Currency

    ' Cộng hai giá trị sử dụng phép cộng bitwise
    intResult = CCur(BitwiseAdd(CLng(intA), CLng(intB)))

    ' Thay thế phép chia bằng các phép trừ và dịch chuyển bitwise
    divisor = scale
    quotient = 0
    Do While intResult >= divisor
        divisor = divisor * 2 ' Tương đương với dịch trái (<< 1)
    Loop
    Do
        divisor = divisor / 2 ' Tương đương với dịch phải (>> 1)
        If intResult >= divisor Then
            intResult = CCur(BitwiseSubtract(CLng(intResult), CLng(divisor))) ' Trừ bằng bitwise
            quotient = quotient + 1 ' Thay thế cộng bằng kiểu Currency
        End If
    Loop While divisor >= scale

    ' Kết quả cuối cùng
    BitwiseAddDecimal = quotient
End Function

2. Trừ hai số bằng cách đảo bít của số thứ hai và sử dụng phép cộng:


JavaScript:
Function BitwiseSubtract(a As Long, b As Long) As Long
    BitwiseSubtract = BitwiseAdd(a, BitwiseAdd(Not b, 1))
End Function

3. Nhân hai số bằng cách dịch chuyển và cộng:

JavaScript:
Function BitwiseMultiply(a As Long, b As Long) As Long
    Dim result As Long
    result = 0
    Do While b <> 0
        If (b And 1) <> 0 Then
            result = BitwiseAdd(result, a)
        End If
        a = a << 1
        b = b >> 1
    Loop
    BitwiseMultiply = result
End Function

4. Chia hai số sử dụng phép trừ và dịch chuyển:


JavaScript:
Function BitwiseDivide(a As Long, b As Long) As Long
    Dim result As Long, temp As Long
    result = 0
    temp = b
    Do While a >= temp
        temp = temp << 1
    Loop
    Do
        temp = temp >> 1
        If a >= temp Then
            a = BitwiseSubtract(a, temp)
            result = BitwiseAdd(result, 1)
        End If
    Loop While temp >= b
    BitwiseDivide = result
End Function

5. Phép chia lấy dư (modulo)

JavaScript:
Function BitwiseModulo(a As Long, b As Long) As Long
    Dim temp As Long
    temp = b
    Do While a >= temp
        temp = temp << 1
    Loop
    Do
        temp = temp >> 1
        If a >= temp Then
            a = BitwiseSubtract(a, temp)
        End If
    Loop While temp >= b
    BitwiseModulo = a
End Function

5. Phép lũy thừa

JavaScript:
Function BitwisePower(base As Long, exponent As Long) As Long
    Dim result As Long
    result = 1
    Do While exponent > 0
        If (exponent And 1) <> 0 Then
            result = BitwiseMultiply(result, base)
        End If
        base = BitwiseMultiply(base, base)
        exponent = exponent >> 1
    Loop
    BitwisePower = result
End Function

6. Phép dịch chuyển bit trái và phải

JavaScript:
Function RShift(ByVal lNum As Long, ByVal lBits As Long) As Long
    If lBits <= 0 Then RShift = lNum
    If (lBits <= 0) Or (lBits > 31) Then Exit Function
 
    RShift = (lNum And (2 ^ (31 - lBits) - 1)) * _
        IIf(lBits = 31, &H80000000, 2 ^ lBits) Or _
        IIf((lNum And 2 ^ (31 - lBits)) = 2 ^ (31 - lBits), _
        &H80000000, 0)
End Function

Function LShift(ByVal lNum As Long, ByVal lBits As Long) As Long
    If lBits <= 0 Then LShift = lNum
    If (lBits <= 0) Or (lBits > 31) Then Exit Function
 
    If lNum < 0 Then
        LShift = (lNum And &H7FFFFFFF) \ (2 ^ lBits) Or 2 ^ (31 - lBits)
    Else
        LShift = lNum \ (2 ^ lBits)
    End If
End Function

Property Get LoWord(dwNum As Long) As Integer
    LoWord = dwNum And &HFFFF
End Property

Property Let LoWord(dwNum As Long, ByVal wNewWord As Integer)
    dwNum = dwNum And &HFFFF0000 Or wNewWord
End Property

Property Get HiWord(dwNum As Long) As Integer
    HiWord = ((dwNum And IIf(dwNum < 0, &H7FFF0000, &HFFFF0000)) \ &H10000) Or (-(dwNum < 0) * &H8000)
End Property

Property Let HiWord(dwNum As Long, ByVal wNewWord As Integer)
    dwNum = dwNum And &HFFFF& Or IIf(wNewWord < 0, ((wNewWord And &H7FFF)  * &H10000) Or &H80000000, wNewWord * &H10000)
End Property

Property Get LoByte(wNum As Integer) As Byte
    LoByte = wNum And &HFF
End Property

Property Let LoByte(wNum As Integer, ByVal btNewByte As Byte)
    wNum = wNum And &HFF00 Or btNewByte
End Property

Property Get HiByte(wNum As Integer) As Byte
    HiByte = (wNum And &HFF00&) \ &H100
End Property

Property Let HiByte(wNum As Integer, ByVal btNewByte As Byte)
    wNum = wNum And &HFF Or (btNewByte * &H100&)
End Property


Người lập trình mục tiêu hướng đến là Độ phức tạp thời gian, Mã ngắn, Tối ưu hóa, Tốc độ, Đồng bộ, Đa luồng, Xử lý memory, Mã máy, Xử lý lỗi, tiết kiệm chi phí, tiện dụng.

Bất kì khả năng nào trong lập trình, đều cần thiết cho một giải thuật, giải pháp, thuật toán.
 
Lần chỉnh sửa cuối:
Upvote 0
Giải pháp
Tiết kiệm bộ nhớ vẫn quan trọng nhé, nhất là khi lập trình nhúng bằng C++ (bộ nhớ RAM hạn chế), viết driver (gpu, thiết bị ngoại vi, v.v,...), v.v., nên cách thức trên vẫn được sử dụng nhiều, các struct của Win32 API vẫn sử dụng cách này để tối ưu sử dụng bộ nhớ nhất có thể, nhiều tham số các hàm cung cấp được đóng gói (pack) vào kiểu DWORD dưới dạng low order 16bit WORD và high order 16bit WORD (những ai lập trình Window desktop chắc không lạ gì tham số wParam, lParam và sử dụng các macro như LOWORD và HIWORD, LOBYTE, HIBYTE thực chất sử dụng những phép dịch chuyển bit trái phải).

Hình như có sự xáo trộn giữa C và C++ đâu đó.
Nhưng mà thôi, chúng ta đi xa đề quá rồi. Bạn nói về Xi đậm đậm Xi lợt lợt trong Windows, tôi thì quen với tụi này trong platform khác. Khi học Xi lợt lợt thì tôi học STL (tiêu chuẩn) chứ không đá động gì đến Win API.

Vả lại bài này bắt đầu từ VBA, và thắc mắc ở bài #2 liên quan đến kiến thức về áp dụng enum và bit values. Bài #1 muốn giản dị ví dụ cho nên không theo sát với enum, khiến code khó hiểu hơn. (Tôi không nói chuyện sai đúng. Tôi chỉ nói về độ khó hiểu.)

Còn vấn đề dùng toán tử thao tác bit thay cho một số phép toán cơ bản thì đôi khi vẫn sử dụng do tốc độ của nó mang lại tốt hơn, vd: Tính căn bậc hai hoặc lũy thừa của một số thì dùng phép dịch chuyển bit trái hoặc phải cho hiệu năng tốt hơn.
Thời buổi bi giờ, các trình dịch thông minh đủ sức để cải tiến lúc dịch sang mã máy. Người viết code C++ không cần phải lo.
Chỉ cần lúc dịch thì chọn "code optimization".
 
Upvote 0
Thời buổi bi giờ, các trình dịch thông minh đủ sức để cải tiến lúc dịch sang mã máy. Người viết code C++ không cần phải lo.
Chỉ cần lúc dịch thì chọn "code optimization".
Nói chung là nhiều người hơi nhạy cảm vấn đề dùng toán tử thao tác bit thay cho phép toán số học vì cho rằng trình biên dịch sẽ không tự tối ưu code, tuy nhiên trình biên dịch hiện nay đã đủ thông minh để nó tự biết nên tối ưu ở chỗ nào và khi nào thì cần can thiệp. Nhiều người đồng tình rằng nên dùng phép toán số học để dễ đọc hơn, tiện bảo trì code, còn việc tối ưu code cứ để cho trình biên dịch làm việc của nó.

1742811642683.png
Xem thêm: What is the fastest way to find if a number is even or odd?
 
Upvote 0
Bài này nếu có giải thích chi tiết từng bước thì sẽ dễ hiểu hơn, kiểu như tại sao dùng toán tử bit AND, OR, NOT, XOR, dịch chuyển bit ở đây chẳng hạn.
Ví dụ: Đóng gói hai giá trị giá trị uint16 vào một giá trị uint32.
Cho hai giá trị uint16 lần lượt là 0xABCD (43891) và 0xBCDE (48350), đầu tiên chuyển 0xABCD sang kiểu uint32, sau đó dịch chuyển trái 16bit, cuối cùng chuyển 0xBCDE sang kiểu uint32 và dùng toán tử bit OR để ghi vào vị trí mà 0xABCD đã chuyển đi bằng phép dịch chuyển bit trên.
Kết quả cuối cùng là 0xABCDBCDE (2882387166), trong đó 0xABCD (43891) là high order bit, còn 0xBCDE (48350) là low order bit.
Từ đây có thể viết thêm hàm HIWORD và LOWORD để trích xuất lần lượt high order bit và low order bit của giá trị.
 

File đính kèm

  • IMG_20250325_094218.jpg
    IMG_20250325_094218.jpg
    117.4 KB · Đọc: 26
Upvote 0
Bài viết hay nhưng mong mọi người thêm các ví dụ nhiều hơn. cách đặt các hằng số bit để dùng toán tử OR và AND như thế nào?
 
Upvote 0
Bài viết hay nhưng mong mọi người thêm các ví dụ nhiều hơn. cách đặt các hằng số bit để dùng toán tử OR và AND như thế nào?
Để ý rằng tiêu đề bài này bắt đầu bằng "VBA nâng cao". Nếu bạn có kinh nghiệm đọc bài của chủ thớt thì cũng biết từ "cao" của thớt có nghĩa là rất cao.
Bạn hiểu được bài #1, #5, #7, #8 chúng nói gì thì trình độ lập trình đã cao lắm rồi.

Ứng dụng vào VBA, các "hằng số bit" mà bạn muốn hỏi chúng thuộc về lý thuyết enum nhiều hơn là đại số nhị phân (binary algebra). Bạn muốn ví dụ về lý thuyết hay thực hành?
 
Upvote 0
Để ý rằng tiêu đề bài này bắt đầu bằng "VBA nâng cao". Nếu bạn có kinh nghiệm đọc bài của chủ thớt thì cũng biết từ "cao" của thớt có nghĩa là rất cao.
Bạn hiểu được bài #1, #5, #7, #8 chúng nói gì thì trình độ lập trình đã cao lắm rồi.

Ứng dụng vào VBA, các "hằng số bit" mà bạn muốn hỏi chúng thuộc về lý thuyết enum nhiều hơn là đại số nhị phân (binary algebra). Bạn muốn ví dụ về lý thuyết hay thực hành?

Vì nội dung này em thấy khó nên tuỳ kinh nghiệm các anh làm sao để em và mọi người hiểu để ứng dụng. có thể cho các ví dụ liên quan đến trình bày trên userform hoặc dữ liệu trên sheet? Bước đầu cứ cơ bản thôi ạ.
Hình như có liên quan đến kiến thức nhị phân 0101 gì đó nếu được anh trình bày chi tiết phần này thì tốt quá ạ.
 
Upvote 0
Vì nội dung này em thấy khó nên tuỳ kinh nghiệm các anh làm sao để em và mọi người hiểu để ứng dụng. có thể cho các ví dụ liên quan đến trình bày trên userform hoặc dữ liệu trên sheet? Bước đầu cứ cơ bản thôi ạ.
Hình như có liên quan đến kiến thức nhị phân 0101 gì đó nếu được anh trình bày chi tiết phần này thì tốt quá ạ.
Tìm một ví dụ thật đơn giản thì diễn tả không hết, quý vị sẽ chẳng thấy kỹ thuật bit flagging có lợi gì cả. Tôi cố gắng lắm nhưng chỉ thấy ví dụ trung bình là đáp ứng được điều kiệ không quá phức tạp thôi.

Bit flag có nghĩa là coi mỗi bít như có lá cờ cắm ở vị trí ấy. Ta có thể tưởng tượng flag (nghiêng) về bên trái thì là OFF, giá trị 0 ở vị trí ấy; flag về bên phải thì là ON, giá trị 1 ở vị trí ấy.
Điển hình loại biến integer 16 bits:
1743432242574.png
Hy vọng ví dụ trên giúp quý vị hiểu rõ thế nào là bit set/flag On/Off
Nếu trên Form thì ta có thể tưởng tượng On/Off theo kiểu của check box.

Một cách áp dụng điển hình của set bit là để diễn tả một array giá trị True/False. Một biến Long có thể diễn tả được một array 31 phần tử. Bit thứ 32 của Long dùng để đặt dấu (+-) cho nên cần tránh.

Đến đây, nếu quý vị nghĩ rằng chúng có thể dùng để "tiết kiệm bộ nhớ" (thay vì 31 bytes thì chỉ cần 4 thôi) thì là sai tét bét. Chủ đích của ví dụ này là để truyền tham số.
Hàm ABC gọi hàm DEF, ngoài các tham số cần thiết, có thể đặt thêm một số OPTIONS. Cách thông thường mà quý vị dùng là Optional Paramarray với một đống Yes/No (True/False). Dùng phương pháp set và xét bits sẽ giản dị hơn nhiều:

Enum VIDU
Option1 = 1
Option2 = 2
Option3 = 4
Option5 = 8
...
End Enum

Sub DEF(t1 As Long, t2 As String, Ops As Long)
If Ops AND VIDU.Option1 Then ' option 1 được chọn
If Ops AND VIDU.Option5 Then ' option 5 được chọn
...
End Sub

Sub ABC(....)
...
' gọi DEF và chọn options 2, 3
DEF 0, "", 2+4
' hoặc
DEF 0, "", VIDU.Option2 + VIDU.Option3
...
End Sub
 
Upvote 0
Tìm một ví dụ thật đơn giản thì diễn tả không hết, quý vị sẽ chẳng thấy kỹ thuật bit flagging có lợi gì cả. Tôi cố gắng lắm nhưng chỉ thấy ví dụ trung bình là đáp ứng được điều kiệ không quá phức tạp thôi.

Bit flag có nghĩa là coi mỗi bít như có lá cờ cắm ở vị trí ấy. Ta có thể tưởng tượng flag (nghiêng) về bên trái thì là OFF, giá trị 0 ở vị trí ấy; flag về bên phải thì là ON, giá trị 1 ở vị trí ấy.
Điển hình loại biến integer 16 bits:
View attachment 307694
Hy vọng ví dụ trên giúp quý vị hiểu rõ thế nào là bit set/flag On/Off
Nếu trên Form thì ta có thể tưởng tượng On/Off theo kiểu của check box.

Một cách áp dụng điển hình của set bit là để diễn tả một array giá trị True/False. Một biến Long có thể diễn tả được một array 31 phần tử. Bit thứ 32 của Long dùng để đặt dấu (+-) cho nên cần tránh.

Đến đây, nếu quý vị nghĩ rằng chúng có thể dùng để "tiết kiệm bộ nhớ" (thay vì 31 bytes thì chỉ cần 4 thôi) thì là sai tét bét. Chủ đích của ví dụ này là để truyền tham số.
Hàm ABC gọi hàm DEF, ngoài các tham số cần thiết, có thể đặt thêm một số OPTIONS. Cách thông thường mà quý vị dùng là Optional Paramarray với một đống Yes/No (True/False). Dùng phương pháp set và xét bits sẽ giản dị hơn nhiều:

Enum VIDU
Option1 = 1
Option2 = 2
Option3 = 4
Option5 = 8
...
End Enum

Sub DEF(t1 As Long, t2 As String, Ops As Long)
If Ops AND VIDU.Option1 Then ' option 1 được chọn
If Ops AND VIDU.Option5 Then ' option 5 được chọn
...
End Sub

Sub ABC(....)
...
' gọi DEF và chọn options 2, 3
DEF 0, "", 2+4
' hoặc
DEF 0, "", VIDU.Option2 + VIDU.Option3
...
End Sub

Hay quá. Dễ hiểu hơn rồi nhưng em cần thêm thời gian để hiểu kỹ hơn ạ. Như em hiểu thì ứng dụng bit này mang tính ứng dụng cao hơn khi mình cần tạo dấu hiệu thuộc tính chứ không phải là tiết kiệm bộ nhớ.
 
Upvote 0
Tìm một ví dụ thật đơn giản thì diễn tả không hết, quý vị sẽ chẳng thấy kỹ thuật bit flagging có lợi gì cả. Tôi cố gắng lắm nhưng chỉ thấy ví dụ trung bình là đáp ứng được điều kiệ không quá phức tạp thôi.

Bit flag có nghĩa là coi mỗi bít như có lá cờ cắm ở vị trí ấy. Ta có thể tưởng tượng flag (nghiêng) về bên trái thì là OFF, giá trị 0 ở vị trí ấy; flag về bên phải thì là ON, giá trị 1 ở vị trí ấy.
Điển hình loại biến integer 16 bits:
View attachment 307694
Hy vọng ví dụ trên giúp quý vị hiểu rõ thế nào là bit set/flag On/Off
Nếu trên Form thì ta có thể tưởng tượng On/Off theo kiểu của check box.

Một cách áp dụng điển hình của set bit là để diễn tả một array giá trị True/False. Một biến Long có thể diễn tả được một array 31 phần tử. Bit thứ 32 của Long dùng để đặt dấu (+-) cho nên cần tránh.

Đến đây, nếu quý vị nghĩ rằng chúng có thể dùng để "tiết kiệm bộ nhớ" (thay vì 31 bytes thì chỉ cần 4 thôi) thì là sai tét bét. Chủ đích của ví dụ này là để truyền tham số.
Hàm ABC gọi hàm DEF, ngoài các tham số cần thiết, có thể đặt thêm một số OPTIONS. Cách thông thường mà quý vị dùng là Optional Paramarray với một đống Yes/No (True/False). Dùng phương pháp set và xét bits sẽ giản dị hơn nhiều:

Enum VIDU
Option1 = 1
Option2 = 2
Option3 = 4
Option5 = 8
...
End Enum

Sub DEF(t1 As Long, t2 As String, Ops As Long)
If Ops AND VIDU.Option1 Then ' option 1 được chọn
If Ops AND VIDU.Option5 Then ' option 5 được chọn
...
End Sub

Sub ABC(....)
...
' gọi DEF và chọn options 2, 3
DEF 0, "", 2+4
' hoặc
DEF 0, "", VIDU.Option2 + VIDU.Option3
...
End Sub

Cách để tạo hằng số bit như cấu trúc Enum ví dụ trên là

Enum VIDU
Option1 = 1
Option2 = 2
Option3 = 4
Option5 = 8
...
End Enum

Như vậy các giá trị 1, 2, 4, 8,.. bắt buộc dùng công thức 2^(vị trí bit-1) phải không ạ?
 
Upvote 0
Giá trị đặt làm hằng số Enum bạn có thể dựa vào giá trị Hexadecimal

JavaScript:
Enum VIDU
Option0 = &H0
Option1 = &H1
Option2 = &H2
Option3 = &H4
Option4 = &H8
Option5 = &H10
Option6 = &H20
...
OptionN1 = &H20 OR Option3
OptionN2 = &H20 OR Option3 OR Option4
End Enum

Quy tắc ghi nhớ rất dễ nhớ, với bốn số 1, 2, 4, 8 khi tăng dần lên cứ thêm số 0 vào đằng sau
Tuy nhiên kiểu giá trị Enum chỉ có giới hạn giá trị là Long. Tức là &H7FFFFFFF.

Để thiết lập số nguyên lớn nhất trong win64 thì phải sử dụng khai báo const với số lớn nhất là &H7FFFFFFFFFFFFFFF^

Hệ Hexadecimal lại có định nghĩa bổ sung là một cách biểu diễn số nguyên có dấu trong máy tính, giúp xử lý phép toán cộng/trừ dễ dàng và tránh sự mơ hồ khi làm việc với số âm. Gồm One's Complement (bổ sung 1) và Two's Complement (bổ sung 2).

Tùy theo cách bạn ép kiểu như thế nào thì giá trị Hex sẽ trả về theo kiểu đó
Nếu bạn nhập Hex là &HFFFF thì giá trị thực tế là -1 nếu bạn ép kiểu Integer, là 65535 nếu bạn ép kiểu Long
Nếu bạn nhập &HFFFF& thì giá trị của chúng bắt buộc là 65535

Trong phép toán Bitwise khi tính thì &HFFFF = -1 và &HFFFF& = 65535 là do phép bổ sung 2, nên chúng là như nhau
Nếu bạn dùng toán tử như sau, thì chúng sẽ trả về chỉ một giá trị:
-1 AND 65535 sẽ là 65535
Không ép kiểu (&HFFFF OR 65535) sẽ là -1, Vì lúc này VBA đã ép kiểu của giá trị 65535 thành -1, nên giá trị trả về là -1
Và ép kiểu (&HFFFF& OR 65535) sẽ là 65535, vì VBA không ép kiểu của giá trị 65535.
 
Lần chỉnh sửa cuối:
Upvote 0
Giá trị đặt làm hằng số Enum bạn có thể dựa vào giá trị Hexadecimal

JavaScript:
Enum VIDU
Option0 = &H0
Option1 = &H1
Option2 = &H2
Option3 = &H4
Option4 = &H8
Option5 = &H10
Option6 = &H20
...
OptionN1 = &H20 OR Option3
OptionN2 = &H20 OR Option3 OR Option4
End Enum

Quy tắc ghi nhớ rất dễ nhớ, với bốn số 1, 2, 4, 8 khi tăng dần lên cứ thêm số 0 vào đằng sau
Tuy nhiên kiểu giá trị Enum chỉ có giới hạn giá trị là Long. Tức là &H7FFFFFFF.

Để thiết lập số nguyên lớn nhất trong win64 thì phải sử dụng khai báo const với số lớn nhất là &H7FFFFFFFFFFFFFFF^

Hệ Hexadecimal lại có định nghĩa bổ sung là một cách biểu diễn số nguyên có dấu trong máy tính, giúp xử lý phép toán cộng/trừ dễ dàng và tránh sự mơ hồ khi làm việc với số âm. Gồm One's Complement (bổ sung 1) và Two's Complement (bổ sung 2).

Tùy theo cách bạn ép kiểu như thế nào thì giá trị Hex sẽ trả về theo kiểu đó
Nếu bạn nhập Hex là &HFFFF thì giá trị thực tế là -1 nếu bạn ép kiểu Integer, là 65535 nếu bạn ép kiểu Long
Nếu bạn nhập &HFFFF& thì giá trị của chúng bắt buộc là 65535

Trong phép toán Bitwise khi tính thì &HFFFF = -1 và &HFFFF& = 65535 là do phép bổ sung 2, nên chúng là như nhau
Nếu bạn dùng toán tử như sau, thì chúng sẽ trả về chỉ một giá trị:
-1 AND 65535 sẽ là 65535
Không ép kiểu (&HFFFF OR 65535) sẽ là -1, Vì lúc này VBA đã ép kiểu của giá trị 65535 thành -1, nên giá trị trả về là -1
Và ép kiểu (&HFFFF& OR 65535) sẽ là 65535, vì VBA không ép kiểu của giá trị 65535.

Quy tắc tăng dần kiểu 1,2,4,8 rồi thêm số 0 hay đấy, dễ nhớ. Đặt giá trị hằng số cho để set bitwise cứ như vậy phải không?

Mình có một câu hỏi nữa. về hình dung thì số Long khi diễn tả theo bit với 16 hay 32 và cứ bit mở là 1 bit đóng là 0 nên người ta hay diễn tả 10101010 và ta tính được trị của biến. Vậy từ trị của biến làm sao biết được một dãy 101010 như thế nào? Tức là cho số bất kỳ ví dụ 1200 thì biểu diễn 10 và 0 như thế nào?
 
Lần chỉnh sửa cuối:
Upvote 0
Cách để tạo hằng số bit như cấu trúc Enum ví dụ trên là

Enum VIDU
Option1 = 1
Option2 = 2
Option3 = 4
Option5 = 8
...
End Enum

Như vậy các giá trị 1, 2, 4, 8,.. bắt buộc dùng công thức 2^(vị trí bit-1) phải không ạ?
Công thức thì nó vậy. Nhưng trên thực tế, tôi cứ việc nhân 2 trị trước cho nó gọn và dễ hiểu.
 
Upvote 0

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

Back
Top Bottom