How to serialize a decimal value (double) to a uint32 in Java? - java

So far I've been using the following code to convert signed to unsigned values that I need to send as a byte array over UDP to an embedded system.
public static byte serializeShort(short a)
{
return ((byte) (a & 0xFF));
}
public static short serializeInt(int a)
{
return ((short) (a & 0xFFFF));
}
public static int serializeLong(long a)
{
return ((int) (a & 0xFFFFFFFF));
}
The issue with the long, is some values can be real values. The output of this method I put into a bytebuffer via put(), putInt(), or putShort().
Any idea on how to translate the signed to unsigned for a double type?
Specifically here is my problem:
I have a UINT32 value that is being populated. I'm filling in my byte buffer with either a java signed LONG or a java signed double. I used the 'serializeLong()' above for the longs and it works fine, but the doubles do not.
ByteBuffer buffer = ByteBuffer.allocate(SIZE);
if (value instanceof Long)
{
buffer.putInt(Util.serializeLong((Long) value));
} else
{
buffer.putInt(Util.serializeLong(Double.doubleToLongBits((Double) value)));
}

Instead of using a Double, you should be using a float and to get it into the uint32 space use: buffer.putInt((Float.floatToRawIntBits(Math.abs((Float) value))));

Related

Parse signed Byte from binary | Java

I have the following problem in Java. I am using an encryption algorithm that can produce negative bytes as outcome, and for my purposes I must be able to deal with them in binary. For negative bytes, the first or most significant bit in the of the 8 is 1. When I am trying to convert binary strings back to bytes later on, I am getting a NumberFormatException because my byte is too long. Can I tell Java to treat it like an unsigned byte and end up with negative bytes? My code so far is this:
private static String intToBinByte(int in) {
StringBuilder sb = new StringBuilder();
sb.append("00000000");
sb.append(Integer.toBinaryString(in));
return sb.substring(sb.length() - 8);
}
intToBinByte(-92); // --> 10100100
Byte.parseByte("10100100", 2) // --> NumberFormatException
Value out of range. Value:"10100100" Radix:2
Is there a better way to parse signed Bytes from binary in Java?
Thanks in advance!
You can just parse it with a larger type, then cast it to byte. Casting simply truncates the number of bits:
byte b = (byte) Integer.parseInt("10100100", 2);
I have written the following function to solve the problem:
private static byte binStringToByte(String in) {
byte ret = Byte.parseByte(in.substring(1), 2);
ret -= (in.charAt(0) - '0') * 128;
return ret;
}

Convert from hex to int and vice versa in java

I have next method for converting to int from hex:
public static byte[] convertsHexStringToByteArray2(String hexString) {
int hexLength = hexString.length() / 2;
byte[] bytes = new byte[hexLength];
for (int i = 0; i < hexLength; i++) {
int hex = Integer.parseInt(hexString.substring(2 * i, 2 * i + 2), 16);
bytes[i] = (byte) hex;
}
return bytes;
}
when I use it for "80" hex string I get strange, not expected result:
public static void main(String[] args) {
System.out.println(Arrays.toString(convertsHexStringToByteArray2("80"))); // gives -128
System.out.println(Integer.toHexString(-128));
System.out.println(Integer.toHexString(128));
}
the output:
[-128]
ffffff80
80
I expect that "80" will be 128. What is wrong with my method?
I have next method for converting to int from hex
The method you posted converts a hex String to a byte array, and not to an int. That's why it is messing with its sign.
Converting from hex to int is easy:
Integer.parseInt("80", 16)
$1 ==> 128
But if you want to get a byte array for further processing by just casting:
(byte) Integer.parseInt("80", 16)
$2 ==> -128
It "changes" its sign. For further information on primitives and signed variable types take a look at Primitive Data Types, where it says:
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). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
One could easily invert the sign by just increasing the value to convert:
(byte) Integer.parseInt("80", 16) & 0xFF
$3 ==> 128
That gets you a byte with the value you expect. Technically that result isn't correct and you must to switch the sign again, if you want to get an int or a hex string back again. I'd suggest you to don't use a byte array if you only want to convert between hex and dec.
A byte in Java stores numbers from -128 to 127. 80 in hex is 128 as an integer, which is too large to be stored in a byte. So, the value wraps around. Use a different type to store your value (such as a short).

Converting Java bitwise "and" operator over to Kotlin

I have a an array of bytes I'm calculating a checksum for in Java. And I'm trying to convert it to Kotlin. But the problem is that I am getting different values when calculating the -128 & 0xff in Java than it's equivalent in Kotlin. When passing in the -128, when I make the calculation in Java, it gives me a positive 128, but when I run it in Kotlin, it gives me a -128.
public class Bytes {
public static byte[] getByteArray() {
return new byte [] {-128};
}
public static int getJavaChecksum() {
int checksum = 0;
for (Byte b : getByteArray()) {
checksum += (b & 0xff);
}
return checksum;
}
}
This is my Kotlin code. I'm calling into the above bytes class to get the "byte array" I'm working with. So both pieces are running on the same input.
fun getKotlinChecksum(array: ByteArray): Byte {
var checksum = 0
for (b in array) {
checksum += (b and 0xFF.toByte())
}
return checksum.toByte()
}
fun main(args: Array<String>) {
println(Bytes.getJavaChecksum())
print(getKotlinChecksum(Bytes.getByteArray()))
}
The Java code is from a legacy code base that uses I2C to send over these bytes to a microcontroller. Is the Java just wrong? Or is there a way that I can get the 128 in the Kotlin code?
Returning a Byte means the function cannot return 128 no matter what, so that needs to be Int. The Java checksum does a "full" sum, not just the lowest byte of the sum. Similarly the bitwise AND cannot be done on bytes, that is useless, the sign extension (the AND with 0xFF is to remove the extended sign bits) would still happen. Then it could be written as a loop, Java style, but in Kotlin it probably makes more sense to write something like this:
fun getKotlinChecksum(array: ByteArray): Int {
return array.map({ it.toInt() and 0xFF }).sum()
}

How is one byte read and returned as an int by read function in InputStream in java?

The read() function reads one byte at a time and the return type of this function is int. I want to know what happens under the hood so that byte is returned as an int. I have no knowledge of bitwise operators so can anyone answer in a way that i grasp it readily.
It depends on the stream implementation. In some cases the method implementation is in native code. In others, the logic is simple; for example, in ByteArrayInputStream the read() method does this:
public class ByteArrayInputStream extends InputStream {
protected byte buf[];
protected int count;
protected int pos;
...
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
}
In other words, the bytes are converted into integers in the range 0 to 255, like the javadoc states, and -1 is returned at the logical end-of-stream.
The logic of buf[pos++] & 0xff is as follows:
buf[pos++] is converted to an int
& 0xff converts the signed integer (-128 to +127) into an "unsigned" byte (0 to 255) represented as an integer.
Under the hood, if the end of stream is reached, read() returns -1. Otherwise, it returns the byte value as an int (the value is thus between 0 and 255).
After you've verified that the result is not -1, you can get the signed byte value using
byte b = (byte) intValue;
That will just keep the 8 rightmost bits of the int, and the 8th bit from the right is used as the sign bit, thus leading to a signed value, between -128 and 127.
If the method returned a byte, there would be no way, other than throwing an exception, to signal that the end of the stream has been reached.
Below is the program to read one byte at a time using read() method of InputStream:
public class Main {
public static void main(String[] args) {
try {
InputStream input = new FileInputStream("E:\\in.txt");
int intVal;
while((intVal = input.read()) >=0)
{
byte byteVal = (byte) intVal;
System.out.println(byteVal);
}
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Please not that the intVal here returned by input.read() is the byte value of the characters read from file in.txt.

Representing a number in a byte array (java programming)

I'm trying to represent the port number 9876 (or 0x2694 in hex) in a two byte array:
class foo {
public static void main (String args[]) {
byte[] sendData = new byte[1];
sendData[0] = 0x26;
sendData[1] = 0x94;
}
}
But I get a warning about possible loss of precision:
foo.java:5: possible loss of precision
found : int
required: byte
sendData[1] = 0x94;
^
1 error
How can I represent the number 9876 in a two byte array without losing precision?
NOTE: I selected the code by #Björn as the correct answer, but the code by #glowcoder also works well. It's just a different approach to the same problem. Thank you all!
Have you tried casting to a byte ? e.g.
sendData[1] = (byte)0x94;
0x94 is 148 in decimal, which exceeds the range of byte in java (-128 to 127).
You can do one of the following:
1) A cast will work fine because it will preserve the binary representation (no meaningful bits are truncated for 0x00 to 0xFF):
sendData[1] = (byte)0x94;
2) The binary representation of 0x94 as a signed byte is -108 (-0x6C), so the following will have the same effect:
sendData[1] = -0x6C; //or -108 in decimal
Björn gave a good generic answer with using streams. You can also do this same thing using java.nio.ByteBuffer which results in slightly less code and you could also control endianess (byte order) of the output.
To create the byte array:
public static byte[] toByteArray(int bits) {
ByteBuffer buf = ByteBuffer.allocate(4);
buf.putInt(bits);
return buf.array();
}
To reverse it:
public static int fromByteArray(byte[] b) {
ByteBuffer buf = ByteBuffer.wrap(b);
return buf.getInt();
}
My first answer would be bitshifting, but on a second thought I think using outputstreams could be better and more simple to understand. I usually avoid casting, but if you're not going for a generic solution I guess that would be okay. :)
Using streams, a generic solution:
public byte[] intToByteArray(final int i) throws java.io.IOException {
java.io.ByteArrayOutputStream b = new java.io.ByteArrayOutputStream();
java.io.DataOutputStream d = new java.io.DataOutputStream(b);
d.writeInt(i);
d.flush();
return b.toByteArray();
}
And to reverse it:
public int byteArrayToInt(final byte[] b) throws IOException {
java.io.ByteArrayInputStream ba = new java.io.ByteArrayInputStream(b);
java.io.DataInputStream d = new java.io.DataInputStream(ba);
return d.readInt();
}
You have to cast to (byte) as default number type in java is int, which is bigger than byte. As long as the value fits in byte it is ok to cast.
Try this:
sendData[0] =(byte)0x26
sendData[1] =(byte)0x94
Or this:
sendData[0] =(byte)38
sendData[1] =(byte)148
You must cast data into byte in order to assign it to a byte!
That does not mean you lost precision, just writing 0x26 means an int to Java compiler..
But also note: range of a byte is from -128 to 127, so in case of 0x94=148 it will be represented after byte casting as '-108' , so it will not work correctly in mathematical computations..
It's because everything in Java is signed. 0x94 (148) is greater than Byte.MAX_VALUE(2^7-1).
What you need is
public static byte[] intToByteArray(int value) {
byte[] b = new byte[4];
for (int i = 0; i < 4; i++) {
int offset = (b.length - 1 - i) * 8;
b[i] = (byte) ((value >>> offset) & 0xFF);
}
return b;
}

Categories

Resources