I am working on a compression algorithm.I am reading an image file of 8 bits/pixel and I want to pack these 8 bit values into 4 bits in order to compress.I want some useful insight into Bit Packing in Java and how can I approach this problem? I dont need a working solution.Just guidance.
Thanks in advance
Your compression routine could look as follows:
void compress(byte[] pic, byte[] picCompressed) {
boolean odd = false;
int pos = 0;
for (byte p : pic)
{
byte b = quantize(p);
if (odd) {
picCompressed[pos++] |= (byte)(b << 4);
} else {
picCompressed[pos] = b;
}
odd = !odd;
}
}
The original array is traversed in a loop. Controlled by an alternating odd variable, the compressed 4 bits are stuffed either in the upper or in the lower half of the byte position in the compressed array.
A simplistic quantizing routine would just ignore the lower 4 bits:
byte quantize(byte p) {
return (byte)((p >> 4) & 0x0F);
}
In practice, quantizing is non-uniform and often implemented using a look-up table. You could use an array of 256 bytes to assign a target value to every possible byte value.
Java has operators to test/manipulate the bits of a number. Take a look at this:
Bitwise and Bit Shift Operators
If you need to handle a larger amount of bits, there is also the Bitset class.
Basically what you need is just the bitwise operators to test/manipulate the bits of variables of either byte or int type.
Related
So the problem I am having is obtaining the least significant and most significant 16 bits of a number over 16 bits but not necessarily of any certain length.
If the number was an int which is 32 bits I believe I could just do something like:
int Num=0xFFFFFFFF
short most = (short)(Num & 0xFFFF0000);
short least =(short)(Num & 0x0000FFFF);
Result:
most=0xFFFF
least=0xFFFF
Which in theory should get me a short 16 bit number with the least and most significant bits. But the problem is I need to be able to do this for an arbitrary amount of bits number, so this approach will not work because it will change what I need to & the number with. Is there a better approach to getting these values?
It seems Like there would be a fairly simple way to do this, but I can't find anything online.
Thanks
Before the main subject. your code have wrong to get most.
you should shift right for 4.
short most = (short)((Num & 0xFFFF0000) >> 0x10);
I guess you want this approach.
// lenMost should be in 0 to 32
int[] divide(int target, int lenMost) {
int MASK = 0xFFFFFFFF;
int lenLeast = 32 - lenMost;
int ret[] = new int[2]();
// get most
ret[0] = target & (MASK << lenLeast)
ret[0] >>= lenLeast;
// get least
ret[1] = target & (MASK >> lenMost);
return ret;
}
If I had a byte instead of an integer, I could easily create a boolean array with 256 positions and check:
boolean[] allBytes = new boolean[256];
if (allBytes[value & 0xFF] == true) {
// ...
}
Because I have an integer, I can't have an array with size 2 billion. What is the fastest way to check if an integer is true or false? A set of Integers? A hashtable?
EDIT1: I want to associate for every possible integer (2 billion) a true or false flag.
EDIT2: I have ID X (integer) and I need a quick way to know if ID X is ON or OFF.
A BitSet can't handle negative numbers. But there's a simple way around:
class BigBitSet {
private final BitSet[] bitSets = new BitSet[] {new BitSet(), new BitSet()};
public boolean get(int bitIndex) {
return bitIndex < 0 ? bitSets[1].get(~bitIndex)
: bitSets[0].get(bitIndex);
}
...
}
The second BitSet is for negative numbers, which get translated via the '~' operator (that's better than simply negating as it works for Integer.MIN_VALUE, too).
The memory consumption may get up to 4 Gib, i.e., about 524 MB.
I feel stupid for even elaborating on this.
The smallest unit of information your computer can store is a bit, right? A bit has two states, you want two states, so lets just say bit=0 is false and bit=1 is true.
So you need as many bits as there are possible int's, 2^32 = 4,294,967,296. You can fit 8 bits into a byte, so you need only 2^32 / 8 = 536,870,912 bytes.
From that easily follows code to address each of these bits in the bytes...
byte[] store = new byte[1 << 29]; // 2^29 bytes provide 2^32 bits
void setBit(int i) {
int byteIndex = i >>> 3;
int bitMask = 1 << (i & 7);
store[byteIndex] |= bitMask;
}
boolean testBit(int i) {
int byteIndex = i >>> 3;
int bitMask = 1 << (i & 7);
return (store[byteIndex] & bitMask) != 0;
}
java.util.BitSet provides practically the same premade in a nice class, only you can use it to store a maximum of 2^31 bits since it does not work with negative bit indices.
Since you're using Java, use BitSet. It's fast and easy. If you prefer, you could also use an array of primitive longs or BigInteger, but this is really what BitSet is for.
http://docs.oracle.com/javase/7/docs/api/java/util/BitSet.html
Would that mean that the 100th constant would have to be 1 << 100?
You can use a BitSet which has any number bits you want to set or clear. e.g.
BitSet bitSet = new BitSet(101);
bitSet.set(100);
You can't do it directly because maximum size for a primitive number which can be used as a bitmask is actually 64 bit for a long value. What you can do is to split the bitmask into 2 or more ints or longs and then manage it by hand.
int[] mask = new int[4];
final int MAX_SHIFT = 32;
void set(int b) {
mask[b / MAX_SHIFT] |= 1 << (b % MAX_SHIFT);
}
boolean isSet(int b) {
return (mask[b / MAX_SHIFT] & (1 << (b % MAX_SHIFT))) != 0;
}
You can only create a simple bitmask with the number of bits in the primitive type.
If you have a 32 bit (as in normal Java) int then 1 << 31 is the most you can shift the low bit.
To have larger constants you use an array of int elements and you figure out which array element to use by dividing by 32 (with 32 bit int) and shift with % 32 (modula) into the selected array element.
Effective Java Item #32 suggests using an EnumSet instead of bit fields. Internally, it uses a bit vector so it is efficient, however, it becomes more readable as each bit has a descriptive name (the enum constant).
Yes, if you intend to be able to bitwise OR any or all of those constants together, then you're going to need a bit representing each constant. Of course if you use an int you will only have 32 bits and a long will only give you 64 bits.
I want to generate a random number of type short exactly like there is a function for integer type called Random.nextInt(134116). How can I achieve it?
There is no Random.nextShort() method, so you could use
short s = (short) Random.nextInt(Short.MAX_VALUE + 1);
The +1 is because the method returns a number up to the number specified (exclusive). See here
This will generate numbers from 0 to Short.MAX_VALUE inclusive (negative numbers were not requested by the OP)
The most efficient solution which can produce all possible short values is to do either.
short s = (short) random.nextInt(1 << 16); // any short
short s = (short) random.nextInt(1 << 15); // any non-negative short
or even faster
class MyRandom extends Random {
public short nextShort() {
return (short) next(16); // give me just 16 bits.
}
public short nextNonNegativeShort() {
return (short) next(15); // give me just 15 bits.
}
}
short s = myRandom.nextShort();
Java shorts are included in the -32 768 → +32 767 interval.
why wouldn't you perform a
Random.nextInt(65536) - 32768
and cast the result into a short variable ?
How about short s = (short) Random.nextInt();? Note that the resulting distribution might have a bias. The Java Language Specification guarantees that this will not result in an Exception, the int will be truncated to fit in a short.
EDIT
Actually doing a quick test, the resulting distribution seems to be uniformly distributed too.
Simply generate an int like:
short s = (short)Random.nextInt(Short.MAX_VALUE);
The generated int will be in the value space of short, so it can be cast without data loss.
I have one array of bytes. I want to access each of the bytes and want its equivalent binary value(of 8 bits) so as to carry out next operations on it. I've heard of BitSet but is there any other way of dealing with this?
Thank you.
If you just need the String representation of it in binary you can simply use Integer.toString() with the optional second parameter set to 2 for binary.
To perform general bit twiddling on any integral type, you have to use logical and bitshift operators.
// tests if bit is set in value
boolean isSet(byte value, int bit){
return (value&(1<<bit))!=0;
}
// returns a byte with the required bit set
byte set(byte value, int bit){
return value|(1<<bit);
}
You might find something along the lines of what you're looking in the Guava Primitives package.
Alternatively, you might want to write something like
public boolean[] convert(byte...bs) {
boolean[] result = new boolean[Byte.SIZE*bs.length];
int offset = 0;
for (byte b : bs) {
for (int i=0; i<Byte.SIZE; i++) result[i+offset] = (b >> i & 0x1) != 0x0;
offset+=Byte.SIZE;
}
return result;
}
That's not tested, but the idea is there. There are also easy modifications to the loops/assignment to return an array of something else (say, int or long).
BitSet.valueOf(byte[] bytes)
You may have to take a look at the source code how it's implemented if you are not using java 7
Java has bitwise operators. See a tutorial example.
The Java programming language also provides operators that perform bitwise and bit shift operations on integral types. The operators discussed in this section are less commonly used. Therefore, their coverage is brief; the intent is to simply make you aware that these operators exist.
The unary bitwise complement operator "~" inverts a bit pattern; it can be applied to any of the integral types, making every "0" a "1" and every "1" a "0". For example, a byte contains 8 bits; applying this operator to a value whose bit pattern is "00000000" would change its pattern to "11111111".
A byte value IS integral, you can check bit state using masking operations.
The least significant bit corresponds to the mask 1 or 0x1, the next bit correspond to 0x2, etc.
byte b = 3;
if((b & 0x1) == 0x1) {
// LSB is on
} else {
// LSB is off
}
byte ar[] ;
byte b = ar[0];//you have 8 bits value here,if I understood your Question correctly :)
Well I think I get what you mean. Now a rather substantial error with this is that it doesn't work on negative numbers. However assuming you're not using it to read file inputs, you might still be able to use it.
public static ArrayList<Boolean> toBitArr(byte[] bytearr){
ArrayList<Boolean> bitarr = new ArrayList<Boolean>();
ArrayList<Boolean> temp = new ArrayList<Boolean>();
int i = 0;
for(byte b: bytearr){
while(Math.abs(b) > 0){
temp.add((b % 2) == 1);
b = (byte) (b >> 1);
}
Collections.reverse(temp);
bitarr.addAll(temp);
temp.clear();
}
return bitarr;
}
Here is a sample, I hope it is useful for you!
DatagramSocket socket = new DatagramSocket(6160, InetAddress.getByName("0.0.0.0"));
socket.setBroadcast(true);
while (true) {
byte[] recvBuf = new byte[26];
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
String bitArray = toBitArray(recvBuf);
System.out.println(Integer.parseInt(bitArray.substring(0, 8), 2)); // convert first byte binary to decimal
System.out.println(Integer.parseInt(bitArray.substring(8, 16), 2)); // convert second byte binary to decimal
}
public static String toBitArray(byte[] byteArray) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteArray.length; i++) {
sb.append(String.format("%8s", Integer.toBinaryString(byteArray[i] & 0xFF)).replace(' ', '0'));
}
return sb.toString();
}