Tuesday, September 30, 2014

Ավարտական աշխատանքի տեքստի ձևավորումը

Վաղուց ես ուզում էի գրել այս թեմայով և ներկայացնել տարիների ընթացքում իմ կուտակած փորձն ու դիտարկումների արդյունքները։ Բայց ստացվեց այնպես, որ վերջերս ես ավելի հաճախ սկսեցի հանդիպել անփույթ ձևավորված տեքստերի, և ավելի հաճախ սկսեցի հարցեր ստանալ այն մասին, թե ինչպես ավարտական կամ կուրսային աշխատանքի փաստաթուղթը կազմելիս ստանալ այս կամ այն արդյունքը։ Օրինակ, ինչպե՛ս ձևավորել գեղեցիկ ու ճիշտ տիտղոսաթերթ, ինչպե՛ս կազմել և որտե՛ղ տեղադրել բովանդակության ցանկը, ինչպե՛ս փաստաթղթում ներդնել պատկերներ, աղյուսակներ, ինչպե՛ս կազմել գրականության (կամ աղբյուրների) ցանկը և հղումներ կատարել դրա տարրերին, ինչպե՛ս և ի՛նչ տեսքով ներկայացնել ծրագրավորման լեզուների տեքստը և այլն, և այլն։ Այս և շատ այլ հարցերի մասին եմ ես պատմում իմ գրառման մեջ՝ որպես աշխատանքային գործիք օգտագործելով TeX հրատարակչական համակարգի համար ստեղծված LaTeX մակրոսների փաթեթը։
Ամեն ինչ գրելիս ես ենթադրում եմ հայերեն տեքստերը, հետևաբար ենթադրում եմ նաև, որ ձեռագիրը պատրաստված է Unicode (ավելի կոնկրետ՝ UTF-8) կոդավորմամբ, և օգտագործվում է LaTeX-ի xetex իրականացման xelatex ծրագիրը։

Փաստաթղթի մակետի ընտրություն

Մակետ (LaTeX-ում ասում են document class) ասելով հասկացվում է փաստաթղթի ընդհանուր հատկությունների ամբողջությունը։ Օրինակ, լուսանցքների չափը, վերնագրերի ձևավորումը, ցանկերի կազմակերպումը, ոչ-տեքստային օբյեկտների տեղադրումը և այլն։ Ստանդարտ LaTeX փաթեթում առավել հաճախ օգտագործվում են չորս հիմնական մակետներ. letter, որ նախատեսված է նամակների համար, article՝ հոդվածների պատրաստման համար, report` ավելի ընդարձակ հոդվածների, փոքր գրքերի, ատենախոսությունների համար, book` լիարժեք գրքերի համար։

Ուսանողական ավարտական (կամ մագիստրոսական) աշխատանքի տեքստի պատրաստման համար ամենահարմարը report մակետն է: Սա հնարավորություն է տալիս \chapter, \section, \subsection այլ նմանատիպ մակրոսներով փաստաթուղթը բաժանել գլուխների, բաժինների ենթաբաժինների և այլ տրամաբանական մասերի։ Մակետի ընտրությունը կատարվում է LaTeX ձեռագրի \documentclass մակրոսով։
\documentclass[a4paper,11pt]{report}
Քառակուսի փակագծերում նշված a4paper պարամետրով նշված է, որ փաստաթուղթը կառուցելիս պետք է նկատի ունենալ A4 ստանդարտի տպագրական թուղթը, իսկ 11pt պարամետրն ասում է, որ տեքստի հիմնական տպատառի չափը 11 է և օգտագործվող մյուս բոլոր տառերի չափն ընտրվելու է 11 չափի հարաբերությամբ։

Լռելությամբ report մակետում ընդունված է լուսանցքների այնպիսի չափ, որ տեքստի համար մնացած տարածում, հաշվի առնելով ընթեռնելիության որոշ հարցեր, մեկ տողը պարունակի 60-70 տառ (նիշ)։ Բայց մեզ մոտ ընդունված չէ այդպիսի լայն լուսանցքներ։ Սովորաբար ընտրվում է (և աչքի համար էլ հաճելի է) ձախից և ներքևից 3 սմ, իսկ աջից և վերևից՝ 2 սմ լուսանցքներ։ Այս կարգավորումներն անելու համար կարելի է օգտագործել geometry փաթեթը՝ \usepackage հրամանի պարամերտրերում տալով լուսանցքների նախընտրելի չափերը։
\usepackage[top=2cm,bottom=3cm,left=3cm,right=2cm]{geometry}

Տպատառերի (կամ տառատեսակների) ընտրություն

Քանի որ մեր բուհերում ավարտական աշխատանքների պաշտպանության ներկայացվող տեքստերը պատրաստվում են հիմնականում հայերենով, ապա ես ուզում եմ հղում կատարել իմ բլոգի մեկ այլ գրառման՝ Հայերեն LaTeX, որտեղ ես մանրամասն պատմում եմ, թե ինչպես LaTeX-ն օգտագործել հայերեն փաստաթղթեր պատրաստելու համար։ Այդտեղ պատմում եմ նաև տպատառերի ընտրության մասին։

Տիտղոսաթերթի պատրաստումը

Տարիների ընթացքում ստացվել է այնպես, որ մեր բուհերում ներկայացվող ավարտական կամ կուրսային աշխատանքների տիտղոսաթերթերն ունեն մի ընդհանուր սխեմա՝ երբեմն այս կամ այն մանր փոփոխություններով։ Ստորև իմ մագիստրոսական աշխատանքի տիտղոսաթերթի նկարն է.
Չեմ պնդում, որ սա անթերի և օրինակելի սխեմա է, բայց այն ընդունելի է շատերի կողմից, իսկ ինձ արված միակ դիտողությունն այն էր, թե էջի վերևում «Երևանի Պետական Համալսարան» ու «Տեղեկատվական Տեխնոլոգիաների Կրթական և Հետազոտական Կենտրոն» արտահայտություններում պետք չէ բոլոր բառերը սկսել մեծատառերով։

LaTeX կոդը, որով ես կառուցել եմ այս տիտղոսաթերթը, այնքան պարզ է, որ նույնիսկ մեկնաբանությունների կարիք չկա։ Ստորև ներկայացնում եմ այն.
% titlepage միջավայրը սկսում է նոր մաքուր էջ, որի վրա բացակայում է էջի համարը
\begin{titlepage}

\begin{centering}
\LARGE{Երևանի \ Պետական \ Համալսարան}\\
\Large{Տեղեկատվական Տեխնոլոգիաների Կրթական և Հետազոտական Կենտրոն}\par
\vskip6cm
\textbf{\Huge{ԱՎԱՐՏԱԿԱՆ~~ԱՇԽԱՏԱՆՔ}}\par
\end{centering}

\null\smallskip\null

\begin{centering}
\begin{tabular}{rl}
\textbf{Թեմա:}    & \textit{Բովանդակությամբ հասցեավորվող հիշող սարքերը}\\
                   & \textit{տեստավորող ալգորիթմների կառուցում} \\[4pt]
\textbf{ՈՒսանող:} & \textit{Արմեն Բադալյան} \\[4pt]
\textbf{Ղեկավար:} & տ.~գ.~թ.~\textit{Գուրգեն Հարությունյան} \\
\end{tabular}
\par
\end{centering}

\null\vfill\null

\begin{centering}
Երևան - 2011\par
\end{centering}

\end{titlepage}

Տեքստի տրամաբանական տրոհում

report մակետում տեքստի տրամաբանական տրոհման ամենամեծ միավորը «գլուխ»-ն է, որ սկսվում է \chapter մակրոսով։ Բացի այն, որ \chapter մակրոսը վերնագիրը ձևավորում է տվյալ պահին որոշված ոճով, այն նաև մեկով ավելացնում է գլուխների հաշվիչի արժեքը։ Օրինակ,
\chapter{Ծրագրի ընդհանուր նկարագրություն}
Հաջորդ տրամաբանական միավորները «բաժին», «ենթաբաժին» և «ենթա-ենթաբաժին»-ն են, որ սկսվում են համապատասխանաբար \section, \subsection և \subsubsection մակրոսներով։ Այդ միավորներից ամեն մեկն ունի իր հաշվիչը, որոնց արժեքը ավելանում է համապատասխան մակրոսի կիրառմամբ, իսկ այդ հաշվիչների արժեքն արտածվում է վերնագրի մեջ։ Օրինակ, իմ աշխատանքի երրորդ գլուխն ուներ հետևյալ տեքստը.
Տեքստի տրամաբանական տրոհման հրամանները տեղեկություններ են հավաքում նաև բովանդակության ցանկն արտածող \tableofcontents հրամանի համար։ Սովորաբար բովանդակության ցանկը տեղադրում են տիտղոսաթերթից հետո։
    Եթե փաստաթուղթը հավելվածներ է պարունակում, ապա ձեռագրի համապատասխան տեղում պետք է ավելացնել \appendix մակրոսը։ Այդ կետից սկսած գլուխների վերնագրերը կսկսվեն «Հավելված» (կամ «Appendix») բառով և կհամարակալվեն լատինական այբուբենի տառերով։ Օրինակ այսպես.

Պատկերների տեղադրում

LaTeX-ը հնարավորություն է տալիս փաստաթղթում ներդնել (համարյա) կամայական ֆորմատի պատկերներ (նկարներ). PNG, JPEG, EPS և այլն։ Նախ հարկավոր է կցել graphicx փաթեթը.
\usepackage{graphicx}
Հետո, տեքստի այն տեղում, որտեղ պետք է ներդրվի նկարը, \includegraphics մակրոսով նշվում է նկարի ֆայլի անունը։ Օրինակ, camcell.png նկարը 0.85 մասշտաբով ներդնելու համար պետք է գրել.
\includegraphics[scale=.85]{camcells.png}
LaTeX-ում նախատեսված են այսպես կոչված «սահող» (floating) միջավայրեր։ Դրանք նախատեսված են պարունակել օբյեկտներ, որոնք ամբողջությամբ պետք է տեղավորվեն մեկ էջի վրա, ինչպես նաև թույլ են տալիս այդ օբյեկտների համար սահմանել վերնագրեր ու խաչաձև հղումների նշիչներ (labels)։ Նկարները տեքստում տեղադրվում են figure սահող միջավայրի օգնությամբ։ Օրինակ,
\begin{figure}[h]
\centering
\includegraphics[scale=.85]{camcells.png}
\caption{\textsf{SRAM}, \textsf{BCAM} բջիջներ։}
\label{fig:cells}
\end{figure}
Ձեռագրի այս հատվածն ասում է, որ 0.85 մասշտաբով ներդրվում է camcells.png նկարը, որի ներքևում գրվելու է «SRAM, BCAM բջիջներ։» վերնագիրը (\caption), իսկ խաչաձև հղումների համար օգտագործվելու է fig:cells նշիչը (\label)։ Իսկ \centering մակրոսի կիրառումը նշում է, որ նկարը հորիզոնական ուղղությամբ պետք է կենտրոնադրվի։
    \begin{figure} տողի պոչից գրված [h] պարամետրը ցույց է տալիս, որ նկարը պետք է տեղադրվի հենց ճիշտ այն տեղում, որտեղ ձեռագրում հանդիպում է figure միջավայրը։ Բացի «h» (here) տառից, կարելի է տալ, օրինակ, նաև «t» (top) և «b» (bottom) տառերը։ Դրանցից առաջինն ասում է, թե նկարը պետք է միշտ տեղադրել (սահեցնել) էջի վերևում, իսկ երկրորդը՝ էջի ներքևում։ Ինչքան գիտեմ, լռելությամբ միացված է «t» պարամետրը (նկարները սահում են էջի վերին մասը)։ Օրինակ, հետևյալ երկու նկարներից առաջինում նկարը տեղադրելիս figure միջավայրին տրված է «h» տեղադրման պարամետրը, իսկ երկրորդում ոչինչ տված չէ։

Գրականության ցանկ և հղումներ

Փաստաթղթի կարևոր բաղադրիչներից է գեղեցիկ կառուցված գրականության ցանկը։ Բարեբախտաբար LaTeX համակարգի համար ստեղծվել է BibTeX գործիքը, որը հնարավորություն է տալիս ստանդարտ և, որ ավելի կարևոր է, պարզ գրառմամբ թվարկել աշխատանքում օգտագործված (կամ օգտագործվելիք) աղբյուրները։ Օրինակ, իմ մագիստրոսական աշխատանքի համար ես պատրաստել էի մի BibTeX ֆայլ (thesisbiblio.bib), որի պարունակության մի մասը այսպիսինն էր.
@article{hgsvz,
    author = "Grigoryan H. and Harutyunyan G. and Shoukourian S. and Vardanian V. and Zorian Y.",
    title = "Generic BIST Architecture for Testing of Content Addressable Memories",
    note = "IEEE International on-line testing symposium",
    year = "2011"
}

@article{art1,
    author="W. K. Al-Assadi and A. P. Jayasumana and Y. K. Malaiya",
    title="On fault modeling and testing of content-addressable Memories",
    journel="IEEE International Workshop on Memory Technology, Design and Testing",
    year=1994
}

@article{art2,
    author="J. Zhao and S. Irrinki and M. Puri and F. Lombardi",
    title="Testing SRAM-Based Content Addressable Memories",
    journal="IEEE Transactions on Computers",
    year=2000
} 
 
@article{art3,
    author="Zh. Xuemei and Y. Yizheng and Ch. Chunxu",
    title="Tests for Word Oriented Content Addressable Memories",
    journal="Asian Test Symposium",
    year=2002
}
Այստեղ BibTeX լեզվով նկարագրված են երեք հոդվածներ (@article), որոնց տրված են համապատասխանաբար hgsvz, art1, art2 և art3 նշիչները։ BibTeX ֆայլում թվարկված գրառումներին LaTeX ձեռագրում հղում են անուն հենց այս նշիչներով։ Հղումները կարող են լինել երկու տեսակի. \cite և \nocite մարոսներով։ Առաջինի օգտագործման դեպքում հղված տարրի համարն արտածվում է հղման կետում, իսկ երկրորդի դեպքում՝ ոչ։ \nocite մակրոսն օգտագործում եմ այն դեպքում, երբ ուզում եմ գրականության ցանկին տարր ավելացնել, բայց այդ տարրը չհիշատակել աշխատանքի տեքստում։ Օրինակ, իմ աշխատանքի առաջին գլխի առաջին նախադասությունը ձեռագրում ունի հետևյալ տեսքը, որտեղ \cite մակրոսով հղում եմ կատարել hgsvz նշիչն ունեցող հոդվածին։
Բովանդակությամբ հասցեավորվող հիշող սարքերը \cite{hgsvz} 
(\textsf{Content Addressable Memory} – \CAM) դրանք հիշող 
սարքերի մի հատուկ տեսակ են, որոնք օգտագործվում են որոնման 
մեծ արագություն պահանջող ապարատային կիրառություններում:
Փաստաթղթի այն տեղում, որտեղ ուզում եմ, որ հայտնվի գրականության ցանկը (սովորաբար գրականության ցանկը տեղադրում են վերջում), գրում եմ հետևյալ տողերը.
\bibliographystyle{plain}
\bibliography{thesisbiblio}  
Սրանցից առաջինն ասում է, որ փաստաթղթում պետք է տեղադրել plain ոճի (այդ ոճերի մասին առաայժմ չընդարձակավեմ) գրականության ցանկ, իսկ երկրորդը նշում է .bib ֆայլի անունը։
    Առաջին անգամ ձեռագիրը կոմպիլյացնելուց հետո .aux ֆայլում գրառումներ են կատարվում գրականության հղումների մասին։ Այնուհետև պետք է աշխատեցնել bibtex ծրագիրը՝ արգումենտում տալով .aux ֆայլը, որը գեներացնում է միայն ձեռագրում հիշատակված աղբյուրները պարունակող .bbl ֆայլը։ Եվ հետո նորից պետք է կոմպիլյացնել ձեռագիրը, որպեսզի փաստաթղթում ավելանա գրականության ցանկը, իսկ այն կետերում, որտեղ կատարվել են հղումները, ավելացվեն համապատասխան համարները։ Հրամանների տիպիկ հաջորդականությունը կարող է ունենալ հետևյալ տեսքը, որտեղ m0.tex-ն ձեռագրի ֆայլն է։
$ xelatex m0.tex
$ bibtex m0.aux
$ xelatex m0.tex

Ծրագրերի կոդի ներկայացումը

Երբեմն անհրաժեշտություն է առաջանում փաստաթղթում ունենալ մի որևէ ծրագրավորման լեզվով գրված տեքստ։ Ստանդարտ LaTeX-ի verbatim միջավայրը իր պարունակությունն արտածում է առանց ֆորմատավորման. այնպես, ինչպես գրված է ձեռագրում։ Բայց այդ, fancyvrb փաթեթը տրամադրում է Verbatim միջավայրը, որը հնարավորություն է տալիս անփոփոխ արտածվող տեքստն արտածել լրացուցիչ ատրիբուտներով, տողերի համարներ, շրջանակ, տառատեսակի փոփոխություն և այլն։

Ամփոփում

Առայժմ այսքանը աշխատանքների ձևավորման մասին։ Կրկնեմ նորից, որ ոճական տեսկետից ես ներկայացնում եմ միայն իմ սեփական կարծիքը։ LaTeX-ը թույլ է տալիս կամայական փոփոխություններ կատարել և վերջնական փաստաթուղթը հարմարեցնել նույնիսկ ամենաքմահաճ պահանջներին։

Thursday, September 18, 2014

C++: Ֆունկցիա

Մաթեմատիկական մեկնաբանությամբ ֆունկցիան մի գործողություն է, որը մի բազմությունը՝ որոշման տիրույթը, արտապատկերում է մեկ այլ բազմության՝ արժեքների տիրույթին։ C++ լեզվում նույնպես այդպես է․ ֆունկցիան ստանում է արգումենտներ և վերադարձնում է արժեք։ Բայց նաև, ծրագրավորման գործի առանձնահատկություններից ելնելով, C++ լեզուն թույլատրում է սահմանել ֆունկցիաներ, որոնք արգումենտներ չեն ստանում կամ/և արժեքներ չեն վերադարձնում։

main ֆունկցիայի օրինակով արդեն տեսանք, որ C++ լեզվում ֆունկցիայի սահմանումն ունի չորս բաղադրիչ. i) վերադարձվող արժեքի տիպ, ii) անուն, iii) արգումենտների ցուցակ, iv) մարմին։ Օրինակ, եթե սահմանենք տրված շառավղով շրջանի մակերեսը հաշվող area ֆունկցիան, ապա այն կունենա այսպիսի տեսք.
double area( double radius )
{
  return radius * radius * 3.14159265358979323846;
}
Այս ֆունկցիայի վերադարձվող արժեքի տիպը double է, անունը area է, արգումենտների ցուցակում թվարկված է միակ radius արգումենտը՝ իր տիպի հետ, իսկ մարմինը բաղկացած է միակ return հրամանից, որի արգումենտում շրջանի մակերեսի հաշվման բանաձևն է։

Ֆունկցիայի տիպ է կոչվում վերադարձրած արժեքի տիպի ու արգուենտների տիպերի ցուցակի համադրությունը։

Եթե հարկավոր է սահմանել մի ֆունկցիա, որից արժեք չենք ակնկալում, ապա պետք է վրա վերադարձվող արժեքի տիպը նշել որպես void։ Այսպիսի ֆունկցիային երբեմն անվանում են նաև պրոցեդուրա։ Օրինակ, սահմանենք մի ֆունկցիա, որը ստանում է առանց նշանի ամբողջ թիվ (unsigned int) և արտածում է այդ թվի տասական, ութական ու տասնվեցական ներկայացումները։ Այդ ներկայացումները ստացվում են հոսքերի dec, oct և hex մանիպուլյատորների օգնությամբ, որոնք սահմանված են iostream ֆայլում։
void print_number( unsigned int num )
{
  std::cout << std::setw(8) << std::dec << num
            << std::setw(8) << std::oct << num
            << std::setw(8) << std::hex << num
            << std::endl;
}
Արտածման հոսքի setw պարամետրով մանիպուլյատորը, որ սահմանված է գրադարանի iomanip ֆայլում, հնարավորություն է տալիս սահմանել այն դիրքերի քանակը, որոնք պետք է օգտագործվեն արժեքի արտածման համար։

Եթե ֆունկցիան պետք է ստանա մի քանի արգումենտներ, ապա դրանք արգումենտների ցուցակում թվարկվում են իրարից ստորակետով անջատված։ Օրինակ, սահմանենք avg3 ֆունկցիան, որը արգումենտում ստանում է երեք իրական թիվ և վերադարձնում դրանց թվաբանական միջինը։
double avg3( double a, double b, double c )
{
  auto sum = a + b + c;
  return sum / 3;
}
Եթե մի որևէ f() ֆունկցիայում օգտագործվելու է մի այլ g() ֆունկցիա, ապա այն պետք է ավելի շուտ հայտարարված կամ սահմանված լինի։ Օրինակ, ծրագրում այդ երկու ֆունկցիաների փոխադարարձ դասավորությունը կարող է լինել այսպիսին.
int g( double a, char b )
{
    // ինչ-որ հրամաններ
    return 777;
}

void f( int x )
{
    // ինչ-որ հրամաններ
    auto v = g( 3.14, 'p' );
    // ինչ-որ հրամաններ
}
Կամ, f() ֆունկցիային կարող է նախորդել միայն g() ֆունկցիայի հայտարարությունը։ Ահա այսպես.
int g( double, char );

void f( int x )
{
    // ինչ-որ հրամաններ
    auto v = g( 3.14, 'p' );
    // ինչ-որ հրամաններ
}

int g( double a, char b )
{
    // ինչ-որ հրամաններ
    return 777;
}
Առաջին տողում գրված արտահայտությունը կոմպիլյատորին տեղեկացնում է, որ գոյություն ունի double և char տիպի արգումենտներ ստացող և int արժեք վերադարձնող g անունով ֆունկցիա, որի սահմանումը գալու է քիչ ավելի ուշ։

Wednesday, September 17, 2014

C++: Փոփոխական

C++ լեզվով գրված ծրագրերի առանցքային բաղադրիչներից մեկը փոփոխականն է։ Ծրագրի տեսակետից փոփոխականը մի անվանված օբյեկտ է, որին կարելի է ծրագրի կատարման տարբեր պահերին վերագրել տարբեր արժեքներ։ Օրինակ, եթե պետք է ունենալ մի փոփոխական, որի մեջ պահելու ենք շրջանի շառավիղը, ապա կարող ենք գրել.
double radius;
Այս արտահայտություն կոչվում է փոփոխականի հայտարարություն. C++ լեզվի double ծառայողական բառը նշում է, որ raduis փոփոխականը հայտարարված է որպես կրկնակի ճշտության (double precision) իրական թիվ։ Կամ ասում են, որ radiusտիպը double է։ Այդ տիպով է որոշվում ԷՀՄ-ի հիշողության մեջ փոփոխականի զբաղեցրած չափը և նրա հետ թույլատրելի գործողությունները։

Մի որևէ տիպի չափն իմանալու համար կարելի է օգտագործել sizeofգործողությունը։ Այն իր արգումենտում սպասում է տիպի կամ փոփոխականի անուն և վերադարձնում է դրա չափը։ Օրինակ, համոզվելու համար, որ կրկնակի ճշտության իրական թվերի double տիպը զբաղեցնում է հիշողության 8 բայթ (64 բիթ), բուլյան bool տիպը՝ 1 բայթ, ամբողջ թվերի int տիպը՝ 4 բայթ և այլն, կարող ենք օգտագործել հետևյալ ծրագիրը.
#include <iostream>

int main()
{
    using namespace std;
    cout << "  bool " << sizeof(bool) << endl;
    cout << "  char " << sizeof(char) << endl;
    cout << "   int " << sizeof(int) << endl;
    cout << "double " << sizeof(double) << endl;
}
Փոփոխականը հայտարարելիս ցանկալի է նշել նաև նրա սկզբնական արժեքը, հակառակ դեպքում հայտնի չէ, թե կատարման ժամանակ այն ինչպիսին կլինի։ Սկզբնական արժեքը տալու համար այն պետք է պարզապես գրել փոփոխականի անունից հետո՝ վերցրած «{» և «}» փակագծերի մեջ։ Օրինակ, count և length ամբողջաթիվ փոփոխականները հայտարարելու և նրանց 0 սկզբնական արժեքը տալու համար պետք է գրել.
int count{0}, length{0};
Փոփոխականի հայտարարությունը ուժի մեջ է այն լեքսիկական բլոկում, որտեղ ինքը սահմանված է։ Այդ բլոկը որոշվում է կամ {} փակագծերով, կամ ղեկավարող կառուցվածքների մարմնով։ Օրինակ, հետևյալ ծրագրի կատարման արդյունքում կարտածվի թվերի 10, 20, 10 հաջորդականությունը, որից էլ երևում է, որ տեքստի 7-րդ տողում սկսվող և 10-րդ տողում ավարտվող բլոկում սահմանված x փոփոխականը և 5-րդ տողում սահմանված x փոփոխականն ունեն տարբեր տեսանելիության տիրույթներ (scope).
#include <iostream>

int main()
{
    int x{10};
    std::cout << x << ", ";
    {
        int x{20};
        std::cout << x << ", ";
    }
    std::cout << x << std::endl;
}
Փոփոխականի ընթացիկ արժեքը փոխվում է (նրան նոր արժեք է վերագրվում) վերագրման (=) գործողության միջոցով։ Օրինակ, վերը հայտարարված radius փոփոխականին \(2.54\) արժեքը (1 մատնաչափ, դյույմ) վերագրելու համար պետք է գրել.
radius = 2.54;
Վերագրման գործողությունը կարելի է օգտագործել նաև փոփոխականի հայտարարության մեջ, նրան սկզբնական արժեք տալու համար։ Օրինակ, սահմանենք area փոփոխականը և նրան վերագրենք radius շառավղով շրջանի մակերեսը.
auto area = radius * radius * 3.1415;
Եթե փոփոխականի հայտարարման ժամանակ տիպի փոխարեն գրված է auto ծառայողական բառը, ապա կոմպիլյատորը փոփոխականի տիպը որոշում է ըստ նրան վերագրված արժեքի. կատարվում է տիպի արտածում (տիպի դուրսբերում)։ Քանի որ radius փոփոխականի և \(3.1415\) թվի տիպերը double են, և բազմապատկման (*) գործողությունն էլ վերադարձնելու է double տիպի արժեք, ապա կոմպիլյատորը եզրակացնում է, որ area փոփոխականի տիպը նույնպես պետք է լինի double։

Գրենք մի ծրագիր, որն օգտագործողից հարցնում է շրջանի շառավիղը և արտածում է այդ նույն շրջանի մակերեսն ու եզրագծի երկարությունը։ Նորից գործարկենք տեքստային խմբագրիչը և ստեղծենք ex04.cpp ֆայլը՝ հետևյալ պարունակությամբ.
#include <iostream>

int main()
{
    std::cout << "ներմուծեք շրջանի շառավիղը ";
    double radius{0.0};
    std::cin >> radius;

    const double pi = 3.14159265358979323846;

    auto length = 2 * pi * radius;
    auto area = pi * radius * radius;

    std::cout << "երկարությունը = " << length << std::endl
              << "      մակերեսը = " << area << std::endl;
}
7-րդ տողում գրված cin (console input) օբյեկտը կապված է համակարգի ստանդարտ ներմուծման հոսքի հետ։ Իսկ >> գործողությունը իր ձախ արգումետից եկած արժեքը գրում է աջ արգումենտի մեջ։ Տվյալ դեպքում cin >> radius արտահայտությունը ստեղնաշարից կարդում է մի թվային արժեք և այն վերագրում radius փոփոխականին։

9-րդ տողում const ծառայողական բառն ասում է, որ պետք է սահմանել pi անունով և \(3.14159265358979323846\) արժեքով իրական հաստատուն։ Հաստատունի արժեքը, բնականաբար, փոխել չի կարելի։ Եթե ծրագրում փորձ կատարվի, օրինակ, pi օբյեկտին նոր արժեք վերագրել, ապա կոմպիլյատորն այդ առթիվ կարտահայտի իր դժգոհությունը և կտա համապատասխան հաղորդագրություն։

10-րդ և 11-րդ տողերում հաշվվում են length (երկարություն) և area (մակերես) փոփոխականների արժեքները։

13-րդ և 14-րդ տողերում կազմված է << գործողությունների շղթա։ Սա հնարավոր է դառնում այն բանի շնորհիվ, որ << գործողությունը որպես արժեք վերադարձնում է իր ձախ արգումենտը։ endl մանիպուլյատորը արտածման հոսքին է ուղարկում նոր տողի անցման նիշը։
Կոմպիլյատորի օգնությամբ թարգմանենք այս ծրագիրը և աշխատեցնենք.
$ g++ -std=c++11 -o ex04 ex04.cpp
$ ./ex04
ներմուծեք շրջանի շառավիղը 2.54
երկարությունը = 15.9593
     շառավիղը = 20.2683
Երբեմն կարող է անհարմարության զգացողություն առաջացնել այն փաստը, որ STL-ի բոլոր օբյեկտների, դասերի կամ ֆունկցիաների անուններից առաջ պետք է գրել stl:: նախդիրը։ Դրանից կարելի է խուսափել main ֆունկցիայի սկզբում գրելով using namespace std; արտահայտությունը։ Սա կոմպիլյատորից պահանջում է տեսանելի դարձնել std անունների տիրույթի բոլոր անունները։ Եթե հարկավոր է տեսանելի դարձնոլ միայն որոշ ընտրված անուններ, օրինակ, cout, cin և endl անունները, ապա կարող ենք using հրամանով թվարկել դրանք.
using std::cin;
using std::cout;
using std::endl;
Այս հայտարարություններից հետո արդեն կարող ենք ծրագրի տեքստում cout, cin և endl անուններից առաջ չգրել stl:: նախդիրը։

Փոփոխականին հատկացված հիշողության տիրույթի առաջին բայթի համարը կոչվում է փոփոխականի հասցե։ Այն կարելի է ստանալ & ունար գործողության միջոցով։ Օրինակ, radius փոփոխականի հասցեն արտածելու համար պետք է գրել.
std::cout << &radius << std::endl;
Փոփոխականի հասցեն կարելի է վերագրել նաև հասցեի տիպ ունեցող մեկ այլ փոփոխականի։ Օրինակ.
auto p_radius = &radius;
Մի որևէ տիպի փոփոխականի հասցե պահելու համար նախատեսված փոփոխական հայտարարելիս պետք է պարզապես հայտարարության մեջ տիպի անունից հետո գրել * նիշը։ Օրինակ,
double* p_radius2{&radius};
Հասցե պարունակող փոփոխականին անվանում են ցուցիչ։ Օրինակ, p_radius և p_radius_2 փոփոխականները double տիպի օբյեկտների ցուցիչներ են։

Եթե ցուցիչի հայտարարման պահին դեռևս հայտնի չէ, թե այն ինչ օբյեկտի է «ցույց տալու», ապա այն պետք է արժեքավորել nullptr արժեքով։ Այսպիսի ցուցիչներին անվանում են զրոյական։

Tuesday, September 16, 2014

C++: Առաջին ծրագիրը մեկնաբանություններով

C++ ծրագրավորման լեզվի ուսումնասիրությունը սկսենք մի կարճ ծրագրից, որը պետք է ստանդարտ արտածման հոսքին դուրս բերի «Ողջո՜ւյն, այդ ես եմ, քո առաջին ծրագիրը։» տողը։

Գործարկենք տեքստային խմբագրիչը և նրա օգնությամբ ստեղծենք ex01.cpp ֆայլը՝ հետևյալ պարունակությամբ․
// Առաջին C++ ծրագիրը
#include <iostream>

int main()
{
    std::cout << "Ողջո՜ւյն, այդ ես եմ, քո առաջին ծրագիրը:\n";
}
Շրագրի տեքստը ֆայլու գրառելուց հետո այն պետք է կոմպիլյատորի օգնությամբ թարգմանել մեքենայական հրամանների և կատարել։ Բայց մի փոքր առաջ անցնենք ու ծրագրի ամեն մի տողի համար տանք համառոտ մեկնաբանություն։

Առաջին տողը «//» նիշերով սկսվող և մինչև տողի վերջը շարունակվող մեկնաբանություն է։ Մեկնաբանությունները, որոնք կարող են պարունակել կամայական տեքստ, ծրագրի իմաստի վրա չեն ազդում և ամբողջովին անտեսվում են կոմպիլյատորի կողմից։ Դրանց նպատակն է ծրագում բացատրություններ թողնել մարդու համար։

Երկրորդ տողում գրված #include հրահանգը նախապրոցեսորից պահանջում է ծրագրին կցենլ iostream գրադարանային ֆայլը։ Այս ֆայլում են սահմանված ստանդարտ ներմուծման ու արտածման հոսքերի հետ աշխատող գործողություններն ու օբյեկտները։ Ի թիվս զանազան ֆունկցիաների ու օբյեկտների, iostream ֆայլը պարունակում է ստանդարտ արտածման հոսքի հետ կապված cout օբյեկտը և իր աջ արգումենտը ձախ արգումենտի մեջ գրող << գործողությունը։

C++ լեզվով գրված ամեն մի ծրագիր պետք է պարունակի main անունով միակ ֆունկցիա։ Այս ֆունկցիան հանդիսանում է ծրագրի մուտքի կետը, այսինքն՝ ծրագրիրը սկսում է կատարվել main ֆունկցիայից։ Ավելի պատկերավոր ասած՝ ծրագիրը կատարելու համար օպերացիոն համակարգը կանչում է main ֆունկցիան։ Տվյալ դեպքում main ֆունկցիան արգումենտներ չի սպասում և վերադարձնում է int (integer, ամբողջ թիվ) տիպի արժեք։ Օպերացիոն համակարգն այս ֆունկցիայի արժեքը մեկնաբանում է որպես ծրագրի հաջող կամ անհաջող ավարտի ազդանշան։ Ըստ պայմանավորվածության, 0 արժեքը համարվում է հաջող ավարտ, իսկ 0-ից տարբեր դրական ամբողջ թվերը՝ անհաջող ավարտ։ C++ ֆունկցիայից որևէ արժեք է վերադարձվում է return հրամանով։ Սակայն միայն main ֆունկցիայի համար կա բացառություն, որ, եթե բացահայտորեն նշված չէ return հրամանը, ապա վերադարձվող արժեքը համարվում է 0։

main ֆունկցիայի մարմինը, որ պարփակված է «{» և «}» փակագծերի մեջ, պարունակում է միակ արտահայտություն, որտեղ << գործողության օգնությամբ «Ողջո՜ւյն, աշխարհ։» տողն ուղարկվում է ստանդարտ արտածման հոսքի հետ կապված cout (cconsole output) օբյեկտին։ cout անունից առաջ գրված std:: նախդիրը ցույց է տալիս, որ այդ երկու անունները պատկանում են լեզվի Կաղապարների ստանդարտ գրադարանին (Standard template library, STL)։
Պետք է հիշել, որ cout-ը C++ լեզվի ծառայողական բառ չէ։ Այն ընդամենը iostream գրադարանում հայտարարված ավտոմատ օբյեկտ է։
Հիմա այս ծրագիրը թարգմանենք (կոմպիլյացնենք) մեքենայական կոդի և աշխատեցնենք։ C++ լեզվով գրված ծրագրերը թարգմանության ժամանակ անցնում է երեք հիմնական փուլ. i) նախնական մշակում - preprocessing -- այս փուլում մշակվում են # նիշով սկսվող հրահանգները, որոնք ծրագրի տեքստի հետ կատարվում են զուտ տեքստային գործողություններ։ Օրինակմ ֆայլերի կցում, անունների փոփոխում արժեքներով և այլն, ii) թարգմանություն - compilation -- այս փուլում ծրագրավորողի գրած տեքստը թարգմանվում է մեքենայական կոդի և ստեղծվում են այսպես կոչված օբյեկտային ֆայլեր, iii) կապակցում - linking -- այս փուլում նոր ստեղծված օբյեկտային ֆայլերը կապակցվում են գրադարանային (կամ այլ) օբյեկտային ֆայլերի հետ և ստեղծվում է կատարվող մոդուլ։

Սովորաբար ծրագրի տեքստից կատարվող մոդուլի ստացման այս երեք փուլերը թաքնված են օգտագործողից և, պարզ ծրագերի դեպքում, կատարվում են մեկ հրամանով։ Օրինակ, Bash ինտերպրետատորի հրամանային տողում ներմուծենք հետևյալը, որտեղ -std=c++11 պարամետրով կոմպիլյատորից պահանջում ենք միացնել C++11 ստանդարտի հատկությունները.
$ g++ -std=c++11 ex01.cpp
կամ, եթե ուզում ենք օգտագործել clang++ կոմպիլյատորը, ապա.
$ clang++ -std=c++11 ex01.cpp
Եթե կոմպիլյատորը որևէ սխալ չի հայտնաբերել, ապա ընթացիկ պանակում ստեղծվում է a.out անունով կատարվող մոդուլը։ Երբ հարկավոր է կատարվող մոդուլին այլ անուն տալ, ապա կարող ենք օգտագործել կոմպիլյատորի -o պարամետրը։ Օրինակ.
$ clang++ -std=c++11 -o ex01 ex01.cpp
այս հրամանի կատարման արդյունքում կատարվող մոդուլը a.out-ի փոխարեն կունենա ex01 անունը։

ex01 մոդուլն աշխատեցնելու համար պետք է Bash—ի հրամանային տողում ներմուծել.
$ ./ex01
Ողջո՜ւյն, աշխարհ։
Ծրագրի կատարման արդյունքում տեսնում ենք արտածված տողը. սա հենց այն է, ինչ ակնկալում էինք առաջին ծրագրից։

Որպեսզի համոզվենք, որ իսկապես main ֆունկցիայի վերադարձրած արժեքը փոխանցվում է օպերացիոն համակարգին, կարող ենք ծրագրի կատարումից հետո Bash ինտերպրետատորի echo հրամանով դուրս բերել $? փսևդոփոփոխականի արժեքը։
$ echo $?
0
Հիմա վերը բերված օրինակի ex01.cpp ֆայլը պատճենենք ex02.cpp անունով, և main ֆունկցիայի մարմինն ավարտող «}» փակագծից առաջ ավելացնենք «return 0;» հրամանը։
#include 

int main()
{
    std::cout << "Ողջո՜ւյն, աշխարհ։" << std::endl;
    return 7;
}
Ապա նորից կոմպիլյացնենք ծրագիրը, աշխատեցնենք ու արտածենք $? փսևդոփոփոխականի արժեքը։ Հրամանների հաջորդականությունը և արտածված արդյունքները հետևյալ տեսքն ունեն.
$ g++ -std=c++11 -o ex02 ex02.cpp
$ ./ex02
Ողջո՜ւյն, աշխարհ։
$ echo $?
7

Sunday, September 14, 2014

Յունգի աղյուսակ - Young tabelau

\(n\times m\) չափի \(A\) մատրիցը կոչվում է Յունգի աղյուսակ (Young tabelau), եթե նրա տարրերը տողերում կարգավորված են ձախից-աջ, իսկ սյուներում՝ վերևից-ներքև։ Եթե աղյուսակի մի որևէ վանդակ դատարկ է, ապա այն նշվում է \(\infty\) (անվերջություն) նշանով։ \(A\) Յունգի աղյուսակը համարվում է դատարկ, եթե \(A[0,0] = \infty\)։ Աղյուսակը համարվում է ամբողջովին լցված, եթե \(A[n-1,m-1] \ne \infty\)։ Աղյուսակի տարրերից կարգով ամենափոքրը միշտ գտնվում է \(A[0,0]\) բջջում։

Ահա Յունգի աղյուսակի մի նմուշ, որը պարունակում է \(0\), \(1\), \(2\), \(3\), \(5\), \(7\), \(9\) թվերը։
0029
357
Յունգի աղյուսակի հետ կատարվող տիպիկ գործողություններից կարելի է համարել նոր տարրի ավելացումը, մինիմալ տարրի հեռացումը, դատարկ կամ լցված լինելը ստուգելը։

Իրական թվերի համար նախատեսված Յունգի աղյուսակը կարելի է սահմանել C++ լեզվի հետևյալ դասով․
class Tabelau {
private:
    int rows;      // տողերի քանակը
    int columns;   // սյուների քանակը
    double** data; // տվյալների աղյուսակ

public:
    Tabelau( int, int );
    ~Tabelau();

    bool is_empty() const; // աղյուսակը դատարկ է
    bool is_full() const;  // աղյուսակը լցված է

    double minimum() const; // փոքրագույն տարրը
    void add( double );     // ավելացնել նոր տարր
    void remove();          // հեռացնել փոքրագույն տարրը

private:
    // աղյուսակի կարգավորում նոր տարրն ավելացնելուց հետո
    void add_aux( int, int );
    // աղյուսակի կարգավորում նոր տարրը հեռացնելուց հետո
    void remove_aux( int, int );
};
Դասի կոնստրուկտորի նպատակը նոր աղյուսակի ստեղծումն է, որի բոլոր բջիջները նախապես լրացված են \(\infty\) արժեքով։
Tabelau::Tabelau( int r, int c)
  : rows{r}, columns{c}
{
  data = new double*[rows];
  for( int i = 0; i < rows; ++i ) {
    data[i] = new double[columns];
    for( int j = 0; j < columns; ++j )
      data[i][j] = INFINITY;
  }
}
Դեստրուկտորը պարզապես ազատում է զբաղեցրած հիշողությունը։
Tabelau::~Tabelau()
{
    for( int i = 0; i < rows; ++i )
        delete[] data[i];
    delete[] data;
}
Աղյուսակի դատարկ լինելը ստուգվում է is_empty() մեթոդով, իսկ լցված լինելը՝ is_full() մեթոդով։
bool Tabelau::is_empty() const
{
  return data[0][0] == INFINITY;
}

bool Tabelau::is_full() const
{
  return data[rows-1][columns-1] != INFINITY;
}
Փոքրագույն տարրը վերադարձնում է minimum() մեթոդը․
double Tabelau::minimum() const
{
  return data[0][0];
}
\(A\) Յունգի աղյուսակում նոր տարրն ավելացվում է \(A[rows-1,columns-1]\) բջջում, այնուհետև այն փոխատեղվում է իրենից վերևում և ձախում գտնվող տարրերից մեծագույնի հետ։ Նույնը կրկնվում է այնքան անգամ, քանի դեռ դիտարկվող տարրից վերև կամ ձախ գոյություն ունի ավելի մեծ արժեքով տարր։
void Tabelau::add( double val )
{
  data[rows-1][columns-1] = val;
  add_aux( rows-1, columns-1 );
}
Նոր տարրը \(A[rows-1,columns-1]\) բջջում գրառելուց հետո աղյուսակի կարգավորումը կատարվում է add_aux() ռեկուրսիվ մեթոդով։
void Tabelau::add_aux( int r, int c )
{
  int k{r}, h{c};
  if( r > 0 && data[r][c] < data[r-1][c] )
    k = r - 1;
  if( c > 0 && data[k][h] < data[r][c-1] )
    k = r, h = c - 1;
  if( k != r || h != c ) {
    double temp{data[r][c]};
    data[r][c] = data[k][h];
    data[k][h] = temp;
    add_aux( k, h );
  }
}
Մինիմալ տարրը, որ միշտ գտնվում է \(A[0,0]\) բջջում, աղյուսակից հեռացնելու համար նրա տեղում գրվում է \(\infty\), և այդ պատճառով էլ խախտվում է Յունգի աղյուսակի հատկությունը։ Աղյուսակը նորից կարգավորելու համար պետք է \(\infty\) արժեքն այնքան ժամանակ տեղափոխել դեպի աջ կամ ներքև, քանի դեռ գոյություն ունի նրանից փոքր տարր։
void Tabelau::remove()
{
  data[0][0] = INFINITY;
  remove_aux( 0, 0 );
}
Տարրը հեռացնելուց հետո աղյուսակի կարգավորումը կատարվում է remove_aux() մեթոդով։
void Tabelau::remove_aux( int r, int c )
{
  int k{r}, h{c};
  if( r < rows - 1 && data[r][c] > data[r+1][c] )
    k = r + 1;
  if( c < columns - 1 && data[k][h] > data[r][c+1] )
    k = r, h = c + 1;
  if( k != r || h != c ) {
    double temp{data[r][c]};
    data[r][c] = data[k][h];
    data[k][h] = temp;
    remove_aux( k, h );
  }
}

Թերևս այսքանը Յունգի աղյուսակների մասին։ Նշեմ նաև, որ այն հաճախ օգտագործվում է նախապատվություններով հերթերի կազմակերպման և կարգավորման heap-sort ալգորիթմների իրականացման համար։

Tuesday, September 9, 2014

C++ ծրագրավորման միջավայր

Հաշվի առնելով այն փաստը, որ C++ լեզուն նոր սովորողները հաճախ դժվարանում են գտնել ու իրենց համակարգիչներում տեղադրել լեզվի կոմպիլյատոր ու ծրագրավոր միջավայր, նաև հաշվի առնելով օգտագործողների ճնշող մեծամասնության կողմից Windows օպերացիոն համակարգի օգտագործման փաստը, ես փորձեցի պարզել, թե գոյություն ունեցող կոմպիլյատորներից ու ծրագրավորման միջավայրերից որն է ավելի հարմար սկսնակների համար։
Հենց սկզբից ասեմ, որ իմ ընտրություն կանգ առավ Code::Blocks ծրագրավորման ինտեգրացված միջավայրի (IDE, integrated development environment) վրա: Այն ունի բազմաթիվ առավելություններ, որոնց թվում են.
  1. Անվճար է և տարածվում է բաց կոդով (open source)։
  2. Բազմապլատֆորմ է։ Աշխատում է Windows, GNU/Linux, Mac OS օպերացիոն համակարգերում։
  3. Հնարավորություն ունի օգտագործել տարբեր կոմպիլյատորներ. Visual C++, GNU GCC, clang և այլն։
  4. Ունի շրագրերի շտկման ներդրված գործիք (debugger):
  5. Բեռնվող փաթեթը բավականին փոքր է՝ իր մեջ պարունակող G++ կոմպիլյատորի հետ միասին մոտ 100 Մբ։
Տեղադրելու համար պետք է բեռնել 13.12 տարբերակի՝ Windows-ի համար նախատեսված փաթեթը և աշխատեցնել այն։ Տեղադրման պրոցեսը որ մի բարդություն չի ներկայացում և ու չեմ ուզում այստեղ ներկայացնել այդ քայլերը։
     Տեղադրելուց հետո, երբ ծրագիրն առաջին անգամ գործարկվում է, առաջարկում է ընտրել համակարգում հայտնաբերված կոմպիլյատորներից մեկը։ Եթե մինչ այդ այլ կոմպիլյատոր տեղադրված չի եղել, ապա միակ ընտրության հնարավորությունը Code::Blocks-ի հետ տեղադրված GNU GCC կոմպիլյատորն է (MinGW ներկայացմաբ): Այնուհետև բացվում է աշխատանքային միջավայրը՝ մոտավորապես ստորև բերված նկարի տեսքով.
Առաջին ծրագիրը գրելու համար պետք է սեղմել «Create new project» հղմանը (կամ մենյուից ընտրել File->New->Project...), այնուհետև Category ցուցակից ընտրել Console կետը, իսկ պրոյեկտների շաբլոնների ցուցակից ընտրել Console application շաբլոնը։
Հետո պետք է ընտրել C կամ C++ ծրագրավորման լեզուն և պրոյեկտի անունն ու տեղը։
Համակարգը պրոյեկտի համար գեներացնում է main.cpp ֆայլը՝ հետևյալ պարունակությոմբ։
#include 

using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    return 0;
}
Բայց այս կոդի վերլուծությունն ու մեկնաբանությունը լրիվ այլ օպերա է :)

* * *
Կարելի է, իհարկե, հետևելով դասախոսների ու խնամի-ծանոթ-բարեկամների խորհրդին, տեղադրել Microsoft ֆիրմայի Visual Studio միջավայրը, որը մի հսկայական փաթեթ է, իր մեջ պարունակում է և՛ C++ լեզվի կոմպիլյատորը, և՛ ծրագրավորման ինտեգրացված միջավայր է, և՛ գրաֆիկական ծրագրերի նախագծման համակարգ է, ...։ Բայց կարծում եմ, որ տեղին չէ, ընդամենը ծրագրավորման հիմունքները սովորոելու համար, համակարգիչը զբաղեցնել տարատեսակ անպետք կամ ավելորդ գործիքներով։ Այլ կերպ ասած՝ «չարժե թնդանոթով կրակել ճնճղուկի վրա»։ Հենց այս պատճառով էլ, ամենևին չթերագնահատելով Visual Studio-ի արժանիքները, ես խորհուրդ չեմ տալիս տեղադրել այս փաթեթը։
     QtCreator ծրագրավորման ինտեգրացված միջավայրը ստեղծվել է Qt գրաֆիկական գրադարանների օգտագործմամբ ծրագրեր գրելու համար։ Այն անվճար տարածվող ծրագիր է։ Փաթեթը, որ պետք է բեռնել ու տեղադրել, մոտավորապես 600 Մբ է։ Նորից կարծում եմ, որ սա էլ շատ ավելորդ ու սկսնակների համար դեռևս անպետք գործիքներ է պարունակում։
     Համակարգչում տեղադրելով GNU GCC կոմպիլյատորը, կարելի է այնուհետև տեղադրել Eclipse կամ NetBeans միջավայրերն ու դրան կարգավորել այնպես, որ աշխատեն նշված կոմպիլյատորի հետ։ Սա նույնպես ընդունելի տարբերակ է, բայց պահանջում է մի քիչ ավելի շատ քայլեր։