package org.yamcs.parameterarchive; import java.nio.ByteBuffer; import org.yamcs.utils.BitReader; import org.yamcs.utils.BitWriter; /** * Implements the floating point compression scheme described here: * http://www.vldb.org/pvldb/vol8/p1816-teller.pdf * * @author nm * */ public class FloatCompressor { /** * *compress the first n elements from the array of floats into the ByteBuffer * */ static public void compress(float[] fa, int n, ByteBuffer bb) { BitWriter bw=new BitWriter(bb); int xor; int prevV = Float.floatToRawIntBits(fa[0]); bw.write(prevV, 32); int prevLz = 100; //such that the first comparison lz>=prevLz will fail int prevTz = 0; for(int i=1; i<n; i++) { // System.out.println("bb.position: "+bb.position()+" i: "+i+" fa.length: "+fa.length); int v = Float.floatToRawIntBits(fa[i]); xor = v^prevV; //If XOR with the previous is zero (same value), store single ‘0’ bit if(xor==0) { bw.write(0, 1); } else { //When XOR is non-zero, calculate the number of leading and trailing zeros in the XOR, store bit ‘1’ followed // by either a) or b): bw.write(1, 1); int lz = Integer.numberOfLeadingZeros(xor); int tz = Integer.numberOfTrailingZeros(xor); if((lz>=prevLz) && (tz>=prevTz) &&(lz<prevLz+7)) { //if((lz==prevLz)&&(tz==prevTz)) { //(a) (Control bit ‘0’) If the block of meaningful bits falls within the block of previous meaningful bits, //i.e., there are at least as many leading zeros and as many trailing zeros as with the previous value, //use that information for the block position and just store the meaningful XORed value. bw.write(0, 1); bw.write(xor>>prevTz, 32-prevLz-prevTz); } else { //(b) (Control bit ‘1’) Store the length of the number of leading zeros in the next 5 bits, then store the // length of the meaningful XORed value in the next 6 bits. Finally store the meaningful bits of the XORed value. int mb = 32-lz-tz; //meaningful bits bw.write(1, 1); bw.write(lz, 5); bw.write(mb, 5); bw.write(xor>>tz, mb); prevLz = lz; prevTz = tz; } } prevV = v; } bw.flush(); } public static float[] decompress(ByteBuffer bb, int n) { BitReader br = new BitReader(bb); float[] fa = new float[n]; int xor; int v = (int)br.read(32); fa[0] = Float.intBitsToFloat(v); int lz = 0; //leading zeros int tz = 0; //trailing zeros int mb = 0; //meaningful bits for(int i=1; i<fa.length; i++) { int bit = br.read(1); if(bit==0) { //same with the previous value fa[i]=fa[i-1]; } else { bit = br.read(1); if(bit==0) {//the block of meaningful bits falls within the block of previous meaningful bits, xor = br.read(mb)<<tz; v = xor^v; } else { lz = br.read(5); mb = br.read(5); //this happens when mb is 32 and overflows the 5 bits if(mb==0) mb=32; tz = 32-lz-mb; xor = br.read(mb)<<tz; v = xor^v; } fa[i] = Float.intBitsToFloat(v); } } return fa; } public static void compress(float[] fa, ByteBuffer bb) { compress(fa, fa.length, bb); } }