2. Kody numeryczne i arytmetyka cyfrowa

2.15. Zapisy resztowe

Zapis resztowy to inaczej zapis rezidualny lub zapis RNS (od ang. Residue Number System). Koncepcja zapisu rezidualnego (lub nieco ogólniej arytmetyki ) pochodzi od A.Svobody i M.Valacha i została podana w pracy zamieszczonej w czeskim czasopiśmie ”Stroje na Zapracovani Informaci” w roku 1955. Niezależnie od A.Svobody i M.Valacha pomysł zapisu rezidualnego podał w 1959 r. H.L.Garner w pracy opublikowanej w IRE Transactions EC-8.

Zapis resztowy umożliwia realizację szybkiej arytmetyki (dokładniej: dodawania, odejmowania i mnożenia) bez propagacji przeniesień. Mnożenia które są dosyć złożonymi działaniami (a np. w cyfrowym przetwarzaniu sygnałów mnożeń wykonujemy bardzo dużo) można jak zobaczymy wykonywać bardzo szybko i prosto. Skomplikowane stają się natomiast w zapisie RNS algorytmy dzielenia i porównania liczb.

Symbolem [x]_m lub x (mod m) będziemy w dalszym ciągu oznaczać resztę z dzielenia liczby xZ przez liczbę mN, mN, m ≥ 2. Potrzebne nam będzie ponadto pojęcie kongruencji. Niech mN, m ≥ 2, mówimy, że dwie liczby a, bZ przystają modulo m jeśli dają tę samą resztę z dzielenia przez m. Zapisujemy to pisząc ≡ b (mod m). Zapis taki nazywamy kongruencją modulo m.

Podstawą zapisu resztowego jest następujące chińskie twierdzenie o resztach.

Twierdzenie (chińskie twierdzenie o resztach dla pierścienia liczb całkowitych Z)
Niech liczby naturalne m1,m2,...mn większe od jedności będą parami względnie pierwsze (tzn. dla każdego  ij mamy NWD(mi,mj) = 1 wówczas dla dowolnych n liczb całkowitych x1,x2,...xn ∈ Z układ kongruencji liniowych

x x1 (mod mi)

x x2 (mod m2)\qquad(1)

...

x xi (mod mn)

ma dokładnie jedno rozwiązanie x w zbiorze <a,a + M − 1>, gdzie aZ, M = m1m1⋅...mn. Rozwiązanie to jest dane wzorem

x = a + \left[ \displaystyle\sum^n_{i=1}k_ix_i \right]_M\qquad(2)

gdzie ki dla = 1,2,3,...n są liczbami całkowitymi spełniającymi warunek

ki ≡ i (mod mi) dla i = 1,2,3,...,n

(3)

ki ≡ 0 (mod mj) dla ij

Dowód: Możemy znaleźć n liczb c1c2,...cn takich, że ciZ{_m}_{_i}oraz c\otimes _{m_i} \left[ \frac{M}{m_i} \right]_{m_{i}} = 1 (lub równoważnie cjest elementem odwrotnym do elementu \left[ \frac{M}{m_i} \right]_{m_i} w pierścieniu Z_{m_{i}} czyli c\left[ \frac{M}{m_i} \right]^{-i}_{m_{i}}). Łatwo sprawdzić, że ki = ci \frac{M}{m_i} = 1,2,3,...,n spełniają warunek (**). Wynika to z tego, że NWD(m_i,\left[ \frac{M}{m_i} \right]_{m_i}) = 1.

Oczywiście rozwiązaniem układu kongruencji (*) będzie również każda taka liczba całkowita y dla której mamy xy (mod m1m2...mn) zbiór {x + <em>kM</em>; <em>k</em> ∈ Z} jest jednocześnie zbiorem wszystkich rozwiązań układu kongruencji (*).
Łatwo można sprawdzić, że \displaystyle\sum^{n}_{i=1}k_i ≡ 1 (mod M)

Niech będzie dana liczba xZ i niech liczby naturalne m1,m2,...mn większe od jedności będą parami względnie pierwsze. Zapisem resztowym liczby x nazywamy ciąg skończony

([x]_{m_1},[x]_{m_2},...x]_{m_n})\qquad(4)

W ten sposób definiujemy kod numeryczny f:  → Z{_{m_1}} \times Z{_{m_2}} \times ... \times Z{_{m_n}}. Zakres tak zdefiniowanego zapisu RNS jest oczywiście równy .

Wybieramy moduły takie: m1 = 3, m2 = 5, m3 = 7, m4 = 8. Możemy wówczas reprezentować 840 liczb (ponieważ m1m2m3m4 = 840). Wszystkie 4 współrzędne dają się zapisać za pomocą 3 bitowego słowa co daje w sumie 11 bitów. Widać pewną redundancję w stosunku do naturalnego zapisu binarnego NKB (10 bitów)

Dodawanie, odejmowanie i mnożenie liczb w zapisie resztowym jest wykonywane po współrzędnych. Dokładniej, jeśli mamy 2 liczby zapisane w zapisie resztowym a = ([a]_{m_1},[a]_{m_2},[a]_{m_n})  = (a_1, a_2,..., a_n)b = ([b]_{m_1}, [b]_{m_2},..., [b]_{m_n} = (b_1, b_2, ..., b_n) to wówczas (jeśli wynik działania należy do zakresu zapisu) algorytmy dodawania, odejmowania i mnożenia dane są wzorami

a+b=(b_1,b_2,...b_n) + (b_1, b_2, ...,b_n) = (a_1\oplus_{m_1}b_1, a_2\oplus_{m_2}b_2, ... a_n\oplus_{m_n}b_n)\qquad(5)

a-b=(b_1,b_2,...b_n) - (b_1, b_2, ...,b_n) = (a_1-_{m_1}b_1, a_2-_{m_2}b_2, ... a_n-_{m_n}b_n)\qquad(6)

a \cdot b=(b_1,b_2,...b_n) \cdot (b_1, b_2, ...,b_n) = (a_1\oplus_{m_1}b_1, a_2\oplus_{m_2}b_2, ... a_n\oplus_{m_n}b_n)\qquad(7)

gdzie a_i \oplus _{m_i} b_ia_i - _{m_i} b_ia_i \otimes _{m_i} b_i są odpowiednio dodawaniem, odejmowaniem i mnożeniem modulo m_i.


Przyjmijmy m1 = 3 m2 = 5 m3 = 7 i niech x = 3, y = 6. Stosując zapis resztowy mamy x = (0,3,3,0), y = (0,1,6).


Dodając liczby x = (0,3,3,0), y = (0,1,6) w zapisie resztowym według zaproponowanego wyżej algorytmu mamy

x + y = (0,3,3,0) + (0,1,6) = (0 \oplus _{m_1} 0,3 \oplus _{m_2}1,3 \oplus _{m_3}6 )= (0,4,2) 

Zauważmy, że x + y = 9 i zapisując 9 w zapisie resztowym mamy (0,4,2) a więc z zaproponowanego algorytmu otrzymaliśmy wynik prawidłowy.

Odejmując liczby y = (0,1,6) i x = (0,3,3), w zapisie resztowym według zaproponowanego wyżej algorytmu mamy

 y − = (0,1,6) − (0,3,3,0) = (0-_{m_1}0, 1-_{m_2}3, 6-_{m_n}3) = (0,3,3)

Zauważmy, że y − = 3 i zapisując 3 w zapisie resztowym mamy (0,3,3) a więc z zaproponowanego algorytmu otrzymaliśmy wynik prawidłowy.


Mnożąc liczby x = (0,3,3,0), y = (0,1,6) w zapisie resztowym według zaproponowanego wyżej algorytmu mamy

 y ⋅ = (0,1,6) ⋅ (0,3,3,0) = (0 \otimes _{m_1}0, 1 \otimes _{m_2}3, 6\otimes _{m_n}3) = (0,3,4)

 

Zauważmy, że y ⋅ = 18 i zapisując 18 w zapisie resztowym mamy (0,3,4) a więc z zaproponowanego algorytmu otrzymaliśmy wynik prawidłowy.

Konwersja zapis NKB liczby x → na zapis RNS liczby x sprowadza się do obliczenia n reszt z dzielenia liczby x przez moduły m1, m2, m3, ..., mn.

Konwersja zapis RNS →  zapis NKB jest nieco bardziej złożona. Podamy dwa algorytmy konwersji.

Podstawowy algorytm konwersji jest na ogół formułowany w samym chińskim twierdzeniu o resztach. Przypomnijmy algorytm:

Niech a1, a2, ..., an będzie zapisem RNS liczby x oraz Mm1, m2, ..., mn.

I. Znajdujemy liczby bj ∈ Z takie, że:

bj ⋅ \frac{M}{m_j} = 1 (mod m_j) dla j = 1,2,...n).\qquad(8)

II. Jeśli x ∈ [0, M], to

x = [a1 ⋅b1 ⋅ \frac{M}{m_1} + a2 ⋅b2 ⋅ \frac{M}{m_2} + ... +  an ⋅bn\frac{M}{m_n}]M,\qquad(9)

a ogólnie, jeśli x ∈ [a, a + m), to

x = a + (a1 ⋅b1 ⋅ \frac{M}{m_1} + a2 ⋅b2 ⋅ \frac{M}{m_2} + ... +  an ⋅b− a)(mod M).\qquad(10)

Niech m1 = 3, m2 = 5, m3 = 7 oraz niech x = (0,3,3). Wyznaczamy stałe b1, b2, b3, spełniające warunek (8) otrzymując b1 = 1, b2 = 1, b3 = 1. Korzystając ze wzoru (9) otrzymujemy x = 3.

Konwersja wykorzystująca „mixed radix representation” (algorytm Garnera).

I. Niech (a1, a2, a3) będzie zapisem RNS liczby x. Definiujemy  \binom{n}{2} stałych cij (liczymy je tylko jeden raz – wstępnie).

cij mi ≡ 1 (mod mj) dla  1 ≤ i < j ≤ n,\qquad(11)

lub co na jedno wychodzi, poszukujemy odwrotności elementu [m_i]_{m_j} w pierścieniu Z_{m_j}, czyli takiego cij, że cij \otimes_{m_j} mj = 1 w pierścieniu Z_{m_j}.

II. Obliczamy ciąg v1, v2,...vn gdzie v1 ∈ [0, mi, −1) będący zapisem mixed radix szukanej liczby x,

v1 := a1 (mod m1)

v2 := (a− v1)c12(mod m2)

v3 := ((a− v1)c13v1)c23(mod m3)\qquad(12)
.
.
.
vr := ((u− v1)c1− v2)c2− ...− vr−1)cr−1,n (mod mn)

III. Obliczamy

x = vn ⋅mn−1 ⋅ ...⋅ m1  + vn−1 ⋅mn−2⋅ ...⋅m1  +...+ v3 ⋅m2 ⋅m1 + v2 ⋅m1 ⋅v1 \qquad(13)

Łatwo zauważyć, że w zapisie RNS złożoność konwersji z RNS → zapis binarny; zapis binarny RNS w pewnym stopniu zależy od wyboru modułów m1,m2,m3,...mn.

Dla modułów postaci 2− 1 konwersja liczby x na jej zapis RNS jest bardzo prosta.

Ogólnie rzecz biorąc, jeśli mamy liczbę Z otrzymujemy jej reprezentację resztową przez dzielenie x przez kolejne moduły mi, co daje ciąg (a1,a2,...ar). Jednak dla modułów postaci 2ei − 1, można zrobić tak:

x = atAt + at−1At−1 +...+ a1A + a0\qquad(14)

gdzie = 2ei i 0 ≤ ak < 2ej i dla każdego k = 0,1,...t.

Zatem:

u = a1at −1 + ... + a1a(mod 2e− 1)\qquad(15)

ponieważ ≡ (mod 2e− 1) i ostatecznie:

ui = a1 \oplus at −1 \oplus...\oplus a10\qquad(16)

ui = atat −1 + ... + a(mod (2e− 1))\qquad(17)

Zajmijmy się modułami postaci mj = 2e− 1, gdzie ejNej ≥ 2, dokładniej. Pokażemy jakie korzyści wynikają z wyboru modułów m1,m2,...mtak, by było mj = 2e− 1, ejNej ≥ 2. Zależy nam na tym, żeby były to moduły parami względnie pierwsze. Następujące twierdzenie stanowi kryterium na to, by dwie liczby postaci 2^f− 1 i 2e − 1 były względnie pierwsze.

Dla e,fN mamy NWD(2e − 1),(2^f− 1) = 2NWD(e, ^f− 1.

Dowód: 1. Zauważmy, że zachodzi równość:

((2e − 1)(mod 2^f− 1)) = 2e, (mod ^f− 1\qquad(18)

Jeśli e ≤ f, to jest to oczywiste. Niech e>f. Równość (18) jest równoważna do kongruencji

(2e − 1) ≡ 2e (mod ^f− 1 (mod (2^f− 1))\qquad(19)

i dalej

2e ≡ 2e mod ^f (mod (2^f− 1))\qquad(20)

2e(mod ^f) 2^f...q^f ≡ 2e mod ^f (mod (2^f− 1))\qquad(21)

ale: 2^f ≡ 1 (mod (2^f− 1)) zatem prawdziwa jest równość (18).

2. Wracamy do dowodzonej równości. Niech e>f (dla e=f równość jest oczywista) wówczas na mocy (18) i algorytmu Euklidesa NWD(2e − 1,2^f− 1) = NWD(2^f− 1,2e mod ^f − 1).

Kolejno stosujemy wzór (18), czyli obliczamy resztę z dzielenia przez liczbę mniejszą, zauważmy przy tym, że NWD(e, f) = NWD(f,e (mod f)).

Postępując zgodnie z algorytmem Euklidesa otrzymamy wreszcie, w kolejnym kroku, iloraz reszt =0.

Będziemy więc mieli: NWD(2e − 1,2^f− 1) = NWD(2a− 1,2− 1) = 2a − 1

oraz  NWD(e, f) = NWD(a0) = a

Wniosek: Liczby 2e − 1 i 2^f − 1 są względnie pierwsze wtedy i tylko wtedy, gdy e i f są względnie pierwsze.

Możemy wybrać jako moduły np.: m1 = 235 − 1, m2 = 234 − 1, m3 = 233 − 1, m4 = 231 − 1, m5 = 229 − 1. Jest to bardzo wygodne jeśli mamy słowo maszynowe 35 bitowe. Możemy w tej sytuacji reprezentować liczby z zakresu od 0 do m1 ⋅ m2 ⋅ m3 ⋅ ... ⋅  m5 > 2161. 

Słowo maszynowe k-bitowe, ogólnie rzecz biorąc może być jednak takie, że 2k > mi lub 2kmi . Jeśli moduły dają się zapisać w kodzie NKB na słowie maszynowym to jest to oczywiście wygodne, ale nie jest to niezbędne.

Zasadnicze znaczenie dla szybkości wykonywania działań arytmetycznych w zapisie resztowym mają sposoby wykonywania działań modulo m. Działania modulo m powinny być realizowane za pomocą odpowiednio zaprojektowanych układów.

Uogólnieniem zapisu RNS na liczby zespolone jest zapis resztowy QRNS (Quadratic Residue Numer System)

Istotę zapisu resztowego w języku algebry można wyrazić tak. Pierścień ilorazowy Z / (m1m2...mnZ) i i suma prosta pierścieni ilorazowych (Z / m1Z) ⊕ (Z / m2Z) ⊕ ...⊕ (Z / mnZ) są izomorficzne tzn.

(Z / m1m2...mnZ) ≅ (Z / m1Z) ⊕ (Z / m2Z) ⊕ ...⊕ (Z / mnZ)

i izomorfizm zadany jest wzorem γ(x) = ([x]_{m_1},[x]_{m_2},...,[x]_{m_n}). Jest to nieco inne sformułowanie chińskiego twierdzenia o resztach.