Bit shuffling to change encoding from little endian - java

So in the program I need to read an number from the user which needs to be changed from little endian encoding to whatever encoding the user wants to change it to. The encoding entered by the user is just a 4 digits number which just means which byte should be where after the encoding. e.g. 4321 means put the 4th byte first followed by the 3rd and so on. the encoding can take other form such as 3214 etc.
This is my code, would really appreciate if someone point out where I am missing out.
import java.util.Scanner;
class encoding {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String byteOrder = sc.next();
long[] bitMask = { // little endian
Long.parseLong("11111111000000000000000000000000", 2),
Long.parseLong("00000000111111110000000000000000", 2),
Long.parseLong("00000000000000001111111100000000", 2),
Long.parseLong("00000000000000000000000011111111", 2)
};
int[] bytes = {
(int)(bitMask[0] & n),
(int)(bitMask[1] & n),
(int)(bitMask[2] & n),
(int)(bitMask[3] & n)
};
int result = 0;
shuffleBytes(bytes, byteOrder);
for (int i = 0; i < 4; i++) {
bytes[i] = bytes[i] << (i * 8);
result |= bytes[i];
}
System.out.println(result);
}
static void shuffleBytes(int[] bytes, String encoding) {
for (int i = 0; i < 4; i++) {
int index = Integer.parseInt(encoding.substring(i, i+1))-1;
int copy = bytes[i];
bytes[i] = bytes[index];
bytes[index] = copy;
}
}
}

Fixing your current solution
There are two problems:
1. Forgot to right-align bytes
In ...
int[] bytes = {
(int)(bitMask[0] & n),
(int)(bitMask[1] & n),
(int)(bitMask[2] & n),
(int)(bitMask[3] & n)
};
... you forgot to shift each "byte" to the right. As a result, you end up with a list of "bytes" of the form 0x……000000, 0x00……0000, 0x0000……00, 0x000000……. This is not a problem yet, but after shuffleBytes you shift each of these entries again using bytes[i] = bytes[i] << (i * 8);. As a result, the relevant parts (__) end up at a completely different spot or are shifted completely out of the integer.
To fix this, shift each (int)(bitMask[…] & n) to the right:
int[] bytes = {
(int)(bitMask[0] & n) >> (3*8),
(int)(bitMask[1] & n) >> (2*8),
(int)(bitMask[2] & n) >> (1*8),
(int)(bitMask[3] & n) >> (0*8)
};
2. Swapping more than once
In ...
static void shuffleBytes(int[] bytes, String encoding) {
for (int i = 0; i < 4; i++) {
int index = Integer.parseInt(encoding.substring(i, i+1))-1;
int copy = bytes[i];
bytes[i] = bytes[index];
bytes[index] = copy;
}
}
... you swap some bytes multiple times because you operate in-place. To understand what happens consider the following minimal example where we want to swap two bytes using order = "21". We inspect the variables before/after each iteration of the for loop.
The original input is bytes = {x, y} and order = "21"
We moved bytes[0] to bytes[1]. Now we have bytes = {y, x}.
But we are not finished yet. The loop continues and moves bytes[1] to bytes[0]. You assumed that bytes[1] would still be y at this point. However, because of the previous iteration this entry now holds x instead. Therefore, the result is bytes = {x, y}.
Here nothing changed, but for more entries you might also end up with something that is neither the original order nor the expected output order.
The easiest way to fix this is to write the result into a new array:
static int[] shuffleBytes(int[] bytes, String encoding) {
int[] result = new int[bytes.length];
for (int i = 0; i < 4; i++) {
int index = Integer.parseInt(encoding.substring(i, i+1))-1;
result[index] = bytes[i];
}
return result; // also adapt main() to use this return value
}
Alternative Solution
Even though you could fix your solution as described above I'm not too happy with it. Therefore, I propose this alternative solution which is cleaner, shorter, and more efficient.
import java.util.Scanner;
public class Encoding {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int input = sc.nextInt();
System.out.format("input = 0x%08x = %1$d%n", input);
String newOrder = sc.next();
int output = reorder(input, newOrder);
System.out.format("output = 0x%08x = %1$d%n", output);
}
/** #param newOrder permutation of "1234" */
static int reorder(int input, String newOrder) {
int output = 0;
for (char byte1Based : newOrder.toCharArray()) {
output <<= 8;
int shift = (byte1Based - '1') * 8;
output |= ((0xFF << shift) & input) >> shift;
}
return output;
}
}

Related

How to encode chars in 2-bits? in java

DNA molecules are denoted by one of four values: A, C, G, or T. I need to convert a string of characters from A, C, G, and T to an array of bytes, encoding each of the characters
with two bits.A with bits 00, C with bits 01, G with 10, and T with 11. I don't understand how to convert characters to 2 bits. I was trying to shift and mask, but got wrong result.
At the very beginning, I check if there are characters in the line. Then i convert each character into a bit value and insert it into an array. When i insert ACGT, in the output i got 0 1 3 2. And here I have a problem, because I don’t understand how to convert the value to 2 bits.
Scanner text = new Scanner(System.in);
String str = text.nextLine();
if (str.contains("A") && str.contains("C") && str.contains("G") && str.contains("T")){
System.out.println("");
}
else
{
System.out.println("wrong command format");
}
byte mas[] = str.getBytes();
System.out.println("String in byte array : " + Arrays.toString(mas));
for (int i = 0; i < mas.length; i++){
byte mask = 3;
byte number = mas[i];
byte result = (byte)((number >> 1) & mask);
System.out.println(result);
}
}
}
It seems that you want to save the bits in a byte. The following example might give some ideas.
public class Main
{
private static final int A = 0x00; // b00
private static final int C = 0x01; // b01
private static final int G = 0x02; // b10
private static final int T = 0x03; // b11
public static void main(String[] args) throws Exception
{
byte store = 0;
store = setByte(store, 0, A);
store = setByte(store, 1, C);
store = setByte(store, 2, G);
store = setByte(store, 3, T);
System.out.println(Integer.toBinaryString(store));
//11111111111111111111111111100100
System.out.println(getByte(store, 0)); //0
System.out.println(getByte(store, 1)); //1
System.out.println(getByte(store, 2)); //2
System.out.println(getByte(store, 3)); //3
}
//Behavior :: Store "value" into "store".
//Reminder :: Valid index 0 - 3. Valid value 0 - 3.
private static byte setByte(byte store, int index, int value)
{
store = (byte)(store & ~(0x3 << (2 * index)));
return store |= (value & 0x3) << (2 * index);
}
private static byte getByte(byte store, int index)
{
return (byte)((store >> (2 * index)) & 0x3);
}
}
I haven't tested this, but it may help you.
byte test = 69;
byte insert = 0b01;
byte index = 2;
final byte ones = 0b00000011;
//Clear out the data at specified index
test = (byte) (test & ~(ones << index));
//Insert data
test |= (byte) (insert << index);
It works as follows:
Clear the 2 bits at the index in the byte (using bitwise AND).
Insert the 2 data bits at the index in the byte using bitwise OR).
You can "convert" the chars ACGT to 0, 1, 2, 3 using bit arithmetic.
byte[] bytes = str.getBytes();
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte)(bytes[i] >> 1 & 3 ^ bytes[i] >> 2 & 1);
}
I suspect your initial check should be:
if (!str.matches("[ACGT]+") {
System.out.println("wrong command format");
return;
}

How can I create a stream of bits from a byte array? [duplicate]

How can i iterate bits in a byte array?
You'd have to write your own implementation of Iterable<Boolean> which took an array of bytes, and then created Iterator<Boolean> values which remembered the current index into the byte array and the current index within the current byte. Then a utility method like this would come in handy:
private static Boolean isBitSet(byte b, int bit)
{
return (b & (1 << bit)) != 0;
}
(where bit ranges from 0 to 7). Each time next() was called you'd have to increment your bit index within the current byte, and increment the byte index within byte array if you reached "the 9th bit".
It's not really hard - but a bit of a pain. Let me know if you'd like a sample implementation...
public class ByteArrayBitIterable implements Iterable<Boolean> {
private final byte[] array;
public ByteArrayBitIterable(byte[] array) {
this.array = array;
}
public Iterator<Boolean> iterator() {
return new Iterator<Boolean>() {
private int bitIndex = 0;
private int arrayIndex = 0;
public boolean hasNext() {
return (arrayIndex < array.length) && (bitIndex < 8);
}
public Boolean next() {
Boolean val = (array[arrayIndex] >> (7 - bitIndex) & 1) == 1;
bitIndex++;
if (bitIndex == 8) {
bitIndex = 0;
arrayIndex++;
}
return val;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public static void main(String[] a) {
ByteArrayBitIterable test = new ByteArrayBitIterable(
new byte[]{(byte)0xAA, (byte)0xAA});
for (boolean b : test)
System.out.println(b);
}
}
Original:
for (int i = 0; i < byteArray.Length; i++)
{
byte b = byteArray[i];
byte mask = 0x01;
for (int j = 0; j < 8; j++)
{
bool value = b & mask;
mask << 1;
}
}
Or using Java idioms
for (byte b : byteArray ) {
for ( int mask = 0x01; mask != 0x100; mask <<= 1 ) {
boolean value = ( b & mask ) != 0;
}
}
An alternative would be to use a BitInputStream like the one you can find here and write code like this:
BitInputStream bin = new BitInputStream(new ByteArrayInputStream(bytes));
while(true){
int bit = bin.readBit();
// do something
}
bin.close();
(Note: Code doesn't contain EOFException or IOException handling for brevity.)
But I'd go with Jon Skeets variant and do it on my own.
I needed some bit streaming in my application. Here you can find my BitArray implementation. It is not a real iterator pattern but you can ask for 1-32 bits from the array in a streaming way. There is also an alternate implementation called BitReader later in the file.
I know, probably not the "coolest" way to do it, but you can extract each bit with the following code.
int n = 156;
String bin = Integer.toBinaryString(n);
System.out.println(bin);
char arr[] = bin.toCharArray();
for(int i = 0; i < arr.length; ++i) {
System.out.println("Bit number " + (i + 1) + " = " + arr[i]);
}
10011100
Bit number 1 = 1
Bit number 2 = 0
Bit number 3 = 0
Bit number 4 = 1
Bit number 5 = 1
Bit number 6 = 1
Bit number 7 = 0
Bit number 8 = 0
You can iterate through the byte array, and for each byte use the bitwise operators to iterate though its bits.
Alternatively, you can use BitSet for this:
byte[] bytes=...;
BitSet bitSet=BitSet.valueOf(bytes);
for(int i=0;i<bitSet.length();i++){
boolean bit=bitSet.get(i);
//use your bit
}

How to manipulate the bits in a long?

I want to transform a long to binary code, then change some bits and get the long again. I have found this post Java long to binary but I still can't achieve what I want.
I think there is two ways to achieve my goal:
Going from long to bitset and to long again
Going from long to binary String and then to int array and then to long again
public static long changeHalf(long x){
int[] firstHalf = new int[32];
int[] secondHalf = new int[32];
int[] result = new int[64];
String binaryOfLong = Long.toBinaryString(x);
for (int i = 0; i < firstHalf.length; i++) {
}
for (int i = 0; i < secondHalf.length; i++) {
result[i] = secondHalf[i];
}
for (int i = 0; i < firstHalf.length; i++) {
result[i+32] = firstHalf[i];
}
String s = Arrays.toString(result);
return Long.parseLong(s);
}
Rather than converting a long to arrays of int, just use bitwise operations.
I want to swap the first 32 bits with the last 32 bits
That would be:
long result = ((x & 0xFFFFFFFF00000000l) >> 32) | ((x & 0x00000000FFFFFFFFl) << 32);
That masks off the first 32 bits, shifts them to the right, masks off the last 32 bits, shifts them to the left, and combines the result with | (OR).
Live example:
class Example
{
public static void main (String[] args) throws java.lang.Exception
{
long x = 0x1000000020000000l;
long result = ((x & 0xFFFFFFFF00000000l) >> 32) | ((x & 0x00000000FFFFFFFFl) << 32);
System.out.printf("0x%016X\n", x);
System.out.printf("0x%016X\n", result);
}
}
Outputs:
0x1000000020000000
0x2000000010000000
More in the Bitwise and Bit Shift Operators tutorial.

Generating all possible binary combinations

I am trying to generate all of the possible binary combinations for two bytes ex.
00000000 00000001
00000000 00000010
00000000 00000011
I have the class that I'm working on but its clearly not working at all. I cant get the method to return the output as it is generated.
I got the code below to work properly, but only for calculation 1 byte. How would I change this to calculate all of the possible outcomes for 2 bytes?
package referenceCode;
public class BinaryGenerator {
private int val = 0;
private int[] values = new int[]{0,1};
//This method converts the Binary Pattern output into a char[] so that it can be printed out to a file
public int[] binaryPatternToString() {
int numBits = 8;
values[0] = 0;
values[1] = 1;
int[] returned = null;
for (int i = 1; i < numBits; i++) {
returned = binaryGenerator(i);
for (int j = 1; j < numBits; j++) {
}
}
return returned;
}
private int[] binaryGenerator(int iVal) {
int[] moreValues = new int[values.length * 2];
int start = (int)Math.pow(2, iVal);
for (int j = 0; j < values.length; j++) {
moreValues[j * 2] = values[j] << 1;
moreValues[j * 2 + 1] = values[j] << 1 | 1;
}
values = moreValues;
for (int value : values) {
System.out.println(Integer.toBinaryString(value));
}
return moreValues;
}}
Would it be a better idea or more efficient to make it a recursive method instead of a method with a for loop?
As you may know all java Integers are based on binary numbers. So for 2 bytes, the maximum number is 2^16 = 65536. Simply loop through all numbers and get their binary values, zero-pad them if necessary and finally store them in a list. This will return all possible 2-byte binary numbers. For more bytes, simply increment the byte-variable.
Implementation:
int bytes = 2;
int nBits = bytes * 8;
int maxNumber = 1 << nBits; //this equals 2^nBits or in java: Math.pow(2,nbits)
ArrayList<String> binaries = new ArrayList<>();
for (int i = 0; i < maxNumber; i++) {
String binary = Integer.toBinaryString(i);
while (binary.length() != nBits) {
binary = "0" + binary;
}
binaries.add(binary);
}
System.out.println(binaries);
The bytes and nBits variables are included simply for clarity.
You can also use a recursive method. Start with an empty String and recursively add a 0 or a 1 to the start of the string and continue until you've reached the number of bits you wanted:
public static ArrayList<String> getBinaries(int bits, String current) {
ArrayList<String> binaries = new ArrayList<>();
if (current.length() == bits) {
binaries.add(current);
return binaries;
}
//pad a 0 and 1 in front of current;
binaries.addAll(getBinaries(bits, "0" + current));
binaries.addAll(getBinaries(bits, "1" + current));
return binaries;
}
You can call this function with: getBinaries(16,"") for 2 bytes.
I took the liberty of writing my own version so you can see a simpler way to produce these numbers.
The hardest part here is incrementing the list of booleans. In general it's just like adding 1. You increment the one's slot, and if it was already a 1, you move on to the 10s slot, and so on. Otherwise, you just loop through all the posobilities, printing each one out.
import java.util.ArrayList;
import java.util.List;
public class Sandbox {
// list of booleans to represent each bit
private static List<Boolean> bytes = new ArrayList<>();
public static void main(String[] args) {
// initialize the list to all false
for(int i = 0; i < 16; i++) {
bytes.add(false);
}
// calculate the number of permutations
int numPermutations = (int)Math.pow(2, 16);
// print the first permutation
print();
// loop through all permutations
for(int i = 0; i < numPermutations; i++) {
// increment the 2 bytes
increment();
// print the current permutation
print();
}
}
/**
* Prints out the current permutation
*/
private static void print() {
// loop through the bytes
for(Boolean bool : bytes) {
// print 1 or 0
if(bool)
System.out.print(1);
else
System.out.print(0);
}
// end the line
System.out.println();
}
/**
* Increment the bytes
*/
private static void increment() {
// set increment position to the end of the list
int position = bytes.size() - 1;
// loop through changing next digit if necessary, stopping
// if the front of the list is reached.
do {
bytes.set(position, !bytes.get(position));
} while(!bytes.get(position--) && position >= 0);
}
}

Bit manipulation and output in Java

If you have binary strings (literally String objects that contain only 1's and 0's), how would you output them as bits into a file?
This is for a text compressor I was working on; it's still bugging me, and it'd be nice to finally get it working. Thanks!
Easiest is to simply take 8 consecutive characters, turn them into a byte and output that byte. Pad with zeros at the end if you can recognize the end-of-stream, or add a header with length (in bits) at the beginning of the file.
The inner loop would look something like:
byte[] buffer = new byte[ ( string.length + 7 ) / 8 ];
for ( int i = 0; i < buffer.length; ++i ) {
byte current = 0;
for ( int j = 7; j >= 0; --j )
if ( string[ i * 8 + j ] == '1' )
current |= 1 << j;
output( current );
}
You'll need to make some adjustments, but that's the general idea.
If you're lucky, java.math.BigInteger may do everything for you.
String s = "11001010001010101110101001001110";
byte[] bytes = (new java.math.BigInteger(s, 2)).toByteArray();
This does depend on the byte order (big-endian) and right-aligning (if the number of bits is not a multiple of 8) being what you want but it may be simpler to modify the array afterwards than to do the character conversion yourself.
public class BitOutputStream extends FilterOutputStream
{
private int buffer = 0;
private int bitCount = 0;
public BitOutputStream(OutputStream out)
{
super(out);
}
public void writeBits(int value, int numBits) throws IOException
{
while(numBits>0)
{
numBits--;
int mix = ((value&1)<<bitCount++);
buffer|=mix;
value>>=1;
if(bitCount==8)
align8();
}
}
#Override
public void close() throws IOException
{
align8(); /* Flush any remaining partial bytes */
super.close();
}
public void align8() throws IOException
{
if(bitCount > 0)
{
bitCount=0;
write(buffer);
buffer=0;
}
}
}
And then...
if (nextChar == '0')
{
bos.writeBits(0, 1);
}
else
{
bos.writeBits(1, 1);
}
Assuming the String has a multiple of eight bits, (you can pad it otherwise), take advantage of Java's built in parsing in the Integer.valueOf method to do something like this:
String s = "11001010001010101110101001001110";
byte[] data = new byte[s.length() / 8];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) Integer.parseInt(s.substring(i * 8, (i + 1) * 8), 2);
}
Then you should be able to write the bytes to a FileOutputStream pretty simply.
On the other hand, if you looking for effeciency, you should consider not using a String to store the bits to begin with, but build up the bytes directly in your compressor.

Categories

Resources