, sizin örnek dosyada bit derinliği başına değerlerin dağılımı aşağıdaki gibidir: Yani

Değerlerin% 52.285'i ya 0 ya da 1'dir, sadece 64'ün altında bir avuç diğer değer (2 ~ 6-bit),% 27.59'u 7 ~ 12-bittir,% 2.1 civarında oldukça eşit bir dağılım vardır. bit başına 20-bit'e kadar ve maksimum 25-bit ile 20-bitlerin sadece% 3'ü. Verilere bakıldığında, 6 ardışık sıfıra kadar birçok dizinin olduğu da açıktır.
00 0xxxxx 0 (xxxxx is the number of consecutive zeros)
00 1xxxxx 1 (xxxxx is the number of consecutive ones)
01 xxxxxx xxxxxxxx 2-14 bit values
10 xxxxxx xxxxxxxx xxxxxxxx 15-22 bit values
11 xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 23-30 bit values
hızlı bir test bu değil mi damgası başına 13,78 bit sıkıştırma oranı yol açtığını gösterdi:
Bu gözlemler bana böyle bir değişken değer başına bit boyutu, bir şeyi kullanma fikrini verdi Tam olarak hedeflediğin 10 bit, ama basit bir plan için kötü bir başlangıç değil.
birkaçı örnek verileri analiz edildikten sonra, bir üst üste 0 ve 1 'S, 0 1 0
gibi kısa dizilerinin bir çok olduğu görülmektedir, böylece bu bir 1 baytlık düzeni ikame:
00xxxxxx 00 = identifies a one-byte value
xxxxxx = index in the sequence table
dizilerin
tablo: 451.210 damgaları ile, örneğin dosya için
index ~ seq index ~ seq index ~ seq index ~ seq index ~ seq index ~ seq
0 0 2 00 6 000 14 0000 30 00000 62 000000
1 1 3 01 7 001 15 0001 31 00001 63 000001
4 10 8 010 16 0010 32 00010
5 11 ... ... ...
11 101 27 1101 59 11101
12 110 28 1110 60 11110
13 111 29 1111 61 11111
bu 676,418 sayılı belgelerde bayt veya zaman damgası başına 11,99 bit kodlanmış dosya boyutu indirir. Yukarıdaki yöntemin test edilmesi, daha büyük aralıklar arasında 98.578 tek sıfır ve 31.271 tekil olduğunu göstermiştir. Bu yüzden, her bir büyük aralığın 1 bitini bir sıfır ile takip edip etmediğini saklamak için kullanmayı denedim, bu da kodlanmış boyutu 592,315 bayta indirdi. Ve daha büyük aralıkların 0, 1 veya 00 (en sık kullanılan dizi) tarafından takip edilip edilmediğini depolamak için 2 bit kullandığımda, kodlanmış boyut, zaman damgası başına 564,034 bayta veya 10.0004 bit'e düştü.
Daha sonra tek 0'lar ve 1'leri önceki kod yerine (yalnızca kod sadeliği nedeniyle) aşağıdaki büyük aralıkta saklamak için değiştirdim ve bunun, dosya boyutu 563.884 bayt ya da zaman damgası 9.997722 bit biti !
Yani tam bir yöntemdir: bir kodlayıcının
Store the first timestamp (8 bytes), then store the intervals as either:
00 iiiiii sequences of up to 5 (or 6) zeros or ones
01 XXxxxx xxxxxxxx 2-12 bit values (2 ~ 4,095)
10 XXxxxx xxxxxxxx xxxxxxxx 13-20 bit values (4,096 ~ 1,048,575)
11 XXxxxx xxxxxxxx xxxxxxxx xxxxxxxx 21-28 bit values (1,048,576 ~ 268,435,455)
iiiiii = index in sequence table (see above)
XX = preceded by a zero (if XX=1), a one (if XX=2) or two zeros (if XX=3)
xxx... = 12, 20 or 28 bit value
Örnek: Çünkü MinGW'nin/gcc içinde long double output bug arasında
#include <stdint.h>
#include <iostream>
#include <fstream>
using namespace std;
uint64_t read_timestamp(ifstream& ifile) { // big-endian
uint64_t timestamp = 0;
uint8_t byte;
for (uint8_t i = 0; i < 8; i++) {
ifile.read((char*) &byte, 1);
if (ifile.fail()) return 0;
timestamp <<= 8; timestamp |= byte;
}
return timestamp;
}
uint8_t read_interval(ifstream& ifile, uint8_t *bytes) {
uint8_t bytesize = 1;
ifile.read((char*) bytes, 1);
if (ifile.fail()) return 0;
bytesize += bytes[0] >> 6;
for (uint8_t i = 1; i < bytesize; i++) {
ifile.read((char*) bytes + i, 1);
if (ifile.fail()) return 0;
}
return bytesize;
}
void write_seconds(ofstream& ofile, uint64_t timestamp) {
long double seconds = (long double) timestamp/1000000;
ofile << seconds << "\n";
}
uint8_t write_sequence(ofstream& ofile, uint8_t seq, uint64_t timestamp) {
uint8_t interval = 0, len = 1, offset = 1;
while (seq >= (offset <<= 1)) {
seq -= offset;
++len;
}
while (len--) {
interval += (seq >> len) & 1;
write_seconds(ofile, timestamp + interval);
}
return interval;
}
int main() {
ifstream ifile ("timestamps.bin", ios::binary);
if (! ifile.is_open()) return 1;
ofstream ofile ("output.txt", ios::trunc);
if (! ofile.is_open()) return 2;
ofile.precision(6); ofile << std::fixed;
uint64_t timestamp = read_timestamp(ifile);
if (timestamp) write_seconds(ofile, timestamp);
while (! ifile.eof()) {
uint8_t bytes[4], seq = 0, bytesize = read_interval(ifile, bytes);
uint32_t interval;
if (bytesize == 1) {
timestamp += write_sequence(ofile, bytes[0], timestamp);
}
else if (bytesize > 1) {
seq = (bytes[0] >> 4) & 3;
if (seq) timestamp += write_sequence(ofile, seq - 1, timestamp);
interval = bytes[0] & 15;
for (uint8_t i = 1; i < bytesize; i++) {
interval <<= 8; interval += bytes[i];
}
timestamp += interval;
write_seconds(ofile, timestamp);
}
}
ifile.close();
ofile.close();
return 0;
}
: bir dekoderin
#include <stdint.h>
#include <iostream>
#include <fstream>
using namespace std;
void write_timestamp(ofstream& ofile, uint64_t timestamp) { // big-endian
uint8_t bytes[8];
for (int i = 7; i >= 0; i--, timestamp >>= 8) bytes[i] = timestamp;
ofile.write((char*) bytes, 8);
}
int main() {
ifstream ifile ("timestamps.txt");
if (! ifile.is_open()) return 1;
ofstream ofile ("output.bin", ios::trunc | ios::binary);
if (! ofile.is_open()) return 2;
long double seconds;
uint64_t timestamp;
if (ifile >> seconds) {
timestamp = seconds * 1000000;
write_timestamp(ofile, timestamp);
}
while (! ifile.eof()) {
uint8_t bytesize = 0, len = 0, seq = 0, bytes[4];
uint32_t interval;
while (bytesize == 0 && ifile >> seconds) {
interval = seconds * 1000000 - timestamp;
timestamp += interval;
if (interval < 2) {
seq <<= 1; seq |= interval;
if (++len == 5 && seq > 0 || len == 6) bytesize = 1;
} else {
while (interval >> ++bytesize * 8 + 4);
for (uint8_t i = 0; i <= bytesize; i++) {
bytes[i] = interval >> (bytesize - i) * 8;
}
bytes[0] |= (bytesize++ << 6);
}
}
if (len) {
if (bytesize > 1 && (len == 1 || len == 2 && seq == 0)) {
bytes[0] |= (2 * len + seq - 1) << 4;
} else {
seq += (1 << len) - 2;
ofile.write((char*) &seq, 1);
}
}
if (bytesize > 1) ofile.write((char*) bytes, bytesize);
}
ifile.close();
ofile.close();
return 0;
}
Örnek 4.8.1 derleyici kullanıyorum, bu geçici çözümü kullanmak zorundaydım: (bu diğer c ile gerekli olmamalıdır gelecek okuyuculara ompilers)
void write_seconds(ofstream& ofile, uint64_t timestamp) {
long double seconds = (long double) timestamp/1000000;
ofile << "1" << (double) (seconds - 1000000000) << "\n";
}
Not: Bu yöntem, örneğin, veri dosyasının analizine dayanmaktadır; Verileriniz farklıysa aynı sıkıştırma oranını vermez.
Güncel dosyada 451210 adet kayıt var. Kayıpsız sıkıştırmaya ihtiyacımız var. Bu gerçekten bir yerde ayarlamak daha büyük bir örnek verileri, belki bir saatlik değer yüklemek için ihtiyacı olan sorulardan biri olduğunu düşünüyorum 1364281200,078739 1364281232,672875 1364281232,788200 1364281232,792756 1364281232,793052 1364281232,795598 ..... – learner
- İşte dosyasında örnek girişlerdir veri her şey çok büyükse? – m69
Bağlantıyı sorudaki veri kümesine ekledim. – learner