Wpisany przez Michał Knasiecki,
28 lipca 2005 17:56
Wszędzie, gdzie przesyłane są dane pojawia się ryzyko wystąpienia błędów, przesyłane informacje mogą dotrzeć zmienione lub zostać zagubione. W takich przypadkach z pomocą przychodzą nam różne sumy kontrolne, najprostszym przykładem jest choćby kontrola parzystości. Istnieje jednak dużo lepsza metoda sprawdzania poprawności danych, jest nią CRC (ang. Cyclic Redundancy Check: Cykliczna Kontrola Nadmiarowa). Jest ona bardzo powszechnie stosowana np: Ethernet, archiwizatory (ZIP, RAR), programy do dzielenia plików itp. Dodatkową zaletą metody CRC jest możliwość zaimplementowania jej w postaci układu składającego się z rejestrów.
Pozwolę sobie pominąć całą teorię (czysta matematyka) i skupić się na implementacji, na końcu strony umieszczam dokument Texas Instruments, w którym teoria została dokładnie wyłożona. Zawiera ona również kilka implementacji w assemblerze.
Warto wspomnieć, że istnieje wiele odmian CRC, różnią się one między sobą postacią wielomianu P, który służy do dzielenia ciągu bitów. Oto kilka z nich:
Zajmiemy się ostatnią odmianą, która jest stosowana w Ethernecie.
Wielomian P jest zapisywany jako liczba całkowita w następujący sposób:
Kluczową czynnością w wyznaczaniu wartości CRC jest obliczanie dla każdego znaku pewnych wartości. Ponieważ znaki w kodowanej informacji powtarzają się bardzo wiele razy, dobrze jest zapisać te wartości w tablicy, przyspieszając w ten sposób działanie algorytmu. Nie będzie trzeba obliczać wielokrotnie tych samych wartości, zamiast tego odczytamy je z tablicy.
Aby zapisać wartości wszystkich możliwych znaków ASCII potrzebujemy tablicy o długości 256. Dla każdego znaku (czyli od 0 do 255) postępujemy w następujący sposób:
Postępując tak iteracyjnie dla wartości KOD od 0 do 255 uzupełnimy całą tablicę.
Wyjaśnienia wymaga instrukcja warunkowa: w punkcie 6. sprawdzamy na ilu bitach zapisana jest liczba KOD (robimy to sprawdzając wartość iloczynu binarnego tej liczby oraz liczby 1032). Jeśli KOD ma 32 bity (wartość iloczynu jest różny od 0) wówczas przesuwamy KOD w lewo o 1 pozycję i wykonujemy operację alternatywy wyłączającej z wielomianem, w przeciwnym wypadku tylko przesuwamy.
Gdy mamy już gotową tablicę, możemy przystąpić do obliczania CRC (tekst wejściowy znajduje się w zmiennej tekst (wskaźnik):
Pozwolę sobie pominąć całą teorię (czysta matematyka) i skupić się na implementacji, na końcu strony umieszczam dokument Texas Instruments, w którym teoria została dokładnie wyłożona. Zawiera ona również kilka implementacji w assemblerze.
Warto wspomnieć, że istnieje wiele odmian CRC, różnią się one między sobą postacią wielomianu P, który służy do dzielenia ciągu bitów. Oto kilka z nich:
Nazwa | Wielomian P |
CRC-12 | x12+x11+x3x2+x+1 |
CRC-16 | x16+x15+x2+1 |
CRC-CCITT | x16+x12+x5+1 |
CRC-32 | x32+x26+x23+ x22+x16+x12+x11+x10+x8+x7+ x5+x4+x2+x+1 |
Zajmiemy się ostatnią odmianą, która jest stosowana w Ethernecie.
Wielomian P jest zapisywany jako liczba całkowita w następujący sposób:
- jeśli współczynnik przy x w k-tej potędze jest równy 1, wówczas ustawiamy bit k-ty na 1
- jeśli współczynnik przy x w k-tej potędze jest równy 0, wówczas ustawiamy bit k-ty na 0
Kluczową czynnością w wyznaczaniu wartości CRC jest obliczanie dla każdego znaku pewnych wartości. Ponieważ znaki w kodowanej informacji powtarzają się bardzo wiele razy, dobrze jest zapisać te wartości w tablicy, przyspieszając w ten sposób działanie algorytmu. Nie będzie trzeba obliczać wielokrotnie tych samych wartości, zamiast tego odczytamy je z tablicy.
Aby zapisać wartości wszystkich możliwych znaków ASCII potrzebujemy tablicy o długości 256. Dla każdego znaku (czyli od 0 do 255) postępujemy w następujący sposób:
- KOD<-kod ASCII kolejnego znaku
- Zamieniamy starsze bity z młodszymi, czyli robimy coś w rodzaju lustrzanego odbicia kodu, np. dla kodu 11001001 jego odbicie ma postać 10010011
- Uzupełniamy kod 24 zerami, czyli przesuwamy go w lewo o 24
- for (int j = 0; j < 8; j++)
- {
- if ((KOD & (1 << 31))!=0)
- KOD = (KOD << 1) XOR P;
- else
- KOD = (KOD << 1);
- }
- Ponownie zamieniamy starsze bity z młodszymi
Postępując tak iteracyjnie dla wartości KOD od 0 do 255 uzupełnimy całą tablicę.
Wyjaśnienia wymaga instrukcja warunkowa: w punkcie 6. sprawdzamy na ilu bitach zapisana jest liczba KOD (robimy to sprawdzając wartość iloczynu binarnego tej liczby oraz liczby 1032). Jeśli KOD ma 32 bity (wartość iloczynu jest różny od 0) wówczas przesuwamy KOD w lewo o 1 pozycję i wykonujemy operację alternatywy wyłączającej z wielomianem, w przeciwnym wypadku tylko przesuwamy.
Gdy mamy już gotową tablicę, możemy przystąpić do obliczania CRC (tekst wejściowy znajduje się w zmiennej tekst (wskaźnik):
- ustaw wartość początkową crc=232-1
- for (i=0;i< długość_tekstu; i++)
- crc=(crc>>8) XOR tablica[(crc&255) XOR *tekst++];
- podstaw crc=crc XOR (232-1)
Implementacje
Autor | Język programowania | Komentarz | Otwórz | Pobierz | Ocena |
Michał Knasiecki | C/C++ | .cpp | .cpp | ***** / 19 |
Poprawiony: 30 lipca 2012 17:52
2. Niestety nie jestem w stanie odpowiedzieć, w tym algorytmie nie ma to większego znaczenia. Nawet jakby był inny bitorder to zawsze w danej implementacji wykorzystywany jest ten sam, czyli tak samo w niej będzie liczone, chyba że chcemy by dana implementacja mogła współdziałać z innymi, wówczas trzeba się dowiedzieć jaki bitorder jest w jakiej (jak zapisywane są dane) i wówczas ewentualnie zamienić, by bity były przetwarzane w tej samej kolejności.
A dlaczego najstarszy bit x32 nie jest brany pod uwagę w tym wielomianie? Zawsze się go odrzuca?