When dealing with the C# shift operators, I encountered a unexpected behavior of the shift-left operator.
Then I tried this simple function:
for (int i = 5; i >= -10; i--) {
int s = 0x10 << i;
Debug.WriteLine(i.ToString().PadLeft(3) + " " + s.ToString("x8"));
}
With this result:
5 00000200
4 00000100
3 00000080
2 00000040
1 00000020
0 00000010
-1 00000000 -> 00000008 expected
-2 00000000 -> 00000004 expected
-3 00000000 -> 00000002 expected
-4 00000000 -> 00000001 expected
-5 80000000
-6 40000000
-7 20000000
-8 10000000
-9 08000000
-10 04000000
Until today, I expected that the << operator can deal with negative values of the second operand.
MSDN tells nothing about the behavior when using negative values of the second operand. But MSDN says that only the lower 5 bits (0-31) are used by the operator, which should fit for negative values.
I also tried with long values: long s = 0x10L << i;, but with the same result.
So what happens here?
EDIT
As stated in your answers, the negative value representation is not the reason for this.
I got the same wrong result for all cases:
0x10<<-3 = 0x00000000 (wrong!)
0x10<<(int)(0xfffffffd) = 0x00000000 (wrong!)
0x10<<(0x0000001d = 0x00000000 (wrong!)
expected = 0x00000002
EDIT #2
One of these two should be true:
1) The shift operator is a real shift-operator, so the results should be:
1a) 0x10 << -3 = 00000002
1b) 0x10 << -6 = 00000000
2) The shift operator is a rotate-operator, so the results should be:
2a) 0x10 << -3 = 00000002 (same as 1a)
2b) 0x10 << -6 = 40000000
But the shown results does not fit either to 1) nor to 2) !!!
Negative numbers are two complemented, so -1 == 0xFFFFFFFF, and 0xFFFFFFFF & 31 == 31, -2 == 0xFFFFFFFE, and 0xFFFFFFFE & 31 == 30 and so on.
-10 == 0xFFFFFFF6, and 0xFFFFFFF6 & 31 == 22, in fact:
(0x10 << 22) == 04000000
Some code to show:
const int num = 0x10;
int maxShift = 31;
for (int i = 5; i >= -10; i--)
{
int numShifted = num << i;
uint ui = (uint)i;
int uiWithMaxShift = (int)(ui & maxShift);
int numShifted2 = num << uiWithMaxShift;
Console.WriteLine("{0,3}: {1,8:x} {2,2} {3,8:x} {4,8:x} {5}",
i,
ui,
uiWithMaxShift,
numShifted,
numShifted2,
numShifted == numShifted2);
}
With long it's the same, but now instead of & 31 you have & 63. -1 == 63, -2 == 62 and -10 == 54
Some example code:
const long num = 0x10;
int maxShift = 63;
for (int i = 5; i >= -10; i--)
{
long numShifted = num << i;
uint ui = (uint)i;
int uiWithMaxShift = (int)(ui & maxShift);
long numShifted2 = num << uiWithMaxShift;
Console.WriteLine("{0,3}: {1,8:x} {2,2} {3,16:x} {4,16:x} {5}",
i,
ui,
uiWithMaxShift,
numShifted,
numShifted2,
numShifted == numShifted2);
}
Just to be clear:
(int x) << y == (int x) << (int)(((uint)y) & 31)
(long x) << y == (long x) << (int)(((uint)y) & 63)
and not
(int x) << y == (int x) << (Math.Abs(y) & 63)
(long x) << y == (long x) << (Math.Abs(y) & 63)
And what you think "should be" "it would be beautiful if it was" "has to be" ecc is irrelevant. While 1 and 0 are "near" (their binary representation has a "distance" of 1 in number of different bits), 0 and -1 are "far" (their binary representation has a "distance" of 32 or 64 in number of different bits)
You think you should get this:
-1 00000000 -> 00000008 expected
-2 00000000 -> 00000004 expected
-3 00000000 -> 00000002 expected
-4 00000000 -> 00000001 expected
but in truth what you don't see is that you are getting this:
-1 (00000008) 00000000
-2 (00000004) 00000000
-3 (00000002) 00000000
-4 (00000001) 00000000
-5 (00000000) 80000000 <-- To show that "symmetry" and "order" still exist
-6 (00000000) 40000000 <-- To show that "symmetry" and "order" still exist
where the part in (...) is the part that is to the "left" of the int and that doesn't exist.
It has to do with the representation of negative numbers. -1 corresponds to all-ones, so its five least significant bits sum to 31 and left-shifting 0x10 by 31 bits gives all zeroes (the high-order bit that is already set is discarded as per the documentation).
Increasingly larger negative numbers correspond to shifting by 30, 29, etc bits. The bit that is already set in 0x10 is in zero-based position 4, so in order for it to not be discarded the shift has to be at most 31 - 4 = 27 bits, which happens when i == -5.
You can easily see what's going on if you try e.g. Console.WriteLine((-1).ToString("x8")):
ffffffff
Update: when first operand is a long you see similar behavior because now six least significant bits are counted from the second operand: 0x10L << -1 shifts left 63 bits, etc.
The left shift operator doesn't see a negative second operand as a right shift. It will just use the lower five bits of the value and make a left shift using that.
The lower five bits of the value -1 (0xFFFFFFFF) will be 31 (0x0000001F), so the first operand 0x10 is shifted to the left 31 steps leaving just the least significant bit in the most significant bit of the result.
In other words, 0x10 << -1 is the same as 0x10 << 31 which will be 0x800000000, but the result is just 32 bits so it will be truncated to 0x00000000.
When you are using a long value, the six least significant bits are used of the second operand. The value -1 becomes 63, and the bits are still shifted out outside the range of the long.
Related
I'm currently writing a solution to a project in my CS class, and I'm getting conflicting results.
Basically, I have to read a single BIT from a BYTE that is read from a file.
These are the relevant methods (ignore the naming standards, I didn't make them and I hate them too):
static bool no_more_bytes()
/**********************/
/*** NO MORE BYTES? ***/
/**********************/
{
return (in_stream.PeekChar() == -1);
}
static byte read_a_byte()
/********************************************************************************/
/*** Function to read a single byte from the input stream and set end_of_file ***/
/********************************************************************************/
{
byte abyte;
if (!no_more_bytes())
abyte = in_stream.ReadByte();
else
{
abyte = 0;
end_of_file = true;
}
return abyte;
}
static byte getbit()
/**********************************************************/
/*** Function to get a single BIT from the input stream ***/
/**********************************************************/
{
byte mask;
if (current_byte == 0 || current_bit_position == 8)
{
current_byte = read_a_byte();
current_bit_position = 0;
}
mask = current_bit_position;
current_bit_position++;
//Your job is to fill in this function so it returns
//either a zero or a one for each bit in the file.
bool set = (current_byte & (128 >> current_bit_position - 1)) != 0; // This is the line in question
if (set)
{
return 1;
} else
{
return 0;
}
}
getbit() is the method I wrote, and it works properly. However, my first solution didn't work.
When the input file contains "ABC", it correctly outputs 01000001 00100001 01100001 (65, 66, 67) by reading 1 bit at a time.
However, my original solution was
bool set = (current_byte & (1 << current_bit_position - 1)) != 0;
So the question is: why does shifting 128 right by the current_bit_position get a different result than shifting 1 left by the current_bit_position
I'm going to interpret this question as one about the order of the bits because, as comments suggest, it doesn't make much sense to expect different operations on the same data to return the same result, in most cases.
So why are we starting with 128 and shifting right instead of starting with 1 and shifting left? Both methods would be valid for enumerating through each bit within the byte, but they operate in reverse order.
If you want to shift 1 left (<<) instead of shifting 128 right (>>) you would have to run current_bit_position from 7 to 0 instead of from 0 to 7.
Shifting 1
1 << 7 == 10000000
1 << 6 == 01000000
1 << 5 == 00100000
1 << 4 == 00010000
1 << 3 == 00001000
1 << 2 == 00000100
1 << 1 == 00000010
1 << 0 == 00000001
Shifting 128
128 >> 0 == 10000000
128 >> 1 == 01000000
128 >> 2 == 00100000
128 >> 3 == 00010000
128 >> 4 == 00001000
128 >> 5 == 00000100
128 >> 6 == 00000010
128 >> 7 == 00000001
Since we generally represent numbers with the most significant digits on the left and the least significant on the right the above sequences are what you would need to use to get the bits in the right order.
How to remove the leftmost bit?
I have a hexadecimal value BF
Its binary representation is 1011 1111
How can I remove the first bit, which is 1, and then it will become 0111 1110?
How to add "0" also to its last part?
To set bit N of variable x to 0
x &= ~(1 << N);
How it works: The expression 1 << N is one bit shifted N times to the left. For N = 7, this would be
1000 0000
The bitwise NOT operator ~ inverts this to
0111 1111
Then the result is bitwise ANDed with x, giving:
xxxx xxxx
0111 1111
--------- [AND]
0xxx xxxx
Result: bit 7 (zero-based count starting from the LSB) is turned off, all others retain their previous values.
To set bit N of variable x to 1
x |= 1 << N;
How it works: this time we take the shifted bit and bitwise OR it with x, giving:
xxxx xxxx
1000 0000
--------- [OR]
1xxx xxxx
Result: Bit 7 is turned on, all others retain their previous values.
Finding highest order bit set to 1:
If you don't know which is the highest bit set to 1 you can find out on the fly. There are many ways of doing this; a reasonable approach is
int x = 0xbf;
int highestSetBit = -1; // assume that to begin with, x is all zeroes
while (x != 0) {
++highestSetBit;
x >>= 1;
}
At the end of the loop, highestSetBit will be 7 as expected.
See it in action.
int i=0xbf;
int j=(i<<1) & 0xff;
or you could do:
(i*2) && 0xff
if you'd rather not do bit twiddling. >>1 is the equivalent of /2, and <<1 is the equivalent of *2.
Given that i have a uint value of 2402914, and i would like to grab the leftmost 17 bits, where is the fault in my logic by doing this code:
int testop = 0;
byte[] myArray = BitConverter.GetBytes(2402914);
fixed (byte* p = &myArray[0])
{
testop = *p >> 15;
}
my expected output is
50516.
You might want to get your expectations to match reality. A right-shift is equivalent to dividing by 2. You are effectively dividing by 2 fifteen times, which is the same as saying you are dividing by 2^15 = 32768. Note that 2402914 / 32768 = 73 (truncating the remainder).
Therefore, I would expect the result to be 73, not 50516.
In fact,
2402914_10 = 0000 0000 0010 0100 1010 1010 0110 0010_2
So that the left-most seventeen bits are
0000 0000 0010 0100 1
Note that
0000 0000 0010 0100 1 = 1 * 1 + 0 * 2 + 0 * 4 + 1 * 8 + 0 * 16 + 0 * 32 + 1 * 64
= 73
Note that you can obtain this result more simply with
int testop = 2402914 >> 15;
*p just gives you the first byte; it is equivalent to p[0]. You'll have to use shifting and ORing to combine bits from the first three bytes (or the last three bytes, depending on endianness...)
If this code is not a simplified version of something more complicated and you're actually trying to just extract the leftmost 17 bits from an int, this should do:
int testop = (someInt >> 15) & 0x1ffff;
(Edit: Added & 0x1ffff to make it work for negative integers too; thanks to #James.)
Wow, this has been a really fun puzzle to figure out. Not the programming part, but trying to figure out where you got the number 50516 and what you are trying to do with your code. It looks like you are taking the 16 least significant bits and ROTATING them LEFT 9 bits.
2402914: 0000 0000 0010 0100 1010 1010 0110 0010
left 9: 0100 1001 0101 0100 1100 010
match: ^^^^ ^^^
>>50516: 1100 0101 0101 0100
match: ^ ^^^^ ^^^^
right 7: 1 0101 0100 110 0010
int value2 = value & 0xffff;
int rotate9left = ((value2 << 9) & 0xffff) | ((value2) >> (16 - 9));
I don't know why you are using a byte array, but it seems like you think your fixed() statement is looping through the array, which it is not. Your statement in the fixed block is taking the byte value at myArray[0] and SHIFTing it right 15 bits (shifting fills with 0s as opposed to rotating which wraps the front bits around to the back). Any thing over 8 would give you zero.
From what I understand, you can apply the bit-shift operator directly to the int datatype, rather than going through the trouble of the unsafe code.
For example:
2402914 >> 15 = 73
This ties to the result predicted by Jason.
Further, I note that
2402914 >> 5 = 75091
and 2402914 >> 6 = 37545
This suggests that your required result cannot be achieved by any similar right shift.
I need a little help with bitmap operations in C#
I want to take a UInt16, isolate an arbitrary number of bits, and set them using another UInt16 value.
Example:
10101010 -- Original Value
00001100 -- Mask - Isolates bits 2 and 3
Input Output
00000000 -- 10100010
00000100 -- 10100110
00001000 -- 10101010
00001100 -- 10101110
^^
It seems like you want:
(orig & ~mask) | (input & mask)
The first half zeroes the bits of orig which are in mask. Then you do a bitwise OR against the bits from input that are in mask.
newValue = (originalValue & ~mask) | (inputValue & mask);
originalValue -> 10101010
inputValue -> 00001000
mask -> 00001100
~mask -> 11110011
(originalValue & ~mask)
10101010
& 11110011
----------
10100010
^^
Cleared isolated bits from the original value
(inputValue & mask)
00001000
& 00001100
----------
00001000
newValue =
10100010
| 00001000
----------
10101010
Something like this?
static ushort Transform(ushort value){
return (ushort)(value & 0x0C/*00001100*/ | 0xA2/*10100010*/);
}
This will convert all your sample inputs to your sample outputs. To be more general, you'd want something like this:
static ushort Transform(ushort input, ushort mask, ushort bitsToSet){
return (ushort)(input & mask | bitsToSet & ~mask);
}
And you would call this with:
Transform(input, 0x0C, 0xA2);
For the equivalent behavior of the first function.
A number of the terser solutions here look plausible, especially JS Bangs', but don't forget that you also have a handy BitArray collection to use in the System.Collections namespace: http://msdn.microsoft.com/en-us/library/system.collections.bitarray.aspx
If you want to do bitwise manipulations, I have written a very versatile method to copy any number of bits from one byte (source byte) to another byte (target byte). The bits can be put to another starting bit in the target byte.
In this example, I want to copy 3 bits (bitCount=3) from bit #4 (sourceStartBit) to bit #3 (destinationStartBit). Please note that the numbering of bits starts with "0" and that in my method, the numbering starts with the most significant bit = 0 (reading from left to right).
byte source = 0b10001110;
byte destination = 0b10110001;
byte result = CopyByteIntoByte(source, destination, 4, 1, 3);
Console.WriteLine("The binary result: " + Convert.ToString(result, toBase: 2));
//The binary result: 11110001
byte CopyByteIntoByte(byte sourceByte, byte destinationByte, int sourceStartBit, int destStartBit, int bitCount)
{
int[] mask = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
byte sourceMask = (byte)(mask[bitCount] << (8 - sourceStartBit - bitCount));
byte destinationMask = (byte)(~(mask[bitCount] << (8-destStartBit - bitCount)));
byte destinationToCopy = (byte)(destinationByte & destinationMask);
int diff = destStartBit - sourceStartBit;
byte sourceToCopy;
if(diff > 0)
{
sourceToCopy = (byte)((sourceByte & sourceMask) >> (diff));
}
else
{
sourceToCopy = (byte)((sourceByte & sourceMask) << (diff * (-1)));
}
return (byte)(sourceToCopy | destinationToCopy);
}
Is there any difference between Arithmetic + and bitwise OR. In what way this is differing.
uint a = 10;
uint b = 20;
uint arithmeticresult = a + b;
uint bitwiseOR = a | b;
Both the results are 30.
Edit : Small changes to hide my stupidity.
(10 | 20) == 10 + 20 only because the 1-bits do not appear in the same digit.
1010 = 10
or 10100 = 20
————————
11110 = 30
However,
11 = 3 11 = 3
or 110 = 6 + 110 = 6
—————— ——¹——————
111 = 7 1001 = 9
# ^ ^
# (1|1==1) (1+1=2)
Counterexample:
2 + 2 == 42 | 2 == 2
Bitwise OR means, for each bit position in both numbers, if one or two bits are on, then the result bit is on. Example:
0b01101001
|
0b01011001
=
0b01111001
(0b is a prefix for binary literals supported in some programming languages)
At the bit level, addition is similar to bitwise OR, except that it carries:
0b01101001
+
0b01011001
=
0b11000010
In your case, 10+20 and 10|20 happen to be the same because 10 (0b1010) and 20 (0b10100) have no 1s in common, meaning no carry happens in addition.
Try setting a = 230 and b = 120. And you'll observer the difference in results.
The reason is very simple. In the arithmentic addition operation the bit-wise add operation may generate carry bit which is added in the next bit-wise addition on the bit-pair available on the subsequent position. But in case of bit wise OR it just performs ORing which never generates a carry bit.
The fact that you're getting same result in your case is that the
numbers co-incidentally don't generate any
carry-bit during addition.
Bit-wise arithmetic Addition
alt text http://www.is.wayne.edu/drbowen/casw01/AnimAdd.gif
Bitwise OR goes through every bit of two digits and applies the following truth table:
A B | A|B
0 0 | 0
0 1 | 1
1 0 | 1
1 1 | 1
Meanwhile the arithmetic + operator actually goes through every bit applying the following table (where c is the carry-in, a and b are the bits of your number, s is the sum and c' is the carry out):
C A B | S C'
0 0 0 | 0 0
0 0 1 | 1 0
0 1 0 | 1 0
0 1 1 | 0 1
1 0 0 | 1 0
1 0 1 | 0 1
1 1 0 | 0 1
1 1 1 | 1 1
For obvious reasons, the carry-in starts-off being 0.
As you can see, sum is actually a lot more complicated. As a side effect of this, though, there as an easy trick you can do to detect overflow when adding positive signed numbers. More specifically, we expect that a+b >= a|b if that fails then you have an overflow!
The case when the two numbers will be the same is when every time a bit in one of the two numbers is set, the corresponding bit int he second number is NOT set. That is to say that you have three possible states: either both bits aren't set, the bit is set in A but not B, or the bit is set in B but not A. In that case the arithmetic + and the bit-wise or would produce the same result... as would the bitwise xor for that matter.
Using arithmetic operations to manipulate bitmasks can produce unexpected results and even overflow. For instance, turning on the n-th bit of a bitmask if it is already on will turn off the n-th bit and turn on the n+1-th bit. This will cause overflow if there are only n-bits.
Example of turning on bit 2:
Arithmetic ADD Bitwise OR
0101 0101
+ 0100 | 0100
---- ----
1001 0101 //expected result: 0101
Like-wise, using arithmetic subtract to turn off the n-th bit will fail if the n-th bit was not already on.
Example of turning off bit 2:
Arithmetic SUB Bitwise AND~
0001 0001
- 0100 &~ 0100
---- ----
0001 0001
+ 1100 & 1011
---- ----
1101 0001 //expected result: 0001
So bitwise operators are safer than arithmetic operators when you are working with bitmasks.
The following bitwise operations have analogous arithmetic operations:
Bitwise Arithmetic
Check n-th bit x & (1 << n) !(x - (1 << n))
Turn on n-th bit x |= (1 << n) x += (1 << n)
Turn off n-th bit x &= ~(1 << n) x -= (1 << n)
Try a = 1 and b = 1 ;)
+ and | have different when two bits at the same positions are 1
00000010
OR
00000010
Result
00000010
VS
00000010
+
00000010
Result
00000100