CRC számítás

A feladat egy adott karaktersorozathoz tartozó “cyclic redundancy check” (CRC) érték számítása, amely nagyjából két lépésben végezhető el: a karaktersorozat átalakítása számsorozattá, matematikai műveletek végzése bináris számjegysorozatokkal.

Szám konvertálása bináris sorozattá

A bináris számokat egy [Int] típussal ábrázoljuk úgy, hogy a lista csak a 0 és az 1 számokat tartalmazza, ahol a lista legutolsó eleme a legkisebb helyiértékhez tartozó együttható.

toBinary :: Int -> [Int]

Test>
[1, 1, 0, 0] :: [Int]
Test>
[1, 1, 1, 1, 1, 1, 1] :: [Int]
Test>
[] :: [Int]

Ennek megfelelően például a 12 decimális szám ábrázolása: [1,1,0,0] vagyis 1 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0.

Karakter konvertálása bináris sorozattá

Alakítsunk át egy karaktert bináris számjegyekké! Ezt a Data.Char.ord függvény segítségével tudjuk megtenni, amely egy 0 és 255 közti értéket fog visszaadni. Ezután ezt a számot alakítsuk át bináris sorozattá úgy, hogy mindenképpen 8 számjegyből álljon! Ha ennél kevesebbet kapunk az átalakítás során, akkor balról egészítsük ki nullákkal.

chrToBinary :: Char -> [Int]

Test>
[0, 0, 0, 0, 1, 0, 1, 0] :: [Int]
Test>
[0, 1, 0, 0, 1, 1, 0, 0] :: [Int]
Test>
[0, 1, 1, 1, 1, 1, 1, 0] :: [Int]

Karaktersorozat konvertálása bináris sorozattá

A következő lépésben egy karaktersorozatot alakítunk át bináris sorozattá úgy, hogy a karaktereket egyenkét bináris sorozatokká alakítjuk, majd ezeket összefűzzük.

strToBinary :: String -> [Int]

Test>
[0, 1, 0, 0, 1, 0, 0, 0] :: [Int]
Test>
[0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] :: [Int]

,,Kizáró vagy’’ bináris sorozatokra

Készítsünk egy olyan függvényt, amely a ,,kizáró vagy’’ műveletet végez el két, bináris számjegyek sorozatával ábrázolt értékén. (Ez bináris számok esetén az összeadás és a kivonás műveleteknek is megfelel, bár ekkor a túlcsorduló biteket elhagyjuk.) A műveletet a sorozatok elemein, vagyis bitenként végezzük el.

A függvényt úgy készítsük el, hogy ha a két sorozat nem egyforma hosszú, akkor a rövidebbiket egészítsük ki jobbról 0 számjegyekkel a másik hosszára.

bxor :: [Int] -> [Int] -> [Int]

Test>
[0, 0, 0, 0] :: [Int]
Test>
[1, 0, 0, 1, 0] :: [Int]
Test>
[0, 0, 1, 1, 1, 1] :: [Int]

Nagyobb vagy egyenlő művelet megvalósítása

Készítsünk egy olyan függvényt, amely a nagyobb vagy egyenlő műveletet végzi el két bináris sorozattal! Az a sorozat nagyobb vagy egyenlő, mint b, ha az a sorozatban az első egyes hamarabb, vagy ugyanazon a pozíción van, mint a b sorozatban.

infix 4 %>=%

(%>=%) :: [Int] -> [Int] -> Bool

Test>
True :: Bool
Test>
False :: Bool
Test>
True :: Bool
Test>
True :: Bool
Test>
True :: Bool
Test>
True :: Bool
Test>
False :: Bool

Két bináris sorozat osztási maradékának kiszámítása

A bináris osztás maradéka a következő (az osztás eredményére nem lesz szükségünk, csak a maradékra) algoritmussal számítható:

Példa: bmod 11010110110000 10011.

       _______________
10011 ) 11010110110000
        10011,,.,,....
        -----,,.,,....
         10011,.,,....
         10011,.,,....
         -----,.,,....
          00001.,,....
          00000.,,....
          -----.,,....
           00010,,....
           00000,,....
           -----,,....
            00101,....
            00000,....
            -----,....
             01011....
             00000....
             -----....
              10110...
              10011...
              -----...
               01010..
               00000..
               -----..
                10100.
                10011.
                -----.
                 01110
                 00000
                 -----
                  1110 = Maradék

A példában, amikor 00000 szerepel az osztó helyén, az arra utal, hogy nem tudunk osztani (mivel az osztandó osztó fölé eső része kisebb, mint az osztónk). A . a 0, a , az 1 számjegyeket jelzi. Ezeket azért írtuk úgy, hogy jobban látható legyen, melyik részekkel kell az adott lépésben dolgozni.

infixl 7 `bmod`

bmod :: [Int]{-osztandó-} -> [Int]{-osztó-} -> [Int]{-maradék-}

Test>
[1, 1, 1, 0] :: [Int]
Test>
[0, 1, 0, 0] :: [Int]
Test>
[0, 1] :: [Int]

Megjegyzések:

Az ellenőrzőkód kiszámítása

Írjunk egy olyan függvényt, amely kap egy karaktersorozatot és egy osztót bináris sorozatként, amellyel a CRC-t számolni kell. A karaktersorozatot először alakítsuk bináris sorozatokká, majd számítsuk ki a kettő maradékát (a karaktersorozatnak megfeleltetett bináris sorozatot osszuk el az osztóként megadott bináris sorozattal). Ez lesz a karaktersorozathoz tartozó ellenőrző (CRC) érték, amely egyben a függvény visszatérési értéke.

crc :: String -> [Int] -> [Int]

Test>
[0, 0, 1] :: [Int]
Test>
[0, 1, 0] :: [Int]
Test>
[1, 0, 1, 0, 1, 1, 0] :: [Int]

Érdekesség: A osztó egyébként egy polinomot ábrázol, ahol a sorozatban megjelenő értékek az egyes tagokhoz tartozó együtthatókat adják meg. Például a [1,0,1,1] sorozat az x^3 + x + 1 polinomot jelöli. Polinomoktól függően más és más módon tudunk CRC értékeket számolni, amely általában a felhasználási területtől függ.