先说说单精度float类型的压缩方法,lucene里面是将-1.0~125.0之间浮点数并且小数点部分为0的值使用1个字节压缩,当然必须排除-0.0f,其余的正数使用4个字节存储,负数使用5个字节存储(第一个字节是0xff)其余是原始的4个字节。
根据第一个字节就能对压缩的数值进行解析,-1~125的二进制形式为0b11111111~0b01111101,lucene将值加1并且将最高位置1,这样值就变成了0b10000000~0b11111110,考虑其余正数的最高位是符号位为0b00000000,其余负数的最高为是0b11111111,可以看出这三种情况是完全不冲突的,相信大家也能看出来为什么-1.0~125.0要排除-0.0f了吧,因为-0.0f的首字节是0b10000000跟前面(0b10000000~0b11111110)是冲突的。有兴趣的可以看看lucene的源码:
int intVal = (int) f;
final int floatBits = Float.floatToIntBits(f);
if (f == intVal
&& intVal >= -1
&& intVal <= 0x7D
&& floatBits != NEGATIVE_ZERO_FLOAT) {
// small integer value [-1..125]: single byte
out.writeByte((byte) (0x80 | (1 + intVal)));
} else if ((floatBits >>> 31) == 0) {
// other positive floats: 4 bytes
out.writeInt(floatBits);
} else {
// other negative float: 5 bytes
out.writeByte((byte) 0xFF);
out.writeInt(floatBits);
}
实际上双精度double类型的原理也是类似的,实现的时候跟float的方式稍有不同