I am putting different binary numbers into a byte array. One of the numbers are: 10001101010010010000000000001000 this number is giving me a NumberFormatException on the line where I try to parse it, obviously because it's too big. See code below where string is the binary number.
int number = Integer.parseInt(string, 2);
ByteBuffer bytes = ByteBuffer.allocate(4).putInt(number);
byte[] byteInstruction = bytes.array();
What I want is to put the numbers in my byte array but as they are 32-bit numbers I don't want to take up more than 4 bytes in my array. When I use long to parse it works but then I take up 8 spaces in my byte array.
long number = Long.parseLong(string, 2);
ByteBuffer bytes = ByteBuffer.allocate(8).putLong(number);
byte[] byteInstruction = bytes.array();
If I print out the array later I get this:
[0, 0, 0, 0, -115, 73, 0, 8]
where we can see that there are 4 spots free. How can I solve this? How did I mess up?
All help is appreciated.
Your input string "10001101010010010000000000001000" represents value that is too big for signed Integer. Integer.MAX_VALUE = 2147483647 and the input string you've passed has a value of 2370371592.
The Integer.parseInt does not interpret the leading 1 at position 32 from right as sign. If you would like parse a negative value it would have to be preceded with - sign.
See this answer for more through explanation.
If you expect the input "10001101010010010000000000001000" to in fact mean "-0001101010010010000000000001000" just replace the first character with +/- depending on the value of 32 bit from right.
Alternatively if you would like to treat the binary string in Two's complement compatible way you can use approach from this answer:
int msb = Integer.parseInt("1000110101001001", 2);
int lsb = Integer.parseInt("0000000000001000", 2);
int result = msb<<16 | lsb;
Related
I need to convert integers that I send over 4bytes per socket in java. The problem is that when the integer exceeds 9, ie [10, +inf] my crash code.
I read in the instructions this line:
All multi-byte integer values are encoded using the two's compliment notation in the big-endian order.
The problem is that I don't know how to write the appropriate conversion function. Here is the one I had implemented and which seems to work for integers from 0 to 9. Can someone help me.
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> (i * 8));
}
ByteBuffer has nice functionality for this:
byte[] bytes = new byte[4];
ByteBuffer.wrap(bytes)
.order(ByteOrder.BIG_ENDIAN) // make explicit
.putInt(intValue);
// bytes is now updated
ByteBuffer Doc in java SE 8
I need to convert integers that I send over 4bytes per socket in java.
Probably no actual conversion is required.
The problem is that when the integer exceeds 9, ie [10, +inf] my crash code.
Nothing in what you have presented suggests why that would be, though in fact the conversion presented is wrong.
All multi-byte integer values are encoded using the two's compliment notation in the big-endian order.
This is Java's native representation for type int. You can write ints to the socket's output stream by wrapping it in a DataOutputStream and using DataOutputStream.writeInt(). Or if you are using NIO then you can put an int into a ByteBuffer via the buffer's putInt() method. Either of these approaches sidesteps any need to manually encode integers into byte arrays.
But if you insist on doing your own conversion, completely manually, then this ...
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> (i * 8));
}
... reads out the bytes in little-endian order instead of big-endian (most-significant to least). This would be a correct alternative:
byte[] size_buffer = new byte[4];
for (int i = 0; i < 4; i++) {
size_buffer[i] = (byte)(msg_size >>> ((3 - i) * 8));
}
You state you tried +Inf, but that is not an int value. The only number type you can stick +Inf into is double or float, but it's a compiler error to attempt to do >>> to a double or float.
Also, the code snippet you wrote doesn't work for anything - it turns things into little endian order. It treats 9 the exact same way it treats 10: 9 turns into [9, 0, 0, 0] (which is 9 in 2's complement int, but, little endian), and 10 becomes [10, 0, 0, 0].
In other words, you've either thoroughly misanalysed your own code, or you aren't running that snippet.
This will work fine:
int n = -2;
byte[] sizeBuffer = new byte[4];
for (int i = 0; i < 4; i++) {
sizeBuffer[i] = (byte)(n >>> (24 - (i * 8)));
}
Turns -1 into [255, 255, 255, 254] (in java bytes are rendered signed, so if you try to print that, it'll probably show as -1, -1, -1, -2. It's the same thing) - and that is indeed -2 in 2's complement big endian.
You can make a ByteBuffer and write that way as well.
I cannot figure out why this works. I am attempting to mask the least significant 32 bits of java on a long but it does not properly AND the 33rd and 34th bit and further. Here is my example
class Main {
public static void main(String[] args) {
long someVal = 17592096894893l; //hex 0xFFFFAAFAFAD
long mask = 0xFF; //binary
long result = mask & someVal;
System.out.println("Example 1 this works on one byte");
System.out.printf("\n%x %s", someVal, Long.toBinaryString(someVal) );
System.out.printf("\n%x %s", result, Long.toBinaryString(result) );
long someVal2 = 17592096894893l; //hex 0xFFFFAAFAFAD
mask = 0xFFFFFFFF; //binary
result = mask & someVal2;
System.out.println("\nExample 2 - this does not work");
System.out.printf("\n%x %s", someVal2, Long.toBinaryString(someVal2) );
System.out.printf("\n%x %s", result, Long.toBinaryString(result) );
}
}
I was expecting the results to drop the most significant byte to be a zero since the AND operation did it on 32 bits. Here is the output I get.
Example 1 - this works
ffffaafafad 11111111111111111010101011111010111110101101
ad 10101101
Example 2 - this does not work
ffffaafafad 11111111111111111010101011111010111110101101
ffffaafafad 11111111111111111010101011111010111110101101
I would like to be able to mask the first least significant 4 bytes of the long value.
I believe what you’re seeing here is the fact that Java converts integers to longs using sign extension.
For starters, what should this code do?
int myInt = -1;
long myLong = myInt;
System.out.println(myLong);
This should intuitively print out -1, and that’s indeed what happens. I mean, it would be kinda weird if in converting an int to a long, we didn’t get the same number we started with.
Now, let’s take this code:
int myInt = 0xFFFFFFFF;
long myLong = myInt;
System.out.println(myLong);
What does this print? Well, 0xFFFFFFFF is the hexadecimal version of the signed 32-bit number -1. That means that this code is completely equivalent to the above code, so it should (and does) print the same value, -1.
But the value -1, encoded as a long, doesn’t have representation 0x00000000FFFFFFFF. That would be 232 - 1, not -1. Rather, since it’s 64 bits long, -1 is represented as 0xFFFFFFFFFFFFFFFFF. Oops - all the upper bits just got activated! That makes it not very effective as a bitmask.
The rule in Java is that if you convert an int to a long, if the very first bit of the int is 1, then all 32 upper bits of the long will get set to 1 as well. That’s in place so that converting an integer to a long preserves the numeric value.
If you want to make a bitmask that’s actually 64 bits long, initialize it with a long literal rather than an int literal:
mask = 0xFFFFFFFFL; // note the L
Why does this make a difference? Without the L, Java treats the code as
Create the integer value 0xFFFFFFFF = -1, giving 32 one bits.
Convert that integer value into a long. To do so, use sign extension to convert it to the long value -1, giving 64 one bits in a row.
However, if you include the L, Java interprets things like this:
Create the long value 0xFFFFFFFF = 232 - 1, which is 32 zero bits followed by 32 one bits.
Assign that value to mask.
Hope this helps!
I'm trying to put the following binary representation into a bytebuffer for 4 bytes. But since Java doesn't do unsigned, I'm having trouble: 11111111000000001111111100000000
ByteBuffer bb = ByteBuffer.allocate(8);
bb.putInt(Integer.parseInt("11111111000000001111111100000000", 2));
//throws numberformatexception
Negating the most significant bit seems to change the binary string value because of how two's compliment works:
bb.putInt(Integer.parseInt("-1111111000000001111111100000000", 2));
System.out.println(Integer.toBinaryString(bb.getInt(0)));
//prints 10000000111111110000000100000000
It's important that the value is in this binary format exactly because later it will be treated as an unsigned int. How should I be adding the value (and future values that start with 1) to the bytebuffer?
Just parse it as a long first, and cast the result:
int value = (int) Long.parseLong("11111111000000001111111100000000", 2);
That handles the fact that int runs out of space, because there's plenty of room in a long. After casting, the value will end up as a negative int, but that's fine - it'll end up in the byte buffer appropriately.
EDIT: As noted in comments, in Java 8 you can use Integer.parseUnsignedInt("...", 2).
You can also use Guava's UnsignedInts.parseUnsignedInt(String string, int radix) and UnsignedInts.toString(int x,int radix) methods:
int v = UnsignedInts.parseUnsignedInt("11111111000000001111111100000000", 2);
System.out.println(UnsignedInts.toString(v, 2));
try this
bb.putInt((int)Long.parseLong("11111111000000001111111100000000", 2));
I have binary string String A = "1000000110101110". I want to convert this string into byte array of length 2 in java
I have taken the help of this link
I have tried to convert it into byte by various ways
I have converted that string into decimal first and then apply the code to store into the byte array
int aInt = Integer.parseInt(A, 2);
byte[] xByte = new byte[2];
xByte[0] = (byte) ((aInt >> 8) & 0XFF);
xByte[1] = (byte) (aInt & 0XFF);
System.arraycopy(xByte, 0, record, 0,
xByte.length);
But the values get store into the byte array are negative
xByte[0] :-127
xByte[1] :-82
Which are wrong values.
2.I have also tried using
byte[] xByte = ByteBuffer.allocate(2).order(ByteOrder.BIG_ENDIAN).putInt(aInt).array();
But it throws the exception at the above line like
java.nio.Buffer.nextPutIndex(Buffer.java:519) at
java.nio.HeapByteBuffer.putInt(HeapByteBuffer.java:366) at
org.com.app.convert.generateTemplate(convert.java:266)
What should i do now to convert the binary string to byte array of 2 bytes?Is there any inbuilt function in java to get the byte array
The answer you are getting
xByte[0] :-127
xByte[1] :-82
is right.
This is called 2's compliment Represantation.
1st bit is used as signed bit.
0 for +ve
1 for -ve
if 1st bit is 0 than it calculates as regular.
but if 1st bit is 1 than it deduct the values of 7 bit from 128 and what ever the answer is presented in -ve form.
In your case
1st value is10000001
so 1(1st bit) for -ve and 128 - 1(last seven bits) = 127
so value is -127
For more detail read 2's complement representation.
Use putShort for putting a two byte value. int has four bytes.
// big endian is the default order
byte[] xByte = ByteBuffer.allocate(2).putShort((short)aInt).array();
By the way, your first attempt is perfect. You can’t change the negative sign of the bytes as the most significant bit of these bytes is set. That’s always interpreted as negative value.
10000001₂ == -127
10101110₂ == -82
try this
String s = "1000000110101110";
int i = Integer.parseInt(s, 2);
byte[] a = {(byte) ( i >> 8), (byte) i};
System.out.println(Arrays.toString(a));
System.out.print(Integer.toBinaryString(0xFF & a[0]) + " " + Integer.toBinaryString(0xFF & a[1]));
output
[-127, -82]
10000001 10101110
that is -127 == 0xb10000001 and -82 == 0xb10101110
Bytes are signed 8 bit integers. As such your result is completely correct.
That is: 01111111 is 127, but 10000000 is -128. If you want to get numbers in 0-255 range you need to use a bigger variable type like short.
You can print byte as unsigned like this:
public static String toString(byte b) {
return String.valueOf(((short)b) & 0xFF);
}
I'm having a small error in my code that I can not for the life of me figure out.
I have an array of strings that are representations of binary data (after converting them from hex) for example:
one index is 1011 and another is 11100. I go through the array and pad each index with 0's so that each index is eight bytes. When I try to convert these representations into actual bytes I get an error when I try to parse '11111111' The error I get is:
java.lang.NumberFormatException: Value out of range. Value:"11111111" Radix:2
Here is a snippet:
String source = a.get("image block");
int val;
byte imageData[] = new byte[source.length()/2];
try {
f.createNewFile();
FileOutputStream output = new FileOutputStream(f);
for (int i=0; i<source.length(); i+=2) {
val = Integer.parseInt(source.substring(i, i+2), 16);
String temp = Integer.toBinaryString(val);
while (temp.length() != 8) {
temp = "0" + temp;
}
imageData[i/2] = Byte.parseByte(temp, 2);
}
Isn't the problem here that byte is a signed type, therefore its valid values are -128...127? If you parse it as an int (Using Integer.parseInt()), it should work.
By the way, you don't have to pad the number with zeroes either.
Once you parsed your binary string into an int, you can cast it to a byte, but the value will still be treated as signed, so binary 11111111 will become int 255 first, then byte -1 after the cast.
Well, eight one's is 255, and according to java.lang.Byte, the MAX_VALUE is 2^7 - 1 or positive 127.
So your code will fail because you number is too large. The first bit is reserved for the positive and negative sign.
according to parseByte
byte's only allow numbers in the range of -128 to 127. I would use an int instead, which holds numbers in the range of -2.1 billion to 2.1 billion.