Kody i szyfry
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 x ∈ Z przez liczbę m ∈ N, m ≥ N, m ≥ 2. Potrzebne nam będzie ponadto pojęcie kongruencji. Niech m ∈ N, m ≥ 2, mówimy, że dwie liczby a, b ∈ Z przystają modulo m jeśli dają tę samą resztę z dzielenia przez m. Zapisujemy to pisząc a ≡ b (mod m). Zapis taki nazywamy kongruencją modulo m.
Podstawą zapisu resztowego jest następujące chińskie twierdzenie o resztach.
Niech liczby naturalne m1,m2,...mn większe od jedności będą parami względnie pierwsze (tzn. dla każdego i ≠ j 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 a ∈ Z, M = m1⋅m1⋅...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 i = 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 i ≠ j
Dowód: Możemy znaleźć n liczb c1c2,...cn takich, że ci ∈ \(Z{_m}_{_i}\)oraz ci \(\otimes _{m_i} \left[ \frac{M}{m_i} \right]_{m_{i}}\) = 1 (lub równoważnie ci jest elementem odwrotnym do elementu \(\left[ \frac{M}{m_i} \right]_{m_i}\) w pierścieniu \(Z_{m_{i}}\) czyli ci = \(\left[ \frac{M}{m_i} \right]^{-i}_{m_{i}}\)). Łatwo sprawdzić, że ki = ci \(\frac{M}{m_i}\) 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.
Niech będzie dana liczba x ∈ Z 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: <0, m_1 \cdot m_2 \cdot ... \cdot m_n - 1 >\) → \(Z{_{m_1}} \times Z{_{m_2}} \times ... \times Z{_{m_n}}\). Zakres tak zdefiniowanego zapisu RNS jest oczywiście równy \(<0, m_1 \cdot m_2 \cdot ... \cdot m_n - 1 >\).
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)\) i \(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_i\), \(a_i - _{m_i} b_i\), \(a_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 − x = (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 − x = 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 ⋅ x = (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 ⋅ x = 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 M = m1, 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 ⋅bn − a)(mod M).\(\qquad\)(10)
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 := (a1 − v1)c12(mod m2)
v3 := ((a1 − v1)c13−v1)c23(mod m3)\(\qquad\)(12)
.
.
.
vr := ((un − v1)c1r − v2)c2n − ...− 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 2e − 1 konwersja liczby x na jej zapis RNS jest bardzo prosta.
Ogólnie rzecz biorąc, jeśli mamy liczbę x ∈ 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 A = 2ei i 0 ≤ ak < 2ej i dla każdego k = 0,1,...t.
Zatem:
u = a1 + at −1 + ... + a1 + a0 (mod 2ej − 1)\(\qquad\)(15)
ponieważ A ≡ (mod 2ej − 1) i ostatecznie:
ui = a1 \(\oplus\) at −1 \(\oplus\)...\(\oplus\) a10\(\qquad\)(16)
ui = at + at −1 + ... + a0 (mod (2ej − 1))\(\qquad\)(17)
Zajmijmy się modułami postaci mj = 2ej − 1, gdzie ej ∈ N, ej ≥ 2, dokładniej. Pokażemy jakie korzyści wynikają z wyboru modułów m1,m2,...mr tak, by było mj = 2ej − 1, ej ∈ N, ej ≥ 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.
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,20 − 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.
Słowo maszynowe k-bitowe, ogólnie rzecz biorąc może być jednak takie, że 2k > mi lub 2k < mi . 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)
(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.