I'm working with bitshift for the first time and I'm experiencing unexpected results.
I'm declaring the shift amount as follows:
byte p_size = 0;
if (ver == 0x12 || ver == 0x13)
p_size = 20;
else
p_size = 40;
The value to be shifted is declared as
int t_size = rinput.ReadInt32();
And finally the code I use to shift:
int temp = t_size >> p_size << p_size;
Let's say t_size = 0x2000385E and p_size = 20. temp = 0x20000000 as expected.
Now if t_size = 0x40001014 and p_size = 40, temp = 0x40001000 instead of 0x40000000. I calculated "manually" using a bitwise calculator and it matches the expected result of 0x40000000.
It's probably a silly oversight on my behalf but I don't understand what would cause the weird results with p_size = 40... any advice is appreciated!
Shifting a 32 integer by 40 bits doesn't really make sense since you would be shifting the integer by more bits than it contains.
Both the left and right shift operators document what they do in this case:
If the first operand is an int or uint (32-bit quantity), the shift
count is given by the low-order five bits of the second operand
(second operand & 0x1f).
So when p_size is 40, the shifts are shifting by 40 & 0x1f = 8 bits.
If you need to shift by 40 bits, but your value into long.
Current behavior is expected as 40 & 0x1f is 8 as described in operator >>
If the first operand is an int or uint (32-bit quantity), the shift count is given by the low-order five bits of the second operand (second operand & 0x1f).
You probably looking for some masking rather than shifts - maybe
t_size & 0xFF000000
Related
I have do not have much knowledge of C and I'm stuck with a problem since one of my colleague is on leave.
I have a 32 bit number and i have to extract bits from it. I did go through a few threads but I'm still not clear how to do so. I would be highly obliged if someone can help me.
Here is an example of what I need to do:
Assume hex number = 0xD7448EAB.
In binary = 1101 0111 0100 0100 1000 1110 1010 1011.
I need to extract the 16 bits, and output that value. I want bits 10 through 25.
The lower 10 bits (Decimal) are ignored. i.e., 10 1010 1011 are ignored.
And the upper 6 bits (Overflow) are ignored. i.e. 1101 01 are ignored.
The remaining 16 bits of data needs to be the output which is 11 0100 0100 1000 11 (numbers in italics are needed as the output).
This was an example but I will keep getting different hex numbers all the time and I need to extract the same bits as I explained.
How do I solve this?
Thank you.
For this example you would output 1101 0001 0010 0011, which is 0xD123, or 53,539 decimal.
You need masks to get the bits you want. Masks are numbers that you can use to sift through bits in the manner you want (keep bits, delete/clear bits, modify numbers etc). What you need to know are the AND, OR, XOR, NOT, and shifting operations. For what you need, you'll only need a couple.
You know shifting: x << y moves bits from x *y positions to the left*.
How to get x bits set to 1 in order: (1 << x) - 1
How to get x bits set to 1, in order, starting from y to y + x: ((1 << x) -1) << y
The above is your mask for the bits you need. So for example if you want 16 bits of 0xD7448EAB, from 10 to 25, you'll need the above, for x = 16 and y = 10.
And now to get the bits you want, just AND your number 0xD7448EAB with the mask above and you'll get the masked 0xD7448EAB with only the bits you want. Later, if you want to go through each one, you'll need to shift your result by 10 to the right and process each bit at a time (at position 0).
The answer may be a bit longer, but it's better design than just hard coding with 0xff or whatever.
OK, here's how I wrote it:
#include <stdint.h>
#include <stdio.h>
main() {
uint32_t in = 0xd7448eab;
uint16_t out = 0;
out = in >> 10; // Shift right 10 bits
out &= 0xffff; // Only lower 16 bits
printf("%x\n",out);
}
The in >> 10 shifts the number right 10 bits; the & 0xffff discards all bits except the lower 16 bits.
I want bits 10 through 25.
You can do this:
unsigned int number = 0xD7448EAB;
unsigned int value = (number & 0x3FFFC00) >> 10;
Or this:
unsigned int number = 0xD7448EAB;
unsigned int value = (number >> 10) & 0xFFFF;
I combined the top 2 answers above to write a C program that extracts the bits for any range of bits (not just 10 through 25) of a 32-bit unsigned int. The way the function works is that it returns bits lo to hi (inclusive) of num.
#include <stdio.h>
#include <stdint.h>
unsigned extract(unsigned num, unsigned hi, unsigned lo) {
uint32_t range = (hi - lo + 1); //number of bits to be extracted
//shifting a number by the number of bits it has produces inconsistent
//results across machines so we need a special case for extract(num, 31, 0)
if(range == 32)
return num;
uint32_t result = 0;
//following the rule above, ((1 << x) - 1) << y) makes the mask:
uint32_t mask = ((1 << range) -1) << lo;
//AND num and mask to get only the bits in our range
result = num & mask;
result = result >> lo; //gets rid of trailing 0s
return result;
}
int main() {
unsigned int num = 0xd7448eab;
printf("0x%x\n", extract(num, 10, 25));
}
I can not understand this shift operator (c# reference):
class MainClass1
{
static void Main()
{
int i = 1;
long lg = 1;
Console.WriteLine("0x{0:x}", i << 1);
Console.WriteLine("0x{0:x}", i << 33);
Console.WriteLine("0x{0:x}", lg << 33);
}
}
/*
Output:
0x2
0x2
0x200000000
*/
class MainClass2
{
static void Main()
{
int a = 1000;
a <<= 4;
Console.WriteLine(a);
}
}
/*
Output:
16000
*/
<< is the left-shift operator; this takes the binary representation of a value, and moves all the bits "n" places to the left (except for "mod", see "1"), back-filling with zeros.
>> is the right-shift operator; this does nearly the opposite (moving to the right), except for signed values (i.e. those that can be negative) it back-fills with 1s for negative values, else zeros.
1:
The shift operator is essentially "mod" the width of the data. An int is 32 bits, so a left shift of 33 (in Int32) is exactly the same as a left shift of 1. You don't get all zeros. A long is 64 bits, so a left-shift of 33 gives a different answer (original times 2^33).
2:
Each left shift (within the data width) is the same (for integers) as x2 - so <<4 is x2x2x2x2 = x16.
This is simple binary:
0000000001 = 1
<< goes to
0000000010 = 2
<< goes to
0000000100 = 4
<< goes to
0000001000 = 8
Just to expand on Marc's answer a little (Marc, feel free to include this in yours and I'll delete this answer) this is specified in section 7.8 of the spec:
The predefined shift operators are listed below.
Shift left:
int operator <<(int x, int count);
uint operator <<(uint x, int count);
long operator <<(long x, int count);
ulong operator <<(ulong x, int count);
The << operator shifts x left by a number of bits computed as described below.
The high-order bits outside the range of the result type of x are discarded, the remaining bits are shifted left, and the low-order empty bit positions are set to zero.
Shift right:
int operator >>(int x, int count);
uint operator >>(uint x, int count);
long operator >>(long x, int count);
ulong operator >>(ulong x, int count);
The >> operator shifts x right by a number of bits computed as described below.
When x is of type int or long, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero if x is non-negative and set to one if x is negative.
When x is of type uint or ulong, the low-order bits of x are discarded, the remaining bits are shifted right, and the high-order empty bit positions are set to zero.
For the predefined operators, the number of bits to shift is computed as follows:
When the type of x is int or uint, the shift count is given by the low-order five bits of count. In other words, the shift count is computed from count & 0x1F.
When the type of x is long or ulong, the shift count is given by the low-order six bits of count. In other words, the shift count is computed from count & 0x3F.
If the resulting shift count is zero, the shift operators simply return the value of x.
A few more notes for the novice programmer:
Why use shift operators? They don't seem to do much. Well, there are 2 reasons:
They are really fast, because nearly all CPUs have shift registers, meaning the shifting operation is done in the hardware, in the minimum amount of effort (cycles).
Because they are fast, a lot of protocols and standards are designed to take advantage of this. For example IP address operations, checking a CRC, graphic operations etc.
"The shift operator is essentially "mod" the width of the data."
Rubbish! If the amount of the shift is greater than, or equal to, the width of the data, the result is undefined. Do not expect the same 'mod' operation that you happen to have seen, to happen with different compilers, or different versions of the same compiler, or in different shift situations in the same program, or when anything else changes. That's what 'undefined' means.
Why does this assigning produce a comile error: Constant value '-2147483648' cannot be converted to a 'ulong' and I have to use unchecked (...) for this case?
ulong xDummy30 = (1 << 30); // works
ulong xDummy31 = (1 << 31); // ERROR 25 Constant value '-2147483648' cannot be converted to a 'ulong'
ulong xDummy32 = (1 << 32); // works
Using this instead works:
ulong xDummy31a = unchecked((ulong)(1 << 31));
// or
ulong xDummy31b = (1ul << 31); // comment from Regis Portalez
Edit
The Question Why do I have to cast 0 (zero) when doing bitwise operations in C#? has a similar answer and the reason for the observed behaviour is the same. But they are different questions.
According to MSDN ulong reference all your integer literals 1, 30, 31 are regarded as int:
When an integer literal has no suffix, its type is the first of these types in which its value can be represented: int, uint, long,
According to MSDN << operator the result of the << operation is also an int. When yo shift by 30 the result is positive, when shifting by 31 the result is a negative int which can't be assigned to an ulong.
Edit: HVD pointed me an error in the following. Thanks HVD!
Start Error - When shifting 32 bits, the compiler knows you want an ulong, and thus the result of the shift operation is a positive long, which can be converted to an unlong - end error
The correct reason why 1<<32 does not lead to compiler error is in the provided link to operator <<:
If the first operand is an int, the shift count is given by the
low-order five bits of the second operand. That is, the actual shift
count is 0 to 31 bits.
32 to binary: 0010 0000; low order five bits: 0 0000, So the actual performed shift is 1 << 0, which results to the int with the value 1, which of course can be assigned to an ulong.
To solve this, make sure that your number 1 is a long. In that case 1<<31 is still a positive long.
You can also use suffixes to specify the type of the literal according to the following rules:
If you use L, the type of the literal integer will be either long or ulong according to its size.
So 1L is a long; 1L <<31 is a positive long, and thus can be assigned to an ulong
var a = (1<<31);
Console.WriteLine(a);
ulong num = unchecked((ulong)(1<<31));
Console.WriteLine(num);
Output:
-2147483648
18446744071562067968
1<<31 value is unable to fit into uInt64
https://dotnetfiddle.net/Widget/TfjnSZ
As a supplement to my question and the accepted answer here is a note:
Quoting first the example of my question:
ulong xDummy30 = (1 << 30); // works
ulong xDummy31 = (1 << 31); // ERROR 25 Constant value '-2147483648' cannot be converted to a 'ulong'
ulong xDummy32 = (1 << 32); // works
It is correct that this assignement brings no compile error:
ulong xDummy32 = (1 << 32);
but it does not "work", contrary to what I wrote in my question. After this the result of xDummy32 is not 4294967296 but it is 1. Therefore bit shifts > 30 must be written this way:
ulong xDummy32 = (1UL << 32);
I have a single byte which contains two values. Here's the documentation:
The authority byte is split into two fields. The three least significant bits carry the user’s authority level (0-5). The five most
significant bits carry an override reject threshold. If these bits are
set to zero, the system reject threshold is used to determine whether
a score for this user is considered an accept or reject. If they are
not zero, then the value of these bits multiplied by ten will be the
threshold score for this user.
Authority Byte:
7 6 5 4 3 ......... 2 1 0
Reject Threshold .. Authority
I don't have any experience of working with bits in C#.
Can someone please help me convert a Byte and get the values as mentioned above?
I've tried the following code:
BitArray BA = new BitArray(mybyte);
But the length comes back as 29 and I would have expected 8, being each bit in the byte.
-- Thanks for everyone's quick help. Got it working now! Awesome internet.
Instead of BitArray, you can more easily use the built-in bitwise AND and right-shift operator as follows:
byte authorityByte = ...
int authorityLevel = authorityByte & 7;
int rejectThreshold = authorityByte >> 3;
To get the single byte back, you can use the bitwise OR and left-shift operator:
int authorityLevel = ...
int rejectThreshold = ...
Debug.Assert(authorityLevel >= 0 && authorityLevel <= 7);
Debug.Assert(rejectThreshold >= 0 && rejectThreshold <= 31);
byte authorityByte = (byte)((rejectThreshold << 3) | authorityLevel);
Your use of the BitArray is incorrect. This:
BitArray BA = new BitArray(mybyte);
..will be implicitly converted to an int. When that happens, you're triggering this constructor:
BitArray(int length);
..therefore, its creating it with a specific length.
Looking at MSDN (http://msdn.microsoft.com/en-us/library/x1xda43a.aspx) you want this:
BitArray BA = new BitArray(new byte[] { myByte });
Length will then be 8 (as expected).
To get a value of the five most significant bits in a byte as an integer, shift the byte to the right by 3 (i.e. by 8-5), and set the three upper bits to zero using bitwise AND operation, like this:
byte orig = ...
int rejThreshold = (orig >> 3) & 0x1F;
>> is the "shift right" operator. It moves bits 7..3 into positions 4..0, dropping the three lower bits.
0x1F is the binary number 00011111, which has the upper three bits set to zero, and the lower five bits set to one. AND-ing with this number zeroes out three upper bits.
This technique can be generalized to get other bit patterns and other integral data types. You shift the bits that you want into the least-significant position, and apply a mask that "cuts out" the number of bits that you want. In some cases, shifting would not be necessary (e.g. when you get the least significant group of bits). In other cases, such as above, the masking would not be necessary, because you get the most significant group of bits in an unsigned type (if the type is signed, ANDing would be required).
You're using the wrong constructor (probably).
The one that you're using is probably this one, while you need this one:
var bitArray = new BitArray(new [] { myByte } );
I was recently studying C# where i came across following for loop
// Display the bits within a byte.
using System;
class ShowBits {
static void Main() {
int t;
byte val;
val = 123;
for(t=128; t > 0; t = t/2) {
if((val & t) != 0)
Console.Write("1 ");
if((val & t) == 0)
Console.Write("0 ");
}
}
}
I am not able to understand that Why in doing t=t/2 in the incrementing/decrementing section of the for loop . plz explain
Decimal 128 is binary 10000000 - i.e. a mask for just the most significant bit of the byte. When you divide it by two, you get 01000000, i.e. the second most significant bit, etc.
Using & between the original value and the mask and just comparing with 0 indicates whether that bit is set in the original value.
Another alternative would be to shift the original value instead:
for (int i = 7; i >= 0; i--)
{
int shifted = val >> i;
// Take the bottom-most bit of the shifted value
Console.Write("{0} ", shifted & 1);
}
It's looping in decreasing powers of two and using that value in a mask.
(base 10): 128, 64, 32, 16, 8, 4, 2, 1
(base 2): 10000000, 01000000, 00100000, 00010000, 00001000, 00000100, 00000010, 00000001
128 is written as 10000000 in binary, so we check if the highest bit in a byte is on. Then we do t=t/2, which is t=128/2=64 which written as 01000000 in binary and so on. Any division shifts the one bit that is on one place to the right.
The t is used as a mask for the bits in val.
So it starts at 128, 10000000 in binary.
When it is divided by 2, it becomes 64 - or 01000000.
This goes until it reaches 0.
Then in each iteration, the '&' is used to mask the bits in val with the current bit in t.