TlačiťTlačiť Slovenčina English Hľadať RSS

© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 25. 4. 2024.

Stránka sa načítava, prosím čakajte…

Dátum: 5. 9. 2021, pred tromi rokmi


~

import static knižnica.Svet.*;
import knižnica.GRobot;

/**
 * Prevod 16 → 10 a naopak… (s tabuľkou znakov, bez generovania výnimiek).
 *
 * Tento algoritmus nerozpoznáva pri prevode zo šestnástkovej do desiatkovej
 * sústavy malé písmená (a – f). Dopracujte ho tak, aby ich vedel správne
 * spracovať.
 */
public class PrevodyTabuľkou extends GRobot
{
	// Nasledujúcu tabuľkou znakov použijeme obojsmerne. Výhodou tohto
	// riešenia je, že index prvku v tabuľke priamo zodpovedá cifre
	// v šestnástkovej sústave.
	//
	// Keby sme za jednotlivé znaky dosadili ľubovoľné unikátne (iba raz
	// sa v tabuľke vyskytujúce) znaky, mohli by sme docieliť primitívne
	// šifrovanie.
	//
	// Nevýhodou tohto riešenia je, že pri spätnom prevode zo šestnástkovej
	// sústavy treba znaky v tabuľke hľadať. Nevieme hodnotu cifry priamo
	// vypočítať.
	public static final char tabuľka[] = {'0', '1', '2', '3', '4', '5', '6',
		'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};


	/**
	 * Statická metóda prijímajúca celé číslo v desiatkovej sústave
	 * a vracajúca reťazec s hodnotou prevedenou do šestnástkovej sústavy.
	 *
	 * @param číslo celé číslo v desiatkovej sústave
	 * @return reťazec s číslom v šestnástkovej sústave
	 */
	public static String doHex(int číslo)
	{
		int dĺžka = 0;
		int záloha = číslo;

		// Keďže na ukladanie výsledku budeme používať polia, potrebujeme
		// najskôr zistiť dĺžku výsledku v šestnástkovej sústave:
		do
		{
			záloha /= 16;
			++dĺžka;
		}
		while (záloha != 0);

		// Rezervujeme počet znakov podľa zistenej dĺžky:
		char prevod[] = new char[dĺžka];

		// Premennú dĺžka „recyklujeme“ a pri prevode ju použijeme
		// na uchovanie indexu aktuálnej cifry:
		dĺžka = 0;

		// Vykonáme prevod…
		do
		{
			prevod[dĺžka] = tabuľka[číslo % 16];
			číslo /= 16;
			++dĺžka;
		}
		while (číslo != 0);

		// Výsledok musíme prevrátiť. Tento krok sa nedá eliminovať,
		// pretože zvyškom po delení vieme zistiť len najnižšiu cifru,
		// čiže tú, ktorá je „najviac vpravo.“ (Pričom číslo postupne
		// delíme 16, takže „najviac vpravo“ sa vždy ocitne ďalšia
		// a ďalšia cifra.)
		char prevrátené[] = new char[dĺžka];

		for (int i = 0; i < dĺžka; ++i)
			prevrátené[i] = prevod[dĺžka - 1 - i];

		// Pole „prevrátené“ je pole znakov vyjadrujúce hodnotu prevedenú
		// do šestnástkovej sústavy. Na reťazec ho prevedieme s pomocou
		// prislúchajúceho konštruktora triedy String:
		return new String(prevrátené);

		/*
		// Celý postup by sa dal skrátiť aj do nasledujúcich pár riadkov,
		// ale tento prístup by bol veľmi neefektívny. Každá cifra by
		// spustila kaskádu implicitných a vo výsledku pomalých krokov.
		// Čím viac cifier by výsledné číslo malo, tým pomalší by bol proces.
		String výsledok = "";

		do
		{
			výsledok = tabuľka[číslo % 16] + výsledok;
			číslo /= 16;
		}
		while (číslo != 0);

		return výsledok;
		*/
	}


	/**
	 * Statická metóda prijímajúca reťazec v šestnástkovej sústave
	 * a vracajúca celé číslo v desiatkovej sústave. Ak sa v reťazci
	 * vyskytne neznámy znak, metóda vypíše chybové hlásenie a vráti
	 * fragment, ktorý sa jej podarilo previesť do toho okamihu.
	 * <!-- To nie je vhodné riešenie, preto v ďalšom kroku použijeme
	 * generovanie výnimiek. -->
	 *
	 * @param reťazec reťazec s číslom v šestnástkovej sústave
	 * @return celé číslo v desiatkovej sústave
	 */
	public static int zHex(String reťazec) // throws …
	{
		int rád = 1;
		int výsledok = 0;

		for (int i = reťazec.length() - 1; i >= 0; --i)
		{
			int cifra;

			// Hľadáme znak v tabuľke znakov:
			for (cifra = 0; cifra < tabuľka.length; ++cifra)
				if (reťazec.charAt(i) == tabuľka[cifra])
					break;

			// Ak nebol nájdený, je to chyba:
			if (cifra >= tabuľka.length)
			{
				vypíšRiadok("Znak " + reťazec.charAt(i) +
					" nie je platným znakom šestnástkovej sústavy.");
				break; // throw …
			}

			výsledok += cifra * rád;
			rád *= 16;
		}

		return výsledok;
	}


	public static void main(String[] args)
	{
		// Svet.použiKonfiguráciu("PrevodyTabuľkou.cfg");
		// new PrevodyTabuľkou();
		//
		// Keďže všetko v tejto triede je statické, okno sveta vytvoríme
		// cez anonymný robot, ktorý zároveň skryjeme:
		new GRobot().skry();

		vypíšRiadok("Výsledok v šestnástkovej sústave: ",
			doHex(zadajCeléČíslo("Zadaj desiatkové číslo").intValue()));

		vypíšRiadok("Výsledok v desiatkovej sústave: ",
			zHex(zadajReťazec("Zadaj šestnástkové číslo")));
	}
}

Výsledok po zadaní hodnôt 22 (desiatkovo) a 10 (šestnástkovo):

Výsledok v šestnástkovej sústave: 16
Výsledok v desiatkovej sústave: 16

~

program PrevodyTabulkou;

(*
 Nasledujúcu tabuľkou znakov použijeme obojsmerne. Výhodou tohto riešenia
 je, že index prvku v tabuľke priamo zodpovedá cifre v šestnástkovej sústave.

 Keby sme za jednotlivé znaky dosadili ľubovoľné unikátne (iba raz sa
 v tabuľke vyskytujúce) znaky, mohli by sme docieliť primitívne šifrovanie.

 Nevýhodou tohto riešenia je, že pri spätnom prevode zo šestnástkovej sústavy
 treba znaky v tabuľke hľadať. Nevieme hodnotu cifry priamo vypočítať.
*)
const tabulka: array [1 .. 16] of char = ('0', '1', '2', '3', '4', '5', '6',
	'7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');

var desiatkove: integer;
	sestnastkove: string;


(*
 Funkcia prijímajúca celé číslo v desiatkovej sústave a vracajúca reťazec
 s hodnotou prevedenou do šestnástkovej sústavy.

 Parametre:
   číslo – celé číslo v desiatkovej sústave

 Návratová hodnota:
   reťazec s číslom v šestnástkovej sústave
*)
function doHex(cislo: integer): string;
var prevod: array of char;
	dlzka, zaloha, i: integer;
// var vysledok: string = '';
begin
	dlzka := 0;
	zaloha := cislo;

	// Keďže na ukladanie výsledku budeme používať polia, potrebujeme
	// najskôr zistiť dĺžku výsledku v šestnástkovej sústave:
	repeat
		zaloha := zaloha div 16;
		inc(dlzka);
	until zaloha = 0;

	// Rezervujeme počet znakov podľa zistenej dĺžky:
	SetLength(prevod, dlzka);

	// Premennú dlzka „recyklujeme“ a pri prevode ju použijeme
	// na uchovanie indexu aktuálnej cifry:
	dlzka := 0;

	// Vykonáme prevod…
	repeat
		prevod[dlzka] := tabulka[1 + (cislo mod 16)];
		cislo := cislo div 16;
		inc(dlzka);
	until cislo = 0;

	// Výsledok musíme prevrátiť. Tento krok sa nedá eliminovať,
	// pretože zvyškom po delení vieme zistiť len najnižšiu cifru,
	// čiže tú, ktorá je „najviac vpravo.“ (Pričom číslo postupne
	// delíme 16, takže „najviac vpravo“ sa vždy ocitne ďalšia
	// a ďalšia cifra.)
	//
	// Premenná „prevod“ je dynamické pole znakov. Počas prevracania
	// ho zároveň prevedieme na reťazec a to tak, že budeme jednotlivé
	// znaky z poľa postupne pridávať do návratovej hodnoty tejto
	// funkcie:

	doHex := '';
	for i := 0 to dlzka do
		doHex := doHex + prevod[dlzka - 1 - i];

	(*
	// Celý postup by sa dal skrátiť aj do nasledujúcich pár riadkov,
	// ale tento prístup by bol veľmi neefektívny. Každá cifra by
	// spustila kaskádu implicitných a vo výsledku pomalých krokov.
	// Čím viac cifier by výsledné číslo malo, tým pomalší by bol proces.
	repeat
		vysledok := tabulka[1 + (cislo mod 16)] + vysledok;
		cislo := cislo div 16;
	until cislo = 0;
	doHex := vysledok;
	*)
end;


(*
 Funkcia prijímajúca reťazec v šestnástkovej sústave a vracajúca celé číslo
 v desiatkovej sústave. Ak sa v reťazci vyskytne neznámy znak, metóda vypíše
 chybové hlásenie a vráti fragment, ktorý sa jej podarilo previesť do toho
 okamihu.

 Parametre:
   retazec – reťazec s číslom v šestnástkovej sústave

 Návratová hodnota:
   celé číslo v desiatkovej sústave
*)
function zHex(retazec: string): integer;
var vysledok, rad, i, cifra: integer;
begin
	rad := 1;
	vysledok := 0;

	for i := length(retazec) downto 1 do
	begin
		if (retazec[i] >= 'a') and (retazec[i] <= 'z') then
			retazec[i] := char(ord(retazec[i]) - 32);

		// Hľadáme znak v tabuľke znakov:
		for cifra := 1 to 16 do
			if retazec[i] = tabulka[cifra] then
				break;

		// Ak nebol nájdený, je to chyba:
		if cifra >= 16 then
		begin
			writeln('Znak ', char(ord(retazec[i]) - 32),
				' nie je platným znakom šestnástkovej sústavy.');
			break;
		end;

		vysledok := vysledok + ((cifra - 1) * rad);
		rad := rad * 16;
	end;

	zHex := vysledok;
end;


begin
	write('Zadaj desiatkové číslo: ');
	readln(desiatkove);
	writeln('Výsledok v šestnástkovej sústave: ', doHex(desiatkove));

	write('Zadaj šestnástkové číslo: ');
	readln(sestnastkove);
	writeln('Výsledok v desiatkovej sústave: ', zHex(sestnastkove));
end.

Ukážka výsledku:

Zadaj desiatkové číslo: 22
Výsledok v šestnástkovej sústave: 16
Zadaj šestnástkové číslo: 10
Výsledok v desiatkovej sústave: 16

  
obrázok 
Vzhľad aplikácie. 
 

~

import static knižnica.Svet.*;
import knižnica.GRobot;
import knižnica.Tlačidlo;

public class Prevody extends GRobot
{
	/**
	 * Statická metóda prijímajúca celé číslo v desiatkovej sústave
	 * a vracajúca reťazec s hodnotou prevedenou do šestnástkovej sústavy.
	 *
	 * @param číslo celé číslo v desiatkovej sústave
	 * @return reťazec s číslom v šestnástkovej sústave
	 */
	public static String doHex(long číslo)
	{
		StringBuffer prevod = new StringBuffer();
		char znak = '0';
		long zvyšok;

		// Vykonáme prevod…
		do
		{
			zvyšok = číslo % 16;
			číslo /= 16;

			if (zvyšok >= 0 && zvyšok <= 9)
			{
				znak = (char)(zvyšok + '0');
			}
			else if (zvyšok >= 10 && zvyšok <= 15)
			{
				znak = (char)(zvyšok - 10 + 'A');
			}
			// Iný prípad by nemal nastať, pretože zvyšok po delení 16
			// je vždy v rozsahu 0 – 15, ale pre istotu sem dáme aj tretiu
			// vetvu, keby sa čokoľvek udialo. (Pozri napr. problematiku
			// tzv. bit flip.)
			else
			{
				znak = '?';
			}
 
			prevod.append(znak);
		}
		while (číslo != 0);

		// Výsledok prevrátime a prevedieme na reťazec:
		prevod.reverse();
		return prevod.toString();
	}

	/**
	 * Statická metóda prijímajúca reťazec v šestnástkovej sústave
	 * a vracajúca celé číslo v desiatkovej sústave.
	 *
	 * @param reťazec reťazec s číslom v šestnástkovej sústave
	 * @return celé číslo v desiatkovej sústave
	 * @throws Exception ak sa v reťazci vyskytne neznámy znak
	 */
	public static long zHex(String reťazec) throws Exception
	{
		int rád = 1;
		int výsledok = 0;
		int cifra;

		for (int i = reťazec.length() - 1; i >= 0; --i)
		{
			// Rozpozná znaky v rozsahu 0 – 9:
			if (reťazec.charAt(i) >= '0' && reťazec.charAt(i) <= '9')
			{
				cifra = reťazec.charAt(i) - '0';
			}
			// Rozpozná znaky v rozsahu A – F:
			else if (reťazec.charAt(i) >= 'A' && reťazec.charAt(i) <= 'F')
			{
				// Keď od znaku v rozsahu A – F „odčítame“ 'A' (t. j. hodnotu
				// 65, pozri ASCII tabuľku), získame numerickú hodnotu 0.
				// Tým istým „vzorcom“ získame pre znak 'B' hodnotu 1, atď.
				// až pre znak 'F' získavame numerickú hodnotu 5. Keďže 'A'
				// má byť rovné 10, pripočítame k získanej hodnote (nech je
				// akákoľvek) ešte 10 (a tým vlastne posunieme aj vypočítané
				// hodnoty celého rozsahu).

				cifra = reťazec.charAt(i) - 'A' + 10;

				// Rovnako dobre by fungovalo aj:
				//
				// 		cifra = reťazec.charAt(i) - 55;
				//
				// Odkiaľ 55?
				//
				// 'A' je rovné 65 (podľa tabuľky ASCII). Zamerajme sa na
				// nasledujúcu časť riadka vyššie (pôvodného riadka):
				//
				// 		reťazec.charAt(i) - 'A' + 10
				//
				// Je to vlastne (dá sa to prepísať aj ako):
				//
				// 		reťazec.charAt(i) - ('A' - 10)
				//
				// Keď za 'A' dosadíme 65, dostávame:
				//
				// 		reťazec.charAt(i) - (65 - 10)
				//
				// čiže nakoniec máme:
				//
				// 		reťazec.charAt(i) - 55
				//
				// …
			}
			// Rozpozná znaky v rozsahu a – f:
			else if (reťazec.charAt(i) >= 'a' && reťazec.charAt(i) <= 'f')
			{
				// Pre rozsah znakov a – f platí ekvivalentne to isté
				// ako pre rozsah A – F:
				cifra = reťazec.charAt(i) - 'a' + 10;
				// Po prepise: cifra = reťazec.charAt(i) - 87;
			}
			else
			{
				throw new Exception("Znak " + reťazec.charAt(i) +
					" nie je platným znakom šestnástkovej sústavy.");
			}

			výsledok += cifra * rád;
			rád *= 16;
		}

		return výsledok;
	}


	// Tlačidlá:
	private final Tlačidlo tlačidloZHex;
	private final Tlačidlo tlačidloDoHex;
	private final Tlačidlo tlačidloVymazať;
	private final Tlačidlo tlačidloDoSchránky;

	// Súkromný konštruktor.
	private Prevody()
	{
		skry();
		tlačidloZHex = new Tlačidlo("Prevod zo 16 do 10 sústavy");
		tlačidloDoHex = new Tlačidlo("Prevod z 10 do 16 sústavy");
		tlačidloVymazať = new Tlačidlo("Vymazať texty");
		tlačidloDoSchránky = new Tlačidlo("Texty do schránky");

		tlačidloZHex.skoč(0, 60);
		tlačidloDoHex.skoč(0, 20);
		tlačidloVymazať.skoč(0, -20);
		tlačidloDoSchránky.skoč(0, -60);

		tlačidloZHex.šírka(200);
		tlačidloDoHex.šírka(200);
		tlačidloVymazať.šírka(200);
		tlačidloDoSchránky.šírka(200);
	}

	// Reakcia na stlačenie niektorého z tlačidiel.
	@Override public void voľbaTlačidla()
	{
		if (tlačidloZHex.zvolené()) preveďZHex();
		else if (tlačidloDoHex.zvolené()) preveďDoHex();
		else if (tlačidloVymazať.zvolené()) vymažTexty();
		else if (tlačidloDoSchránky.zvolené()) textyDoSchránky();
	}

	// Pomocná metóda na prevod zo šestnástkovej sústavy.
	private void preveďZHex()
	{
		String hex = zadajReťazec("Zadaj číslo v šestnástkovej sústave");
		if (null != hex)
			try
			{
				vypíšRiadok(hex, "(16): ", zHex(hex), "(10)");
			}
			catch (Exception e)
			{
				vypíšRiadok(e.getMessage());
			}
	}

	// Pomocná metóda na prevod do šestnástkovej sústavy.
	private void preveďDoHex()
	{
		Long číslo = zadajCeléČíslo("Zadaj číslo v desiatkovej sústave");
		if (null != číslo)
			vypíšRiadok(číslo, "(10): ", doHex(číslo), "(16)");
	}

	public static void main(String[] args)
	{
		new Prevody();
	}
}

  
obrázok 
Vzhľad aplikácie.

ikonaProjekt Lazarusa na prevzatie 61,87 kB (60,42 KiB), 5. 9. 2021

 

~

unit Prevody;

{$mode objfpc}{$H+}

interface

uses
	Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

	{ TForm1 }

	TForm1 = class(TForm)
		Button1: TButton;
		Button2: TButton;
		Memo1: TMemo;
		procedure Button1Click(Sender: TObject);
		procedure Button2Click(Sender: TObject);
	private
		procedure vypisRiadok(riadok: string);

	public

	end;

var
	Form1: TForm1;

implementation

uses StrUtils;

{$R *.lfm}

(*
 Funkcia prijímajúca celé číslo v desiatkovej sústave
 a vracajúca reťazec s hodnotou prevedenou do šestnástkovej sústavy.

 Parametre:
   cislo celé číslo v desiatkovej sústave

 Návratová hodnota:
   reťazec s číslom v šestnástkovej sústave
*)
function doHex(cislo: integer): string;
var
	prevod: string = '';
	znak: char = '0';
	zvysok: integer;
begin
	// Vykonáme prevod…
	repeat
		zvysok := cislo mod 16;
		cislo := cislo div 16;

		if (zvysok >= 0) and (zvysok <= 9) then
		begin
			znak := chr(zvysok + ord('0'))
		end
		else if (zvysok >= 10) and (zvysok <= 15) then
		begin
			znak := chr(zvysok - 10 + ord('A'))
		end
		// Iný prípad by nemal nastať, pretože zvyšok po delení 16
		// je vždy v rozsahu 0 – 15, ale pre istotu sem dáme aj tretiu
		// vetvu, keby sa čokoľvek udialo. (Pozri napr. problematiku
		// tzv. bit flip.)
		else
		begin
			znak := '?'
		end;

		prevod := prevod + znak;
	until cislo = 0;

	// Výsledok prevrátime:
	doHex := ReverseString(prevod)
end;

(*
 Funkcia prijímajúca reťazec v šestnástkovej sústave
 a vracajúca celé číslo v desiatkovej sústave.

 Parametre:
   retazec reťazec s číslom v šestnástkovej sústave

 Návratová hodnota:
   celé číslo v desiatkovej sústave

 Vrhne výnimku Exception, ak sa v reťazci vyskytne neznámy znak.
*)
function zHex(retazec: string): integer;
var
	rad: integer = 1;
	vysledok: integer = 0;
	i, cifra: integer;
begin
	for i := length(retazec) downto 1 do
	begin
		// Rozpozná znaky v rozsahu 0 – 9:
		if (retazec[i] >= '0') and (retazec[i] <= '9') then
		begin
			cifra := ord(retazec[i]) - ord('0')
		end
		// Rozpozná znaky v rozsahu A – F:
		else if (retazec[i] >= 'A') and (retazec[i] <= 'F') then
		begin
			// Keď od ASCII hodnoty znaku v rozsahu A – F „odčítame“ 'A'
			// (t. j. ASCII hodnotu 65, pozri ASCII tabuľku), tak získame
			// numerickú hodnotu 0.
			// Tým istým „vzorcom“ získame pre znak 'B' hodnotu 1, atď.
			// až pre znak 'F' získavame numerickú hodnotu 5. Keďže 'A'
			// má byť rovné 10, pripočítame k získanej hodnote (nech je
			// akákoľvek) ešte 10 (a tým vlastne posunieme aj vypočítané
			// hodnoty celého rozsahu).

			cifra := ord(retazec[i]) - ord('A') + 10;

			// Rovnako dobre by fungovalo aj:
			//
			// 		cifra := ord(retazec[i]) - 55;
			//
			// Odkiaľ 55?
			//
			// 'A' je rovné 65 (podľa tabuľky ASCII). Zamerajme sa na
			// nasledujúcu časť riadka vyššie (pôvodného riadka):
			//
			// 		ord(retazec[i]) - ord('A') + 10
			//
			// Je to vlastne (dá sa to prepísať aj ako):
			//
			// 		ord(retazec[i]) - (ord('A') - 10)
			//
			// Keď za ord('A') dosadíme 65, dostávame:
			//
			// 		ord(retazec[i]) - (65 - 10)
			//
			// čiže nakoniec máme:
			//
			// 		ord(retazec[i]) - 55
			//
			// …
		end
		// Rozpozná znaky v rozsahu a – f:
		else if (retazec[i] >= 'a') and (retazec[i] <= 'f') then
		begin
			// Pre rozsah znakov a – f platí ekvivalentne to isté
			// ako pre rozsah A – F:
			cifra := ord(retazec[i]) - ord('a') + 10;
			// Po prepise: cifra := ord(retazec[i]) - 87
		end
		else
		begin
			raise Exception.Create('Znak ' + retazec[i] +
				' nie je platným znakom šestnástkovej sústavy.')
		end;

		vysledok += cifra * rad;
		rad := rad * 16
	end;

	zHex := vysledok
end;

{ TForm1 }

procedure TForm1.vypisRiadok(riadok: string);
begin
	Memo1.Lines.Add(riadok)
end;

procedure TForm1.Button1Click(Sender: TObject);
var
	hex: string;
begin
	hex := InputBox('Vstup', 'Zadaj číslo v šestnástkovej sústave', '');
	if '' <> hex then
	try
		vypisRiadok(hex + ' (16): ' + IntToStr(zHex(hex)) + ' (10)')
	except
		on E: Exception do
			vypisRiadok(E.Message)
	end
end;

procedure TForm1.Button2Click(Sender: TObject);
var
	vstup: string;
	cislo: longint;
begin
	vstup := InputBox('Vstup', 'Zadaj číslo v šestnástkovej sústave', '');
	if TryStrToInt(vstup, cislo) then
		vypisRiadok(IntToStr(cislo) + ' (10): ' + doHex(cislo) + ' (16)')
end;


end.

Prosím, vyberte kartu s riešením.