#include <iostream> #include <cmath> #include <algorithm> #include <numeric> #include <iterator> #include <vector> #include <cstdlib> #include <cstddef> #include <stdint.h> #include <iomanip> enum { // Config ZERO_POS = 2, INDEX_SIZE = 5, VALUE_LIMIT = -100, // Constants"Internal error: nibble buffer overflow\n"; exit(1); } *stream++ = block; } block = 0; pos = 0; } }; class ArWriter { // http://w...content-available-to-author-only...s.com/ac_arithmetic.html uint16_t* stream; uint16_t* table; uint16_t* tableEnd; uint16_t high; uint16_t low; uint16_t result; uint16_t resultUsed; uint16_t underflows; public: ArWriter(uint16_t* p, uint16_t* t, uint16_t* e) : stream(p) , table(t) // Zero value in *(t-1) expected , tableEnd(e) , high(0xFFFF) , low(0) , result(0) , resultUsed(0) , underflows(0) {} void write(uint16_t value) { uint32_t range = static_cast<uint32_t>(high) - low + 1; high = low + ((range * table[value]) / *(tableEnd - 1)) - 1; low = low + (range * table[value - 1]) / *(tableEnd - 1); while (true) { if ((high ^ low) & 0x8000) // different msb { if ((high & 0x4000) < (low & 0x4000)) { ++underflows; low &= 0x3FFF; high |= 0x4000; shift(); } else { break; } } else // equal msb { writeBit((low >> 15) & 1); while (underflows) { writeBit((~low >> 15) & 1); --underflows; } shift(); } } } void shift() { low <<= 1; high <<= 1; high |= 1; } void writeBit(uint16_t bit) { result <<= 1; result |= bit; ++resultUsed; if (resultUsed == 16) flushResult(); } void flushResult() { *stream++ = result; result = 0; resultUsed = 0; } void flush() { writeBit((low >> 14) & 1); ++underflows; while (underflows--) writeBit((~low >> 14) & 1); while (resultUsed) writeBit(0); } uint16_t* getStreamPos() const { return stream; } }; void encoder() { // Pass 1: calculate frequencies vector<uint16_t> freq(1024); uint16_t binary4 = 0; uint16_t binary12 = 0; Taylor lastTaylor; for (size_t row = 0; row < NUM_ROWS; ++row) { for (size_t col = 0; col < NUM_COLUMNS - 1; ++col) { // last column is not encoded Taylor taylor(my_array[row][col], lastTaylor); int16_t fixup = taylor.d[0] - lastTaylor.predict(); // Hack for values, jumping from -100 to 100 if (taylor.d[0] >= VALUE_LIMIT_POS && lastTaylor.d[0] < 0) fixup -= 2 * taylor.d[0]; // Value too big for arithmetic codec, use nibbles if (fixup > INDEX_PLUS + NUM_BIN_OUTLIERS || fixup < -ZERO_POS - NUM_BIN_OUTLIERS) { ++binary12; } else if (fixup > INDEX_PLUS || fixup < -ZERO_POS) { ++binary4; } // Hack for values, jumping from -100 to 100 if (taylor.d[0] >= VALUE_LIMIT_POS && lastTaylor.d[0] < 0) { lastTaylor.negate(); taylor.update(lastTaylor); } // This will be used to predict the next value // (derivative is not updated for the first column) lastTaylor.copyFrom(taylor, col? 3: 1); // Update table of frequencies ++freq[512 + fixup]; } } cout << "fixup: "; ostream_iterator<int> out_it (cout, " "); std::copy(freq.begin()+480, freq.end()-480, out_it); cout << "\n"; cout << "binary4=" << binary4 << "\n"; cout << "binary12=" << binary12 << "\n"; cout << "-----------\n"; double bitsPerValue = accumulate(freq.begin(), freq.end(), 0., Entropy(0)); cout << " Entropy=" << NUM_VALUES * bitsPerValue / 8. << " bits=" << bitsPerValue << "\n"; Entropy entropy(binary4 + binary12); cout << "Static=" << 2 * (INDEX_FULL_SIZE + (2 + binary4 + binary12*3 + 3) / 4) << "\n"; // Add nibble frequencies freq[512 - ZERO_POS + INDEX_SIZE] = binary4; freq[512 - ZERO_POS + INDEX_SIZE + 1] = binary12; bitsPerValue = accumulate(freq.begin() + 512 - ZERO_POS, freq.begin() + 512 - ZERO_POS + INDEX_FULL_SIZE, 0., entropy); cout << "Entropy2=" << NUM_VALUES * bitsPerValue / 8. << " bits=" << bitsPerValue << "\n"; // Pass 2: encode arithmetic coder bitstream & nibbles vector<uint16_t> compacted(1024); // Cumulative sum of frequencies partial_sum(freq.begin() + 512 - ZERO_POS, freq.begin() + 512 - ZERO_POS + INDEX_FULL_SIZE, compacted.begin() + 1); // Configure nibble writer uint16_t* pNibbles = &compacted[INDEX_FULL_SIZE + 1]; uint16_t nibbles = (3 + binary4 + binary12*3 + 3) / 4; NibbleWriter nibbleWriter(pNibbles, nibbles); uint16_t* pData = pNibbles + nibbles; // Configure arithmetic coder ArWriter arWriter(pData, &compacted[1], &compacted[1 + INDEX_FULL_SIZE]); lastTaylor.clear(); for (size_t row = 0; row < NUM_ROWS; ++row) { for (size_t col = 0; col < NUM_COLUMNS - 1; ++col) { // last column is not encoded Taylor taylor(my_array[row][col], lastTaylor); int16_t fixup = taylor.d[0] - lastTaylor.predict(); // Hack for values, jumping from -100 to 100 if (taylor.d[0] >= VALUE_LIMIT_POS && lastTaylor.d[0] < 0) fixup -= 2 * taylor.d[0]; // Value too big for arithmetic codec, use nibbles if (fixup > INDEX_PLUS + NUM_BIN_OUTLIERS || fixup < -ZERO_POS - NUM_BIN_OUTLIERS) { nibbleWriter.write12(fixup); arWriter.write(INDEX_SIZE + BIN12); } else if (fixup > INDEX_PLUS || fixup < -ZERO_POS) { if (fixup > 0) nibbleWriter.write4(fixup - INDEX_PLUS - 1); else nibbleWriter.write4((-fixup - ZERO_POS - 1) | 0x8); arWriter.write(INDEX_SIZE + BIN4); } else { arWriter.write(ZERO_POS + fixup); } // Hack for values, jumping from -100 to 100 if (taylor.d[0] >= VALUE_LIMIT_POS && lastTaylor.d[0] < 0) { lastTaylor.negate(); taylor.update(lastTaylor); } // This will be used to predict the next value // (derivative is not updated for the first column) lastTaylor.copyFrom(taylor, col? 3: 1); } } nibbleWriter.flush(); arWriter.flush(); size_t size = arWriter.getStreamPos() - &compacted[0]; cout << "ArEnc=" << (arWriter.getStreamPos() - pNibbles - nibbles) * 2 << "\nTotal=" << size * 2 << "\n---------\n"; for (size_t i = 0; i < size; i += 8) { cout << " " << hex << showbase; ostream_iterator<int> out_it (cout, ", "); std::copy(compacted.begin() + i, (i + 8 < size)? compacted.begin() + i + 8: compacted.begin() + size, out_it); cout << "\n"; } } int main() { encoder(); return 0; }
Standard input is empty
fixup: 0 0 0 0 0 0 1 0 0 0 2 0 0 1 0 0 1 1 0 0 1 0 1 4 0 4 3 4 7 12 75 583 1252 600 74 11 11 1 1 0 1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
binary4=61
binary12=19
-----------
Entropy=680.231 bits=2.04274
Static=74
Entropy2=641.075 bits=1.92515
ArEnc=648
Total=726
---------
0, 0x4b, 0x292, 0x776, 0x9ce, 0xa18, 0xa55, 0xa68,
0x601f, 0xea09, 0x4e8c, 0xafff, 0xbfed, 0x6ff1, 0x10fe, 0xfdb1,
0xa100, 0xd1fe, 0xd800, 0x129f, 0xf010, 0x730f, 0x9ec1, 0x80e9,
0x9a9c, 0x8888, 0x9880, 0x1, 0x2ab9, 0x8105, 0x101, 0xdfb8,
0xfeaf, 0xc030, 0x8100, 0x930, 0x8c1, 0xcaf4, 0, 0xfff6,
0xefb9, 0x416, 0x78eb, 0xe5d2, 0xeaf7, 0x597e, 0x8a50, 0xf278,
0x30c, 0xad5a, 0x7f2a, 0x96cd, 0x860a, 0xbad7, 0x2145, 0x1b7,
0x807f, 0xba8f, 0x8b22, 0x40c9, 0xcfe5, 0x43c, 0x56a9, 0x75e4,
0x6b43, 0x23e, 0x3db4, 0xac48, 0x71bf, 0xeaf9, 0x4a9a, 0xe927,
0x855, 0xe54, 0xd56f, 0xe170, 0x1c88, 0x57c, 0x99b2, 0xfd79,
0xa8c8, 0xf5f6, 0xcd89, 0xfd66, 0x9815, 0xc126, 0x32e1, 0x56f,
0xfe7a, 0xd86d, 0x155b, 0x4a22, 0x62d2, 0x36b8, 0x877e, 0xbd70,
0x2746, 0xa87f, 0x169d, 0x4af0, 0xe059, 0x6cfb, 0xb27a, 0x49a6,
0xae32, 0xd0ab, 0x14b1, 0xa498, 0xb5e9, 0xae0e, 0x9427, 0x9b4f,
0x4957, 0xebd5, 0xf1fa, 0xf288, 0xff72, 0xc29f, 0x475e, 0xf4ca,
0xaa0e, 0xd455, 0x1b1f, 0xeaee, 0xf2ba, 0xaee, 0x96d2, 0xa942,
0xaeed, 0x8a5a, 0xdfda, 0x3ce7, 0x31d2, 0x60cb, 0xe98d, 0x8162,
0xb0c, 0x27af, 0x6e6c, 0xd2e5, 0x6022, 0xe421, 0xe7f7, 0x394a,
0x173b, 0xed47, 0xaef7, 0x4b78, 0x283b, 0x9d78, 0x3e13, 0x4a6,
0xa6e, 0xcda6, 0x3bb0, 0x62b7, 0x2b9a, 0xee3f, 0xda27, 0x88ee,
0x8280, 0xe658, 0x1668, 0xb701, 0x4e70, 0x147, 0xe058, 0xa1a0,
0x3455, 0x5994, 0xd390, 0x1fac, 0xb58c, 0x3680, 0x3d42, 0xf12,
0xba9e, 0x949f, 0x51df, 0x9603, 0x52af, 0x74d8, 0xbdc7, 0xefe9,
0x3b5e, 0xe273, 0xbae, 0x13c4, 0x5844, 0x3c6d, 0xf045, 0x52ba,
0x6ef2, 0xa428, 0x67b7, 0x91f7, 0x31ee, 0xbcb9, 0xfe7f, 0xefd3,
0x367e, 0x4308, 0x2b58, 0xbd30, 0xc4bd, 0xa28f, 0xca5d, 0x2230,
0x8f65, 0x134e, 0xaaa8, 0x6499, 0x4a14, 0x15ec, 0xf83f, 0x8c92,
0x3928, 0x2d35, 0x176f, 0x1080, 0xc982, 0x1bae, 0xfb7a, 0x616a,
0xc069, 0x8177, 0xe7f3, 0x70e3, 0x5d99, 0x8dfa, 0xdf80, 0x364b,
0x6b3f, 0x1aec, 0x66c8, 0x87cc, 0xd62f, 0x687, 0x9a3d, 0x3704,
0xe486, 0xa47e, 0xa87a, 0x1bd, 0xd8e2, 0x9f6d, 0xdd2, 0xd150,
0xcdf3, 0xb4e4, 0x9bd7, 0xabc9, 0x52e8, 0x553c, 0xa2ab, 0x18b8,
0x70fb, 0xa594, 0xd34c, 0x9450, 0xd928, 0xd581, 0x54a, 0x3096,
0x30c7, 0x6899, 0xcfd0, 0x5a37, 0xa664, 0xfe0, 0x4b1a, 0x616c,
0x9eba, 0x591a, 0xfa80, 0x2911, 0x2c5b, 0xe310, 0x32e1, 0x3680,
0x55a8, 0x7e, 0xd7fd, 0xe81d, 0x13f2, 0x919d, 0x972f, 0x5c52,
0xdf86, 0x4576, 0xd6ea, 0x2afd, 0x1759, 0xcf24, 0x1b0e, 0xc73f,
0x75aa, 0x7f2, 0x7432, 0x8691, 0x389c, 0xb9a4, 0xf1ad, 0xb21a,
0xa644, 0x2b0f, 0x8e52, 0x8a81, 0x9558, 0xed0a, 0xcff4, 0x217,
0x5e98, 0x1d53, 0x59f2, 0x9b70, 0xb4b1, 0x2bd9, 0xbbec, 0xfa03,
0xbf55, 0x3651, 0x6d8, 0xcdc0, 0x132d, 0x9c88, 0x349b, 0x4ac9,
0x89c6, 0x5cc1, 0x7826, 0xc599, 0x763f, 0x735f, 0x1e1, 0xc668,
0x67b6, 0xc22, 0xbc5, 0x2324, 0x9c9c, 0xc8fe, 0xf55a, 0x5218,
0x4406, 0x2fff, 0xfffb, 0xe0e6, 0x12b0, 0xc3e9, 0xc119, 0x883c,
0xd877, 0x8973, 0xf93f, 0x3684, 0xfffb, 0x7eeb, 0x730c, 0x7cbb,
0xcea, 0x856, 0x8000,