#include <iostream>
#include <numeric>
#include <cstdlib>
#include <cstddef>
#include <stdint.h>
enum {
// Config
ZERO_POS = 2,
INDEX_SIZE = 5,
VALUE_LIMIT = -100,
// Constants// 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 code;
uint16_t source;
uint16_t sourceUsed;
public:
ArReader(uint16_t* p, uint16_t* t, uint16_t* e)
: stream(p + 1)
, table(t) // Zero value in *(t-1) expected
, tableEnd(e)
, high(0xFFFF)
, low(0)
, code(*p)
, source(0)
, sourceUsed(0)
{}
uint16_t read()
{
uint32_t range = static_cast<uint32_t>(high) - low + 1;
uint16_t temp =
((static_cast<uint32_t>(code) - low + 1) * *(tableEnd - 1) - 1) /
range;
uint16_t result = searchTable(temp);
high = low + ((range * table[result]) / *(tableEnd - 1)) - 1;
low = low + (range * table[result - 1]) / *(tableEnd - 1);
while (true) {
if ((high ^ low) & 0x8000) // different msb
{
if ((high & 0x4000) < (low & 0x4000))
{
code ^= 0x4000;
low &= 0x3FFF;
high |= 0x4000;
shift();
}
else
{
break;
}
}
else // equal msb
{
shift();
}
}
return result;
}
uint16_t searchTable(uint16_t x)
{
uint16_t* p = table;
while (x >= *p)
++p;
return p - table;
}
void shift()
{
low <<= 1;
high <<= 1;
high |= 1;
code <<= 1;
code |= readBit();
}
uint16_t readBit()
{
if (sourceUsed == 0)
load();
return (source >> --sourceUsed) & 1;
}
void load()
{
source = *stream++;
sourceUsed = 16;
}
};
int16_t get(size_t r, size_t c)
{
if (c == NUM_COLUMNS - 1)
c = 0; // last column is equal to the first one
Taylor lastTaylor;
NibbleReader nibbleReader(compacted + 1 + INDEX_FULL_SIZE);
ArReader
arReader(compacted + 1 + INDEX_FULL_SIZE + nibbleReader.read12(),
compacted + 1,
compacted + 1 + INDEX_FULL_SIZE);
for (size_t row = 0; row < NUM_ROWS; ++row)
{
for (size_t col = 0; col < NUM_COLUMNS - 1; ++col)
{ // last column is not encoded
uint16_t value = arReader.read();
int16_t fixup = static_cast<int16_t>(value) - ZERO_POS;
// Value was encoded in nibbles
if (value == INDEX_SIZE + BIN4)
{
uint16_t x16 = nibbleReader.read4();
if (x16 & 0x8)
fixup = -ZERO_POS - 1 - (x16 & ~0x8);
else
fixup = INDEX_PLUS + 1 + x16;
}
else if (value == INDEX_SIZE + BIN12)
{
fixup = static_cast<int16_t>(nibbleReader.read12());
fixup |= -(fixup & (1 << 11));
}
// Restore original value (extrapolate and add a correction)
Taylor taylor(lastTaylor.predict() + fixup, lastTaylor);
// Hack for values, jumping from -100 to 100
if (taylor.d[0] <= VALUE_LIMIT)
{
taylor.d[0] = -taylor.d[0];
lastTaylor.negate();
taylor.update(lastTaylor);
}
// Got the result
if (row == r && col == c)
return taylor.d[0];
// This will be used to predict the next value
// (derivative is not updated for the first column)
lastTaylor.copyFrom(taylor, col? 3: 1);
}
}
return 0; // Out of range
}
int main()
{
for (int row = 0; row < NUM_ROWS; ++row)
for (int col = 0; col < NUM_COLUMNS; ++col)
if (get(row, col) != my_array[row][col])
{
cerr
<< "Mismatch in row " << row << ", column " << col
<< "; got " << get(row, col)
<< ", must be " << my_array[row][col]
<< "\n";
exit(1);
}
return 0;
}