Firstly, apologies if this question ends up being a duplicate.
I am trying to do some stuff with bits in Java. And I have a need to get awkward amounts of bits in a single variable. So I am still using a byte but want to only store like 7 bits or 4 bits.
So lets say I have a byte which is something like '1101 0110' and I want to get the '0110' at the end. I have seen someone do this: (byte)(b & 0x0F) where b is a byte.
So the way I understand what happens here is: b (1101 0110) is ANDed with 0x0F (0000 1111) then turned to int and casted back to byte.
1101 0110 &
0000 1111
---------
0010 0110 -> 0000 0000 0000 0000 0000 0000 0010 0110 -> 0010 0110
In this instance, I did not get the 4 bits, i got the whole byte and not what I started with either. Am I misunderstanding how the bitwise and works?
I am pretty sure that this works somehow, but I am at a loss how.
Could someone explain this please?
I would think that doing the following would yield a more reliable result:
(byte) ((b<<4)>>>4)
This way I can make sure that the first 4 bits are always 0.
Your assumption is incorrect as well as provided example: AND is always reliable. The reason why it's used more often is that it's more flexible. This way you can replace with zeroes not only the highest bits, but any bits you want just supplying the appropriate mask. Also using shift you should pay additional attention to the sign bit which is unnecessary when you use AND.
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
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).
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 was looking over this code to calculate math.sqrt in Java. Why did they use hex values in some of the loops and normal values for variables? What benefits are there to use hex?
Because hex corresponds much more closely to bits that decimal numbers. Each hex digit corresponds to 4 bits (a nibble). So, once you've learned the bitmask associated with each hex digit (0-F), you can do something like "I want a mask for the low order byte":
0xff
or, "I want a mask for the bottom 31 bits":
0x7fffffff
Just for reference:
HEX BIN
0 -> 0000
1 -> 0001
2 -> 0010
3 -> 0011
4 -> 0100
5 -> 0101
6 -> 0110
7 -> 0111
8 -> 1000
9 -> 1001
A -> 1010
B -> 1011
C -> 1100
D -> 1101
E -> 1110
F -> 1111
They probably used hex values because the numbers are easier to remember in hex. For example, 0x7fffffff is the same as 2147483647, but is a lot easier to remember.
Hex is a human readable form of the binary the CPU actually uses. When looking at low level commands it often makes more sense to match the CPU and think in hex,