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 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 ≡ 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
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 ∈ oraz ci
= 1 (lub równoważnie ci jest elementem odwrotnym do elementu
w pierścieniu
czyli ci =
). Łatwo sprawdzić, że ki = ci
i = 1,2,3,...,n spełniają warunek (**). Wynika to z tego, że NWD(
) = 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
W ten sposób definiujemy kod numeryczny →
. Zakres tak zdefiniowanego zapisu RNS jest oczywiście równy
.
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 =
=
i
=
to wówczas (jeśli wynik działania należy do zakresu zapisu) algorytmy dodawania, odejmowania i mnożenia dane są wzorami
gdzie ,
,
są odpowiednio dodawaniem, odejmowaniem i mnożeniem modulo
.
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,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,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,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 ⋅ = 1 (mod
) dla j = 1,2,...n).
(8)
II. Jeśli x ∈ [0, M], to
x = [a1 ⋅b1 ⋅ + a2 ⋅b2 ⋅
+ ... + an ⋅bn
]M,
(9)
a ogólnie, jeśli x ∈ [a, a + m), to
x = a + (a1 ⋅b1 ⋅ + a2 ⋅b2 ⋅
+ ... + an ⋅bn − a)(mod M).
(10)
Konwersja wykorzystująca „mixed radix representation” (algorytm Garnera).
I. Niech (a1, a2, a3) będzie zapisem RNS liczby x. Definiujemy stałych cij (liczymy je tylko jeden raz – wstępnie).
cij ⋅ mi ≡ 1 (mod mj) dla 1 ≤ i < j ≤ n,(11)
lub co na jedno wychodzi, poszukujemy odwrotności elementu w pierścieniu
, czyli takiego cij, że cij
mj = 1 w pierścieniu
.
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)(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 (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(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)(15)
ponieważ A ≡ (mod 2ej − 1) i ostatecznie:
ui = at + at −1 + ... + a0 (mod (2ej − 1))(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− 1 i 2e − 1 były względnie pierwsze.
Dowód: 1. Zauważmy, że zachodzi równość:
((2e − 1)(mod 2− 1)) = 2e, (mod
) − 1
(18)
Jeśli e ≤ , to jest to oczywiste. Niech e>
. Równość (18) jest równoważna do kongruencji
(2e − 1) ≡ 2e (mod ) − 1 (mod (2
− 1))
(19)
i dalej
2e(mod ) 2
...q
≡ 2e mod
(mod (2
− 1))
(21)
ale: 2 ≡ 1 (mod (2
− 1)) zatem prawdziwa jest równość (18).
2. Wracamy do dowodzonej równości. Niech e> (dla e=
równość jest oczywista) wówczas na mocy (18) i algorytmu Euklidesa NWD(2e − 1,2
− 1) = NWD(2
− 1,2e mod
− 1).
Kolejno stosujemy wzór (18), czyli obliczamy resztę z dzielenia przez liczbę mniejszą, zauważmy przy tym, że NWD(e, ) = NWD(
,e (mod
)).
Postępując zgodnie z algorytmem Euklidesa otrzymamy wreszcie, w kolejnym kroku, iloraz reszt =0.
Będziemy więc mieli: NWD(2e − 1,2− 1) = NWD(2a− 1,20 − 1) = 2a − 1
Wniosek: Liczby 2e − 1 i 2 − 1 są względnie pierwsze wtedy i tylko wtedy, gdy e i
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],[x]
,...,[x]
). Jest to nieco inne sformułowanie chińskiego twierdzenia o resztach.