Skip to content

Commit 5814ed5

Browse files
committed
complete with GolombEncoder
1 parent caa45e2 commit 5814ed5

File tree

3 files changed

+105
-13
lines changed

3 files changed

+105
-13
lines changed

src/main/java/com/github/myibu/algorithm/data/Bits.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.github.myibu.algorithm.data;
2+
3+
import java.util.Iterator;
4+
import java.util.NoSuchElementException;
5+
26
/**
37
* Bits entity
48
* @author myibu
59
* Created on 2021/9/14
610
*/
7-
public class Bits {
11+
public class Bits implements Iterable<Bit> {
812
public static final int BYTE_SIZE = 8;
913
public static final int SHORT_SIZE = 16;
1014
public static final int INT_SIZE = 32;
@@ -457,4 +461,38 @@ public String toString() {
457461
.append(", used=").append(used).append("}");
458462
return builder.toString();
459463
}
464+
465+
@Override
466+
public Iterator<Bit> iterator() {
467+
return new Itr();
468+
}
469+
470+
private class Itr implements Iterator<Bit> {
471+
int cursor = 0;
472+
int lastRet = -1;
473+
474+
@Override
475+
public boolean hasNext() {
476+
return cursor != length();
477+
}
478+
479+
@Override
480+
public Bit next() {
481+
try {
482+
int i = cursor;
483+
Bit next = get(i);
484+
lastRet = i;
485+
cursor = i + 1;
486+
return next;
487+
} catch (IndexOutOfBoundsException e) {
488+
throw new NoSuchElementException();
489+
}
490+
}
491+
}
492+
493+
public Bit get(int index) {
494+
if (index < 0 || index >= used)
495+
throw new IndexOutOfBoundsException();
496+
return table[index];
497+
}
460498
}

src/main/java/com/github/myibu/algorithm/endode/GolombEncoder.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.myibu.algorithm.endode;
22

3+
import com.github.myibu.algorithm.data.Bit;
34
import com.github.myibu.algorithm.data.Bits;
45

56
/**
@@ -10,7 +11,7 @@
1011
*/
1112
public class GolombEncoder implements Encoder {
1213
/**
13-
*
14+
* encode n to binary bits based on argument m
1415
* @param n the value to encode
1516
* @param m m, like 5
1617
* @return the length of encoded bits
@@ -23,7 +24,7 @@ public Bits encode(int n, int m) {
2324
int r = n % m;
2425
int k = (int)(Math.ceil(Math.log(m) / Math.log(2)));
2526
if ((m & 0x01) == 0) {
26-
return bits.append(encodeToStandardBinary(r, k));
27+
return bits.append(encodeToBinary(r, k));
2728
} else {
2829
// truncated binary encoding
2930
if (r < Math.pow(2, k) - m) {
@@ -34,10 +35,6 @@ public Bits encode(int n, int m) {
3435
}
3536
}
3637

37-
private Bits encodeToStandardBinary(int x, int len) {
38-
return encodeToBinary(x, len);
39-
}
40-
4138
private Bits encodeToTruncatedBinary(int x, int n) {
4239
// Set k = floor(log2(n)), i.e., k such that 2^k <= n < 2^(k+1).
4340
int k = 0, t = n;
@@ -60,4 +57,55 @@ private Bits encodeToBinary(int x, int len) {
6057
while (s.length() < len) s = Bits.ofZero().append(s);
6158
return s;
6259
}
60+
61+
/**
62+
* decode binary bits to n
63+
* @param bits encoded binary bits
64+
* @param m m, like 5
65+
* @return decoded value
66+
*/
67+
public int decode(Bits bits, int m) {
68+
// To decode, read the first k bits.
69+
// If they encode a value less than u, decoding is complete.
70+
// Otherwise, read an additional bit and subtract u from the result.
71+
boolean isRStart = false;
72+
Bits qb = new Bits(), rb = new Bits();
73+
for (Bit bit: bits) {
74+
if (!isRStart && bit == Bit.ZERO) {
75+
isRStart = true;
76+
continue;
77+
}
78+
if (!isRStart) {
79+
qb.append(bit);
80+
} else {
81+
rb.append(bit);
82+
}
83+
}
84+
int q = qb.length();
85+
int r = 0;
86+
if ((m & 0x01) == 0) {
87+
r = encodeToBinary(rb);
88+
} else {
89+
r = decodeTruncatedBinary(rb, m);
90+
}
91+
return q * m + r;
92+
}
93+
94+
public int decodeTruncatedBinary(Bits bits, int m) {
95+
// Set k = floor(log2(n)), i.e., k such that 2^k <= n < 2^(k+1).
96+
int k = 0, t = m;
97+
while (t > 1) { k++; t >>= 1; }
98+
// Set u to the number of unused codewords = 2^(k+1) - n.
99+
int u = (1 << k+1) - m;
100+
int x = encodeToBinary(bits);
101+
return (x < u) ? x : (x - u);
102+
}
103+
104+
private int encodeToBinary(Bits bits) {
105+
int x = 0;
106+
for (int i = 0; i < bits.length(); i++) {
107+
x += (bits.get(i).value() << (bits.length() - i - 1));
108+
}
109+
return x;
110+
}
63111
}

src/test/java/com/github/myibu/algorithm/AlgorithmTest.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import org.junit.Test;
2121

2222
import java.nio.charset.StandardCharsets;
23+
import java.util.ArrayList;
2324
import java.util.Arrays;
25+
import java.util.List;
2426
import java.util.Set;
2527

2628
public class AlgorithmTest {
@@ -177,12 +179,16 @@ public void testLZ77Compressor() {
177179

178180
@Test
179181
public void testGolombEncoder() {
180-
int m = 5;
182+
int m = 4;
181183
GolombEncoder encoder = new GolombEncoder();
182-
System.out.println(5 + "= " + encoder.encode(5, m));
183-
System.out.println(6 + "= " + encoder.encode(6, m));
184-
System.out.println(7 + "= " + encoder.encode(7, m));
185-
System.out.println(8 + "= " + encoder.encode(8, m));
186-
System.out.println(9 + "= " + encoder.encode(9, m));
184+
List<Bits> encodeList = new ArrayList<>();
185+
for (int i = 1; i <= 9; i++) {
186+
encodeList.add(encoder.encode(i, m));
187+
}
188+
for (int i = 0; i < encodeList.size(); i++) {
189+
Bits bits = encodeList.get(i);
190+
System.out.println("encode " + (i+1) + " => " + bits);
191+
System.out.println("decode " + bits + " => " + encoder.decode(bits, m));
192+
}
187193
}
188194
}

0 commit comments

Comments
 (0)