-
Mar 3rd, 2008, 04:56 AM
#1
>> and << functions for VB
VB does not have >> and << operators but we can create functions to simulate them.
Without unsign data type other than Byte, so we can use only 31 right bits of Long (the largest Long number is 2^31-1).
(Notation "&" below denotes a Long number)
Edit: See New version in post#7
Code:
Function RShift(Num as Long, b as Byte) As Long
'--- Num >> b
If Num > 0 then
If b < 31 then
'-- shift to the right with 0's patched to the left
RShift = Num \ (2& ^ b)
Else
RShift = 0 '-- all bits are shifted away
End if
ElseIf Num = 0 then
RShift = 0
Else
'-- can raise an error here
MsgBox "Num must be >= 0"
End If
End Function
Code:
Function LShift(Num as Long, b as Byte) As Long
'-- Num << b
If Num > 0 then
If b = 0 then
LShift = Num '-- shift nothing
ElseIf b < 31 then
'-- Num mod 2&^(31-b) will shift the left-most bits away first to avoid overflow.
' * (2& ^ b) will shift the remaining bits to the left
' with 0's patched to the right.
LShift = (Num mod 2&^(31-b)) * (2& ^ b)
Else
LShift = 0 '-- all bits are shifted away
End if
ElseIf Num = 0 then
LShift = 0
Else
'-- can raise an error here
MsgBox "Num must be >= 0"
End If
End Function
Last edited by anhn; Jun 19th, 2010 at 09:02 PM.
-
Jun 16th, 2010, 10:45 AM
#2
Re: >> and << functions for VB
It is better to write bitshifting inline. Unfortunatenaly to have any performance you have to write a different line for different amount of bitshift:
Code:
Option Explicit
Public Function Bit(ByVal Value As Long) As String
Dim I As Long
Bit = "00000000000000000000000000000000"
If Value < 0 Then Value = Value And &H7FFFFFFF: Mid$(Bit, 1, 1) = "1"
For I = 32 To 2 Step -1
If Value And 1 Then Mid$(Bit, I, 1) = "1"
Value = Value \ 2
Next I
End Function
Private Sub Form_Load()
Dim Shift As Long
' initial status
Shift = &HFFFFFFFF
Debug.Print "<< 0", Bit(Shift)
' left shift one bit
Shift = (Shift And &H3FFFFFFF) * 2 Or -((Shift And &H40000000) > 0) * &H80000000
Debug.Print "<< 1", Bit(Shift)
' left shift two bits
Shift = (Shift And &H1FFFFFFF) * 4 Or -((Shift And &H20000000) > 0) * &H80000000
Debug.Print "<< 2", Bit(Shift)
' left shift three bits
Shift = (Shift And &HFFFFFFF) * 8 Or -((Shift And &H10000000) > 0) * &H80000000
Debug.Print "<< 3", Bit(Shift)
' left shift four bits
Shift = (Shift And &H7FFFFFF) * 16 Or -((Shift And &H8000000) > 0) * &H80000000
Debug.Print "<< 4", Bit(Shift)
' left shift five bits
Shift = (Shift And &H3FFFFFF) * 32 Or -((Shift And &H4000000) > 0) * &H80000000
Debug.Print "<< 5", Bit(Shift)
' right shift one bit
Shift = (Shift And &H7FFFFFFF) \ 2 Or -(Shift < 0) * &H40000000
Debug.Print ">> 1", Bit(Shift)
' right shift two bits
Shift = (Shift And &H7FFFFFFF) \ 4 Or -(Shift < 0) * &H20000000
Debug.Print ">> 2", Bit(Shift)
' right shift three bits
Shift = (Shift And &H7FFFFFFF) \ 8 Or -(Shift < 0) * &H10000000
Debug.Print ">> 3", Bit(Shift)
' right shift four bits
Shift = (Shift And &H7FFFFFFF) \ 16 Or -(Shift < 0) * &H8000000
Debug.Print ">> 4", Bit(Shift)
' right shift five bits
Shift = (Shift And &H7FFFFFFF) \ 32 Or -(Shift < 0) * &H4000000
Debug.Print ">> 5", Bit(Shift)
End Sub
The Bit function is only for displaying the effect of the math. I only did the first five shifts for both left & right shift, because all the remaining ones are easy enough to write based on what has already been given.
The bitshifting codes in this post are compatible with unsigned values.
-
Jun 17th, 2010, 07:25 AM
#3
Re: >> and << functions for VB
How can you remember all that to write inline for LShift and RShift with any bits from 0 to 32, and what hex numbers to use for 6 to 32 bits?
I have seen a similar code somewhere on internet with a full Select Case from 0 to 32 bits (64 cases in total) for LShift() and RShift().
Perhaps use bitwise operators inline is fast but too many cases and hex numbers to remember (cannot remember anyway.)
Last edited by anhn; Jun 18th, 2010 at 06:06 AM.
-
Jun 17th, 2010, 08:47 AM
#4
Re: >> and << functions for VB
In most cases that I've needed unsigned bitshift I've also needed it in one or two spots in the entire code. Thus it doesn't really make it worth to write a function. Also, remembering the hex codes isn't required: you can see a logic in the five samples that I gave. Each next one is similar to what has been posted before, just the amount of zeros decrease (every fourth is similar, so 1 is similar to 5, 2 is similar to 6 etc.).
You don't even need to take unsigned bit into account in every case: in some file formats the value is restricted already so that you'll never hit the highest bit. So the math would be simple Shift = Shift * 2 or Shift = Shift \ 2 for << 1 and >> 1. The sample codes I gave are valuable for those who need to have support for unsigned values.
A lot of the cases you may be doing simple stuff such as combining two Integers to a Long – you don't even need to think it as a bitshift in those cases: Long = Low And &HFFFF& Or (High And &H7FFF&) * &H10000 Or -(High < 0) * &H80000000
Personally I admit I really dislike any "do it via string" solution. It is an awful lot of performance waste, like using an excavator where a simple shovel would be fit. I wouldn't encourage anyone to use those methods for data processing. But if you need to display something then that is a different case – it just happens to be a very rare case, not really something you'd put up for end user unless the app is aimed towards knowleable people.
I also think learning & knowing hex numbers is a good skill for any developer, be it VB or be it something else.
-
Jun 18th, 2010, 06:04 AM
#5
Re: >> and << functions for VB
Recursive method:
Code:
Function LShift(ByVal Num As Long, ByVal Bits As Byte) As Long
If Num = 0 Or Bits = 0 Then LShift = Num Else _
LShift = LShift((Num And &H3FFFFFFF) * 2 Or -((Num And &H40000000) > 0) * &H80000000, Bits - 1)
End Function
Function RShift(ByVal Num As Long, ByVal Bits As Byte) As Long
If Num = 0 Or Bits = 0 Then RShift = Num Else _
RShift = RShift((Num And &H7FFFFFFF) \ 2 Or -(Num < 0) * &H40000000, Bits - 1)
End Function
Code:
Function Bin(ByVal Num As Long) As String
Dim b As Long
b = 32: Bin = String$(b, "0")
If Num < 0 Then Mid$(Bin, 1, 1) = "1": Num = (Num And &H7FFFFFFF)
Do Until (Num = 0) Or (b = 1)
If (Num And 1) Then Mid$(Bin, b, 1) = "1"
b = b - 1: Num = Num \ 2
Loop
End Function
Code:
Sub Test()
Dim n0 As Long, n As Long, b As Byte
n0 = Int(Rnd * 2 ^ 24) * (Int(Rnd * 2 ^ 8) - 2 ^ 7)
b = 0
Do
n = LShift(n0, b)
Debug.Print n0; "<<"; b, n, Hex(n), Bin(n)
b = b + 1
Loop Until n = 0
Debug.Print String$(89, "-")
b = 0
Do
n = RShift(n0, b)
Debug.Print n0; ">>"; b, n, Hex(n), Bin(n)
b = b + 1
Loop Until n = 0
Debug.Print String$(89, "=")
End Sub
Last edited by anhn; Jun 18th, 2010 at 09:08 AM.
-
Jun 18th, 2010, 08:35 PM
#6
Re: >> and << functions for VB
Recursion makes very little sense performance wise:
Code:
Function LShift(ByVal Num As Long, ByVal Bits As Byte) As Long
If Bits < 32 Then
For Bits = 1 To Bits: Num = (Num And &H3FFFFFFF) * 2 Or -((Num And &H40000000) > 0) * &H80000000: Next
LShift = Num
End If
End Function
Function RShift(ByVal Num As Long, ByVal Bits As Byte) As Long
If Bits < 32 Then
If Bits Then Num = (Num And &H7FFFFFFF) \ 2 Or -(Num < 0) * &H40000000
For Bits = 2 To Bits: Num = Num \ 2: Next
RShift = Num
End If
End Function
-
Jun 19th, 2010, 03:02 AM
#7
Re: >> and << functions for VB
The loop should be terminated when Num = 0, no need to keep shifting.
Code:
Function LShift(ByVal Num As Long, ByVal Bits As Byte) As Long
If (Num = 0) Or (Bits >= 32) Then Exit Function
Do Until (Bits = 0) Or (Num = 0)
If (Num And &H40000000) = 0 Then Num = (Num And &H3FFFFFFF) * 2 _
Else Num = (Num And &H3FFFFFFF) * 2 Or &H80000000
Bits = Bits - 1
Loop
LShift = Num
End Function
Function RShift(ByVal Num As Long, ByVal Bits As Byte) As Long
If (Num = 0) Or (Bits >= 32) Then Exit Function
If Bits = 0 Then RShift = Num: Exit Function
If Num < 0 Then Num = (Num And &H7FFFFFFF) \ 2 Or &H40000000: Bits = Bits - 1
Do Until (Bits = 0) Or (Num = 0): Num = Num \ 2: Bits = Bits - 1: Loop
RShift = Num
End Function
Code:
Function Bin(ByVal Num As Long) As String
Dim b As Byte, Bit(63) As Byte
Bit(0) = 49 + ((Num And &H80000000) = 0)
For b = 1 To 31: Bit(2 * b) = 49 + ((Num And 2 ^ (31 - b)) = 0): Next
Bin = Bit
End Function
Function GetBit(ByVal Num As Long, ByVal Bit As Byte) As Byte
'-- Bit number count right-to-left from 0 to 31
If Bit < 31 Then
If (Num And 2 ^ Bit) Then GetBit = 1
ElseIf Bit = 31 Then
If (Num And &H80000000) Then GetBit = 1
End If
End Function
-
Jun 19th, 2010, 05:35 AM
#8
Re: >> and << functions for VB
The math is so lightweight in compiled application that adding the extra check for value being zero mostly results only in a longer & possibly slower code. I don't find this much worth of benchmarking as inline code would be tremendously faster than any function call – you could do this calculation multiple times before it would become more time consuming than a single function call.
-
Jun 19th, 2010, 06:28 AM
#9
Re: >> and << functions for VB
Stick with your inline code method, that is your choice.
I still like the recursive versions in this case because the code is so simple.
No point to loop 31 times when doing RShift(1, 31) or LShift(&H80000000, 31).
-
Jun 19th, 2010, 11:20 AM
#10
Re: >> and << functions for VB
Recursion is looping in this case
-
Jun 19th, 2010, 09:00 PM
#11
Re: >> and << functions for VB
Originally Posted by Merri
Recursion is looping in this case
Yes, but it will stop looping when Num=0 or Bits=0.
-
Jun 20th, 2010, 04:40 AM
#12
Re: >> and << functions for VB
Then how about the second recursive call to RShift? At that point it is clearly pointless to check for the highest bit.
-
Jun 27th, 2010, 09:00 AM
#13
Fanatic Member
Re: >> and << functions for VB
Merri, hasn't this reached the point of "who cares" yet? Sure performance MAY be affected, but most cases in vb code it will never make a difference. I dare say that the performance that really counts is being able to write the code faster and meet deadlines at work. If you have to shift so many bits that it becomes a bottleneck, it can be dealt with then. Otherwise too much time spent.
-
Jun 27th, 2010, 10:28 AM
#14
Re: >> and << functions for VB
But we aren't talking about work deadlines here.
Last edited by Merri; Jun 27th, 2010 at 10:32 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|