brouter/brouter-codec/src/main/java/btools/codec/NoisyDiffCoder.java
2022-07-25 06:14:46 +02:00

80 lines
1.8 KiB
Java

package btools.codec;
/**
* Encoder/Decoder for signed integers that automatically detects the typical
* range of these numbers to determine a noisy-bit count as a very simple
* dictionary
* <p>
* Adapted for 3-pass encoding (counters -&gt; statistics -&gt; encoding )
* but doesn't do anything at pass1
*/
public final class NoisyDiffCoder {
private int tot;
private int[] freqs;
private int noisybits;
private StatCoderContext bc;
private int pass;
/**
* Create a decoder and read the noisy-bit count from the gibe context
*/
public NoisyDiffCoder(StatCoderContext bc) {
noisybits = bc.decodeVarBits();
this.bc = bc;
}
/**
* Create an encoder for 3-pass-encoding
*/
public NoisyDiffCoder() {
}
/**
* encodes a signed int (pass3 only, stats collection in pass2)
*/
public void encodeSignedValue(int value) {
if (pass == 3) {
bc.encodeNoisyDiff(value, noisybits);
} else if (pass == 2) {
count(value < 0 ? -value : value);
}
}
/**
* decodes a signed int
*/
public int decodeSignedValue() {
return bc.decodeNoisyDiff(noisybits);
}
/**
* Starts a new encoding pass and (in pass3) calculates the noisy-bit count
* from the stats collected in pass2 and writes that to the given context
*/
public void encodeDictionary(StatCoderContext bc) {
if (++pass == 3) {
// how many noisy bits?
for (noisybits = 0; noisybits < 14 && tot > 0; noisybits++) {
if (freqs[noisybits] < (tot >> 1))
break;
}
bc.encodeVarBits(noisybits);
}
this.bc = bc;
}
private void count(int value) {
if (freqs == null)
freqs = new int[14];
int bm = 1;
for (int i = 0; i < 14; i++) {
if (value < bm)
break;
else
freqs[i]++;
bm <<= 1;
}
tot++;
}
}