Ćwiczenie 0 1 2 3

Celem ćwiczenia jest nabycie praktycznych umiejętności korzystania z operatorów bitowych w językach wysokiego poziomu.

Państwa zadanie polega na napisaniu aplikacji, która zakoduje wejściowy plik zawierający tekst w postaci znaków ASCII (8 bitów na symbol) w taki sposób, by w pliku wynikowym otrzymać reprezentację tekstu przy użyciu 5 bitów na znak. Uzyskana w ten sposób kompresja będzie wynosić około 37,5%. Mniejsza liczba bitów przeznaczona do kodowania symboli wiąże się z koniecznością zawężenia tablicy znaków ASCII do zbioru 2 do potęgi 5 (32 symboli). W naszym zadaniu do wspomnianego zbioru z powodzeniem można załączyć litery i podstawowe znaki przestankowe: '.', ',', etc.

Ponieważ do pliku wynikowego zapisywać możemy wyłącznie wielokrotności 8 bitów (1 bajta), a nasz sposób kodowania może dawać ciągi bitów nie podzielne bez reszty przez 8, to konieczne przed zapisem możne być uzupełnienie ciągu bitów kodowych do liczby podzielnej przez 8. Takie rozwiązanie może wprowadzać w pewnych przypadkach błędy podczas kodowania, gdyż dodatkowe bity uzupełnień mogą być potraktowane jako dodatkowy znak. Na przykład, gdy w plików wejściowym było 7 znaków. W Państwa gestii leży rozwiązanie tego problemu, np. poprzez wprowadzenie do pliku kodów nagłówka, w którym zapisana będzie liczba dołączonych bitów. Taki nagłówek nie musi być wówczas dłuższy niż 3 bity.

Oczywiście poza programem kodera wymagane jest również zaimplementowanie programu dekodującego.

Również dla potrzeb kolejnych zadań w ramach ćwiczenia 0 wymaga się zaimplementowania następujących dwóch funkcji:

void set_bit(unsigned char* buf, int n, bool v);


bool get_bit(unsigned char* buf, int n);

Działanie pierwszej z nich ma polegać na ustawieniu bitu o zadanym numerze n na wartość v w N-elementowej tablicy bajtów. Wówczas w programie kodującym można utworzyć tablicę o długości N bajtów, która jest wystarczająca dla przedstawienia zakodowanej postaci tekstu, a następnie przy użyciu funkcji set_bit() odpowiednio ustawić bity informacji zakodowanej, i tak wypełnioną tablicę zapisać do pliku wynikowego.

Druga funkcja ma za zadanie odczyt wartości bitu z pozycji n w tablicy N-elementowej. Tę funkcję możecie Państwo wykorzystać podczas dekodowia danych. Wystarczy wówczas utworzyć tablicę o długości równej długości pliku dekodowanego i korzystając z funkcji get_bit() odzyskać zakodowane znaki ASCII, które następnie można zapisać do wynikowego pliku tekstowego.

Dla ułatwienia zadania zamieszczamy poniżej przykładowe funkcje realizujące zapis i odczyt do plików poprzez mechanizm strumieni.

#include <fstream>

void zapisz(char* fname, unsigned char* bufor, int len) { ofstream ofs(fname, ios::binary); ofs.write((char*)bufor, len); ofs.close(); } unsigned char* wczytaj(char* fname, int& len) { unsigned char* bufor; ifstream ifs(fname, ios::binary); ifs.seekg (0, ios::end); len = ifs.tellg(); ifs.seekg (0, ios::beg); bufor = new unsigned char[len]; ifs.read((char*)bufor,len); ifs.close(); return bufor; }

Funkcja zapis() realizuje operację zapisu len bajtów do pliku o nazwie fname z tablicy bufor. Natomiast funkcja odczyt() czyta z pliku o nazwie fname wszystkie bajty do dynamicznie utworzonej tablicy, której adres zpostaje zwrócony. Liczba bajtów wpisywana jest do drugiego argumentu funkcji.

Specyfikacja ćwiczenia

Przykładowy scenariusz kodowania danych



Ostatnia aktualizacja: 18:49 2008-03-01.