算术编码FPAQ0(一个简单的0阶算术文件压缩器)

时间:2018-04-22 05:15:27

标签: c++ compression data-compression

我正在尝试理解fpaq0 aritmetic压缩器的代码,但我无法完全理解它。这是代码的链接 - fpaq0.cpp

我无法完全理解ct [512] [' 2]和cxt是如何工作的。我也不太清楚解码器是如何工作的。为什么在编码每个字符之前e.encode(0正在被召唤。

请注意;我已经理解链接中提供的算术编码器 - Data Compression with Arithmetic Encoding

  void update(int y) {
if (++ct[cxt][y] > 65534) {
  ct[cxt][0] >>= 1;
  ct[cxt][1] >>= 1;
}
if ((cxt+=cxt+y) >= 512)
  cxt=1;
}
   // Assume a stationary order 0 stream of 9-bit symbols
int p() const {
 return 4096*(ct[cxt][1]+1)/(ct[cxt][0]+ct[cxt][1]+2);
}
inline void Encoder::encode(int y) {

// Update the range
const U32 xmid = x1 + ((x2-x1) >> 12) * predictor.p();
assert(xmid >= x1 && xmid < x2);
if (y)
 x2=xmid;
else
x1=xmid+1;
predictor.update(y);

// Shift equal MSB's out
while (((x1^x2)&0xff000000)==0) {
putc(x2>>24, archive);
x1<<=8;
x2=(x2<<8)+255;
}
}

inline int Encoder::decode() {

// Update the range
const U32 xmid = x1 + ((x2-x1) >> 12) * predictor.p();
assert(xmid >= x1 && xmid < x2);
int y=0;
if (x<=xmid) {
 y=1;
 x2=xmid;
}
else
x1=xmid+1;
predictor.update(y);

// Shift equal MSB's out
while (((x1^x2)&0xff000000)==0) {
x1<<=8;
x2=(x2<<8)+255;
int c=getc(archive);
if (c==EOF) c=0;
x=(x<<8)+c;
}
return y;
}

1 个答案:

答案 0 :(得分:0)

fpaq0是一个文件压缩器,它使用0阶按位模型进行建模,并使用12位无进位算术编码器进行熵编码。 ct[512][2]存储每个上下文的计数器以计算符号概率。上下文(fpaq0中的order-0)是使用带有前导位的部分位计算的(为了简化计算)。

为了便于解释,我们暂时跳过EOF符号。在没有EOF符号的情况下计算如下的0阶上下文(简化):

// Full byte encoding
int cxt = 1; // context starts with leading one
for (int i = 0; i < 8; ++i) {
  // Encoding part
  int y = ReadNextBit();
  int p = GetProbability(ctx);
  EncodeBit(y, p);

  // Model updating
  UpdateCounter(cxt, y); // Update related counter
  cxt = (cxt << 1) | y; // shift left and insert new bit
}

对于解码,使用上下文而不使用EOF符号,如下所示(简化):

// Full byte decoding
int cxt = 1; // context starts with leading one
for (int i = 0; i < 8; ++i) {
  // Decoding part
  int p = GetProbability(ctx);
  int y = DecodeBit(p);
  WriteBit(y);

  // Model updating
  UpdateCounter(cxt, y); // Update related counter
  cxt = (cxt << 1) | y; // shift left and insert new bit
}

fpaq0被设计为流式压缩器。这意味着它不需要知道输入流的确切长度。那么,解码器应该如何知道何时停止? EOF符号恰好用于此。在对每个字节进行编码时,将零位编码为标志,以指示还有更多数据要遵循。一个表明我们到达了流的末尾。所以,解码器知道何时停止。这就是为什么我们的上下文模型是9位(EOF标志+ 8位数据)的原因。

现在,最后一部分:概率计算。 fpaq0仅使用order-0上下文中的过去符号计数来计算最终概率。

n0 = count of 0
n1 = count of 1
p = n1 / (n0 + n1)

应该解决两个实现细节:计数器溢出和除零。

计数器溢出通过将两个计数达到阈值时减半来解决。因为,我们正在处理p,这是有道理的。

通过在每个变量的公式中插入一个来解决除零。所以,

p = (n1 + 1) / ((n0 + 1) + (n1 + 1))