Pack 3 ints into short - java

I am trying to pack 3 ints into short and then get the values back; I am using a test code with the following values:
160, 71, 50
But when I try to unpack the values, ​​x & z are wrong, I get 15, 71, 50 (please, note 15 when 160 is expected).
Why is this? thanks. My code is
public static void main(String[] args) {
int[] testValue = new int[]{160, 71, 50};
short packed = pack(testValue[0], testValue[1], testValue[2]);
int[] output = unpack(packed);
System.out.println(output[0]);
System.out.println(output[1]);
System.out.println(output[2]);
}
public static short pack(int x, int y, int z) {
return (short) (x << 12 | z << 8 | y);
}
public static int[] unpack(short packed) {
int x = packed >> 12 & 0xF;
int y = packed & 0xFF;
int z = packed >> 8 & 0xF;
return new int[]{x, y, z};
}

Well, it's impossible; let's see why. We have 3 values to pack 160, 71, 50:
160 == 10100000 (binary), 8 bits long
71 == 1000111 (binary), 7 bits long
50 == 110010 (binary), 6 bits long
Please, note, that
160 is 8 bits long
71 is 7 bits long
50 is 6 bits long
------------------
21 bits for all 3 numbers
we need at least 21 bits (8 + 7 + 6) to store all three numbers when char as well as short is 16 bit value only.

You don't have enough bits in a 16 bit short to pack those three values.
Here is a breakdown of your bits:
160 << 12 = 0x0AA000
50 << 8 = 0x003200
71 << 0 = 0x000047
ORing these together results in:
0xA3247
Which can be stored in 3 bytes not two.
When casting to a short you end up with
0x3247
You could fit three values in the short if you could store each number in 5 bits individually.
Each number ranging from 0 - 31 for unsigned values. With only one value being able to take up 6 bits. This would yield 5 + 5 + 6 = 16 bits.

Related

Combine two 3 byte integers, and one 2 byte integer into one 8 byte integer

Trying to store three integers into one to use for a hash, and decode back into their original values.
The variables:
x = 3 byte integer (Can be negative)
z = 3 byte integer (Can be negative)
y = 2 byte integer (Cannot be negative)
My current code - doesn't work with negatives:
long combined = (y) | (((long) z) << 16) | ((((long) x)) << 40);
int newX = (int) (combined >> 40); // Trim off 40 bits, leaving the heading 24
int newZ = (int) ((combined << 24) >> (40)); // Trim off 24 bits left, and the 16 bits to the right
int newY = (int) ((combined << 48) >> 48); // Trim off all bits other then the first 16
It doesn't work for negatives because your "3 byte integer" or "2 byte integer" is actually a regular 4-byte int. If the number is negative, all the highest bits will be set to "1"; if you binary-or the numbers together, these high 1 bits will overwrite the bits from the other numbers.
You can use bit-masking to encode the number correctly:
long combined = (y & 0xffff) | (((long) z & 0xffffff) << 16) | ((((long) x & 0xffffff)) << 40);
This will cut off the high-bits outside the 16 or 24 bit range that you're interested in.
The decoding already works fine, because the bit-shifting that you perform takes care of sign-extension.

Folding paper strip and generate numbers while unfolding

I have an assignment question that I am struggling with and need some direction to solve.
Suppose i have a strip of paper and i fold it from the center such that the left half goes behind the right half. Then i number the folded peices in sequence i get the numbers when i unfold as follows.
1 : 2
If i fold twice i get the numbers when unfolded as follows
1 : 4 : 3 : 2
if I fold thrice i get as follows
1 8 5 4 3 6 7 2
I want to generate the array of numbers when I fold it n times. so if i fold it for example 25 times i will get 2^25 numbers in similar sequence.
These are the observations i made
the first and last numbers are always 1 and 2.
the middle two numbers are always 4 and 3
the number at index 1 is largest number and number at second last location is second largest number.
It looks like a preorder traversal of binary search tree but I dont know how that helps.
I tried to construct binary tree from the preorder and then convert it to inorder assuming that I can reverse this process to get the same series and I was wrong about it.
EDIT : For searching an element in this generated array I can do a sequential search which will be O(n) efficient. But I realise there has to be a much faster way to search for a number in this series.
I cannot do binary search because this is not sorted and there are over a billion numbers when 25+ foldings are done.
What kind of search tactics can i use to find a number and its index?
This was one of the reasons I wanted to convert it into a binary search tree which will have log(n) search efficiency.
EDIT 2: I tried the table folding algorithm as suggested by one of the answers and it is not memory efficient. I cannot store over a billion numbers in my memory so there has to be a way to find a numbers index without actually creating the array of numbers.
1st fold: 1 2
2nd fold: 1 4 3 2
3rd fold: 1 8 5 4 3 6 7 2
4th fold: 1 16 9 8 5 12 13 4 3 14 11 6 7 10 15 2
Generate table (with example to 4th fold)
Imagine you have a nth fold paper and then unfold it.
Generate a table with size ( column = 1, row = 2^n ) and fill the column from down to up with values in ascending order
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
Resize the table to size (column = org. column*2, row = org. row / 2) recursively by sticking top x row to bottom x row from back to front
8 9
7 10
6 11
5 12
4 13
3 14
2 15
1 16
4 13 12 5
3 14 11 6
2 15 10 7
1 16 9 8
2 15 10 7 6 11 14 3
1 16 9 8 5 12 13 4
1 16 9 8 5 12 13 4 3 14 11 6 7 10 15 2
Read the final 1 row table from front to end as result
1 16 9 8 5 12 13 4 3 14 11 6 7 10 15 2
The remaining work to you is to prove this work and then code it (I only test up to n=4 because I am lazy)
You can calculate the number of a fold without having to calculate the whole sequence by using bit-reversal (which reverses the binary representation of a number, so that e.g. 0001 becomes 1000).
These are the sequences you get with bit reversal:
1 bit: 0 1
2 bits: 0 2 1 3
3 bits: 0 4 2 6 1 5 3 7
4 bits: 0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15
And these are the paper-folding sequences (counting from 0):
1 fold: 0 1
2 folds: 0 3 2 1
3 folds: 0 7 4 3 2 5 6 1
4 folds: 0 15 8 7 4 11 12 3 2 13 10 5 6 9 14 1
If you split the paper-folding sequences into even and odd numbers, you get:
0
1
0 2
3 1
0 4 2 6
7 3 5 1
0 8 4 12 2 10 6 14
15 7 11 3 13 5 9 1
You'll see that the paper-folding sequences are the same as the bit-reversal sequences, but with the first half (even numbers) interlaced with the reverse of the second half (odd numbers).
You'll also notice that each pair of adjacent even/odd numbers adds up to 2n-1 (where n is the number of folds), which means they are each other's inverse, and you can calculate one from the other using a bit-wise NOT.
So, to get the paper-folding number of fold x (counting from 0) of a strip folded n times:
divide x by 2, perform bitwise NOT if x was odd, then bit-reverse (using n digits)
Example (folding 4 times):
fold x/2 binary inverted bit-reversed from 1
0 0 0000 0000 0 1
1 0 0000 1111 1111 15 16
2 1 0001 1000 8 9
3 1 0001 1110 0111 7 8
4 2 0010 0100 4 5
5 2 0010 1101 1011 11 12
6 3 0011 1100 12 13
7 3 0011 1100 0011 3 4
8 4 0100 0010 2 3
9 4 0100 1011 1101 13 14
10 5 0101 1010 10 11
11 5 0101 1010 0101 5 6
12 6 0110 0110 6 7
13 6 0110 1001 1001 9 10
14 7 0111 1110 14 15
15 7 0111 1000 0001 1 2
Example: billionth fold: (folding 30 times)
fold: 1,000,000,000
counting from 0: 999,999,999 (x is odd)
x/2: 499,999,999
binary: 011101110011010110010011111111 (30 digits)
bitwise NOT: 100010001100101001101100000000 (because x was odd)
bit-reversed: 000000001101100101001100010001
decimal: 3,560,209
counting from 1: 3,560,210
I don't speak Java, but something like this should do the trick:
public static long foldIndex(int n, long x) { // counting from zero
return Long.reverse((x & 1) == 0 ? x >>> 1 : ~(x >>> 1)) >>> (Long.SIZE - n);
}
Here'a an algorithm to find what index a number will be at after the
unfolding.
It keeps track of the coordinates of where your search number is moving to based on the folds. For example, if you are interested in 3 folds (n=3, numFolds) and you want to know where the number 7 will be (searchNumber), the algorithm runs as follows:
Initial State:
8
7
6
5
4
3
2
1
The 7 is at [1,7] - column 1, row 7
Now, when we fold the top half down:
4 5
3 6
2 7
1 8
The 7 is at [2, 1] - column 2, row 2
When we do the next fold the 7 does not move (hence the if (row > half) logic)
2 7 6 3
1 8 5 4
On the last fold:
1 8 5 4 3 6 7 2
The 7 is at [7, 1] - column 7, row 1 and the code will return 7.
public static long getIndexOfAfterFold (long numFolds, long searchNumber)
{
long total = (long) Math.pow(2, numFolds);
long [] coordsOfSearchNumber = new long [] {1, searchNumber};
int iterations = 0;
while (iterations < numFolds)
{
long half = total / 2;
long row = coordsOfSearchNumber[1];
// we are folding down
if (row > half)
{
long newRow = (total - row) + 1;
long col = coordsOfSearchNumber[0];
long newFoldThickness = (long) Math.pow(2, iterations + 1);
long newCol = newFoldThickness - (col - 1);
coordsOfSearchNumber[0] = newCol;
coordsOfSearchNumber[1] = newRow;
}
total = total / 2;
iterations++;
}
return coordsOfSearchNumber[0];
}
EDIT: Converted the above code to use long instead on int.
Notes:
It runs in O(n) time where n is the number of folds.
Usage: System.out.println(getIndexOfAfterFold(4, 13));
This code will give the list of all numbers after the folding
Note: This is based on the answer supplied by #hk6279 (the table folding algorithm)
public static void unFold (int numFolds)
{
int total = (int) Math.pow(2, numFolds);
List<ArrayList<Integer>> table = new ArrayList<ArrayList<Integer>> (total);
// populate the single column table
for (int i = 0; i < total; i++)
{
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(i + 1);
table.add(list);
}
int iterations = 0;
while (iterations < numFolds)
{
int half = table.size() / 2;
// place the fold back on itself
for (int i = 0; i < half; i++)
{
ArrayList<Integer> list = table.get(i);
ArrayList<Integer> foldList = table.get(table.size() - (i + 1));
// reverse the fold
Collections.reverse(foldList);
// add the fold to front
list.addAll(foldList);
}
// remove the part we folded
table.subList(half, table.size()).clear();
iterations++;
}
System.out.println(table);
}
This is what n=5 looks like:
1, 32, 17, 16, 9, 24, 25, 8, 5, 28, 21, 12, 13, 20, 29, 4, 3, 30, 19, 14, 11, 22, 27, 6, 7, 26, 23, 10, 15, 18, 31, 2
I don't know Java, but this should be easy to port and works for arbitrary numbers of folds. Idea's about the same as m69's, so I won't explain the logic myself.
#include <iostream>
size_t reverse(size_t n, int bits)
{
size_t result = 0;
size_t msb_value = 1 << (bits - 1);
while (n)
{
if (n & 1) result |= msb_value;
msb_value >>= 1;
n >>= 1;
}
return result;
}
struct Fold_Sequence
{
Fold_Sequence(size_t folds) : folds_(folds), max_(1 << folds) { }
size_t operator[](size_t i) const
{
size_t x = reverse((i / 2) % max_, folds_);
return i & 1 ? (max_ - x - 1) : x;
}
size_t folds_, max_, i = 0;
};
int main()
{
const size_t folds = 4;
const unsigned num_parts = 1 << folds;
Fold_Sequence seq{folds};
for (unsigned j = 0; j < num_parts; ++j)
std::cout << seq[j] + 1 << '\n';
}
I liked the elegance of hk6279's solution too, so I implemented it (also in C++, and I was too lazy to use a multidimensional array/vector<vector<>> and have to resize things carefully all the time, so it's inefficiently implemented using a map keyed on x,y coordinates):
#include <iostream>
#include <map>
#define DBG(X) do { std::cout << X << '\n'; } while (false)
typedef std::pair<size_t, size_t> Coord;
struct matrix : std::map<Coord, size_t>
{
matrix(size_t n)
: y_size_(n)
{
for (size_t i = 0; i < n; ++i)
(*this)[{0, i}] = i; // bottom left is 0,0; 0,1 is above
}
void fold()
{
size_t x_size_ = x_size();
for (size_t y = y_size_ / 2; y < y_size_; ++y)
for (size_t x = 0; x < x_size_; ++x)
move(x, y, x_size_ * 2 - x - 1, y_size_ - y - 1);
y_size_ /= 2;
}
void move(size_t from_x, size_t from_y, size_t to_x, size_t to_y)
{
DBG("move(" << from_x << ',' << from_y << " -> " << to_x << ',' << to_y
<< ") value " << ((*this)[{from_x, from_y}]));
(*this)[{to_x, to_y}] = (*this)[{from_x, from_y}];
erase({from_x, from_y});
}
size_t operator()(size_t x, size_t y) const
{
auto it = find({x, y});
if (it != end()) return it->second;
std::cerr << "m(" << x << ',' << y << ") doesn't exist\n";
exit(1);
}
size_t x_size() const { return size() / y_size_; }
size_t y_size() const { return y_size_; }
size_t y_size_;
};
std::ostream& operator<<(std::ostream& os, const matrix& m)
{
for (size_t y = m.y_size_ - 1; y <= m.y_size_; --y)
{
for (size_t x = 0; x < m.x_size(); ++x)
os << m(x, y) << ' ';
os << '\n';
}
return os;
}
int main()
{
const size_t n = 4;
matrix m(1 << n);
for (int i = 0; i < n; ++i)
{
m.fold();
std::cout << i+1 << " folds ==> " << m.x_size() << 'x' << m.y_size()
<< " matrix:\n" << m << '\n';
}
}

Bitwise Operators Left Shift

I'm confused with bitwise operators. Whenever I do 99(0110 0011) << 2, the answer is 396. My understanding with left shifts is that add two 0s on the right side. So my answer would be 140(1000 1100) and not 396. Why is the answer 396 for 99 << 2 in Java?
You are only showing 8 bits, but an int is 32 bits.
byte 8 bits
short 16 bits
int 32 bits
long 64 bits
Integer calculations in Java are coerced to int or long, so even if your 99 value was a byte, the result of ((byte)99) << 2 is still an int.
0110 0011 = 99 (byte)
0000 0000 0000 0000 0000 0001 1000 1100 = 396 (int)
Now, you can always cast it back to a byte, which will discard all high-order bits:
(byte)(99 << 2) = (byte)0b10001100 = (byte)0x8C = -116
Or you can discard the high-order bits while keeping it an int:
(99 << 2) & 0xFF = 0b10001100 = 0x0000008C = 140
Because a Java int is a signed 32-bit quantity (not 8 bits) and a bitwise left shift by 2 (<< 2) is the same as * 4. You can see this like
int i = 99;
System.out.printf(" %s (%d)%n", Integer.toBinaryString(i), i);
i <<= 2;
System.out.printf("%s (%d)%n", Integer.toBinaryString(i), i);
Output is
1100011 (99)
110001100 (396)

Can I bit shift 0 to the beginning?

I'm trying to learn bit shifting/masking. Here is my code:
int health = 511; // max 512, 9 bits
int aimAngle = 510; // max 512, 9 bits
int test = 511; // max 512, 9 bits
boolean bool = false; // max 1, 1 bit
int packed;
packed = health | aimAngle << 9 | test << 18 | (bool?1:0) << 19;
Debug.log("health: " + ((packed ) & 0b111111111));
Debug.log("aimAngle: " + ((packed >> 9) & 0b111111111));
Debug.log("test: " + ((packed >> 18) & 0b111111111));
Debug.log("bool: " + ((packed >> 19) & 0b1));
I'm getting all the values correctly except bool. It's always 1. What is wrong? Can't I shift zero to the beginning?
test is up to nine bits long. You shift it right 18 places. Therefore it occupies bits 18 to 27. You need to shift bool to place 28 to avoid it, not to place 19.
The 19th digit of packed is the second digit of test, which is a 1.

How can I split/combine bytes into audio?

I'm playing around with audio in Java. I discovered that a commonly used AudioFormat uses two bytes. However, I couldn't figure out how to put the bytes together into a single int. So I tried doing it in reverse:
public class SineWave {
public static void main(String[] args) throws LineUnavailableException {
int hz = 440;
int samplerate = 16384;
int amplitude = 127;
AudioFormat format = new AudioFormat((float) samplerate, 16, 1, true, true);
SourceDataLine sdl = AudioSystem.getSourceDataLine(format);
sdl.open(format, samplerate * 2);
sdl.start();
while (true) {
byte[] toWrite = new byte[samplerate * 2];
for (int x = 0; x < samplerate; x++) {
int y = (int) Math.round(amplitude * Math.sin(2 * Math.PI * x * hz / samplerate));
byte b1 = (byte) (y & 0xFF);
byte b2 = (byte) ((y >> 8) & 0xFF);
toWrite[2 * x] = b1;
toWrite[2 * x + 1] = b2;
// System.out.printf("%d %d%n", b1, b2);
}
sdl.write(toWrite, 0, toWrite.length);
}
}
}
However, this only works up to an amplitude of 127. When the System.out.printf is uncommented, it is clear that this amplitude uses only 1 byte. When I go up to 128, I get outputs like this (and ugly sounds):
0 0
21 0
42 0
62 0
80 0
96 0
109 0
118 0
125 0
-128 0
127 0
123 0
115 0
104 0
90 0
73 0
55 0
35 0
13 0
Negative values are similar, without the change in sign, and the second byte is always -1
I have deduced that this is because of signed bytes and two's complement, but I still can't figure out what I can do to fix this.
How does Java compose its audio?
You are on the right track, although you might have your byte ordering backwards (try swapping b1 and b2 in the toWrite assignments to see if that makes things sound better). That could explain why things sound bad. Also, an amplitude of 127 is very small so you should try increasing it to the max (32767).
The way you are printing the bytes out is probably adding to the confusion. Splitting a signed 16-bit number into 2 signed 8-bit numbers doesn't really make any sense. Consider when the 16-bit number is -1 (0xffff), you print out two signed bytes and you get -1 (0xff) and -1 (0xff). You'd be better off printing the bytes out as hex values and dealing with the sign in your head.

Categories