2. Kody numeryczne i arytmetyka cyfrowa

2.2. Naturalne kody wagowe dla liczb naturalnych i zera

Podstawowy fakt z arytmetyki umożliwiający skonstruowanie dużej klasy kodów liczbowych tzw. naturalnych kodów wagowych jest następujący:

Twierdzenie: Dla dowolnej liczby N i ustalonego ciągu (m_i)^\infty_{i=0}, gdzie mi ∈ {2,3,...} istnieje dokładnie jeden ciąg skończony ak, ak-1, ..., a1, a0 taki, że

1) \qquaddla każdego i = 0,1,...,k, a∈ {0,1...<em>m<sub>i </sub></em><sub>-1</sub>}, ak ≠0

2) \qquadm = akmk-1mk-2 ⋅  ... ⋅ m0 + ak-1mk-2mk-3 ⋅ ...⋅  m0 + ...a2m1m0 + a1m0 + a0

Dowód: Prosty dowód pozostawiamy Czytelnikowi (por. też D.E.Knuth [5]) 

Wniosek: Dla dowolnej liczby mN i ustalonej liczby W ∈ {2,3} istnieje dokładnie jeden ciąg skończony ak,ak-1...a1a0 taki, że

1) ak,ak-1...a1a0 ∈ {0,1...<em>W</em>-1}, a {0}

2) makWk . ak-1Wk-1 a1a0

Powyższy wniosek pozostaje również z pewnymi modyfikacjami prawdziwy dla W = -2 (tzw. zapis minusdwójkowy) i innych wag ujemnych (por. [10]). Wagi ujemne nie mają jednak obecnie większego praktycznego znaczenia

Liczba W nosi nazwę wagi lub podstawy zapisu wagowego (ang. radix). W praktyce na oznaczenie liczb {0,1...<i>W </i>- 1} używamy ustalonych symboli z pewnego równolicznego z {0,1...<i>W </i>- 1} alfabetu V, nazywając je cyframi. Wygodnie jest niekiedy te symbole utożsamiać z liczbą ze zbioru  {0,1...<i>W </i>- 1} w tym sensie, że raz traktujemy je jak symbole, raz jak liczby. Możemy też wręcz przyjąć, że V = {0,1...<i>W </i>- 1}.

Odwzorowanie K: N ∪ {0} ∋ → K(m) = akak-1...a1a0 ∈ V* określone na zbiorze ∪ {0} i zdefiniowane w powyższym wniosku nazywamy kodem wagowym z wagą W ≥ 2 przy czym przyjmujemy K(0) = 0.

Typowe najczęściej używane wagi to 2, 8, 10, 16, 26 (26 to liczba małych liter w alfabecie angielskim). Wag W=26 i W=256 używamy w kryptografii do utożsamienia tekstu z liczbą ze zbioru N ∪ {0}.

Zapisy wagowe dla wag 2, 8, 10, 16, noszą następujące nazwy:

Zapisy wagowe dla wag 2, 8, 10, 16, noszą następujące nazwy:

W=2, kod NKB - naturalny kod binarny lub zapis dwójkowy naturalny (lub zwykły zapis dwójkowy), mamy dwie cyfry: 0, 1

W=8, zapis oktalny, mamy 8 cyfr 0, 1, 2, 3, 4, 5, 6, 7

W=10, zapis dziesiętny, mamy 10 cyfr 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

W=16, zapis hexadecymalny (lub szesnastkowy) , mamy 16 cyfr 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F (stosujemy dodatkowe cyfry A, B, C, D, E, F)

Jeśli mamy wątpliwości, jakiego zapisu używamy, to po zapisie liczby stosujemy znak spoza alfabetu w jakim zapisujemy liczbę, np.: B – dla zapisu binarnego, O - dla zapisu oktalnego, D - dla zapisu dziesiętnego i H - dla zapisu hexadecymalnego. Czasami z kontekstu wynika jakim zapisem operujemy więc dodatkowe wyjaśnienia nie są potrzebne. Zapis dziesiętny będziemy w dalszym ciągu traktować zwyczajowo jako wyróżniony i z reguły literę D będziemy pomijać.

101(B) lub 101B dla zapisu binarnego oraz 1A2(H) lub 1A2H dla zapisu hexadecymalnego.

Wygodnie jest też ciąg K(m) = akak-1...a1a0 ∈ V*utożsamiać jeśli trzeba z liczbą m tak jak to zwyczajowo czynimy dla zapisu z wagą W=10 czyli dla dobrze znanego zapisu dziesiętnego.

Zapis binarny : 5= 1001 B, 8= 1000 B, 7=111 B
Zapis hexadecymalny: 8= 8 H, 7=7 H, 15=F H
Kod NKB (naturalny kod binarny) dla zbioru liczb {0,1,...,7}.
 Kod NKB (naturalny kod binarny) dla zbioru liczb {0,1,...,7}.

0→0
1→1
1→10
3→11
4→100
5→101
6→110
7→111

Warto podkreślić, że zbiorem obiektów kodowanych jest dla rozważanych w tym punkcie kodów zbiór liczb naturalnych z zerem tzn. N ∪ {0} a więc rozważane kody są kodami numerycznymi. Jednocześnie słowa kodowe mogą być dowolnie długie. Nie są to więc kody ze stałą długością słowa kodowego. Dla ustalonej liczby a ∈ N ∪ {0} i ustalonej wagi W ∈ {2,3...} łatwo można obliczyć długość słowa kodowego l(a) reprezentującego liczbę a. Jeśli a = 0, to l(a) = 1, jeśli a ≠ to

l(a) = \lfloor log_wa\rfloor+1\qquad(*)

gdzie \lfloor \cdot \rfloor RZ jest tzw. funkcją podłogi (lub jak mówimy krótko podłogą). Jeśli x ∈ R to \lfloor x \rfloor jest największą liczbą całkowitą nie większą od x .

Przykład: Obliczmy korzystając ze wzoru (*) za pomocą ilu bitów zapisujemy w kodzie NKB liczby 2n + 1, 2n - 1. Ponieważ log22n = log102 i funkcja logarytmiczna jest ściśle monotoniczna łatwo obliczamy kolejno:

l(a) = \lfloor log_22^n\rfloor + 1 = n +1 \\ l(a) = \lfloor log_2(2^n+1)\rfloor + 1 = n +1 \\ l(a) = \lfloor log_2(2^n-1)\rfloor + 1 = n

gdzie a oznacza słowo binarne reprezentujące liczbę.

Ile cyfr hexadecymalnych potrzeba do zapisu liczby 2n? Stosując wzór (*) dostajemy l(a) = \lfloor \text {log}_{16}2^n\rfloor + 1 = \lfloor n/4 \rfloor +1.
Obliczmy korzystając ze wzoru (*) za pomocą ilu cyfr dziesiętnych zapisujemy w naturalnym kodzie wagowym dziesiętnym (czyli jak mówimy krótko w zapisie dziesiętnym) liczby 2n, dla n=10. Ponieważ log102n = n log102 łatwo obliczamy kolejno: l(a) = \lfloor log_{10}2^{10}\rfloor + 1 = \lfloor \text{log}_{10}2\rfloor +1 = 4. Podobnie można wykazać, że taka sama liczba cyfr dziesiętnych jest potrzebna do zapisu liczby 2+ 1 i 2n  − 1 przy = 10.

Algorytm dodawania w naturalnym zapisie wagowym z wagą W. Algorytm dodawania w naturalnym zapisie wagowym z wagą W jest w zasadzie identyczny jak w przypadku naturalnego zapisu dziesiętnego. Jeśli dodajemy w naturalnym zapisie wagowym z wagą W 2 liczby a i b reprezentowane słowami

a = anan-1...a1a0 \qquadi\qquad b = bkbk-1,...b1b0

to żeby uzyskać sumę s = snsn-1...s1s0 postępujemy tak:

1) Obliczamy s0 = a0 + b0 (mod W). Jeśli s0 = a0 + b0 ≥ W to podstawiamy c1 := 1 a jeśli s0 = a0 + b0W to podstawiamy c1 := 0 

2) Obliczamy s= a1 + b1+ c1 (mod W). Jeśli s= a1 + b1 + c1 ≥ W to podstawiamy c2 := 1 a jeśli s= a1 + b1 + c1 < W to podstawiamy c2 := 0

.....

i) Obliczamy si = ai + b+ ci (mod W). Jeśli si = ai + b+ ciW to podstawiamy ci+1 := 1 a jeśli si = ai + b+ ci < W to podstawiamy ci+1 := 0

......

n) Obliczamy sn = an + b+ cn (mod W). Jeśli sn = an + b+ cnW to podstawiamy cn+1 := 1 a jeśli sn = an + b+ cn < W to podstawiamy ci+1 := 0.

Algorytm mnożenia w naturalnym zapisie wagowym z wagą W jest w zasadzie identyczny jak w przypadku naturalnego zapisu dziesiętnego ale używamy „tabelki mnożenia” właściwej dla W tzn. używamy „tabelki mnożenia” dla par liczb <0,W−1>×<0,W−1>.

Istota rzeczy: algorytmy dodawania i mnożenia w naturalnych zapisach wagowych pozostają właściwie takie same jak w przypadku dodawania liczb w zapisie dziesiętnym.

Przykład: Mamy 2 liczby w zapisie NKB 10101010a=11111111b=. Stosując opisany algorytm otrzymujemy sumę:

             10101010
Suma:     11111111
            110101001

Mamy 2 liczby w zapisie NKB a = 1010 b =1111. Stosując opisany algorytm mnożenia otrzymujemy iloczyn:

                       1010
                       1111
                      1010
                    1010
                  1010
Iloczyn:    1010
              10010110