Кто-нибудь пробовал написать подобную вещь? Я пробую но не очень хорошо выходит. Где-то через 50 символов проиходит разнос декодера (неверно восстанавливается частота). Переполнений нигде нет! Может у кого-нибудь, как вариант, если исходник простого интервального кодера, в чистом виде (не как часть какого-либо PPM и прочего). Код (Text): #define CODEBITS (unsigned int)31 #define TOP (1<<CODEBITS) #define BOTTOM (TOP>>8) #define BIGBYTE (0xFF<<(CODEBITS-8)) Код (Text): void Encoder::EncodeSym(FILE *output,int sym) { range/=cum_freq[0]; low+=cum_freq[sym] * range; range*=freq[sym]; while(range<BOTTOM) { if(low&BIGBYTE==BIGBYTE && range+(low&BOTTOM-1)>=BOTTOM) range=BOTTOM-(low&BOTTOM-1); fputc(low>>24,output); range<<=8; low<<=8; } } Код (Text): int Decoder::DecodeSym(FILE *input) { int sym,c; range/=cum_freq[0]; c=(value-low)/range; for(sym=1; cum_freq[sym]>c; sym++); low+=cum_freq[sym] * range; range*=freq[sym]; while(range<BOTTOM) { if(low&BIGBYTE==BIGBYTE && range+(low&BOTTOM-1)>=BOTTOM) range=BOTTOM-(low&BOTTOM-1); range<<=8; low<<=8; if(feof(input)) break; value=(value<<8)|fgetc(input); } return sym; }
Предполагаю, что имеется в виду range encoding. Если это действительно так, то в сети можно найти примеры кода (начиная с ссылок в Википедии)
Не знаю как тебе насчет "просто" Код (Text): class RangeEncoder { public: RangeEncoder(DataStreamWriter::SP writer) { m_cacheOrg = 0; m_writer = writer; m_low = 0; m_buffer = m_count = 0; m_range = 0xffffffff; } ~RangeEncoder() { for (int i = 0; i < 5; i++) Shift(); Flush (); } void Encode (DWORD start, DWORD freq, DWORD total) { m_range /= total; m_low += start * m_range; m_range *= freq; while (m_range < (1 << 24)) { m_range <<= 8; Shift(); } } void Flush () { if (m_cacheOrg) { m_writer->SetData (m_cache,m_cacheOrg); m_cacheOrg = 0; } } private: QWORD m_low; DWORD m_range, m_buffer, m_count; BYTE m_cache[RANGE_CODER_CACHE_SIZE]; DWORD m_cacheOrg; DataStreamWriter::SP m_writer; void Shift() { if ((m_low ^ 0xff000000) > 0x00ffffff) { // flush cache early if next portion may not fit if (m_cacheOrg >= sizeof(m_cache) - (1+m_count)) Flush (); BYTE outB = (m_low >> 32); m_cache[m_cacheOrg++] = outB + m_buffer; outB += 0xff; while (m_count > 0) { m_cache[m_cacheOrg++] = outB; m_count--; } m_buffer = ((DWORD) m_low) >> 24; } else m_count++; m_low = ((DWORD) m_low) << 8; } }; class RangeDecoder { public: RangeDecoder (DataStreamReader::SP reader) { m_reader = reader; ZeroMemory(m_cache,sizeof(m_cache)); FillCache (); m_range = 0xffffffff; for (int i = 0; i < 5; i++) { m_buffer <<= 8; m_buffer |= m_cache[m_cacheOrg++]; } } void Update (DWORD start, DWORD freq) { m_buffer -= start * m_range; m_range *= freq; while (m_range < (1 << 24)) { m_range <<= 8; m_buffer <<= 8; if (m_cacheOrg >= m_cacheLen) FillCache (); m_buffer |= m_cache[m_cacheOrg++]; } } DWORD getFreq (DWORD total) { m_range /= total; return m_buffer / m_range; } private: DWORD m_range, m_buffer; BYTE m_cache[RANGE_CODER_CACHE_SIZE]; DWORD m_cacheOrg, m_cacheLen; DataStreamReader::SP m_reader; void FillCache () { m_cacheOrg = 0; m_cacheLen = m_reader->GetData (m_cache, sizeof (m_cache)); } };
Так как раз ничерта нет... Можно только из PPM выдирать, но это нафиг не нужно... С виду формулы все понятные, а когда ошибка начинает возникать, отлаживать задалбливаешься...