Confused with byte convertion to int - java

How a byte value b when uses as int in the Integer.toBinaryString() have a binary value much more than byte type can contain? I thought s1 should be in range [0, 11111111]. And how this bitwise operator (b & 0B11111111) changes the situation? It seems that it changes nothing because 0 & 1 = 0 and 1 & 1 = 1
public class Test
{
public static void main(String[] args)
{
byte b = (byte) -115;
String s1 = Integer.toBinaryString(b);
String s2 = Integer.toBinaryString(b & 0B11111111);
System.out.println(s1); // 11111111111111111111111110001101
System.out.println(s2); // 10001101
}
}

Integer.toBinaryString accepts an int, so you are actually converting the int -115 to a binary string. As far as Integer.toBinaryString is concerned, the number you passed to it is always an int. The fact that you are able to pass a byte is because there is a conversion from byte to int in an invocation context. The byte is converted to int first, then passed to Integer.toBinaryString.
What's -115 represented in 32 bit two's complement (representation of an int)? Well,
1111 1111 1111 1111 1111 1111 1000 1101
That is the binary string you got.
The & 0B11111111 here actually does something. The & operator causes the byte to undergo numeric promotion, converting it to an int. Now we have -115 as a 32-bit int, with all those extra leading 1s that we don't want. The bit mask then gets applied, resulting in the int 141 (1000 1101). We then convert this int to a binary string.

For a byte, -115 dec is 10001101 bin. If you promote that byte to an int with the same value (which is what happens when you call Integer.toBinaryString(b)), -115 dec is 11111111111111111111111110001101 bin.
Whereas if you take your int -115 and & it with 0B11111111, you get the last eight bits of 11111111111111111111111110001101, which is 10001101 bin, 141 dec.
For a byte 10001101 bin is -115, because the largest bit is negative.
For an int 10001101 bin is 141 dec, and the largest bit isn't set because you're only using the smallest 8 bits of a 32 bit integer.

Related

Automatic Type Promotion in Java

I understand that the operands are automatically converted to int and we need to cast the expression to byte again. And for byte conversion the 24 bits are truncated and only 8 bits are evaluated. But I am not able to understand this output -56. The final value of e is 200 and converting it in binary gives 11001000. How is the output -56?
public class ByteIntAutomaticPromotionInExpressions {
public static void main(String[] args) {
byte e = 50;
e = (byte)(e *2);
System.out.println(e);
e *= 2;
System.out.println(e);
}
}
OUTPUT:
100
-56
As you can see here:
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive).
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
If the data type was unsigned, 11001000 would be 200 in decimal.
But since it is signed, you treat it like a negative binary number which is -(inverted bits +1) => - (0110111 + 1) = -(0111000) = -56
https://www.allaboutcircuits.com/textbook/digital/chpt-2/negative-binary-numbers/
8 bits, 2^8=256 in this case 200-256 = -56

Casting of byte data type

Please explain how below code is working, as we know byte data type in java allows a range from -128 to 127.
My code snippet is:
public class DataTypes {
public static void main(String args[]){
byte b = (byte)140;
System.out.println(b);
}
}
Output: -116
A Byte will have 8 bits in its memory space. Using this space it can hold 256 values. This will span from -128 to 127 including 0. To support this spanning, a Byte value will be represented in binary format using two's compliment method. The MSB (Most Significant Bit) will determine the sign (0 - positive & 1 - negative) of the value.
If we consider the case of 140, it will be clear if we represent 140 in binary format which is 1000 1100. Remember the MSB will determine the sign and a 1 means the number is a negative value and 0 means it's a positive value. In this case we have a 1 making it a negative number.
If we apply reverse process to this two's compliment, we will first get 0111 0011 by inverting all the 1s to 0s and 0s to 1s. Then by adding 1, we get 0111 0100 which is equal to 116 in decimal format. But the MSB said it's a negative value, hence -116
Maybe this will help explain. The uppermost bit determines the 'sign'(positive or negative) of a variable. Since Java does not have an explicit 'unsigned' integer form the best you can do is apply a 'bitwise' operation to the item in advance of displaying it force it to be considered 'unsigned'...or you can display it using it's hex format which is inherently unsigned.
public class DataTypes {
public static void main(String args[]){
byte b = (byte)140;
System.out.println("hex value = "+String.format("0x%02X",b)+"\n");
System.out.println("dec value = "+String.format("%d",(b & 0xff))+"\n");
}
}
and a result of
hex value = 0x8C
dec value = 140
140 is a int. It is converted to a byte, according to the Java Language Specification, section 5.1.3, as follows:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits
The lowest 8 bits of the int with value 140 are 10001100, which is the correct value for the byte, but which is negative since its highest bit, the sign bit, is 1.
I think, when you cast the integer (140) to byte, the integer value converted into unsigned byte then b variable value is converted into signed byte. The number 140 considered as unsigned value because the number has not sign value indicator (+ or -)
Note about unsigned byte (the right value is representation (in file byte(s)) of left value):
0-127 = 0-127
(-128) - (-1) = 128 - 255

How to use bitshifting in Java

I am trying to construct an IP header.
An IP header has the following fields: Version, IHL, DSCP etc. I would like to populate a Byte Array such that I can store the information in bytes.
Where I get confused however is that the Version field is only 4 bits wide. IHL is also only 4 bits wide. How do I fit the values of both of those fields to be represented as a byte? Do I need to do bitshifting?
E.g. Version = 4, IHL = 5. I would need to create a byte that would equal 0100 0101 = 45h or 69 decimal.
(byte) (4 << 4) | 5
This shifts the value 4 to the left, then sets lower 4 bits to the value 5.
00000100 A value (4)
01000000 After shifting left 4 bits (<< 4)
00000101 Another value (5)
01000101 The result of a bitwise OR (|) of #2 and #3
Because the operands are int types (and even if they were byte values, they'd be promoted to int when operators like | act on them), the final result needs a cast to be stored in a byte.
If you are using byte values as operands in any bitwise operations, the implicit conversion to int can cause unexpected results. If you want to treat a byte as if it were unsigned in that conversion, use a bitwise AND (&):
byte b = -128; // The byte value 0x80, -128d
int uint8 = b & 0xFF; // The int value 0x00000080, 128d
int i = b; // The int value 0xFFFFFF80, -128d
int uintr = (b & 0xFF) | 0x04; // 0x00000084
int sintr = b | 0x04; // 0xFFFFFF84
You can do something like this:
int a = 0x04;
a <<= 4;
a |= 0x05;
System.out.println(a);
which essentially turns 0b00000100 into 0b01000000, then into 0b01000101.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
To make a compact field containing both Version and IHL in one byte, try doing
byte b = (byte)((Version << 4) + IHL);
This will only work if Version and IHL are numbers from 0 to 15
Just because a byte is 8 bits and your values can only be a maximum of 4 is not a problem. The extra 4 bits will just always be zeroes.
So if you were storing 1 for example:
0000 0001
or 15 (which is the maximum value right?):
0000 1111
Byte shifting is not possible in Java.
How does bitshifting work in Java?
However, as far as the logic is concerned, if you want the version and IHL in one byte, you could do it using the following
byte value = (byte) (IHL | VERSION << 4);

Why Integer.toBinaryString returns 32 bits if the argument is negative?

I was just messing around the Integer.toBinaryString(int) method.
When I pass a positive number say 7, it outputs 111 but when I pass negative 7, it outputs 11111111111111111111111111111001. I understand that Java uses 2's complement to represent negative numbers, but why 32 bits (I also know that an int is 32 bits long but doesn't fit in the answer)?
Ok so I did some digging...
I wrote up a little program probably close to what you did.
public class IntTest {
public static void main(String[] args){
int a = 7;
int b = -7;
System.out.println(Integer.toBinaryString(a));
System.out.println(Integer.toBinaryString(b));
}
}
My output:
111
11111111111111111111111111111001
So 111 is the same if it had 29 "0"s in front of it. That is just wasted space and time.
If we follow the instructions for twos compliment from this guy here you can see that what we must do is flip the bits ( zeros become ones and ones become zeros ) then we add 1 to the result.
So 0000 0000 0000 0000 0000 0000 0000 0111 becomes 1111 1111 1111 1111 1111 1111 1111 1001
The ones can not be thrown out because they are significant in the twos compliment representation. This is why you have 32 bits in the second case.
Hope this helps! -- Code on!!!
Because Java ints are signed 32-bit. If you use a negative number the first bit must be 1.
System.out.println(Integer.toBinaryString(0));
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE)); // 31 bits
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE - 1)); // 31 bits
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE + 1)); // 32 bits
System.out.println(Integer.SIZE);
Output is
0
1111111111111111111111111111111
1111111111111111111111111111110
10000000000000000000000000000000
32
Note that Integer.MAX_VALUE + 1 is Integer.MIN_VALUE (and it has an extra bit).
It outputs the smallest number it can, stripping leading zeroes. In the case of a negative number, the first bit of the 32 bits is a sign bit (i.e. -1 is 1, 30 zeros, and another 1). So, since it has to output the sign bit (it's significant), it outputs all 32 bits.
Here's a cool semi-relevant example of using the sign bit and the unsigned shift operator :). If you do:
int x = {positive_value};
int y = {other_positive_value};
int avg = (x + y) >>> 1;
The x and y integers can both use the first 31 bits since the 32nd bit is the sign. This way, if they overflow, they overflow into the sign bit and make the value negative. The >>> is an unsigned shift operator which shifts the value back one bit to the right which is effectively a divide by two and floor operation, which gives a proper average.
If you, on the other hand, had done:
int x = {value};
int y = {other_value};
int avg = (x + y) / 2;
And you had gotten an overflow, you would end up with the wrong result as you'd be dividing a negative value by 2.

Set greater than 127 int byte variable in java

I write the following sample code:
public static void main(String[] args) throws Exception
{
byte number_1 = 127;
byte number_2 = (byte) 128;
System.out.println("number_1 = " + number_1);
System.out.println("number_2 = " + number_2);
}
I get the following result in output:
number_1 = 127
number_2 = -128
I know range of a byte data type( -128 to 127).
Is my sample is correct? What happened? Is there a two's complement operation? I don't understand this behavior.
Because one byte can hold upto -128 to 127 only, This is expected behavior of overflow
Check with this loop
for(int index = 0 ; index < 258 ; index ++ ){
System.out.println((byte)index);
}
Also See
Endless for loop
Nice comic illustration
This is because of byte range . A byte can store values from -128 to 127 only.
You're seeing the effect of a narrowing primitive conversion: casting the integer literal 128 to a byte results all all but the last byte being thrown out. The last byte of an integer has value 10000000, which when interpreted in two's complement as a one-byte value comes out to -128.
In contrast, the same value interpreted as a four-byte value filled with zeroes on the left, i.e. 00000000 00000000 00000000 10000000, equals 128.
From the official documentation on primitive datatypes :
byte: The byte data type is an 8-bit signed two's complement integer.
It has a minimum value of -128 and a maximum value of 127 (inclusive).
To respond your question : How to Set greater than 127 int byte variable in java ?
The best way to represent an unsigned byte is to use a signed integer, because the Java VM represents bytes as 32 bits, you're not saving anything by using a byte.
Because one byte can hold upto -128 to 127 only, when you transform a int which is
more than 127 or less than -127, the java compiler makes the change automatically.
In fact, the following statement
byte number_2 = (byte) 128;
has been changed to
byte number_2 = (byte) -128;
Once you check out the bytecode using javap, you will find it.

Categories