How BigInteger convert a byte array to number in Java? - java

I have this small code :
public static void main(String[] args) {
byte[] bytesArray = {7,34};
BigInteger bytesTointeger= new BigInteger(bytesArray);
System.out.println(bytesTointeger);
}
Output:1826
My question is what just happened how an array of bytes {7,34} converted into this number 1826 , what is the operation that caused this result ? like how to convert it manually

The number 1826 is, in binary, 11100100010.
If you split that in groups of 8 bits, you get the following:
00000111 00100010
Which are the numbers 7 and 34

7 and 34 is converted to binary and give 00000111 and 00100010.After join it becomes 11100100010 which is in decimal 1826.

As said, this creates a BigDecimal from its byte representation in big-endian order.
If we used long to store result, manual conversion may look like the following:
long bytesToLong(byte[] bs) {
long res = 0;
for (byte b : bs) {
res <<= 8; // make room for next byte
res |= b; // append next byte
}
return res;
}
E. g.:
byte[] bs;
bs = new byte[]{ 7, 34 };
assertEquals(new BigInteger(bs).longValue(), bytesToLong(bs)); // 1826
bs = new byte[]{ -1 };
assertEquals(new BigInteger(bs).longValue(), bytesToLong(bs)); // -1

Related

How to convert array of 16-bit signed integers to byte array in Java?

Let's say that on Android (Java) we have a byte array that represents a sequence of 16-bit signed integers.
I am needing to be able to decode the values from this array by using a for-loop and concatenating each pair of bytes to retrieve the original value back again (Please don't suggest a different method such as a ByteBuffer).
In order to test my algorithm, I want to encode and decode a list of ints and see if I get the same numbers back.
However, I can't figure out how to encode the original list of ints into a byte array for testing purposes. I don't want to simply reverse my algorithm because I don't know if it works yet... I would be open to using ByteBuffer or any other known-good means to do the encoding because it's only for testing/simulation purposes -- in the real app, the byte array is already encoded by Android.AudioRecord.
// dec : short : byte a : byte b
// 4536 : 0001000100000100 : 17 : 4
// -1 : 1111111111111111 : -1 : -1
// -32768 : 1000000000000000 : -128 : 0
// 32767 : 1000000000000001 : -128 : 1
// 0 : 0000000000000000 : 0 : 0
// -2222 : 1111011101010010 : -9 : 82
void _go() {
int[] source = {4536,-1,-32768,32767,0,-2222};
// is this even correct?
byte[] expectedEncoding = {17,4,-1,-1,-128,0,-128,1,0,0,-9,82};
byte[] encoded = ??? // <----- what goes here?
int[] decoded = new int[source.length];
// the algorithm I'm testing
for (int i=0; i < encoded.length/2; i++) {
byte a = encoded[i];
byte b = encoded[i+1];
decoded[i] = (short) (a<<8 | b & 0xFF);
}
Log.i("XXX", "decoded values: " + decoded.toString());
}
You can convert an array of 16-bit signed integers to a byte array in Java using the following steps:
Here is an example implementation:
public static byte[] convertToByteArray(short[] shortArray) {
byte[] byteArray = new byte[shortArray.length * 2];
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
for (short value : shortArray) {
byteBuffer.putShort(value);
}
return byteArray;
}
Note: This conversion is also known as serialization and deserialization, which can be done by different libraries like Avro, Thrift etc.
Here an exemple...
short[] arrayOfShorts = {6, 1, 2, 5};
byte[] arrayOfBytes = new byte[shortArray.length * 2];
ByteBuffer.wrap(byteArray)
.order(ByteOrder.LITTLE_ENDIAN)
.asShortBuffer().put(shortArray);

How can i convert a hexadicimal string to hexadecimal byte?

In my application i am reading some data from table. Which is in string format. i need to parse this data to byte.
Example:
suppose my string contain 0e
than i want to get 0e as byte value.
here (byte) (Integer.parseInt("0e",16) & 0xff); will not work as it will parse this value to integer .. Any help on this will be appreciated .Thanks in advance.
Even though Integer.parseInt("0e", 16) & 0xff produces an integer, there's nothing preventing you from adding a cast:
byte b = (byte)(Integer.parseInt("0e",16) & 0xff);
You can use String.Format to verify that the conversion has worked properly:
String backToHex = String.format("%02x", b); // produces "0e"
Try:
byte b = Byte.parseByte("0e", 16);
You can parse byte by the following code:
byte b = Byte.parseByte("0e", 16)
This will convert your string into a list of bytes.
public static List<Byte> parseStringBytes(String str)
{
if (str.length() % 2 == 1)
str = "0" + str; // otherwise 010 will parse as [1, 0] instead of [0, 1]
// Split string by every second character
String[] strBytes = str.split("(?<=\\G.{2})");
List<Byte> bytes = new ArrayList<>(strBytes.length);
for (String s : strBytes) {
bytes.add(Byte.parseByte(s, 16));
}
return bytes;
}
Call like so:
System.out.println(parseStringBytes("05317B13"));
// >>> [5, 49, 123, 19]

How does this Java code work to convert an ip address?

In the example code below could someone walk through a more detailed explanation of exactly what the lines below are actually doing like you'd explain it to a beginning developer.
for (byte octet : octets) {
result <<= 8;
result |= octet & 0xff;
}
public class Example {
public static long ipToLong(InetAddress ip) {
byte[] octets = ip.getAddress();
long result = 0;
for (byte octet : octets) {
result <<= 8;
result |= octet & 0xff;
}
return result;
}
public static void main(String[] args) throws UnknownHostException {
long ipLo = ipToLong(InetAddress.getByName("192.200.0.0"));
long ipHi = ipToLong(InetAddress.getByName("192.255.0.0"));
long ipToTest = ipToLong(InetAddress.getByName("192.200.3.0"));
System.out.println(ipToTest >= ipLo && ipToTest <= ipHi);
}
}
byte[] octets = ip.getAddress(); -> stores entire IP address as byte array
for (byte octet : octets) {} -> splits the byte-array into octets and iterates over them
result <<= 8 (shorthand for result = result<<8) -> Left-shift 8 bits shifts the result in binary by 8 bits, and adds 8 trailing zeros. (Multiplies the value of result by 2^8)
result |= octet & 0xff; (same as result|=octet which is shorthand for result = result | or octect -> Bitwise ORing, same as addition in this case, because we have 8 zeros at the end of result, after the previous step.
EDIT (thanks to #jtahlborn) -> the bitwise-anding with 0xFF is necessary to avoid sign extension when the byte is converted to an int.
Example
192.200.3.0 is the IP address in question. The final value is
This is generated in the following manner
192*(2^24) + 200*(2^16) + 3*(2^8) + 0*(2^0)
3221225472 + 13107200 + 768 = 3234333440
Now your code does the same, but using bitwise shifts
192 in binary is 11000000. First, it is added to result = 0;
result is now 11000000.
Then it is shifted left by 8 bits (effectively multiplying it by 2^8)
result is 11000000 00000000
Now, binary value of 200, which is 11001000 is added, making result now 11000000 11001000
This process is carried on, till you have the following 32 bit number,
11000000 11001000 00000011 00000000 which translates to the same 3234333440

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;
}

Convert Bytes to bits

I'm working with java.
I have a byte array (8 bits in each position of the array) and what I need to do is to put together 2 of the values of the array and get a value.
I'll try to explain myself better; I'm extracting audio data from a audio file. This data is stored in a byte array. Each audio sample has a size of 16 bits. If the array is:
byte[] audioData;
What I need is to get 1 value from samples audioData[0] and audioData[1] in order to get 1 audio sample.
Can anyone explain me how to do this?
Thanks in advance.
I'm not a Java developer so this could be completely off-base, but have you considered using a ByteBuffer?
Assume the LSB is at data[0]
int val;
val = (((int)data[0]) & 0x00FF) | ((int)data[1]<<8);
As suggested before, Java has classes to help you with this. You can wrap your array with a ByteBuffer and then get an IntBuffer view of it.
ByteBuffer bb = ByteBuffer.wrap(audioData);
// optional: bb.order(ByteOrder.BIG_ENDIAN) or bb.order(ByteOrder.LITTLE_ENDIAN)
IntBuffer ib = bb.asIntBuffer();
int firstInt = ib.get(0);
ByteInputStream b = new ByteInputStream(audioData);
DataInputStream data = new DataInputStream(b);
short value = data.readShort();
The advantage of the above code is that you can keep reading the rest of 'data' in the same way.
A simpler solution for just two values might be:
short value = (short) ((audioData[0]<<8) | (audioData[1] & 0xff));
This simple solution extracts two bytes, and pieces them together with the first byte being the higher order bits and the second byte the lower order bits (this is known as Big-Endian; if your byte array contained Little-Endian data, you would shift the second byte over instead for 16-bit numbers; for Little-Endian 32-bit numbers, you would have to reverse the order of all 4 bytes, because Java's integers follow Big-Endian ordering).
easier way in Java to parse an array of bytes to bits is JBBP usage
class Parsed { #Bin(type = BinType.BIT_ARRAY) byte [] bits;}
final Parsed parsed = JBBPParser.prepare("bit:1 [_] bits;").parse(theByteArray).mapTo(Parsed.class);
the code will place parsed bits of each byte as 8 bytes in the bits array of the Parsed class instance
You can convert to a short (2 bytes) by logical or-ing the two bytes together:
short value = ((short) audioData[0]) | ((short) audioData[1] << 8);
I suggest you take a look at Preon. In Preon, you would be able to say something like this:
class Sample {
#BoundNumber(size="16") // Size of the sample in bits
int value;
}
class AudioFile {
#BoundList(size="...") // Number of samples
Sample[] samples;
}
byte[] buffer = ...;
Codec<AudioFile> codec = Codecs.create(AudioFile.class);
AudioFile audioFile = codec.decode(buffer);
You can do it like this, no libraries or external classes.
byte myByte = (byte) -128;
for(int i = 0 ; i < 8 ; i++) {
boolean val = (myByte & 256) > 0;
myByte = (byte) (myByte << 1);
System.out.print(val ? 1 : 0);
}
System.out.println();
byte myByte = 0x5B;
boolean bits = new boolean[8];
for(int i = 0 ; i < 8 ; i++)
bit[i] = (myByte%2 == 1);
The results is an array of zeros and ones where 1=TRUE and 0=FALSE :)

Categories

Resources