how to read signed int from bytes in java? - java

I have a spec which reads the next two bytes are signed int.
To read that in java i have the following
When i read a signed int in java using the following code i get a value of 65449
Logic for calculation of unsigned
int a =(byte[1] & 0xff) <<8
int b =(byte[0] & 0xff) <<0
int c = a+b
I believe this is wrong because if i and with 0xff i get an unsigned equivalent
so i removed the & 0xff and the logic as given below
int a = byte[1] <<8
int b = byte[0] << 0
int c = a+b
which gives me the value -343
byte[1] =-1
byte[0]=-87
I tried to offset these values with the way the spec reads but this looks wrong.Since the size of the heap doesnt fall under this.
Which is the right way to do for signed int calculation in java?
Here is how the spec goes
somespec() { xtype 8 uint8 xStyle 16 int16 }
xStyle :A signed integer that represents an offset (in bytes) from the start of this Widget() structure to the start of an xStyle() structure that expresses inherited styles for defined by page widget as well as styles that apply specifically to this widget.

If you value is a signed 16-bit you want a short and int is 32-bit which can also hold the same values but not so naturally.
It appears you wants a signed little endian 16-bit value.
byte[] bytes =
short s = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
or
short s = (short) ((bytes[0] & 0xff) | (bytes[1] << 8));
BTW: You can use an int but its not so simple.
// to get a sign extension.
int i = ((bytes[0] & 0xff) | (bytes[1] << 8)) << 16 >> 16;
or
int i = (bytes[0] & 0xff) | (short) (bytes[1] << 8));

Assuming that bytes[1] is the MSB, and bytes[0] is the LSB, and that you want the answer to be a 16 bit signed integer:
short res16 = ((bytes[1] << 8) | bytes[0]);
Then to get a 32 bit signed integer:
int res32 = res16; // sign extends.
By the way, the specification should say which of the two bytes is the MSB, and which is the LSB. If it doesn't and if there aren't any examples, you can't implement it!
Somewhere in the spec it will say how an "int16" is represented. Paste THAT part. Or paste a link to the spec so that we can read it ourselves.

Take a look on DataInputStream.readInt(). You can either steel code from there or just use DataInputStream: wrap your input stream with it and then read typed data easily.
For your convenience this is the code:
public final int readInt() throws IOException {
int ch1 = in.read();
int ch2 = in.read();
int ch3 = in.read();
int ch4 = in.read();
if ((ch1 | ch2 | ch3 | ch4) < 0)
throw new EOFException();
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
}

I can't compile it right now, but I would do (assuming byte1 and byte0 are realling of byte type).
int result = byte1;
result = result << 8;
result = result | byte0; //(binary OR)
if (result & 0x8000 == 0x8000) { //sign extension
result = result | 0xFFFF0000;
}
if byte1 and byte0 are ints, you will need to make the `&0xFF
UPDATE because Java forces the expression of an if to be a boolean

do you have a way of finding a correct output for a given input?
technically, an int size is 4 bytes, so with just 2 bytes you can't reach the sign bit.

I ran across this same problem reading a MIDI file. A MIDI file has signed 16 bit as well as signed 32 bit integers. In a MIDI file, the most significant bytes come first (big-endian).
Here's what I did. It might be crude, but it maintains the sign. If the least significant bytes come first (little-endian), reverse the order of the indexes.
pos is the position in the byte array where the number starts.
length is the length of the integer, either 2 or 4. Yes, a 2 byte integer is a short, but we all work with ints.
private int convertBytes(byte[] number, int pos, int length) {
int output = 0;
if (length == 2) {
output = ((int) number[pos]) << 24;
output |= convertByte(number[pos + 1]) << 16;
output >>= 16;
} else if (length == 4) {
output = ((int) number[pos]) << 24;
output |= convertByte(number[pos + 1]) << 16;
output |= convertByte(number[pos + 2]) << 8;
output |= convertByte(number[pos + 3]);
}
return output;
}
private int convertByte(byte number) {
return (int) number & 0xff;
}

Related

How to convert 18 bits two-complements into float number using java

The data is uploaded by 18-bits ADC. One data is split into three bytes and the last 6 bits is useless. The reference voltage is 1 volt, that means 0x1FFFF represents 1 and 0x3FFFF represents -1. How to convert 18-bits twos-complement into float using java. I have written one and it works, but I think it is not efficient enough. My java is terrible.
float data;
int value = ((byte0 & 0xff) << 10) | ((byte1 & 0xff) << 2) | ((byte2 & 0xff) >> 6); // combine 3 bytes into int
int tmp = value & 0x2000; // judge positive or negative
if (tmp != 0) {
value = value - 262144 /* 2^18 */;
data = ((float)value) * 2 / 262143 /* 2^18-1 */;
} else {
data = ((float)value) * 2 / 262143;
}
You could try
double data = (value << 14) / (double) (0x1FFFF << 14);
This will use a shifted 32-bit 2s complement value.
NOTE: If it was 2s complement, 0x3ffff should be the smallest negative number, and 0x20000 is the largest negative number.
Put the sign bit of the ADC in the same place as the sign bit of a 32-bit integer and you can simplify by using the native sign.
public static final float ADC_RANGE = 1.0f; // From -1V to +1V
public static final int ADC_BITS = 18;
public static final int ADC_RANGE = 1 << (ADC_BITS - 1);
public static final int ADC_MASK = (ADC_RANGE - 1) << (32 - ADC_BITS);
int bits = ((byte0 & 0xFF) << 24) | ((byte1 & 0xFF) << 16) | ((byte2 & 0xC0) << 8); // Combine 3 bytes into int, left-aligned
float value = bits / (float)ADC_MASK * ADC_RANGE;
[edit] use constants for 'magic numbers'

Byte Operations and Datagrams in Java

I am trying to program a handshake type message as follows where C=Client S=Server:
C-->S: "I'd like to talk" //session initiation
S-->C: "80" //(n, randomly generated number)
C-->S: "81" //(n+1)
S: "does n= (n+1)-1?" //confirms the connection.
For the purposes of this question assume that the logic above is correct. I would like the random number I generated to be a 32 bit number (i.e. 4 bytes sent in a UDP datagram). Since an int is 32 bits, I would prefer to use this data type, but I seem to run into one of two problems:
When using an array of bytes, it is easy to send in a datagram but difficult to perform a simple math operation (such as subtract 1) for a 32 bit number.
When using an int it is easy to perform a simple math operation, but it is difficult to convert between ints and bytes when sending back and forth between the client and server.
I found a method that can convert from an int to bytes. I found some information regarding using a Bytebuffer to convert to an int, but I'm not sure it's even correct. Is there an easier way to go about a process of sending an int in a datagram? It seems like an extraordinary amount of work to keep converting back and forth between bytes and ints.
Nothing hard about any of those operations. DataInputStream and DataOutputStream take care of the stream->int->stream conversions, and ByteArrayInputStream and ByteArrayOutputStream take care of the stream->byte[]->stream conversions.
There are two options:
the above mentioned bytebuffer
converting via bitshift:
//int to byte[]
int val = someval;
byte[] bytes = new byte[4];
for(int i = 0 ; i < 4 ; i++)
bytes[i] = (byte) (val >>> (i * 8));
//byte[] to int
int val = 0;
byte[] bytes = input();
for(int i = 0 ; i < 4 ; i++)
val |= ((int)(bytes[i])) << i * 8;
If you are defining your own format of the datagram, it's easy enough to establish that the nth 4 bytes of content represent an integer.
You then can use some simple conversion functions to go from int to byte[] and vice-versa.
A small class implementing this two methods should do:
public static byte[] toByteArray(int value) {
byte[] b = new byte[4];
// MSB to LSB
b[0] = (byte) (value >> 24);
b[1] = (byte) (value >> 16);
b[2] = (byte) (value >> 8);
b[3] = (byte) (value);
return b;
}
public static int fromByteArray(byte[] value) {
int i = ((((int) value[0]) & 0xFF) << 24) |
((((int) value[1]) & 0xFF) << 16) |
((((int) value[2]) & 0xFF) << 8) |
((((int) value[3] & 0xFF)));
return i;
}

Sending Java int to C over TCP

I'm trying to send Java's signed integers over TCP to a C client.
At the Java side, I write the integers to the outputstream like so:
static ByteBuffer wrapped = ByteBuffer.allocateDirect(4); // big-endian by default
public static void putInt(OutputStream out, int nr) throws IOException {
wrapped.rewind();
wrapped.putInt(nr);
wrapped.rewind();
for (int i = 0; i < 4; i++)
out.write(wrapped.get());
}
At the C side, I read the integers like so:
int cnt = 0;
char buf[1];
char sizebuf[4];
while(cnt < 4) {
iResult = recv(ConnectSocket, buf, 1, 0);
if (iResult <= 0) continue;
sizebuf[cnt] = buf[0];
cnt++;
}
However, how do I convert the char array to an integer in C?
Edit
I have tried the following (and the reverse):
int charsToInt(char* array) {
return (array[3] << 24) | (array[2] << 16) | (array[1] << 8) | array[0];
}
Edited again, because I forgot the tags.
Data
For example of what happens currently:
I receive:
char 0
char 0
char 12
char -64
the int becomes 2448
and use the function for creating the int from the char array:
int charsToInt(char* array) {
return ntohl(*((int*) array));
}
I expect the signed integer: 3264
Update
I will investigate more after some sleep..
Update
I have a Java client which interprets the integers correctly and receives the exact same bytes:
0
0
12
-64
That depends on endianness, but you want either:
int x = sizebuf[0] +
(sizebuf[1] << 8) +
(sizebuf[2] << 16) +
(sizebuf[3] << 24);
or:
int x = sizebuf[3] +
(sizebuf[2] << 8) +
(sizebuf[1] << 16) +
(sizebuf[0] << 24);
Note that sizebuf needs to have an unsigned type for this to work correctly. Otherwise you need to mask off any sign-extended values you don't want:
int x = (sizebuf[3] & 0x000000ff) +
((sizebuf[2] << 8) & 0x0000ff00) +
((sizebuf[1] << 16) & 0x00ff0000) +
((sizebuf[0] << 24) & 0xff000000);
The classical C library has the method you want already, and it is independent from the machine endianness: ntohl!
// buf is a char */uint8_t *
uint32_t from_network = *((uint32_t *) buf);
uint32_t ret = ntohl(from_network);
This, and htonl for the reverse etc expect that the "network order" is big endian.
(the code above presupposes that buf has at least 4 bytes; the return type, and argument type, of ntohl and htonl are uint32_t; the JLS defines an int as 4 bytes so you are guaranteed the result)
To convert you char array, one possibility is to cast it to int* and to store the result :
int result = *((int*) sizebuf)
This is valid and one line. Other possibility is to compute integer from chars.
for (i = 0 ; i < 4; i++)
result = result << sizeof(char) + buf[0]
Choose the one that you prefer.
Alexis.
Edit :
sizeof(char) is 1 because sizeof return a Byte result. So the right line is :
result = result << (sizeof(char) * 8) + buf[0]

How to fill high-end bits in a Java byte with '1' without knowing the last 1 in advance? (FAST FIX Negative Integer decoder)

I am writing a FIX/FAST decoder for negative numbers as described below:
My question is:
How to fill the high-end bits of a Java byte with 1s as it is described above? I am probably unaware of some bit manipulation magic I need to in this conversion.
So I need to go from 01000110 00111010 01011101 to 11110001 10011101 01011101.
I know how to shift by 7 to drop the 8th bit. What I don't know is how to fill the high-end bits with 1s.
It seems like the question you're asking doesn't really match up with the problem you're trying to solve. You're not trying to fill in the high bits with 1; you're trying to decode a stop-bit-encoded integer from a buffer, which involves discarding the sign bits while combining the payload bits. And, of course, you want to stop after you find a byte with a 1 in the stop bit position. The method below should decode the value correctly:
private static final byte SIGN_BIT = (byte)0x40;
private static final byte STOP_BIT = (byte)0x80;
private static final byte PAYLOAD_MASK = 0x7F;
public static int decodeInt(final ByteBuffer buffer) {
int value = 0;
int currentByte = buffer.get();
if ((currentByte & SIGN_BIT) > 0)
value = -1;
value = (value << 7) | (currentByte & PAYLOAD_MASK);
if ((currentByte & STOP_BIT) != 0)
return value;
currentByte = buffer.get();
value = (value << 7) | (currentByte & PAYLOAD_MASK);
if ((currentByte & STOP_BIT) != 0)
return value;
currentByte = buffer.get();
value = (value << 7) | (currentByte & PAYLOAD_MASK);
if ((currentByte & STOP_BIT) != 0)
return value;
currentByte = buffer.get();
value = (value << 7) | (currentByte & PAYLOAD_MASK);
if ((currentByte & STOP_BIT) != 0)
return value;
currentByte = buffer.get();
value = (value << 7) | (currentByte & PAYLOAD_MASK);
return value;
}
A loop would be cleaner, but I unrolled it manually since messaging protocols tend to be hot code paths, and there's a fixed maximum byte length (5 bytes). For simplicity's sake, I read the bytes from a ByteBuffer, so you may need to adjust the logic based on how you're reading the encoded data.
Fillig the high bits might go as:
int fillHighBits(int b) { // 0001abcd
int n = Integer.highestOneBit(b); // 00010000
n = ~n; // 11101111
++n; // 11110000
return (n | b) 0xFF; // 1111abcd
}
As expression
(~Integer.highestOneBit(b) + 1) | b
Though the examples you gave lets me doubt this is what you want.
This can be done very simply using a simple accumulator where you shift in 7 bits at a time. You need to keep track of how many bits you have in the accumulator.
Sign extension can be performed by simple logical shift left follwed by arithmetic shift right (by the same distance) to copy the topmost bit to all unused positions.
byte[] input = new byte[] { 0x46, 0x3A, (byte) 0xDD };
int accumulator = 0;
int bitCount = 0;
for (byte b : input) {
accumulator = (accumulator << 7) | (b & 0x7F);
bitCount += 7;
}
// now sign extend the bits in accumulator
accumulator <<= (32 - bitCount);
accumulator >>= (32 - bitCount);
System.out.println(Integer.toHexString(accumulator));
The whole trick is that >>N operator replicates the top bit N times.
do logical OR (|) with a number which has highend bits set to 1 and rest are 0
for example:
1010101010101010
OR 1111111100000000
--------------------
11111111101010101
something like this:
int x = ...;
x = x | 0xF000;

How can I convert a 4-byte array to an integer?

I want to perform a conversion without resorting to some implementation-dependent trick. Any tips?
You need to know the endianness of your bytes.
Assuming (like #WhiteFang34) that bytes is a byte[] of length 4, then...
Big-endian:
int x = java.nio.ByteBuffer.wrap(bytes).getInt();
Little-endian:
int x = java.nio.ByteBuffer.wrap(bytes).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt();
Assuming bytes is a byte[4] of an integer in big-endian order, typically used in networking:
int value = ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16)
| ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
The & 0xFF are necessary because byte is signed in Java and you need to retain the signed bit here. You can reverse the process with this:
bytes[0] = (byte) ((value >> 24) & 0xFF);
bytes[1] = (byte) ((value >> 16) & 0xFF);
bytes[2] = (byte) ((value >> 8) & 0xFF);
bytes[3] = (byte) (value & 0xFF);
Not sure if this is correct java syntax, but how about:
int value = 0;
for (i = 0; i <= 3; i++)
value = (value << 8) + (bytes[i] & 0xFF);
You need to specify the byte order of the array, but assuming that the bytes[0] is the most significant byte then:
int res = ((bytes[0] & 0xff) << 24) | ((bytes[1] & 0xff) << 16) |
((bytes[2] & 0xff) << 8) | (bytes[3] & 0xff);
This code is 100% portable, assuming that you use the reverse algorithm to create the byte array in the first place.
Byte order problems arise in languages where you can cast between a native integer type and byte array type ... and then discover that different architectures store the bytes of an integer in different orders.
You can't do that cast in Java. So for Java to Java communication, this should not be an issue.
However, if you are sending or receiving packets to some remote application that is implemented in (say) C or C++, you need to "know" what byte order is being used in the network packets. Some alternative strategies for knowing / figuring this out are:
Everyone uses "network order" (big-endian) for stuff on the wire as per the example code above. Non-java applications on little-endian machines need to flip the bytes.
The sender finds out what order the receiver expects and uses that order when assembling the data.
The receiver figures out what order the sender used (e.g. via a flag in the packet) and decodes accordingly.
The first approach is simplest and most widely used, though it does result in 2 unnecessary endian-ness conversions if both the sender and receiver are little-endian.
See http://en.wikipedia.org/wiki/Endianness
Assuming your byte[] come from somewhere e.g. a stream you can use
DataInputStream dis = ... // can wrap a new ByteArrayInputStream(bytes)
int num = dis.readInt(); // assume big-endian.
or
ByteChannel bc = ... // can be a SocketChannel
ByteBuffer bb = ByteBuffer.allocate(64*1024);
bc.read(bb);
bb.flip();
if (bb.remaining()<4) // not enough data
int num = bb.getInt();
When you send data, you should know if you are sending big-endian or little endian. You have to assume other things such as whether you are sending a 4-byte signed integer. A binary protocol is full of assumptions. (Which makes it more compact and faster, but more brittle than text)
If you don't want to be making as many assumptions, send text.
WE can also use following to make it more dynamic byte array size
BigEndian Format:
public static int pareAsBigEndianByteArray(byte[] bytes) {
int factor = bytes.length - 1;
int result = 0;
for (int i = 0; i < bytes.length; i++) {
if (i == 0) {
result |= bytes[i] << (8 * factor--);
} else {
result |= bytes[i] << (8 * factor--);
}
}
return result;
}
Little Endian Format :
public static int pareAsLittleEndianByteArray(byte[] bytes) {
int result = 0;
for (int i = 0; i < bytes.length; i++) {
if (i == 0) {
result |= bytes[i] << (8 * i);
} else {
result |= bytes[i] << (8 * i);
}
}
return result;
}
This will helps you lot for converting bytes to int values
public static int toInt( byte[] bytes ) {
int result = 0;
for (int i=0; i<3; i++) {
result = ( result << 8 ) - Byte.MIN_VALUE + (int) bytes[i];
}
return result;
}

Categories