Konwertowanie liczb całkowitych

Zanim napiszemy program przekształcający liczby dziesiętne do postaci w systemie dwójkowym (binarnymsystem binarnybinarnym), przypomnimy algorytm konwersji.

Posłużymy się przykładem. Chcemy zapisać liczbę 26Indeks dolny (10) w systemie dwójkowym:

26(10)()(2)

Używając długopisu i kartki, rozwiązalibyśmy zadanie w następujący sposób:

Ruvi6PwajVoxh
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-SA 3.0.

Zaczynamy od podzielenia liczby 26 przez 2 (czyli podstawę systemu binarnego). Zapisujemy resztę z dzielenia i otrzymany iloraz, który ponownie dzielimy przez 2. Wynikiem jest kolejna reszta i iloraz; resztę znowu zapisujemy, a iloraz dzielimy przez 2. Postępujemy tak aż do momentu, w którym iloraz wyniesie 0. Zapamiętane reszty z dzielenia, odczytane od ostatniej (najnowszej) do pierwszej, składają się na zapis liczby w postaci dwójkowej.

Przełóżmy opisane wyżej operacje na listę czynności:

  1. Dzielimy liczbę przez 2.

  2. Zapisujemy iloraz całkowity oraz resztę.

  3. Przyjmujemy iloraz całkowity za nową liczbę i wracamy do punktu 1. Czynności z punktów 1. i 2. powtarzamy do momentu, w którym iloraz wyniesie zero.

  4. Zapisujemy reszty z dzielenia otrzymane na kolejnych etapach w kolejności od ostatniej (najnowszej) do pierwszej (obliczonej podczas pierwszej operacji dzielenia). Tak uszeregowane cyfry 1 oraz 0 składają się na dwójkową postać konwertowanej liczby.

Rozwiązaniem przykładowego zadania jest zatem:

26(10)11010(2)

Możemy przystąpić do napisania programu, w którym wykorzystamy opisany algorytm.

Realizacja algorytmu konwersji w języku Java

Chcemy napisać program, który odczyta podaną przez użytkownika całkowitą liczbę dziesiętną, przekształci ją do postaci dwójkowej, a następnie wypisze rezultat. Algorytm konwersji zrealizujemy w postaci osobnej funkcji, aby program był bardziej czytelny.

Zacznijmy od napisania tej części kodu, dzięki której użytkownik poda liczbę przeznaczoną do konwersji. Wykorzystamy w tym celu klasę Scanner oraz strumień wejścia (System.in):

Linia 1. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 2. int liczbaTest znak równości scanner kropka nextInt otwórz nawias okrągły zamknij nawias okrągły średnik.

Zmienna liczbaTest przechowa liczbę wpisaną przez użytkownika za pomocą klawiatury.

Przejdźmy do zdefiniowania funkcji decBin(), odpowiadającej za proces konwersji:

Linia 1. public static String decBin otwórz nawias okrągły int liczbaDec zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. String wynik znak równości cudzysłów cudzysłów średnik. Linia 3. int reszta znak równości 0 średnik. Linia 5. while otwórz nawias okrągły liczbaDec zamknij nawias ostrokątny 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. reszta znak równości liczbaDec procent 2 średnik. Linia 7. liczbaDec znak równości liczbaDec prawy ukośnik 2 średnik. Linia 8. wynik znak równości reszta plus wynik średnik. Linia 9. zamknij nawias klamrowy. Linia 11. return wynik średnik. Linia 12. zamknij nawias klamrowy.

Funkcja zwróci wartość typu String, ponieważ wynikowa liczba w systemie binarnym będzie powstawać dzięki zapisywaniu kolejnych reszt z dzielenia (symboli 0 lub 1) od strony prawej do lewej (zapis zaczynamy od końca, czyli od bitu najmłodszego, a kończymy na najstarszym). Funkcja będzie miała jeden parametr, liczbę całkowitą liczbaDec. W momencie wywołania funkcji parametr przyjmie wartość argumentu - liczby dziesiętnej podanej przez użytkownika przeznaczonej do konwersji.

W ciele funkcji deklarujemy dwie zmienne: łańcuch znaków i liczbę (String wynik oraz int reszta). Pierwsza przechowuje wynik końcowy, czyli postać dwójkową liczby dziesiętnej. Zmiennej reszta będą przypisywane wartości kolejnych reszt z dzielenia przekształcanej liczby przez 2. Odpowiednią instrukcję zapisaliśmy w linii numer 7 (reszta = liczbaDec % 2). Operator % (modulo) służy do obliczania reszty z dzielenia.

Do zmiennej wynik dopisujemy („doklejamy”) kolejne reszty z dzielenia. Używamy przy tym operatora dodawania (+). Możemy tak postąpić, ponieważ zapisujemy rezultat przekształceń jako ciąg znaków (String), a nie liczbę. Zwróć jednak uwagę na kolejność działań. To do zmiennej reszta dopisujemy zmienną wynik, a nie odwrotnie. Jest to ważne, ponieważ rezultatem przekształceń są kolejne reszty zapisywane od strony prawej do lewej. Gdybyśmy odwrócili kolejność dodawania, to w przypadku konwertowania liczby 26Indeks dolny (10) otrzymalibyśmy błędny wynik  01011Indeks dolny (2) zamiast poprawnego ciągu 11010Indeks dolny (2).

Oto końcowa wersja kodu:

Linia 1. import java kropka util kropka Scanner średnik. Linia 3. public class DecBin otwórz nawias klamrowy. Linia 4. public static String decBin otwórz nawias okrągły int liczbaDec zamknij nawias okrągły otwórz nawias klamrowy. Linia 5. String wynik znak równości cudzysłów cudzysłów średnik. Linia 6. int reszta znak równości 0 średnik. Linia 8. while otwórz nawias okrągły liczbaDec zamknij nawias ostrokątny 0 zamknij nawias okrągły otwórz nawias klamrowy. Linia 9. reszta znak równości liczbaDec procent 2 średnik. Linia 10. liczbaDec znak równości liczbaDec prawy ukośnik 2 średnik. Linia 11. wynik znak równości reszta plus wynik średnik. Linia 12. zamknij nawias klamrowy. Linia 14. return wynik średnik. Linia 15. zamknij nawias klamrowy. Linia 17. public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły otwórz nawias klamrowy. Linia 18. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 19. int liczbaTest znak równości scanner kropka nextInt otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 21. System kropka out kropka println otwórz nawias okrągły decBin otwórz nawias okrągły liczbaTest zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 22. zamknij nawias klamrowy. Linia 23. zamknij nawias klamrowy.

W linii 21. wywołujemy funkcję decBin() i od razu podajemy wynik jej działania.

Konwertowanie części ułamkowej

Przekształcanie części ułamkowej różni się od procesu konwertowania liczb całkowitych.

Przedstawimy sposób zapisania liczby dziesiętnej 0,777 w systemie dwójkowym:

ReUMopaifnka3
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-SA 3.0.

Łatwo zauważyć podstawową cechę zastosowanego algorytmu: zamiast dzielić przekształcaną liczbę przez 2, mnożymy ją przez tę wartość. Poza tym wynik zapisujemy w kolejności innej niż w przypadku konwertowania liczb całkowitych: zaczynamy od bitu najstarszego, a kończymy na najmłodszym.

Zapiszmy po kolei etapy konwersji:

  1. Mnożymy przekształcaną liczbę (0,777) przez 2.

  2. Sprawdzamy czy otrzymany iloczyn jest większy lub równy 1:

    • jeżeli tak jest, jako wartość bitu w zapisie dwójkowym liczby przyjmujemy 1; od iloczynu odejmujemy 1;

    • gdy iloczyn jest mniejszy niż 1, wartość bitu wynosi 0.

  3. Wracamy do punktu 1., ponownie mnożymy iloczyn przez 2 i sprawdzamy, czy wynik jest większy niż 1. Powtarzamy czynność aż do uzyskania iloczynu równego 0 lub osiągnięcia oczekiwanej dokładności liczby (np. 5 cyfr po przecinku).

  4. Rezultatem przekształcenia jest ciąg cyfr 0 oraz 1, otrzymanych jako części całkowite kolejnych iloczynów. Zapisujemy je w kolejności od najstarszej do najnowszej („od góry do dołu”).

Wynikiem końcowym przekształcenia jest:

0,777(10)0,11000(2)

Liczba zapisana w systemie dwójkowym jest tylko przybliżeniem wartości dziesiętnej 0,777; dlatego właśnie użyliśmy znaku zaokrąglenia. Zwróćmy uwagę, że przekształcając liczbę ograniczyliśmy dokładność do pięciu miejsc po przecinku, chociaż konwersję można było prowadzić dalej.

W następnej sekcji zaimplementujemy opisany algorytm w języku Java.

Słownik

system binarny
system binarny

(system dwójkowy); pozycyjny system liczbowy, którego podstawą (bazą) jest liczba 2, a do zapisu liczb potrzebne są tylko dwie cyfry: 0 i 1

parametr funkcji
parametr funkcji

element składni w określonym języku programowania; umożliwia komunikację pomiędzy podprogramem (funkcją) wywołanym a programem wywołującym; parametry określa się w nagłówku podprogramu (przy jego definicji)

argument funkcji
argument funkcji

element składni w określonym języku programowania, który w wyniku wywołania podprogramu zostaje utożsamiony (skojarzony) z określonym parametrem podprogramu