Divide byte into two smaller numbers - java

Like in topic. I am writing application where I must save as much RAM as possible. I want to split byte into two parts 4 bits each (numbers from 0 to 15) - how can I save and later read this values?

If what you want is store 2 numbers (range 0-15) in one byte, here's an example on how to save and restore them. Note that you have to make sure your original numbers are within the allowed range, otherwise this will not work.
// Store both numbers in one byte
byte firstNumber = 10;
byte secondNumber = 15;
final byte bothNumbers = (byte) ((firstNumber << 4) | secondNumber);
// Retreive the original numbers
firstNumber = (byte) ((bothNumbers >> 4) & (byte) 0x0F);
secondNumber = (byte) (bothNumbers & 0x0F);
Also worth noting that if you want to save as much memory as possible you shouldn't be using Java to start with. JVM already consumes memory by itself. Native languages are much more suited to this requirement.

You can get lower bits as
byte lower = b & 0xF;
higher bits as
byte higher = (b >> 4) & 0xF;
and back to one byte
byte b = (byte) (lower + (higher << 4));

Related

Is there a more efficient way to combine 2 bytes and get the resulting decimal value?

I have 2 bytes in a byte array, and I'd like to "merge" them together so as to get byte 2's binary appended to byte 1's binary, and then get the decimal value of that binary.
byte 1: 01110110
byte 2: 10010010
combined gives 16 bits: 0111011010010010.
desired output: 30354
I am doing it like this right now, but wanted to know if there's a way that doesn't involve strings?
StringBuilder combined = new StringBuilder();
byte[] buffer = new byte[2];
buffer[0] = input[i];
buffer[1] = input[i + 1];
combined.append(Integer.toBinaryString(buffer[0] & 255 | 256).substring(1));
combined.append(Integer.toBinaryString(buffer[1] & 255 | 256).substring(1));
int key = Integer.parseInt(combined.toString(), 2);
Thanks!
To concatenate two bytes together efficiently, some bitwise arithmetic is required. However, to achieve the result that you want, we need to operate on the bytes as int values, as the result may be represented by more than 8 bits.
Consequently, we need to ensure that we're always working with the least significant 8 bits of each value (keep in mind that negative integers are represented using leading 1s in binary instead of 0s).
This can be accounted for by performing a bitwise-and of each value with 0xFF:
byte higher = (byte) 0b01110110;
byte lower = (byte) 0b10010010;
int concatenated = ((higher & 0xFF) << 8) | (lower & 0xFF);
System.out.println(concatenated);
As expected, the output of this snippet is:
30354

Don't understand how these bitwise operators operate on bytes and integers

I am working with some code that takes in a binary file as input. However, I am having trouble understanding the for loop in the code, as I don't understand what the bitwise operators do to IFD_Address, such as the |=, <<, and & 0xff. I think IFD_Address refers to a pointer in the binary file, but I am not sure. What is this piece of code trying to achieve?
byte[] IFD_Address_tmp = Arrays.copyOfRange(bytes, 4, 8);
int IFD_Address = 0;
int i = 0;
int shiftBy = 0;
for (shiftBy = 0; shiftBy < 32; shiftBy += 8) {
IFD_Address |= ((long) (IFD_Address_tmp[i] & 0xff)) << shiftBy;
i++;
}
This behavior is best understood in terms of moving bits around, not numbers. Bytes comprise eight bits, integers, 32 bits. The loop basically takes each byte in the array and places the corresponding bits in the integer IFD_Address in 8-bit chunks, from right (least significant) to left (most significant), like this:
About the bitwise operations:
& 0xff is required to capture the 8 bits into an integer;
<< shifts the bits to the left to select the appropriate place in IFD_Address;
|= sets the bits in IFD_Address.
See this tutorial for details.

Converting short-list to byte array, but only using last X bits

I have to compress a list of short-values into a byte array, but only the last X bits of the value.
Given this method:
byte[] compress(int bitsPerWord, List<Short> input){
...
}
The BitsPerWorld will never be bigger than the given values in the input field.
Example: 10 bits per word => maximum value 1023
I also may not waste bits, I have to save X bits in the first Y bytes, and then append the next X bits directly to them.
Example:
Input(Short) [ 500, 150, 100 ]
Input(Binary):0000000111110100 0000000001101000 0000000001100100
Output (10 bits per short): 0111110100 0001101000 0001100100
Output (As byte array):0111 1101 0000 0110 1000 0001 1001 0000
What the result should look like
Any way to do this efficiently? BitSet seems not fitting for this task, because i would have to set every single bit explicit.
Thanks
Efficient in what way?
In terms of work required, extending BitSet adding a bulk put method and an index is super efficient; little work and thinking required.
The alternative, shifting and masking bits is moderately complicated in terms of programming effort if you know your ways with bitwise operations. It may be a major obstacle if you don't.
Considering you already use wrapper types and collections, indicating troughput is not your major concern, extending BitSet is probably all you need.
You need to perform some bit manipulations, and for that to work you need to find a repeatable pattern. In this case, you have a list of "short" values, but actually you just use the rightmost 10 bits. Since you want to pack those into bytes, the minimum repeatable pattern is 40 bits long (5 bytes, 4 10-bit values). That is the "block size" for processing.
You would then have a loop that would do the main parsing of full blocks, plus maybe a special case at the end for the final incomplete block.
byte[] pack10(List<Short> source) {
final int nBlk = source.size() / 4;
final int remBits = (source.size() % 4) * 10;
final int remBytes = (remBits / 8) + (remBits % 8 > 0 ? 1 : 0);
byte[] ret = new byte[nBlk*5 + remBytes];
final short bitPat = (short)0b0000001111111111;
for (int iBlk = 0; iBlk < nBlk; ++iBlk) {
// Parse full blocks
List<Short> curS = source.subList(iBlk*4, (iBlk+1)*4);
ret[iBlk*5 ] = (byte) ((curS.get(0) & bitPat) >> 2);
ret[iBlk*5+1] = (byte) ((curS.get(0) & bitPat) << 6
| (curS.get(1) & bitPat) >> 4);
ret[iBlk*5+2] = (byte) ((curS.get(1) & bitPat) << 4
| (curS.get(2) & bitPat) >> 6);
ret[iBlk*5+3] = (byte) ((curS.get(2) & bitPat) << 2
| (curS.get(3) & bitPat) >> 8);
ret[iBlk*5+4] = (byte) (curS.get(3) & bitPat);
}
// Parse final values
List<Short> remS = source.subList(nBlocks*4, source.size());
if (remS.size() >= 1) {
ret[nBlk*5 ] = (byte) ((remS.get(0) & bitPat) >> 2);
ret[nBlk*5+1] = (byte) ((remS.get(0) & bitPat) << 6);
}
if (remS.size() >= 2) { // The first byte is appended to
ret[nBlk*5+1] |= (byte) ((remS.get(1) & bitPat) >> 4);
ret[nBlk*5+2] = (byte) ((remS.get(1) & bitPat) << 4);
}
if (remS.size() == 3) { // The first byte is appended to
ret[iBlk*5+2] |= (byte) ((curS.get(2) & bitPat) >> 6);
ret[iBlk*5+3] = (byte) ((curS.get(2) & bitPat) << 2);
}
return ret;
}
That is a specific version for 10-bit values; if you want a version with a generic number of values you'd have to generalise from that. The bit pattern operations changes, and all the system becomes less efficient if the pattern is computed at runtime (i.e. if the number of bits is a variable like in your example).
There are several people who have already written a BitOutputStream in Java. Pick one of them, wrap it in a ByteArrayOutputStream, and you’re done.

How can I concatenate two bytes in java?

I have an integer called writePos that takes a value between [0,1023]. I need to store it in the last two bytes of a byte array called bucket. So, I figure I need to represent it as a concatenation of the array's last two bytes.
How would I go about breaking down writePos into two bytes that, when concatenated and cast into an int, produces writePos again?
How would I go about concatenating once I get it broken down into the bytes?
This would be covered high-level by a ByteBuffer.
short loc = (short) writeLocation;
byte[] bucket = ...
int idex = bucket.length - 2;
ByteBuffer buf = ByteBuffer.wrap(bucket);
buf.order(ByteOrder.LITTLE__ENDIAN); // Optional
buf.putShort(index, loc);
writeLocation = buf.getShort(index);
The order can be specified, or left to the default (BIG_ENDIAN).
The ByteBuffer wraps the original byte array, and changes to ByteBuffer effect on the byte array too.
One can use sequential writing and reading an positioning (seek), but here I use overloaded methods for immediate positioning with index.
putShort writes to the byte array, modifying two bytes, a short.
getShort reads a short from the byte array, which can be put in an int.
Explanation
A short in java is a two-byte (signed) integral number. And that is what is meant. The order is whether LITTLE_ENDIAN: least significant byte first (n % 256, n / 256) or big endian.
Bitwise operations.
To byte:
byte[] bytes = new byte[2];
// This uses a bitwise and (&) to take only the last 8 bits of i
byte[0] = (byte)(i & 0xff);
// This uses a bitwise and (&) to take the 9th to 16th bits of i
// It then uses a right shift (>>) then move them right 8 bits
byte[1] = (byte)((i & 0xff00) >> 8);from byte:
To go back the other way
// This just reverses the shift, no need for masking.
// The & here is used to handle complications coming from the sign bit that
// will otherwise be moved as the bytes are combined together and converted
// into an int
i = (byte[0] & 0xFF)+(byte[1] & 0xFF)<<8;
There is a working example here of some of the conversions that you can play around with:
http://ideone.com/eRzsun
You need to split the integer into two bytes. The high and the low byte. Following your description it's stored as bug endian in the array.
int writeLocation = 511;
byte[] bucket = new byte[10];
// range checks must be done before
// bitwise right rotation by 8 bits
bucket[8] = (byte) (writeLocation >> 8); // the high byte
bucket[9] = (byte) (writeLocation & 0xFF); // the low byte
System.out.println("bytes = " + Arrays.toString(bucket));
// convert back the integer value 511 from the two bytes
bucket[8] = 1;
bucket[9] = (byte) (0xFF);
// the high byte will bit bitwise left rotated
// the low byte will be converted into an int
// and only the last 8 bits will be added
writeLocation = (bucket[8] << 8) + (((int) bucket[9]) & 0xFF);
System.out.println("writeLocation = " + writeLocation);

Is there a way to represent int value in byte over 127 without doing bitwise operations?

I am really short on time for doing the learning of bitwise operations.
I want to convert large integer(>127) values without doing '<<' or anything similar.
I need byte representation of integer values used to identify sequence numbers of packets in header sent across UDP. If there is no solution I will introduce two bytes..
Something like: 1, 1 ; 1,2 ; 1,3 ; packet lost ; 1,4 ; packet lost; 2,1 ,2,2
and then reset it upon reaching 127; 127
I can introduce third, but this is rather ugly.
It would be really useful to have black box that is part of java api doing all that byte conversion for me. Is there?
Thanks,
To pack an unsigned 8-bit value into a byte:
static byte toByte(int i) {
if ((i < 0) || (i > 255))
throw new IllegalArgumentException(String.valueOf(i));
return (byte) i;
}
To convert back:
static int toInt(byte b) {
return (b < 0) ? (b + 256) : b;
}
After reading your comments on other answers, it sounds like you might want something like this:
byte[] b = BigInteger.valueOf(counter).toByteArray();
and
long counter = new BigInteger(b).longValue();
Since the length of the array would vary as the counter grows, you'd need some way to indicate its length or delimit it. But this technique will convert any integer value to an array of bytes.
Is the problem that you want unsigned bytes, as in, numbers between 128 and 255 inclusive?
That's...tricky. The Java language won't let you directly treat bytes as unsigned...but with library support it gets a little easier. Guava provides an UnsignedBytes utility class for some of these needs. Addition, multiplication, and subtraction are all exactly the same on signed and unsigned bytes.
EDIT: Judging from your additional comments, you might be interested in Ints.toByteArray(int) and the like, which work on types between byte and BigInteger.
According to my understanding, you want to separate an int into 4 bytes. If so, then just copy paste this code:
int i = /* your int */
int[] b = { (i >> 24) & 0xff, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff };
Indices 0-3 are each of the 4 bytes in the int.

Categories