How to read negative byte values in Java less than -128 - java

I'm reading data from another system using the serial port. I'm reading packets of 133 bytes. The second byte is the packet number and the third byte is the negative value of the packet number.
The problem is that the type byte has a range of -128 to 127. When I attempt to read -129 (outside the range of byte) it will give the value as 127.
What should I do so I can get -129?

You have to determine what range you expect byte values to have. if you expect the range -129 to 126 for example you can use.
int min = 129;
int i = ((b + min) & 0xFF) - min;
BTW You cannot have more than 256 value.

You are getting 127 because a byte is only 8 bits and so the value is wrapping around. -129 won't fit in a java byte. You will have to modify your program to use shorts at the least if you want to fit -129 in a given variable.

I have to guess here a little as I don't know the protocol.
Maybe boths values should be treated as unsigned (positive) bytes in the protocol,
they you can convert them to ints later.
// 0-255
int plus = (int)(plusByte & 0xFF);
// -255 - 0
int minus = 0 - (int)(minusByte & 0xFF);
Is it related to this Us Pat 6313763 ? But as the length of the packet is fixed, I don't get it.
It is not possible to store "bigger" numbers than the range 256 in a byte. Maybe you misunderstood the protocol, and its the high and low bits of an int stored in two bytes?

Values less than -128 dont fit into a signed byte. You need to read a short etc.

Related

How does overflow work in java?

I've read about overflow, I know that "Overflow is when a number is so large that it will no longer fit within the data type, so the system “wraps around” to the next lowest value and counts up from there".
For example:
short s = (short)1921222; // Stored as 20678
In that example we started counting from -32768 (Short.MIN_VALUE), but when I try to prove in another integer data types, it doesn't seem work the same way...
byte b = (byte)400; // Stored as -112
The example above started counting from 0 that was the only way I found to get -112
I don't know if I am doing something wrong.
The Java Language Specification says:
The integral types are byte, short, int, and long, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed two's-complement integers, respectively, and char, whose values are 16-bit unsigned integers representing UTF-16 code units.
So, short and byte are both two's complement integers.
short is 16 bits, meaning it can hold 2^16 = 65536 different values. After the 65536th value, it overflows.
1921222 modulo 65536 is 20678 . This is less than 32768 (2^15, the turning point for the two's complement) so we keep a positive number.
byte is 8 bits, meaning it can hold 2^8 = 256 different values. This one overflows after the 256hth value.
400 modulo 256 is 144. This value is higher than 128, the turning point for the two's complement - hence it will be interpreted as a negative two's complement number.
The cast is truncating the number. (JLS)
0000 0001 1001 0000
loses the high byte to become
1001 0000
which is -112.
In java, byte primitive type is an 8 bit signed integer, that's why you got -112 from calling:
byte b = (byte) 400;
You can avoid that and get its un-signed value, by binary adding it with 0xFF like this:
int b = (byte) 400 & 0xFF;
For further details you can check:
Java Primitive data types Documentation.
How to Convert Int to Unsigned Byte and Back
In addition to the other answers, you can get to that answer by manual calculation as well.
In Java, the data type byte is an 8-bit, signed integer. So the values are in the interval [-128, 127]. If you have a value of 400 and you want to see the actual value for that type, you can subtract the size of the interval from that number until you reach a value that's inside the interval.
As I said, byte is 8 bit, so the size of the interval is 256. Subtract that from your initial value: 400 - 256 = 144. This value is still outside of the interval so you have to subtract again: 144 - 256 = -112. This value is now inside the interval and is indeed the value you've seen in your test.
The same is true for your first example: short is 16 bit and signed, so the interval is [-32768, 32767] with size 65536. Doing repeated subtraction from the value 1921222 will eventually give you the value 20678 as seen in your test.

Incoming Data of bytes

I am dealing with a socket connection in which I send and then receive bytes. I have the socket code written and I can both send and receive bytes but there is a catch...
I am sending data within a language called Delphi and then receiving them in the android code. But I come into a bit of a problem.
In delphi a byte has a maximum value of 255 whereas in Android the maximum byte is 127. How would you get around this? Is there a way to use an unsigned byte? Should I use shorts instead of bytes?
Any help is appreciated.
To read a single byte you can cast it to a larger Java/Android primitive type to interpret it as an unsigned value by performing a bitwise & (AND) with an 8 bit mask. To write a value to the socket as an unsigned byte value use a larger primitive type to set the value, then cast this value to a byte to write to the socket. For example:
short shortVal = 255;
byte byteVal = (byte) shortVal;
System.out.println("signed value = " + byteVal);
shortVal = (short) (byteVal & 0xFF);
System.out.println("unsigned value = " + shortVal);
Java/Android interprets the byte as a signed value (in this case, -1), but the 8 bits in the byte (11111111) are still the same as the least significant 8 bits in the short 255 (0000000011111111).
The same technique can be used with larger types (use int with 16 bit mask to interpret short as unsigned, long with 32 bit mask to interpret int as unsigned), but with multibyte values be careful to take into account the endianness of the network protocol and convert byte order if needed.

Java how to parse uint8 in java?

I have a uint8 (unsigned 8 bit integer) coming in from a UDP packet. Java only uses signed primitives. How do I parse this data structure correctly with java?
Simply read it as as a byte and then convert to an int.
byte in = udppacket.getByte(0); // whatever goes here
int uint8 = in & 0xFF;
The bitmask is needed, because otherwise, values with bit 8 set to 1 will be converted to a negative int. Example:
This: 10000000
Will result in: 11111111111111111111111110000000
So when you afterwards apply the bitmask 0xFF to it, the leading 1's are getting cancelled out. For your information: 0xFF == 0b11111111
0xFF & number will treat the number as unsigned byte. But the resultant type is int
You can store 8-bit in a byte If you really need to converted it to an unsigned value (and often you don't) you can use a mask
byte b = ...
int u = b & 0xFF; // unsigned 0 .. 255 value
You can do something like this:
int value = eightBits & 0xff;
The & operator (like all integer operators in Java) up-casts eightBits to an int (by sign-extending the sign bit). Since this would turn values greater than 0x7f into negative int values, you need to then mask off all but the lowest 8 bits.
You could simply parse it into a short or an int, which have enough range to hold all the values of an unsigned byte.

Understanding Java bytes

So at work yesterday, I had to write an application to count the pages in an AFP file. So I dusted off my MO:DCA spec PDF and found the structured field BPG (Begin Page) and its 3-byte identifier. The app needs to run on an AIX box, so I decided to write it in Java.
For maximum efficiency, I decided that I would read the first 6 bytes of each structured field and then skip the remaining bytes in the field. This would get me:
0: Start of field byte
1-2: 2-byte length of field
3-5: 3-byte sequence identifying the type of field
So I check the field type and increment a page counter if it's BPG, and I don't if it's not. Then I skip the remaining bytes in the field rather than read through them. And here, in the skipping (and really in the field length) is where I discovered that Java uses signed bytes.
I did some googling and found quite a bit of useful information. Most useful, of course, was the instruction to do a bitwise & to 0xff to get the unsigned int value. This was necessary for me to get a length that could be used in the calculation for the number of bytes to skip.
I now know that at 128, we start counting backwards from -128. What I want to know is how the bitwise operation works here--more specifically, how I arrive at the binary representation for a negative number.
If I understand the bitwise & properly, your result is equal to a number where only the common bits of your two numbers are set. So assuming byte b = -128, we would have:
b & 0xff // 128
1000 0000-128
1111 1111 255
---------
1000 0000 128
So how would I arrive at 1000 0000 for -128? How would I get the binary representation of something less obvious like -72 or -64?
In order to obtain the binary representation of a negative number you calculate two's complement:
Get the binary representation of the positive number
Invert all the bits
Add one
Let's do -72 as an example:
0100 1000 72
1011 0111 All bits inverted
1011 1000 Add one
So the binary (8-bit) representation of -72 is 10111000.
What is actually happening to you is the following: You file has a byte with value 10111000. When interpreted as an unsigned byte (which is probably what you want), this is 88.
In Java, when this byte is used as an int (for example because read() returns an int, or because of implicit promotion), it will be interpreted as a signed byte, and sign-extended to 11111111 11111111 11111111 10111000. This is an integer with value -72.
By ANDing with 0xff you retain only the lowest 8 bits, so your integer is now 00000000 00000000 00000000 10111000, which is 88.
What I want to know is how the bitwise operation works here--more specifically, how I arrive at the binary representation for a negative number.
The binary representation of a negative number is that of the corresponding positive number bit-flipped with 1 added to it. This representation is called two's complement.
I guess the magic here is that the byte is stored in a bigger container, likely a 32 bit int. And if the byte was interpreted as being a signed byte it gets expanded to represent the same number in the 32 bit int, that is if the most significant bit (the first one) of the byte is a 1 then in the 32 bit int all the bits left of that 1 are also turned to 1 (that's due to the way negative numbers are represented, two's complement).
Now, if you & 0xFF that int you cut off those 1's and end up with a "positive" int representing the byte value you've read.
Not sure what you really want :) I assume you are asking how to extract a signed multi-byte value? First, look at what happens when you sign extend a single byte:
byte[] b = new byte[] { -128 };
int i = b[0];
System.out.println(i); // prints -128!
So, the sign is correctly extendet to 32 bits without doing anything special. The byte 1000 0000 extends correctly to 1111 1111 1111 1111 1111 1111 1000 0000.
You already know how to suppress sign extension by AND'ing with 0xFF - for multi byte values, you want only the sign of the most significant byte to be extendet, and the less significant bytes you want to treat as unsigned (example assumes network byte order, 16-bit int value):
byte[] b = new byte[] { -128, 1 }; // 0x80, 0x01
int i = (b[0] << 8) | (b[1] & 0xFF);
System.out.println(i); // prints -32767!
System.out.println(Integer.toHexString(i)); // prints ffff8001
You need to suppress the sign extension of every byte except the most significant one, so to extract a signed 32-bit int to a 64-bit long:
byte[] b = new byte[] { -54, -2, -70, -66 }; // 0xca, 0xfe, 0xba, 0xbe
long l = ( b[0] << 24) |
((b[1] & 0xFF) << 16) |
((b[2] & 0xFF) << 8) |
((b[3] & 0xFF) );
System.out.println(l); // prints -889275714
System.out.println(Long.toHexString(l)); // prints ffffffffcafebabe
Note: on intel based systems, bytes are often stored in reverse order (least significant byte first) because the x86 architecture stores larger entities in this order in memory. A lot of x86 originated software does use it in file formats, too.
To get the unsigned byte value you can either.
int u = b & 0xFF;
or
int u = b < 0 ? b + 256 : b;
For bytes with bit 7 set:
unsigned_value = signed_value + 256
Mathematically when you compute with bytes you compute modulo 256. The difference between signed and unsigned is that you choose different representatives for the equivalence classes, while the underlying representation as a bit pattern stays the same for each equivalence class. This also explains why addition, subtraction and multiplication have the same result as a bit pattern, regardless of whether you compute with signed or unsigned integers.

Why byte b = (byte) 0xFF is equals to integer -1?

Why byte b = (byte) 0xFF is equal to integer -1?
Ex:
int value = byte b = (byte) 0xFF;
System.out.println(value);
it will print -1?
Bytes are signed in Java. In binary 0x00 is 0, 0x01 is 1 and so on but all 1s (ie 0xFF) is -1, 0xFE is -2 and so on. See Two's complement, which is the binary encoding mechanism used.
b is promoted to an int in determining which overload of system.out.println to call.
All bytes in Java are signed.
The signed byte 0xff represents the value -1. This is because Java uses two's complement to represent signed values. The signed byte 0xff represents -1 because its most significant bit is 1 (so therefore it represents a negative value) and its value is -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = -1.
perhaps your confusion comes from why (byte)0xFF is somehow equal to (int)0xFFFFFFFF. What's happening here is the promotion from smaller to larger signed types causes the smaller value to be sign extended, whereby the most significant bit is copied to all of the new bits of the promoted value. an unsigned type will not become sign-extended, they get zero extended, the new bits will always be zero.
If it helps you to swallow it, think of it this way, every integer of any size also has some 'phantom' bits that are too significant to be represented. they are there, just not stored in the variable. a negative number has those bits nonzero, and positive numbers have all zeros for phantom bits when you promote a smaller value to a larger one, those phantom bits become real bits.
If you are using a signed int then 0xFF = -1 due to the 2-complement.
This wiki article explains it well, see the table on the right:
http://en.wikipedia.org/wiki/Two%27s_complement
Because Java (and most languages) represent negative integer values using two's-complement math. In two's-complement, 0xFF (11111111) represents (in a signed int) the value -1.
reduced modulo
byte = 256
0xff = 255
255 / 256 -> remainder 255
So 255 - 256 = -1
Simple Logic
Cheers
Its not just Java that does 2's complement math. That is the way every microprocessor and DSP that I can think of does math. So, its the way every programming language represents it.

Categories