Projekt do PROG2 – Parser aritmetických výrazů

Když jsem si předmět Programování v jazyce C pro fyziky zapisoval, věděl jsem, že bude zakončen poměrně rozsáhlým projektem. Ale když mi přišlo zadání, poněkud mi přeběhl mráz po zádech. Jako nejjednodušší byl označena hra Labyrint (bludiště je v textovém souboru, algoritmus najde nejkratší cestu), z dalších zadání bych jmenoval ještě Piškvorky, Lodě nebo kecálka Karla.

Příznakem „Dle mého osobního názoru asi nejtěžší“ bylo značeno zadání programu, který měl jako vstup textový řetězec reprezentující matematický výraz a jako výstup tento výraz ve formě stromové struktury. Samozřejmě, nějakým lidským způsobem reprezentovaný.

Tak jsem se pousmál, protože o vlastním parseru aritmetických výrazů sním už od dob, co jsem začal programovat a teď jsem měl konečně příležitost. Řekl jsem si tedy Challenge accepted a začal přemýšlet jak na to. V zadání byl sice návod na nejjednodušší postup, ale trvalo mi asi týden než jsem jej pochopil. Jeho filosofie spočívala v tom, že výraz je tvořen nějakým termem (jeden „sčítanec“), symbolem +/- a případně dalším (pod)výrazem. Je to tedy rekurzivní definice, a když se nad ní zamyslíme, zjistíme, že se vlastně jedná o lineární spojový seznam termů (kde každý term má příznak, jestli se k předchozímu přičítá nebo se od něj odčítá).

Velmi obdobně je definován i onen term – je to součin nebo podíl faktoru s dalším termem. Vyvrcholení nastává při definici faktoru – tedy činitele / dělitele / dělence. Tím může být obyčejné číslo, záporné číslo (v mé reprezentaci obecně funkce), nebo výraz v závorce. Kde pojmem výraz je myšlen opět ten výraz výše.

Krásně je z těchto definic poznat, že jejich rekurze může být ukončena pouze číslem, což nám poté umožní výraz jednoznačně vyčíslit (kromě jeho vypsání a případného vymazání z paměti). Pokud si toto uvědomíte, a nebojíte se pointerů, hloubkové rekurze a předávání odkazů na globální proměnné odkazem je pak implementace hračka.

Opravdu hračka. De facto celý program jsem zvládl za necelý den. Ve skutečnosti výraz a term jsou implementačně velmi podobné (liší se akorát tím, jestli jsou tvořeny termem a výrazem nebo formem a termem), takže je stačilo jen zkopírovat a upravit pár řádků. Nicméně kód tak narostl na přibližně 500 řádků. I já jsem zíral. 500 řádků plných pointerování, a práce s globálním indexem a já jsem to stihl za necelý pátek. O tom, že jsem komplet celý program tvořil v C write’n’run ani nemluvě. Ideální způsob, jak se naučit používat základní vimové příkazy, jako GG nebo / či :%s/foo/bar/g.

Jenže. To byl opravdu základ. Chybělo sice už jen dodělat funkčnost funkcí (s těmi jsem si vyhrál – byly totiž reprezentovány ukazateli na funkce) a ošetřit syntaktické chyby (a varování) vstupu.

Moje první idea byla, že pokud při parsování některého elementu dojde k syntaktické chybě (například 4+*6), vrátí jen jeho první část a to, počínaje chybou bude ignorovat. Až jsem to měl hotové, tak nějak jsem si uvědomil, že to je stejně pitomost. Přece, když je výrazu chyba, tak je ve výrazu chyba. Může to být překlep, ale co když není? Tento algoritmus prostě z chyby udělal varování a opravil ji tím nejjednodušším způsobem. Tím se však výraz stal nekonzistentní, tedy špatný. Takže jsem tam prostě nacpal, že jakmile narazí parser na chybu, nekompromisně vrací NULL s tím, že i procedura která ji volala, pak automaticky také vrací NULL, a tak to probublává až na samotný výraz, který se tím pádem také stane NULL.

Z původního algoritmu mi však ve funkcích na výpočet, vypsání a vymazání zůstaly testovací podmínky na testování konzistence výrazu, tak jsem je tam nechal (i když tam nemají význam).

Několik dní mi pak zabrala snaha vyřešit kontrolu parity závorek. Původní idea byla taková, že přibude další globální proměnná, nazvaná zanoření závorek – z, na počátku inicializovaná na začátku na nulu. Při začátku parsování faktoru „výraz v závorce“ se měla zvýšit o 1 a po dokončení opět snížit. Pokud na konci parsování celého výrazu byla hodnota větší, než 0, nebyla některá závorka uzavřena, a tak se program tvářil, jakoby byla na konci, ale pokud tam byla nějaká uzavírací navíc, tak ji měl přeskočit.

Ale jak chce odchytávat uzavřenou závorku u výrazu, který není výraz v závorce? Nijak. To by prostě nefungovalo. Řešením tedy bylo přesunout obsluhu uzavírající závorky do samotné funkce parsuj_vyraz, do míst, kde se testuje právě nalezený znak. Jenže tím bych totálně zabil přehlednost kódu. Při představě, že otevírání a zavírání závorky jsou každé na úplně jiném konci a v úplně jiné části kódu. Ale ani po mnoha dnech jsem nevymyslel ideální řešení, ale alespoň jsem tu obsluhu rozbil na aplikační a uživatelskou část. Aplikační jsem ponechal přehledně při parsování výrazu závorce (stará se jen o inkrementaci a dekrementaci proměnné z), zatímco uživatelskou jsem tedy rozházel po celém kódu, což už mi nepřišlo tak nehumální, neboť se tak ztratila mezi ostatními chybovými a varovnými hláškami celého programu.

Doufám, že vám program půjde zkompilovat (panu profesor s tím měl na Windows menší problémy). Po zkompilování si jej, linuxáci, můžete hodit do třeba do /bin a pokud si jej lehce zmodifikujete (tady dodávám mou, odevzdávanou verzi, nijak neupravenou), můžete jej volat třeba

nebo například

který vám samozřejmě ten_slozitej_vzorecek vyčíslí pro x=14.5.

V plánu mám po vzoru z Paradigmat programování 2 (kde jsme něco podobného dělali objektově v Lispu) vytvořit si program na parsování výrazů s proměnnými a derivování/integrování (případně další operace s funkcemi jako tabelace hledání inflexních bodů), přičemž na to asi použiji přecejen C++. Uvidím, jestli bude čas.

 

Nainstalovat (Linux)

Stáhnout zdrojový kód

martlin’s simple console ascii art generator

Článek s na první pohled šíleným a nesrozumitelným názvem – (opakovat už ho nebudu ;-)) – je další z řady mých programů v jazyce C. Ano, opravdu jsem si napsal vlastní ASCII Art generátor.  Cesta k němu byla ale dlouhá.

Co je to ASCII Art

ASCII Art je, no, ale asi ano, umělecký proud, zabývající se především výtvarnou tvorbou použitím znaků (ASCII znaků). Česky řečeno je to taková mozaika z písmenek, která při dostatečném množství znaků v obrázku působí velmi realisticky. ASCII Art generátor je pak pochopitelně program, který převádí z obrázku na text- ASCII Art.

ASCII generátorů je plno online, nebo i ke stažení, placených, shareware, demo a podobně. Ale nevěděl jsem o tom, že by nějaký existoval na linux. Teď už určitě aspoň jeden existuje ;-).

Jak jsem se já dostal k Ascii Art

Tux
Tux

Znáte Projekt AA? To se čtveřice linuxáků (pokud vím, tak z Brna) dala do hromady a napsala grafickou knihovnu AA. Ukázkové video BB Demo, nám pustil ve třeťáku na střední pan Ing. Nožka. Já, jelikož jsem tou dobou pracoval na kampani Drag Race, kde se několik málo ASCII obrázků vyskytuje, jsem se o to začal zajímat.

V prváku na vysoké, jsem se dal do diskuze s jedním kamarádem, zarytým linuxákem o tom, jestli neznám nějaký způsob, jak zobrazovat obraz v textovém režimu. Kromě AA padly úvahy i na ASCII Art. Zatímco kamarád to zabalil po nastudování struktury PNG souboru, já jsem na to šel od lesa.

Lenna
Lenna

Hodil jsem do googlu formát BMP- Windows BitMap a dostal jsem se na článek Grafický formát BMP – používaný a přitom neoblíbený. Zde je celá bitmapa rozebrána do posledního Bytu a tak u nebyl problém s jeho pomocí začít něco kutit ve vimu (resp. samozřejmě v C-write ‚n‘ run). Ve snaze vytvořit si struktury pro jednotlivé hlavičky, do nich nahrát data a ta posléze zpracovat takovým způsobem, že bych to publikoval jako hlavičkový soubor bitmap.h, který by měl univerzální použití (vykreslení bitmapy jako ASCII by byla jen jedna z několika funkcí) však selhala.

Tak jsem se vykašlal na struktury a začal psát program s příznačným názvem „fast-bitmap-load.c“. Ten prostě posbíral potřebné informace o bitmapě a vykreslil ji. Tečka hotovo. Zabralo mi to asi týden (no jo, když člověk nemá zkušenosti, tak by při 20. pohledu na Segmentation fault něčím opravdu mrštil o zem) a má to v uvozovkách pouhých 283 řádků. Včetně nápovědy a kontrol všeho možného (viz dále).

Nixie Pixel
Nixie Pixel

Jak to funguje

Stručně:

  • Načte název souboru a je-li zadána tak i škálu znaků, ze kterých se má obrázek vykreslit („gradient“).
  • Soubor otevře nebo skončí chybou.
  • Ověří z metadat, jestli se jedná opravdu o BitMapu.
  • Zkontroluje, jestli se nepoužívá komprese.
  • Zjistí bitovou hloubku. Program podporuje pouze bitové hloubky 24/32 bitů/pixel (osmibitové RGB a RGBA).
  • Získá začátek a „konec“ samotných obrazových dat.
  • Vytáhne rozlišení obrázku (šířku a výšku v pixelech).
  • Do dvojrozměrného pole nahraje odbarvený obrázek. (ve verzi 1.2 nejdříve nahraje, poté odbarví a následně změní velikost)
  • Obrázek jednoduše vytiskne – 1 znak na 1 pixel.

Jak na to

V případě pochybností nebo jiných problémů je program samozřejmě vybaven nápovědou, kterou zavoláte standartně

Jak jsem psal, výstup, tedy vytvořený ASCII obrázek můžete uložit do souboru. Není v tom žádná věda, prostě jeho standartní výstup přesměrujete do požadovaného souboru:

m@rtlin's web

Jak na to s použitím původní verze 1.0

Začneme obrázkem. Najdeme si tedy nějaký vhodný (bitmapa to být nemusí, stejně jej budeme muset upravovat) a jako správný linuxák vám doporučím otevřít si jej v Gimpu. Následně totiž obrázek, obzvláště pokud je to nějaká fotka, vezmeme a je více než vhodné pohrát si s jasem a kontrastem (i když to by šlo kompenzovat použitím jiného řetězce gradientu). Také bych vám doporučil obrázek mírně roztáhnout – obrazový pixel má přece jen rozměry 1×1 jednotka (pixel), zatímco obvyklé neproporcionální písmo má obvykle 5×8 jednotek na jeden znak, tedy ne ve stejném poměru. Ideální je tedy obrázek roztáhnout do šířky 1,6 krát nebo stlačit výšku na přibližně 0,6.

Pokud nechcete výstup ukládat do souboru (viz níže), je vhodné přizpůsobit mu šířku. Většina výchozích konzolí má 80×25 znaků, tedy obrázek by minimálně tuto šířku měl dodržet. U maximalizovaného terminálu jsou rozměry terminálu přibližně 170×47 znaků.

Obrázek uložíme jako bitmapu a přejdeme k samotnému vykreslení. Program byl tvořen na linuxu a tak se drží jeho koncepce. To znamená, že překreslení obrázku uděláte tak, že program spustíte v konzoli s parametry. Prvním je název souboru bitmapy, druhým, nepovinným je gradient, který chcete použít. Například tedy

Nezdá-li se řetězec gradientu, volí se výchozí, .-xdOM#(první případ). Čím více znaků gradientu zadáte, tím čistější budou přechody mezi různými barvami a tím realističtější obrázek bude (druhý případ). Naopak, jak je vidět na třetím příkladu, použitím jen 2 znaků získáte obraz jen dvoubarevný (jakoby doslova černobílý).

Jak na to s novou verzí 1.2

Zde vás odsměruji na nápovědu, tedy přepínače -h|--help . Tam je vše celkem důkladně popsáno a  už se mi to nechce popisovat znovu.

 

Poznámka pro nezkušené linuxáky

Předchozí zápisy budou fungovat jen tehdy, pokud máte mascaag v některé složce uložené v proměnné $PATH. V ostatních případech musíte volat program s celou cestou, tedy absolutně ( /home/uzivatel/mascaag), relativně od domovského adresáře ( ~/mascaag) nebo relativně od aktuálního adresáře ( ./mascaag).

Nová verze, mascaag 1.2

Hned z několika důvodů jsem se rozhodl původní mascaag upravit a rozíšřit. Refactoroval jsem značnou část, zavedl trošku „objektovější“ a strukturovanější přístup a dodal pár dalších funkcí. Mezi ně patří:

  • možnost invertovat barvy
  • možnost, zvolit si které barevné kanály chcete pro zobrazení použít (R,G,B nebo jen alfu)
  • možnost změny počtu pixelů na jeden znak

Generátor je tak sice trošku pomalejší (u velikých bitmap si pár set milisekund počkáte), ale získané možnosti budou jistě velmi praktické. Ušetří tak hodně práce, které by jste jinak zbytečně promrhali nad grafickým editorem.

Bohužel kód tak ztratil na jednoduchosti, která byla předchozí verzi základem, takže se moc nehodí ke studiu práce s bitmapami. Z tohoto důvodu nechám původní verzi stále uvolněnou.

 

Stažení / Instalace mascaag

Mascaag je Open-source multiplatformní projekt, takže zde předkládám de facto pouze a jen zdrojový kód. Pokud se vám jej, milí linuxáci, nechce kompilovat ručně, mám tu pro vás připravený váš oblíbený instalátor. Stačí kliknout na odkaz níže, stáhnout instalační skript, nastavit mu práva spustit jej – například takto:

Instalátor má i nějaké drobné možnosti konfigurace, vizte jeho nápovědu (fungují opět obě varianty):

Samoinstalátor pro Linux

Stažení ZIP archivu se zdrojovým kódem

původní mascaag 1.0: samoinstalátor  – zdrojové kódy

Moje prográmky III (C*)

Po veleúspěšných dílech Moje prográmky I – Pascal a Moje prográmky II – Delphi příchází Moje prográmky III, s nyní už trochu rozsáhlejšími a v rodině jazyka C (C a C++) psanými prográmky.

A protože jsem fanda linuxu a tak nějak se mi nechtělo oficiálně distribuovat svoje kódy, tak jsem vytvořil Samorozbalovací instalátor pro Linux. Z následujícího rozbalovacího seznamu si pouze vyberete požadovaný program, stáhne se vám skript, kterému pouze nastavíte práva a spustíte a on se už o vše postará:

Instalátor má i nápovědu, volá se standartními přepínači:

Nainstalovat program:

 

Samozřejmě zde ovšem dodávám mou oblíbenou tabulku všech programů, jako vždy s krátkým popiskem funkce onoho programu.

Generátor mocnin dvojky

Výstupem jsou soubory s binárním, hexadecimálním a především dekadickým zápisem čísla 2EXP, kde EXP si volíte a v závislosti na vaší výpočetní kapacitě se může pohybovat klidně v řádech desetitisíců.

celý článek

 

Pascalův trojúhelník, binomická věta, kombinační čísla

Program využívá zajímavých vlastností Pascalova trojúhelníka a díky nim snadno mimo samotný trojúhelník může vypisovat také kombianční čísla a binomické rozvoje. Je obsluhován jednoduchou příkazovou řádkou.
Instalačka pro Linux ZDE
Zdrojový kód

martlin’s simple console ascii art generator 1 a 1.2

Programu jako argument předáte název bitmapy, ona vám ho vykreslí v ASCII znacích, které si také můžete zadat, nebo použije výchozí.

celý článek

 

Parser aritmetických výrazů

Závěrečný projekt do Programování pro fyziky, dá se říci pokročilejší konzolová kalkulačka. V tuto chvíli má aplikace jen minimální uživatelské rozhraní, takže je v praxi téměř nepoužitelná, slouží především k nastudování jednoho z algoritmů parsování.
Instalačka pro Linux ZDE

celý článek

 

Anny’s Lab

Velmi jednoduchá konzolová bludišťovka, napsaná přes prázdniny v C++. Program je poněkud rozsáhlejší, takže bohužel nejde použít samoinstalátor.

celý článek

 

To je zatím vše.

Generátor mocnin dvojky

Začalo to nějak takto

V předmluvě Stopařova průvodce se praví: „Vesmír je velký, fakt velký, ani by jste nevěřili, jak hrozně moc úžasně velký je; a tak dále. Také se tam praví, že pokud se zhluboka nadechnete, můžete ve vesmírném vakuu přežít asi 30 vteřin. Ovšem vzhledem k té velikosti je pravděpodobnost, že vás během té doby někdo zachrání rovna jedna ku dvěma na dvě miliardy sedmdesát devět miliónů čtyřista šedesát tisíc třista čtyřicátou sedmou, což je náhodou také telefoní číslo izlingtonského bytu, kam se Arthur vydal na maškarní večírek a potkal dívku, kterou se mu nepodařilo sbalit.

Vzdělanější z vás poznali, že se jedná o úryvek z filmu Stopařův průvodce po galaxii. Ono číslo 22 079 460 347 mě fascinovalo a inspirovalo k vytvoření tohoto programu. Řekl jsem si, že toto číslo by bylo zajímavé si vyčíslit. A tak jsem začal pracovat na jeho vyčíslení. Aby to však nebylo tak jednoduché, vzal jsem to obecněji a vytvořil jsem univerzální generátor mocnin dvojky od 20 do 24 294 967 296 s tím, že vygenerované číslo se uloží do textového souboru. A jako třešničku jsem k tomu dodal ještě soubory BIN.TXT a HEX.TXT, které tak zadané číslo uloží kromě dekadické soustavy také v binární a hexadecimální.

Při tvorbě programu jsem však zjistil, že kromě toho, že nemám dostatečně dobrý hardware na odzkoušení plné funkce programu (momentálně mě tížil nedostatek místa na disku, takže soubor s binárním číslem 2150 000 000 se mi na disk vešel jen tak tak. Po dopsání algoritmu na generování dekadického čísla jsem pak zjistil, že doba generování je exponenciálně závislá na velikosti zadaného exponentu, takže zatímco číslo 210 000 mi vyplivl asi po 3 sekundách, číslo 2100 000 se generovalo asi minutu, generování 21 0000 000 jsem po asi hodině zastavil.

Účel programu, zhmotnit číslo 22 079 460 347, sice nebyl naplněn, nicméně program je hotov a co je hlavní, uveřejňuji zde jeho zdrojové kódy (ty jsou ovšem jen pro silnější povahy!).

Binární číslo

Zapsat binární číslo bylo to nejjednodušší, proto tím také začínám. Máte-li totiž číslo 2n, pak zapsáno binárně je vlastně tvořeno tolika ciframi, kolik je exponent n. Samozřejmě, že binární číslo začíná vždy jedničkou, takže ji tam stačí prostě vepsat. Tím by byl algoritmus hotov: Vypíšeme jedničku a za i n nul. Pro přehlednost (má-li u kupy nul přehlednost vůbec smysl) jsem použil i oddělovač číslic, klasicky binárně po čtveřicích. Podstatně se tak algoritmus zrychlil, protože je rychlejší vypsat tisíckrát ‚ 0000‘ než čtyřtisíckrát ‚0‘.

Aby však byl zápis validní, musel jsem si číslo na čtveřice rozdělit a zjistit co mi zbyde a to dát na začátek (například číslo 26D=100 0000B). Tento zbytek se určí opravdu doslova – v 7. řádku se prostě vypíše po jedné tolik nul, kolik zbývá (počítá se zbytek po celočíselném dělení – 8. řádek) do kompletní čtveřice a teprve potom už se vypíšou kompletní čtveřice (řádek 11).

 

Hexadecimální číslo

U hexa čísla je situace podobná jako u binárního. Ve své podstatě stačí říci, že každé 4 cifry binárně jsou 1 cifra hexadecimálně. Tím pádem má-li binární číslo třeba 1000 kompletních čtveřic, v hexa soustavě to bude rovných 250 cifer. Všechny (až na jednu) kompletní binární čtveřice jsou však nulové a tak se opět do hexadecimálního soubru zapíše n-krát ‚ 00‘, neboť hexadecimální čísla se oddělují po dvojicích cifer.

Ovšem problém nastal u té nekompletní úvodní dvojice cifer (například 223D=80 00 00H) neboť ta narozdíl od binárního čísla není pouze 1 a několik nul. Nabývá hodnot 1H (dvojnásobek je) 2H (další dvojnásobek je) 4H (pak) 8H (poté pozor, nikoliv 16H, ale) 10H, 20H, 40H, 80H a 1 00H, tedy 1H a další kompletní dvojice.

O vygenerování tohoto začátku se starají řádky 9 až 23. Nejdříve si opět určí zbytek, stejně jak u binárního čísla (jen pochopitelně s jiným dělitelem), a poté by stačilo vyčíslit 2tento zbytek a převést toto číslo do hexadecimální soustavy. Číslo by sice by nebylo moc velké (nejvyšší hodnota by byla 80H, 128D), takže by tomuto postupu moc nebránilo. Ale to málo je jednak, fakt, že jazyk C nenabízí moc funkcí k umocňování (funkce pow nefungovala, tak jak měla) a pro převody číslených soustav neznám žádnou, a navíc by to bylo zbytečně časově náročné, když to jde i trošku „oprasit“.

Prostě se zeptá jestli ten zbytek je v hexa soustavě jednociferný (řádek 12), a pokud je, tak tu 1 cifru vyčíslí a vypíše. Pokud není, je tedy dvojciferný, vyčíslí tu první cifru a za ni vepíše nulu. Poslední řádek (25.) pak doplní zbývající, kompletní dvojce.

 

Dekadické číslo

Algoritmus pro generování dekadického čísla je z této trojice nejšílenější a proto si jej nechávám úplně na závěr. Dvojkový a šestnáctkový měly totiž základ, který určitým způsobem stál na čísle 2, jehož mocniny jsme chtěli zpracovávat. Ale desítka, ta je sice pětinásobkem dvojky, ale ta pěkta nám tam pořád hapruje a dělá velké problémy.

První myšlenka algoritmu měla fungovat asi nějak tak, že cyklus n-krát (kde n je počet mocnin), prodvojnásobí číslo počínaje jedničkou ( přičemž nás zajímá pouze poslední cifra, zbytek se ignrouje) ale po každé, když přeteče do vyššího řádu, zinkrementuje se (už jenom kvůli tomuto názvu jsem to chtěl napsat 😉 registr postupných inkrementací, jehož obsah by se pak předal dál a stejným způsobem násobil a násobil, a toto celé by se pak nějak opakovalo, až by se došlo do stavu, kdy by byl RPI prázdný, tedy už by nemělo co přetékat.

Bohužel tento systém selhal a tak mě napadl druhý, a to ten, že jsem zjistil, že čísla se v každém řádu opakují – pro řád jednotek je to (1), 2, 4, 8, (1)6, (3)2, a znovu. Opakují-li se takto čísla v jednotkách, opakují se i v desítkách, stovkách, tisících … Jenže perioda tohoto opakování rostla exponenciálně s řádem (pro jednotky zmiňované 4 čísla, pro desítky 20, pro stovky 100, pro tisíce 500, …) a navíc mě nenapadlo, jak ty data získat.

Jedinná použitelná metoda byla průběžné násobení a přičítání přetečení, tedy metoda, jakou to počítají děti na základní škole. Opravdu, musel jsem si vytvořit (dynmické) pole, ve kterém jsou uloženy jednotlivé cifry. Vzhledem k tomu, že ukládat 1 číslici, tedy číslo 0 až 9 na 4Byty dávalo účinnost asi 0,000002‰, tak mě napadlo, že když tam dám místo jedné cifry 3, nejen že se zjednoduší oddělování tisíců, ale možná to bude i rychlejší.

Doba generování 2100 000 snížíla z cca 57 sekund na pouhých 23. Jen tak z hecu jsem tam zkusil uložit těch cifer šest (čímž se ovšem naprosto brutálně zkomplikoval výpis do souboru a počet cifer se také musí celý přepočítávat) avšak když jsem zjistil, že čas je ještě téměř poloviční (14 vteřin), a paměti je také potřeba polovina, zmlkl jsem a nechal to tak.

Popis funkce algoritmu

Algoritmus tedy začne zalokováním paměti do zásoby (1 tisíc prvků). Poté začne násobit dvěma prvky pole (řádek 15), z nichž první začíní čislem 1 (řádek 9) a když už bude větší než 1 000 000 (řádek 17), tak uloží do proměnné carry jedničku (řádek 19), která se přičte v dalším „řádu“ (v další šestici). Jakmile dojede jednou (projde všechny číslice), ptá se, jestli přetekl i ten poslední řád (řádek 22)(třeba přechod z 512 na 1024), a tak zvýší počet řádů, které má procházet (řádek 29), automaticky tam zapíše tu jedničku, která do něj přetekla (řádek 28), ale to až po té, co si je jist, že ještě sem může zapisovat (že má ještě zalokovaný dostatek paměti; jinak si musí zabrat místo na dalších 2 000 prvků).

Jakmile číslo vygeneruje, musí poměrně složitě to, co má v paměti vypsat do souboru, tak aby to nějak vypadalo. To znamená, že čísla rozdělí na první a zbývající 3 cifry, které vypíše po sobě, avšak první musí vypsat bez bezvýznaných nul ( a to se v 34. řádku rozhoduje jestli tak má učinit u té první nebo až zbývající trojice). Součastně se musí hlídat, aby nevypsal dvakrát to samé nebo se nepokusil vypsat data, která už nepatří tomuto programu. S poslední šesticí cifer jsem měl problém vypsat ji v cyklu na 37 řádku a tak ji vypisuji zvlášť o řádek níž.

Tím, že v proměnné pocet majíce původně sloužit k uchování počtu cifer je uložen počet šestic cifer, je třeba určit přesný počet cifer. Ty se určují tak, že vezme první šestici a postupně ji provnává s mocninami desíti.

 

Stažení programu

Program jsem tvořil v mém IDE C write’n’run 1 (verze 2 je ke stažení zde) na Ubuntu, takže je primárně optimalizován na linuxové operační systémy. Při jeho tvorbě jsem s ním však měl nemalé problémy (proto jsem jej také tvořil měsíc) a při tom jsem jej zkoušel i na Windows, takže dodám i Windows verzi.

Nicméně zatím zde dodávám alespoň zdrojový kód:

Stažení zdrojového kódu generátoru mocnin dvojky.

a automatickou instalačku pro linux (stačí uložit a spustit):

Instalačka pro Linux ZDE

 

On-line verze programu

Ještě před tím, než jsem začal psát tento program v jazyce C, vytvořil jsem jej v PHP. Tuto prvotní verzi algoritmu samozřejmě dodávám také. Akorát on-line verze je omezena na exponent 5 000.

On-line verze zde