Go Back  Xtreme Visual Basic Talk > Legacy Visual Basic (VB 4/5/6) > General > Bit Shifting Left and Right on an 8 bit Integer


Reply
 
Thread Tools Display Modes
  #1  
Old 11-19-2005, 06:30 PM
jgbarber65's Avatar
jgbarber65 jgbarber65 is offline
Regular
 
Join Date: Jul 2003
Location: Newark, DE
Posts: 69
Default Bit Shifting Left and Right on an 8 bit Integer


I couldn't find anything on this here, but has anyone ever taken a single byte (0 to 255) and shifted the 8 bits left or right x number of times? I know there is an easy way to do this, but I can't figure it out. Is there a VB command that does this or a short routine that you could post here.

Thank you,
Joe
Reply With Quote
  #2  
Old 11-19-2005, 07:44 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,909
Default

I'm sure there are some bit-shifting code around here, although most probably work on more than just 8-bits.
Assuming you're talking shifting, and not rotation, then any shift will lose bits off the top or bottom of the number.
To shift left, you just need to multiply by 2 the number of times you shift (2 raised to the number of bits to shift, i.e. to shift 4 bits you would multiply by 16).
But since you will get an overflow, you would need to deal with that by masking off the high bits that will be lost (overflow) as a result of the shift, or since you are only dealing with a byte, copy the byte to an integer, do the multiply, and use a mask to keep the lower 8 bits to copy back to your byte.

To shift right, just do an Integer "\" divide by 2 the number of bits to shift.

So you can code it a number of ways.
You could loop the number of bits to shift and multiply or integer divide by 2 each pass.
You could calculate 2^(x-1), where x is the number of bits to shift and then integer divide of multiply by that.
You could just create a lookup table and index by x, and integer divide or multiply by that.

An example: add a couple of textboxes, a label and a command button, and try the following code.
Code:
Option Explicit Dim shiftVal(0 To 7) As Integer Private Sub Command1_Click() Dim b As Byte, s As Integer b = Val(Text1.Text) s = Val(Text2.Text) Label1 = Str$(ShiftByte(b, s)) End Sub Private Sub Form_Load() Dim p As Integer, i As Integer p = 1 For i = 0 To 7 shiftVal(i) = p p = p * 2 Next End Sub Private Function ShiftByte(b As Byte, num As Integer) As Byte Dim t As Integer If Abs(num) < 8 Then t = b If num < 0 Then t = t \ shiftVal(Abs(num)) Else t = t * shiftVal(num) End If ShiftByte = t And &HFF Else ShiftByte = 0 End If End Function

That's off the top of my head. Someone may have something better.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #3  
Old 11-19-2005, 08:19 PM
jgbarber65's Avatar
jgbarber65 jgbarber65 is offline
Regular
 
Join Date: Jul 2003
Location: Newark, DE
Posts: 69
Default

Sorry I wan't clearer. Yes I wanted a rotating shift. For example: 01011001 shifted 1 time right would be 10101100. I could convert the decimal value to binary and then using a for next loop, read each one and zero and maually shft them and then convert the result back to decimal. I just thought there was an easier way. I think Visual C++ uses >> and << to do this.

Thanks,
Joe

Quote:
Originally Posted by passel
I'm sure there are some bit-shifting code around here, although most probably work on more than just 8-bits.
Assuming you're talking shifting, and not rotation, then any shift will lose bits off the top or bottom of the number.
To shift left, you just need to multiply by 2 the number of times you shift (2 raised to the number of bits to shift, i.e. to shift 4 bits you would multiply by 16).
But since you will get an overflow, you would need to deal with that by masking off the high bits that will be lost (overflow) as a result of the shift, or since you are only dealing with a byte, copy the byte to an integer, do the multiply, and use a mask to keep the lower 8 bits to copy back to your byte.

To shift right, just do an Integer "\" divide by 2 the number of bits to shift.

So you can code it a number of ways.
You could loop the number of bits to shift and multiply or integer divide by 2 each pass.
You could calculate 2^(x-1), where x is the number of bits to shift and then integer divide of multiply by that.
You could just create a lookup table and index by x, and integer divide or multiply by that.

An example: add a couple of textboxes, a label and a command button, and try the following code.
Code:
Option Explicit Dim shiftVal(0 To 7) As Integer Private Sub Command1_Click() Dim b As Byte, s As Integer b = Val(Text1.Text) s = Val(Text2.Text) Label1 = Str$(ShiftByte(b, s)) End Sub Private Sub Form_Load() Dim p As Integer, i As Integer p = 1 For i = 0 To 7 shiftVal(i) = p p = p * 2 Next End Sub Private Function ShiftByte(b As Byte, num As Integer) As Byte Dim t As Integer If Abs(num) < 8 Then t = b If num < 0 Then t = t \ shiftVal(Abs(num)) Else t = t * shiftVal(num) End If ShiftByte = t And &HFF Else ShiftByte = 0 End If End Function

That's off the top of my head. Someone may have something better.
Reply With Quote
  #4  
Old 11-20-2005, 07:25 AM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,909
Default

Well, legacy VB doesn't have any shift, or rotate operators.
As for C++, the << and >> operators are doing arithmetic shifts, not rotates.
The type you select for your 8-bit type will affect the result.
An arithmetic shift will replicate the sign bit in the most significant bit when doing right shifts.
So if you choose an unsigned number in C++ then the code in C++ would work the same as I gave in VB, which is essentially doing a logical shift.
i.e. the code below uses an unsigned 8 bit value
Code:
 #include <stdio.h>
int main ()
{
  unsigned char b = 255;

  b = b >> 2;
  printf ("%d",b);
}
and would print 63, as would my VB code if you entered 255 in text1 and -2 in text2.

If you want to rotate, then you would have to write code in either language (unless there is a library function in C++, which could be since I really haven't used C++ in depth at this point).

I don't have the time to do a Rotate example at this point, but I think using the previous example, it would be similar.
Since we're talking an 8-bit value any number of bits to be rotated can be reduced to a rotate of 0 to 7 bits. 8-bit rotate would be the same as not rotating or rotating by 0(assuming not emulating the rotate with carry).
A 9-bit rotate would be the same as a 1-bit rotate.
So the first modification I would do is to take the number of bits to rotate and mod it with 8. If the value is 0, there's nothing to do (although the table is set up to multiply or divide by 1 for 0, so you don't have to check for that case specifically).

I would switch to using a Long, instead of an Integer for our temporary shift register.
The second thing is to decide which way we are rotating.
If we are rotating to the left, put the byte into the long directly.
If we are rotating to the right, put the byte shifted by 8 bits in the long (put in in the long and multiply by 256).

Then just do the multiply (shift left), or the divide (shift right) as we did before.
The last thing is to Or the two lower bytes of the Long together (combine the upper and lower parts of our shift) to get the rotated value and return that.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #5  
Old 11-20-2005, 01:31 PM
jgbarber65's Avatar
jgbarber65 jgbarber65 is offline
Regular
 
Join Date: Jul 2003
Location: Newark, DE
Posts: 69
Default

I wrote this last night after searching and not finding an easier way. It seems to work good but is not very fast:

Note: I called the Function Shift but it actually rotates the bits.

Code:
Public Function ShiftLeft(ByVal lftShft As Integer) byteString = "" Dim andByte As Long andByte = 128 Do While andByte > 0 If lftShft And andByte Then byteString = byteString & "1" Else byteString = byteString & "0" End If andByte = andByte / 2 Loop savBit = Left(byteString, 1) rgtBits = Right(byteString, 7) byteString = rgtBits & savBit andByte = 128 newDec = 0 For t = 1 To 8 eaChar = Mid(byteString, t, 1) If eaChar = "1" Then newDec = newDec + andByte End If andByte = andByte / 2 Next t End Function

You can call it with ShiftLeft( integer byte value from 0 to 255 )

You can also use the following to rotate it x number of times:
Code:
newDec = 'any integer byte 0 to 255 For x = 1 To 'number of rotations ShiftLeft (newDec) Next x

To Right Rotate

Code:
'REPLACE savBit = Left(byteString, 1) rgtBits = Right(byteString, 7) byteString = rgtBits & savBit 'WITH savBit = Right(byteString, 1) lftBits = Left(byteString, 7) byteString = savBit & lftBits

Last edited by reboot; 11-20-2005 at 02:30 PM.
Reply With Quote
  #6  
Old 11-20-2005, 07:45 PM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 7,909
Default

Well, in case you're interested, a coded example of what I described above follows.
You can just put this function in place of the function in the earlier example to test it out.

Code:
Private Function ShiftByte(b As Byte, num As Integer) As Byte 'This code uses two bytes within a Long to rotate a byte. 'To rotate left the byte is placed in the lower byte and shifting left (the upper bits shift into 'the lower bits of the next higher byte). 'Likewise to rotate right, the byte is place in the higher byte and shifted right into the lower byte '(the lower bits shift into the higher bits of the next higher byte). 'You then just OR the two bytes (containing the lower and higher bits) together to get the rotated result. Dim t As Long, d As Integer, shiftDir As Integer shiftDir = Sgn(num) 'Save the sign, -1 rotate right, 1 rotate left d = Abs(num) Mod 8 'Reduce the rotate to the range 0 to 7 If shiftDir = 1 Then 'If we're rotating to the left then t = b ' Put the byte in the lowest byte of our long t = t * shiftVal(d) ' Shift the long word to the left Else 'Else (we're rotating to the right) t = CLng(b) * 256 ' Put the byte in the 2nd lowest byte (shifted 8-bits left) t = t \ shiftVal(d) ' Shift the long word to the right End If 'End if ShiftByte = (t And 255) Or (t \ 256) 'OR the lower byte and the 2nd byte together End Function
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 11-21-2005 at 03:03 AM.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->