In Java, why both (byte) 400000 and (byte) -400000 have result -128?
Actually, I followed the calculation method from https://stackoverflow.com/a/9085666/1037217
For case: 400000
Binary: 1100001101010000000
Trim to 8 digits: 10000000
Since the left most digit is 1, so -1 from it: 01111111
Then invert it: 10000000
Result: -128
For case: -400000
Binary: -1100001101010000000
Trim to 8 digits: 10000000
Since the left most digit is 1, so -1 from it: 01111111
Then invert it: 10000000
Result: 128
The same method works on
(short) 40000 = -25536
(short) -40000 = 25536
Casting an int to byte will preserve the int number's last 8 bits (the last byte).
400000 = 0x61a80
-400000 = 0xfff9e580
Both of your numbers have the same last 8 bits: 0x80 which is -1 in 2's complement.
For example:
System.out.println((byte)0x23403); // Prints 3 (the last 8 bits: 0x03 = 3)
System.out.println((byte)0x23483); // Prints -125 (last 8 bits: 0x83 = -125)
// (in 2's complement: 0x83 = -(128-3) = -125)
Because byte has the range -128 to 127. Both of your values overflow and are then subject to a narrowing conversion. To quote JLS Example 5.1.3-2. Narrowing Primitive Conversions that lose information,
// An int value too big for byte changes sign and magnitude:
As you say:
For case: 400000 Binary: 1100001101010000000 Trim to 8 digits: 10000000 Since the left most digit is 1, so -1 from it: 01111111 Then invert it: 10000000 Result: -128
For case: -400000 Binary: -1100001101010000000 Trim to 8 digits: 10000000 Since the left most digit is 1, so -1 from it: 01111111 Then invert it: 10000000 Result: 128
In both cases, the bit pattern you get is 10000000. That equates to -128 both times. A byte cannot represent the value 128; it is out of range.
However, your procedure is not quite right. You can't just put a negative sign there and then "trim to 8 digits". A negative sign is not a valid state for a bit. You should probably study the 2s complement representation of integers.
Related
This question already has answers here:
Casting long to byte in Java
(4 answers)
Closed 1 year ago.
I used this site for conversion:
https://www.binaryhexconverter.com/binary-to-decimal-converter
9223372036854775807 is represented as 0111111111111111111111111111111111111111111111111111111111111111
And a byte takes up 1 byte, which is 8 bit, so the last 8 bit is: 11111111
Converting this back to a number using the website linked above I get 255, not -1.
Please see my code.
Thank you very much for helping me out.
long l = 9223372036854775807L;
System.out.println("Value of B: " + l);
byte b = (byte) (l);
System.out.println("Value of B: " + b);
This has the following result:
Value of B: 9223372036854775807
Value of B: -1
This is perfectly normal, because in Java bytes go from -128 to 127, not from 0 to 255. -1 in a Java signed byte corresponds to 255 in an unsigned byte.
byte byteVal = (byte)238; // -18
int intVal = byteVal; // sign extended to maintain 2's complement value
System.out.println(byteVal);
System.out.println(intVal);
prints
-18
-18
To print a byte as an unsigned value, AND it with 0xFF (255).
the byte is converted to an int as above.
the ANDing of the value preserves the lower 8 bits.
System.out.println(byteVal&0xFF);
prints
238
I don't understand why there's a difference between this code:
byte b = (byte) (0xff >> 1);
(so now b = 01111111),
and this code:
byte b = (byte) 0xff;
b >>= 1;
(but now b = 11111111).
Thanks in advance for your help!
In the first code, (0xff >> 1) is 255 >> 1, which is 127. That is calculated with ints and then you cast it to a byte. 127 as a byte is 01111111 bin.
In the second code, you start with (byte) 0xff, which is 11111111 bin, which is the two's complement representation of -1 in 8 bits. So (byte) 0xff is -1.
When you perform shifting, the byte value -1 is promoted to the int value -1. That's 11111111 11111111 11111111 11111111 bin.
Shifting it right one place with the arithmetic right shift operator, (-1) >> 1 gives you 11111111 11111111 11111111 11111111 again, because the >> operator on a negative number moves the bits to the right and fills in the left with ones instead of zeroes.
Then, since you're using >>=, the result is cast back to a byte to be stored in b. That only retains the last 8 bits, which are 11111111.
Alternatively, if you used the logical right shift operator, (-1) >>> 1 would give you 01111111 11111111 11111111 11111111 in binary (a zero followed by 31 ones). Since the last 8 bits are the same, this would still give you 11111111 when it is cast back to a byte.
I'm coding a personal project in Java right now and have recently been using bit operations for the first time. I was trying to convert two bytes into a short, with one byte being the upper 8 bits and the other being the lower 8 bits.
I ran into an error when running the first line of code below.
Incorrect Results
short regPair = (short) ( (byte1 << 8) + (byte2) );
Correct Results
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
The expected results were: AAAAAAAABBBBBBBB, where A represents bits from byte1 and B represents bits from byte2.
Using the 1st line of code I would get the typical addition between a bit-shifted byte1 with byte 2 added to it.
Example of incorrect results
byte1 = 11, byte2 = -72
result = 2816 -72
= 2744
When using the line of code which produces the expected results I can get the proper answer of 3000. I am curious as to why the bit-masking is needed for byte2. My thoughts are that it converts byte2 into binary before the addition and then performs binary addition with both bytes.
In the incorrect case, byte2 is promoted to an int because of the + operator. This doesn't just mean adding some zeros to the start of the binary representation of byte2. Since integer types are represented in two's complement in Java, 1s will be added. After the promotion, byte2 becomes:
1111 1111 1111 1111 1111 1111 1011 1000
By doing & 0xFF, you force the promotion to int first, then you keep the least significant 8 bits: 1011 1000 and make everything else 0.
Print the intermediate value directly to see what is going on. Like,
System.out.printf("%d %s%n", ((byte) -72) & 0xFF, Integer.toBinaryString(((byte) -72) & 0xFF));
I get
184 10111000
So the correct code is actually adding 184 (not subtracting 72).
So I totally forgot that byte is singed in Java, therefore when performing math with a variable of this data type it will take the signed interpretation and not the direct value of the bits. By performing byte2 & 0xFF, Java converts the signed byte value into an unsigned int with all but the first 8 bits set as 0's. Therefore you can perform binary addition correctly.
signed byte value 0x11111111 = -1
unsigned byte value 0x11111111 = 255
In both cases byte values are promoted to int in the expression when
it is evaluated.
byte byte1 = 11, byte2 = -72;
short regPair = (short) ( (byte1 << 8) + (byte2) );
(2816) + (-72) = 2744
And even in below expression byte is promoted to int
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
2816 + 184 = 3000
Here in this expression there is no concatenation of two bytes like it has been expressed in the above question- AAAAAAAABBBBBBBB, where A represents bits from byte1 and B represents bits from byte2.
Actually -7 & 255 gives 184 which is added to 2816 to give the output 3000.
Could anybody tells me how can this Operations results "sar" a negative number?
data[0] is promoted to int before the shift operator is applied.
Therefore, if for example, data[0] is -128,
you are applying the shift on the int -128, whose binary representation is :
11111111 11111111 11111111 10000000
This results in
00000011 11111111 11111111 11111110
And after you cast that back to byte, you end up with a negative number
11111110 (-2)
If you want to ignore the 1 bits that were added as a result of the int promotion, you can write :
byte sar = (byte) ((data[0]&0xff)>>>6);
This will result in 2 (when data[0] is -128).
I receive datas, from a RS422 communication, in a byte tab (byte[]).
Some of my data are in two's complement binary with the following rules :
Significant bits Two's complement
MSB LSB
00000000 0
00000001 + LSB
01111111 + MSB - LSB
10000000 - MSB
10000001 - MSB + LSB
11111111 - LSB
To convert byte[] data to decimal, in pure binary, I use the following code :
Byte b05 = new Byte(new Integer(0x7A).byteValue()); // I use those bytes for my test
Byte b06 = new Byte(new Integer(0x00).byteValue());
Byte[] byteTabDay = new Byte[2] ;
byteTabDay[0] = b05 ;
byteTabDay[1] = b06 ;
int valueDay = byteTabDay[1] << 8 | byteTabDay[0] ;
System.out.println("day :" + valueDay); // print 122
But I don't know how to convert, like previously, byte[] that contain two's complement binary data like that:
Byte b20 = new Byte(new Integer(0x00).byteValue());
Byte b21 = new Byte(new Integer(0xFF).byteValue());
Byte b22 = new Byte(new Integer(0x3C).byteValue());
Those data contain, in theory, the value (more or less) : 1176
So I need help cause I don't understand how I can convert my byte data which contains two's complement binary to decimal.
Two's complement binary is the standard for representing numbers with negative numbers included.
For three-bit numbers:
Base 2 (One's Two's
complement) complement
000 = 0
001 = 1
010 = 2
011 = 3
100 = 4 -3 -4
101 = 5 -2 -3
110 = 6 -1 -2
111 = 7 -0 -1
Java assumes two's complement: the most significant bit being 1 means negative..
Also in java byte, short, int, long are signed.
As an aside, you used the Object wrappers for the primitive types. Primitive types are more immediate.
byte b05 = (byte) 0x7A;
byte b06 = (byte) 0x00; // MSB, positive as < 0x80
nyte[] byteTabDay = new byte[2];
byteTabDay[0] = b05;
byteTabDay[1] = b06;
int valueDay = ((int) byteTabDay[1]) << 8) | (0xFF & byteTabDay[0]);
System.out.println("day :" + valueDay); // print 122
What one has to do: keep the sign extension of the most significant byte, but for other bytes keep them to 8 bits by masking them with 0xFF.
The easiest way to convert an arbitrary byte array containing a two’s complement value to a decimal representation is new BigInteger(bytearray).toString().
This, however, expects the data to be in the big endian byte order. If the data is in little endian order as it seems in your question, you have to reverse it for the use with BigInteger.
byte[] bytearray={ 0x7A, 0x00 };
ByteBuffer b=ByteBuffer.allocate(bytearray.length);
for(int ix=bytearray.length; ix>0; ) b.put(bytearray[--ix]);
System.out.println(new BigInteger(b.array()).toString()); // print 122
If the length of the array matches a standard primitive value type size, you can use ByteBuffer to get the value directly:
byte[] bytearray={ 0x7A, 0x00 };
System.out.println(ByteBuffer.wrap(bytearray)
.order(ByteOrder.LITTLE_ENDIAN).getShort()); // print 122
However, don’t expect the value 1176.61254 as a result. That’s impossible.
If you think that this is the encoded value you will have to adapt your specification. There is no standard three-byte format for floating point values.