W poprzednich dwóch rozdziałach nauczyliśmy was obliczać wartość liczby zapisanej w dowolnym systemie pozycyjnym. Teraz zajmiemy się zadaniem odwrotnym - jak przedstawić daną liczbę w systemie pozycyjnym o podstawie p.
Problem sprowadza się do znalezienia kolejnych cyfr zapisu liczby w systemie docelowym. Wartość liczby L jest równa zgodnie ze wzorem:
L = Cn-1 pn-1 + Cn-2 pn-2 + ... + C2 p2 + C1 p + C0
Do wydobycia poszczególnych cyfr Ci , i = 0,1,2,...,n-1, są nam potrzebne dwa działania:
- div - dzielenie całkowitoliczbowe - określa ile całkowitą ilość razy dzielnik mieści się w dzielnej, na przykład:
9 div 4 = 2, gdyż 4 mieści się w 9 2 razy.- mod - reszta z dzielenia całkowitoliczbowego, na przykład:
9 mod 4 = 1, gdyż 4 mieści się w 9 dwa razy, co daje 8 i pozostaje reszta 1.
Reszta z dzielenia jest zawsze mniejsza od dzielnika (dlaczego?).Oba działania występują powszechnie we wszystkich językach programowania. Wyjątkiem jest JavaScript, który posiada swobodne typy danych, zatem brak w nim dzielenia całkowitoliczbowego, ale można sobie z tym w prosty sposób poradzić.
Realizacja operacji div i mod | ||
---|---|---|
Pascal | div mod | a div b a mod b |
C++ | div mod | a / b a % b |
Basic | div mod | a \ b a MOD b |
Python | div mod | a // b a % b |
JavaScript | div mod | Math.floor(a / b) a % b |
Jeśli podzielimy L przez p, otrzymamy:
Ostatnia cyfra C0 nie dzieli się przez p (każda cyfra jest mniejsza od podstawy systemu), zatem będzie resztą z dzielenia całkowitoliczbowego L przez p. Pozostała część wyrażenia jest jak widać podzielna przez p. Zauważ, iż w wyniku dostajemy liczbę z mniejszą ilością cyfr. W porównaniu z poprzednią liczbą wszystkie cyfry są przesunięte o 1 pozycję w prawo - teraz najmłodszą cyfrą jest C1. Operację powyższą powtarzamy aż do znalezienia wszystkich cyfr zapisu liczby.
Przedstawić w systemie piątkowym liczbę 139(10).
L = 139
p = 5
C0 = L mod p = 139 mod 5 = 4
L = L div p = 139 div 5 = 27
C1 = L mod p = 27 mod 5 = 2
L = L div p = 27 div 5 = 5
C2 = L mod p = 5 mod 5 = 0
L = L div p = 5 div 5 = 1
C3 = L mod p = 1 mod 5 = 1
L = L div p = 1 div 5 = 0 - kończymy, ponieważ wynik dzielenia daje wartość 0.
139(10) = 1024(5).Praktycznie działania te wykonujemy w słupku dzieląc całkowitoliczbowo liczbę przez podstawę systemu i wypisując reszty z dzielenia. Gdy rachunki zakończymy, otrzymane reszty odczytujemy w kierunku z dołu do góry otrzymując kolejne cyfry zapisu liczby.
Przedstawić w systemie czwórkowym liczbę 2743(10).
2743 div 4 = 685 i reszta 3 685 div 4 = 171 i reszta 1 171 div 4 = 42 i reszta 3 42 div 4 = 10 i reszta 2 10 div 4 = 2 i reszta 2 2 div 4 = 0 i reszta 2 - koniec, ponieważ wynik dzielenia wynosi 0 2743(10) = 222313(4).
Przedstawić w systemie dziewiątkowym liczbę 35921(10).
35921 div 9 = 3991 i reszta 2 3991 div 9 = 443 i reszta 4 443 div 9 = 49 i reszta 2 49 div 9 = 5 i reszta 4 5 div 9 = 0 i reszta 5 - koniec 35921(10) = 54242(9).
Przedstawić w systemie trójkowym liczbę 325748(10).
325748 div 3 = 108582 i reszta 2 108582 div 3 = 36194 i reszta 0 36194 div 3 = 12064 i reszta 2 12064 div 3 = 4021 i reszta 1 4021 div 3 = 1340 i reszta 1 1340 div 3 = 446 i reszta 2 446 div 3 = 148 i reszta 2 148 div 3 = 49 i reszta 1 49 div 3 = 16 i reszta 1 16 div 3 = 5 i reszta 1 5 div 3 = 1 i reszta 2 1 div 3 = 0 i reszta 1 - koniec 325748(10) = 121112211202(3).
Podsumujmy podane dotychczas informacje w formie algorytmu.
Dane wejściowe
L - przeliczana liczba, L N + {0} p - podstawa docelowego systemu pozycyjnego, p N, p {2,3,...,10} Dane wyjściowe
Ciąg znaków s reprezentujący zapis liczby L w systemie pozycyjnym o podstawie p.
Zmienne pomocnicze i funkcje
s - przechowuje docelowy zapis liczby. c - przechowuje wartość cyfry, c N + {0} kod(znak) - funkcja zwraca kod ASCII znaku znak(kod) - zwraca znak ASCII o podanym kodzie
krok 1: Czytaj L i p krok 2: s "" krok 3: c L mod p krok 4: s znak(c + kod('0')) + s krok 5: L L div p krok 6: Jeśli L = 0, to pisz s i zakończ algorytm. Inaczej idź do kroku 3.
Odczytujemy liczbę L, którą chcemy przeliczyć oraz podstawę p docelowego systemu pozycyjnego. Podany algorytm pracuje poprawnie tylko dla podstaw p od 2 do 10 (dlaczego?).
Wyliczone cyfry będziemy odkładać w zmiennej łańcuchowej s. Inicjujemy ją pustym tekstem.
Rozpoczynamy pętlę warunkową, która będzie wykonywana, aż liczba L osiągnie wartość 0. Wewnątrz pętli obliczamy wartość ostatniej cyfry liczby L i umieszczamy wynik w zmiennej c. Aby wstawić cyfrę do zmiennej łańcuchowej s musimy ją wyrazić za pomocą kodu ASCII. Dlatego w wyrażeniu wyliczamy kod znaku cyfry jako sumę wartości cyfry oraz kodu cyfry 0. Na przykład dla cyfry 5 otrzymamy kod 5 + 48 = 53 (cyfra 0 ma w ASCII kod 48). Znak o kodzie 53 to właśnie cyfra 5. Obliczony kod cyfry przekształcamy w znak i łączymy z zawartością łańcucha s. Bardzo ważna jest tutaj kolejność łączenia. Cyfra musi być dopisana przed poprzednio wyliczonymi cyframi, ponieważ algorytm wyznacza cyfry od końca zapisu liczby. Po dołączeniu cyfry do łańcucha liczbę L dzielimy całkowitoliczbowo przez p i przechodzimy do sprawdzenia warunku zakończenia pętli. Jeśli po operacji dzielenia liczba L nie jest równa zero, to nie zostały jeszcze wyznaczone wszystkie cyfry, zatem pętla kontynuuje się. Jeśli natomiast liczba L jest równa zero, zmienna s zawiera komplet cyfr liczby w docelowym systemie pozycyjnym. Wychodzimy z pętli, wypisujemy zawartość łańcucha s i kończymy algorytm.
Poniższe, przykładowe programy są praktyczną realizacją omawianego w tym rozdziale algorytmu. Zapewne można je napisać bardziej efektywnie. To już twoje zadanie. Dokładny opis stosowanych środowisk programowania znajdziesz we wstępie. Programy przed opublikowaniem w serwisie edukacyjnym zostały dokładnie przetestowane. Jeśli jednak znajdziesz jakąś usterkę (co zawsze może się zdarzyć), to prześlij o niej informację do autora. Pozwoli to ulepszyć nasze artykuły. Będziemy Ci za to wdzięczni.
Na podstawie algorytmu tworzymy programy wyznaczające zapis podanej liczby dziesiętnej w systemie pozycyjnym o podstawie od 2 do 10. Zwróć uwagę, iż algorytm nie sprawdza poprawności danych wprowadzonych przez użytkownika. Jeśli użytkownik poda podstawę systemu docelowego równą 1, to pętla warunkowa nigdy nie zakończy się dla L > 0 (dlaczego?). Zastanów się nad sposobami usunięcia tych wad.
Wydruk z uruchomionego programu |
---|
Przeliczanie podanej liczby na zapis |
Microsoft Visual Basic 2005 Express Edition |
Wyznaczmy złożoność obliczeniową zaprezentowanego algorytmu przy znajdowaniu reprezentacji liczby L w systemie pozycyjnym o podstawie p.. Za operację dominującą przyjmijmy 1 obieg pętli warunkowej. Każdy obieg zmniejsza wartość liczby L p razy. Obiegi wykonywane są do momentu, aż L osiągnie wartość 0. Zatem ich ilość wyraża się wzorem:
Ze wzoru wynika, iż algorytm jest klasy O(logp n), gdzie n oznacza wartość liczby, której reprezentację wyznaczamy w systemie pozycyjnym o podstawie p.
Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.
Źródło: mgr Jerzy Wałaszek