將整個訊息序列編碼為 [0, 1) 區間內單一浮點數。核心參數:
[Low, High),隨符號處理持續縮小。設 d = High - Low 為當前區間長度。第 i+1 個符號區間更新:
high = Low + d * 符號上限;
low = Low + d * 符號下限;
High = high;
Low = low;
d *= 符號機率;
最終輸出 [Low, High) 區間內任一數值的二進位表示即為壓縮碼流。
#include <iostream>
#include <iomanip>
#define M 100 // 最大編碼長度
#define N 4 // 符號種類數
class ArithmeticCoder {
int count, length;
char symbol[N];
long double prob[N];
char code[M];
long double High, Low, high, low, d;
public:
ArithmeticCoder() : High(1.0), Low(0.0), d(1.0) {}
void inputSymbols() {
std::cout << "Input symbol and probability (e.g. a 0.5):\n";
for (int i = 0; i < N; ++i) {
std::cin >> symbol[i] >> prob[i];
}
count = N;
}
void inputCode() {
std::cout << "Input code sequence: ";
std::cin >> code;
length = strlen(code);
}
void encode() {
// 建立初始區間邊界
long double cum = 0.0;
long double upper[N], lower[N];
for (int i = 0; i < count; ++i) {
lower[i] = cum;
cum += prob[i];
upper[i] = cum;
}
// 逐符號編碼
for (int k = 0; k < length; ++k) {
int idx = -1;
for (int i = 0; i < count; ++i)
if (code[k] == symbol[i]) { idx = i; break; }
if (idx == -1) { std::cerr << "Unknown symbol: " << code[k] << std::endl; return; }
high = Low + d * upper[idx];
low = Low + d * lower[idx];
High = high;
Low = low;
d *= prob[idx];
std::cout << "Step " << k+1 << ": ["
<< std::setprecision(20) << Low << ", " << High << ")\n";
}
std::cout << "Final interval: [" << Low << ", " << High << ")\n";
std::cout << "Compressed value (mid): " << (Low + High) / 2 << std::endl;
}
};
int main() {
ArithmeticCoder ac;
ac.inputSymbols();
ac.inputCode();
ac.encode();
return 0;
}
| 挑戰 | 解決方案 |
|---|---|
| 浮點精度不足 | 使用 long double (80-bit) 或整數定點運算 (32/64-bit 移位實現) |
| 區間過小導致下溢 | 重新縮放:輸出確定位元,區間左移擴大 |
| 自適應機率模型 | 動態更新符號計數,同步編碼/解碼端模型 |
| 位元流輸出 | 緩衝位元,按位寫入檔案/網路流 |