Skip to content

Instantly share code, notes, and snippets.

@ztellman
Created September 9, 2015 19:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ztellman/b1dfb60e73d5b210716b to your computer and use it in GitHub Desktop.
Save ztellman/b1dfb60e73d5b210716b to your computer and use it in GitHub Desktop.
package compression;
import java.lang.Exception;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
public class FPC {
// adapted from http://users.ices.utexas.edu/~burtscher/papers/tr08.pdf
private static final int PREDICT_TABLE_SIZE = 32768;
public static void compress(DoubleBuffer in, ByteBuffer out) {
int hash = 0, dhash = 0;
long val, prev = 0, pred1 = 0, pred2 = 0;
boolean even = true;
long[] fcm = new long[PREDICT_TABLE_SIZE];
long[] dfcm = new long[PREDICT_TABLE_SIZE];
int headerLength = (int) Math.ceil(in.remaining() / 2.0f);
out.position(headerLength);
int index = 0;
while (in.hasRemaining()) {
val = Double.doubleToRawLongBits(in.get());
// direct predictor table
long xor1 = pred1 ^ val;
fcm[hash] = val;
hash = ((hash << 6) ^ (int)(val >>> 48)) & (PREDICT_TABLE_SIZE - 1);
pred1 = fcm[hash];
// offset predictor table
long stride = val - prev;
long xor2 = (prev + pred2) ^ val;
dfcm[dhash] = stride;
dhash = ((dhash << 2) ^ (int)(stride >>> 40)) & (PREDICT_TABLE_SIZE - 1);
pred2 = dfcm[dhash];
byte code = 0;
if (xor1 < 0 || xor1 > xor2) {
xor1 = xor2;
code = 0x8;
}
long xor = xor1;
byte bcode = 8;
for (int i = 0; i < 8; i++) {
if ((0xFF00000000000000L & xor) == 0) {
xor <<= 8;
bcode--;
} else {
break;
}
}
if (bcode > 4) bcode--;
if (even) {
code |= bcode;
out.put(index >> 1, code);
} else {
code = (byte)((code | bcode) << 4);
out.put(index >> 1, (byte)(code | out.get(index >> 1)));
}
int limit = bcode > 3 ? bcode + 1 : bcode;
for (int i = limit-1; i >= 0; i--) {
int offset = (i << 3);
long mask = 0xFFL << offset;
out.put((byte)((xor1 & mask) >> offset));
}
prev = val;
index++;
even = !even;
}
}
public static void decompress(int length, ByteBuffer in, DoubleBuffer out) {
int hash = 0, dhash = 0;
long prev = 0, pred1 = 0, pred2 = 0;
long[] fcm = new long[PREDICT_TABLE_SIZE];
long[] dfcm = new long[PREDICT_TABLE_SIZE];
int headerLength = (int) Math.ceil(length / 2.0f);
in.position(headerLength);
boolean even = true;
for (int i = 0; i < length; i++) {
byte code = in.get(i >> 1);
if (!even) code >>= 4;
code &= 0xF;
boolean fcmPredictor = (code & 0x8) != 0x8;
byte bcode = (byte)(code & 0x7);
bcode = bcode > 3 ? (byte)(bcode + 1) : bcode;
long val = 0;
for (int j = 0; j < bcode; j++) {
val <<= 8;
val |= in.get() & 0xFF;
}
if (!fcmPredictor) {
pred1 = pred2;
}
val ^= pred1;
out.put(Double.longBitsToDouble(val));
// standard predictor table
fcm[hash] = val;
hash = ((hash << 6) ^ (int)(val >>> 48)) & (PREDICT_TABLE_SIZE - 1);
pred1 = fcm[hash];
// offset predictor table
long stride = val - prev;
dfcm[dhash] = stride;
dhash = ((dhash << 2) ^ (int)(stride >>> 40)) & (PREDICT_TABLE_SIZE - 1);
pred2 = val + dfcm[dhash];
prev = val;
even = !even;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment