Stránka sa načítava, prosím čakajte…
© 2005 – 2024 Roman Horváth, všetky práva vyhradené. Dnes je 25. 4. 2024.
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
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(); } }
Vzhľad aplikácie.
Projekt 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.