As 'byte' is 8-bit and 'short' is 16-bit in Java, I believe this should --
byte[] packet = reader.readPacket();
short sh;
sh = (short)packet[1]; //packet[1] holds '0xff'
sh <<= 8;
sh &= 0xFF;
System.out.print(sh+" ");
produce some big positive value, since lower 8bits are promoted to higher 8 bits.
Instead I receive a '0' (zero). Why does it happen so?
What you're doing is shifting the initial value to the left:
0000 0000 1111 1111
<<=8
1111 1111 0000 0000
Then, you're doing a bitwise AND with 0xFF:
1100 0011 0000 0000
&
0000 0000 1111 1111
==
0000 0000 0000 0000
Thus, your end result is 0.
The code first shifts left 8 places. So you have all the right most 8 bits set to 0.
Then you AND it with 0xFF which has left most 8 bits 0.
So your final result is all 0's!
Additional comment: It is a good practice to avoid using short for Java as Java typecasts everything below int as int. Also, it is not clear from your code what output you expected. If you add additional information, it will be easy to spot exactly what is needed to be done for the logic you are trying to implement.
Go through this step-by-step:
sh = (short)0xff; //Since you said that packet[1] holds '0xff'
So now sh = 0x00ff. Next, consider the shift sh <<= 8;. Afterwards, sh = 0xff00.
I'll leave the last sh &= 0xFF; to you (should hopefully be clear why the & op is setting sh to 0).
Related
I was going through a java file and saw this block of code and can't really understand what's happening here. What does the & symbol means here and when I run this, I get the values 2 and 8 respectively.
package com.company;
public class Question_2 {
public static void main(String[] args) {
int mask = 0x000F;
int value = 0x2222;
int f = 90;
int h = 9;
System.out.println(value & mask);
System.out.println(f & h);
}
}
This is The output I get:
2
8
& is a bit wise operation
& is 1 if both bit at the same position is 1 otherwise 0
Also, to perform this operation, your operands will be converted to base 2
90 = 0101 1010 in base 2
09 = 0000 1001 in base 2
_________
0000 1000 which is 8 convert to decimal
000f in hexadecimal = 0000 0000 0000 1111
2222 in hexadecimal = 0010 0010 0010 0010
using & on this is 0000 0000 0000 0010 which is 2 convert to decimal
That is how basic & operator works.
& refers to Bitwise AND operation.
the mask variable used to enable specific bit and disable the others.
in this code,
System.out.println(value & mask);
the mask keeps the first (from right to left) 4 bits and unsets the others, so always the value of the bitwise AND between the mask variable and any value will be less than 15 because 0x000F -> 0000 0000 0000 1111
mathematically: since the mask is 0x000F if the value of & between the mask and any value is zero then the number is dividable by 16 otherwise it's not dividable by 16
& is the bitwise AND operation.
System.out.println(value & mask);
outputs the hex representation of bitwise ANS.
System.out.println(f & h);
outputs the decimal representation of the bitwise AND.
& is smart enough to return the result of the same representation as it's arguments.
& is used as a relational operator to check a conditional statement just like && operator.
but there is a small change in how & takes care of conditional statement. && would first check the first data, if its true then it checks the next one and son on.. but in case of single & character, it just evaluate all conditions even if previous one is a failed one. Thus, any change in the data values due to the conditions will only be reflected in this case.
& can also be used as bitwise operator
println(f & h ) ->
01011010
& 00001001
00001000 -> 8 in decimal
Decimal Binary
x1 = 105 0110 1001
x2 = -38 1101 1010
1. (byte) (x>>2)
2. (byte) (x>>>26)
I understand the first shift will shift it two times to the right, and replace the missing bits with a 1. so the shift results in:
1111 0110
but I have no idea why the second shifts results in:
0011 1111 or 63.
My understanding is that the x >> adds 1 if x is negative and adds a 0 if x is positive. The >>> adds a 0 regardless of the sign. So if that is the case wouldn't the result of x2 >>> 26 be 0000 0000?
The reason for the "strange" bit shift result is because the values are widened to 32 bit (int) before the shift.
I. e. -38 isn't 1101 1010 here, but 1111 1111 1111 1111 1111 1111 1101 1010.
Which should make it clear why -38 >>> 26 is 0000 0000 0000 0000 0000 0000 0011 1111 (or 63).
The widening is described in the the Java Language Specification:
Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (ยง5.1.2).
If you want to perform bit shift operations on an 8 bit (byte) value, you could mask the value to use only the lower 8 bits, after widening but before shifting, like Federico suggests:
byte x = -38;
(x & 0xFF) >>> 26;
This would give the expected value of 0 (though I'm not sure if it makes sense, as any 8 bit value will be 0 if you right shift by more than 8).
I was looking into when one would want to/should use the bit shift operators. I understand that we don't need to use them to multiply by two and such, because JIT compilation will take care of that. I came across why do we need to use shift operators in java, and am confused by part of the accepted answer:
For example, say I have two bytes that are the high-order and low-order bytes
of a two-byte (16-bit) unsigned value. Say you need to construct that value.
In Java, that's:
int high = ...;
int low = ...;
int twoByteValue = (high << 8) | low;
You couldn't otherwise do this without a shift operator.
To answer your questions: you use them where you need to use them! and nowhere else.
I know that I'm missing something, because to me it looks like he's just multiplying high by 2^8 and adding it to low (I've never actually seen | used in this context before, but when I plugged in dummy values and ran my code, it looked like it was just adding the two together). What's actually going on here?
EDIT: For reference, I had high = 10 and low = 3.
As an example, lets compose the 16-bit representation of the number 54321: 1101 0100 0011 0001 from its high-order 8 bits and low-order 8 bits.
The high-order 8 bits would be: 1101 0100
The low-order 8 bits would be : 0011 0001
1101 0100 << 8
will produce
1101 0100 0000 0000
We then bitwise OR this (|) against the low order bits
1101 0100 0000 0000
0011 0001
-------------------
1101 0100 0011 0001
We now have the full binary representation on 54321 (assuming I'm using unsigned ints of course)
Edit:
To use your example: high=10 and low=3
high, written out in 8 bits, would be 0000 1010
low, written in the same fashion, would be 0000 0011
If we shift high to the left 8 bits:
0000 1010 0000 0000
If we OR that against low:
0000 1010 0000 0000
0000 0011
-------------------
0000 1010 0000 0011
If we treat this pattern as a decimal integer it would mean 2563
Perhaps the confusing part is that the 10 and 3 independently really hold no meaning at all in this context. It is the composition of the two that has value here.
Perhaps you are reading a file byte by byte but in one part of the file there is a sequence of 16-bit integers. You would have to take every pair of bytes and combine them in exactly this fashion to get the 16-bit integers.
Now imagine if, on a platform where the largest integer possible is 64 bits, you wanted to store an integer that is so large it occupies 128 bits. Well, you could use a trick similar to this one to fudge the math and store that really big integer in two separate values. OK, maybe its more complicated than this example, but hopefully that makes it hit home why we would need bitwise operators like these.
I'm parsing unsigned bits from a DatagramSocket. I have a total of 24bits (or 3 bytes) coming in - they are: 1 unsigned 8bit integer followed by a 16bit signed integer. But java never stores anything more than a signed byte into a byte/byte array? When java takes in these values, do you lose that last 8th bit?
DatagramSocket serverSocket = new DatagramSocket(666);
byte[] receiveData = new byte[3]; <--Now at this moment I lost my 8th bit
System.out.println("Binary Server Listing on Port: "+port);
while (true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
byte[] bArray = receivePacket.getData();
byte b = bArray[0];
}
Did I now lose this 8th bit since I turned it into a byte? Was it wrong I initialized a byte array of 3 bytes?
When java takes in these values, do you lose that last 8th bit?
No. You just end up with a negative value when it's set.
So to get a value between 0 and 255, it's simplest to use something like this:
int b = bArray[0] & 0xff;
First the byte is promoted to an int, which will sign extend it, leading to 25 leading 1 bits if the high bit is 1 in the original value. The & 0xff then gets rid of the first 24 bits again :)
No, you do not lose the 8th bit. But unfortunately, Java has two "features" which make it harder than reasonable to deal with such values:
all of its primitive types are signed;
when "unwrapping" a primitive type to another primitive type with a greater size (for instance, reading a byte to an int as is the case here), the sign bit of the "lower type" is expanded.
Which means that, for instance, if you read byte 0x80, which translates in binary as:
1000 0000
when you read it as an integer, you get:
1111 1111 1111 1111 1111 1111 1000 0000
^
This freaking bit gets expanded!
whereas you really wanted:
0000 0000 0000 0000 0000 0000 1000 0000
ie, integer value 128. You therefore MUST mask it:
int b = array[0] & 0xff;
1111 1111 1111 1111 1111 1111 1000 0000 <-- byte read as an int, your original value of b
0000 0000 0000 0000 0000 0000 1111 1111 <-- mask (0xff)
--------------------------------------- <-- anded, give
0000 0000 0000 0000 0000 0000 1000 0000 <-- expected result
Sad, but true.
More generally: if you wish to manipulate a lot of byte-oriented data, I suggest you have a look at ByteBuffer, it can help a lot. But unfortunately, this won't save you from bitmask manipulations, it is just that it makes it easier to read a given quantity of bytes as a time (as primitive types).
In Java, byte (as well as short, int and long) is only a signed numeric data types. However, this does not imply any loss of data when treating them as unsigned binary data. As your illustration shows, 10000000 is -128 as a signed decimal number. If you are dealing with binary data, just treat it as its binary form and you will be fine.
I'm just beginning to learn about file compression and I've run into a bit of a roadblock. I have an application that will encode a string such as "program" as a compressed binary representation "010100111111011000"(note this is still stored as a String).
Encoding
g 111
r 10
a 110
p 010
o 011
m 00
Now I need to write this to the file system using a FileOutputStream, the problem I'm having is, how can I convert the string "010100111111011000" to a byte[]/bytes to be written to the file system with FileOutputStream?
I've never worked with bits/bytes before so I'm kind of at a dead end here.
An introduction to bit-shift operators:
First, we have the left-shift operator, x << n. This will shift all the bits in x left by n bits, filling the new bits with zero:
1111 1111
<< 3: 1111 1000
Next, we have the signed right-shift operator, x >> n. This shifts all the bits in x right by n, copying the sign bit into the new bits:
1111 1111
>> 3: 1111 1111
1000 0000
>> 3: 1111 0000
0111 1111
>> 3: 0000 1111
Finally, we have the zero-fill right-shift operator, x >>> n. This shifts all bits in x right by n bits, filling the new bits with zero:
1111 1111
>>> 3: 0001 1111
You may also find useful the bitwise-or operator, x | y. This compares the bits in each position in x and y, setting the new number's bit on if it was on in either x or y, off otherwise:
1010 0101
| 1010 1010
---------
1010 1111
You should only need the previous operators for the problem at hand, but for the sake of completeness, here are the last two:
The bitwise-and operator, x & y sets the bits in the output to one if and only if the bit is on in both x and y:
1010 0101
& 1010 1010
---------
1010 0000
The bitwise-xor operator, x ^ y sets the output bits to one if the bit is on in one number or the other but not both:
1010 0101
^ 1010 1010
---------
0000 1111
Now, applying these to the situation at hand:
You will need to use the bit-shift operators to add and manipulate bits. Start setting bits at the right side according to their string representations and shift them over. Continue until you hit the end of a byte, and then move to the next byte. Say we want to create a byte representation of "1100 1010":
Our byte Target
--------- --------
0000 0000
1100 1010
0000 0001 ^
1100 1010
0000 0011 ^
1100 1010
0000 0110 ^
1100 1010
0000 1100 ^
1100 1010
0001 1001 ^
1100 1010
0011 0010 ^
1100 1010
0110 0101 ^
1100 1010
1100 1010 ^
I will, of course, leave it to you to apply this to your work.
Chop your String up into lengths of 8 and call Byte#parseByte. If you set the radix to 2, it will parse the String as a binary number.
I guess, you want to write these zeros and ones as binary values in a file. I so, you can iterate the string taking 8 signs everytime (String.substring() or smth) and create bytes with Byte(String) constructor.
It's the easiest solution that comes to my mind for now.
If i'm not right about the problem, tell more about it please.