☰

C Answers to Exercises

\(\newcommand{\footnotename}{footnote}\) \(\def \LWRfootnote {1}\) \(\newcommand {\footnote }[2][\LWRfootnote ]{{}^{\mathrm {#1}}}\) \(\newcommand {\footnotemark }[1][\LWRfootnote ]{{}^{\mathrm {#1}}}\) \(\let \LWRorighspace \hspace \) \(\renewcommand {\hspace }{\ifstar \LWRorighspace \LWRorighspace }\) \(\newcommand {\TextOrMath }[2]{#2}\) \(\newcommand {\mathnormal }[1]{{#1}}\) \(\newcommand \ensuremath [1]{#1}\) \(\newcommand {\LWRframebox }[2][]{\fbox {#2}} \newcommand {\framebox }[1][]{\LWRframebox } \) \(\newcommand {\setlength }[2]{}\) \(\newcommand {\addtolength }[2]{}\) \(\newcommand {\setcounter }[2]{}\) \(\newcommand {\addtocounter }[2]{}\) \(\newcommand {\arabic }[1]{}\) \(\newcommand {\number }[1]{}\) \(\newcommand {\noalign }[1]{\text {#1}\notag \\}\) \(\newcommand {\cline }[1]{}\) \(\newcommand {\directlua }[1]{\text {(directlua)}}\) \(\newcommand {\luatexdirectlua }[1]{\text {(directlua)}}\) \(\newcommand {\protect }{}\) \(\def \LWRabsorbnumber #1 {}\) \(\def \LWRabsorbquotenumber "#1 {}\) \(\newcommand {\LWRabsorboption }[1][]{}\) \(\newcommand {\LWRabsorbtwooptions }[1][]{\LWRabsorboption }\) \(\def \mathchar {\ifnextchar "\LWRabsorbquotenumber \LWRabsorbnumber }\) \(\def \mathcode #1={\mathchar }\) \(\let \delcode \mathcode \) \(\let \delimiter \mathchar \) \(\def \oe {\unicode {x0153}}\) \(\def \OE {\unicode {x0152}}\) \(\def \ae {\unicode {x00E6}}\) \(\def \AE {\unicode {x00C6}}\) \(\def \aa {\unicode {x00E5}}\) \(\def \AA {\unicode {x00C5}}\) \(\def \o {\unicode {x00F8}}\) \(\def \O {\unicode {x00D8}}\) \(\def \l {\unicode {x0142}}\) \(\def \L {\unicode {x0141}}\) \(\def \ss {\unicode {x00DF}}\) \(\def \SS {\unicode {x1E9E}}\) \(\def \dag {\unicode {x2020}}\) \(\def \ddag {\unicode {x2021}}\) \(\def \P {\unicode {x00B6}}\) \(\def \copyright {\unicode {x00A9}}\) \(\def \pounds {\unicode {x00A3}}\) \(\let \LWRref \ref \) \(\renewcommand {\ref }{\ifstar \LWRref \LWRref }\) \( \newcommand {\multicolumn }[3]{#3}\) \(\require {textcomp}\) \(\newcommand {\intertext }[1]{\text {#1}\notag \\}\) \(\let \Hat \hat \) \(\let \Check \check \) \(\let \Tilde \tilde \) \(\let \Acute \acute \) \(\let \Grave \grave \) \(\let \Dot \dot \) \(\let \Ddot \ddot \) \(\let \Breve \breve \) \(\let \Bar \bar \) \(\let \Vec \vec \) \(\renewcommand {\vec }{\boldsymbol }\) \(\newcommand {\Edge }{\ensuremath {\,\textemdash \,}}\) \(\newcommand \Const [1]{\text {\textsf {#1}}}\) \(\DeclareMathOperator {\lerp }{lerp}\) \(\DeclareMathOperator {\bitlen }{bitlen}\) \(\DeclareMathOperator {\sign }{sign}\) \(\newcommand {\I }{\mathrm {i}}\) \(\newcommand \AND {\mathbin {\&}}\) \(\newcommand \OR {\mathbin {|}}\) \(\newcommand \XOR {\mathbin {{}^{\wedge }}}\) \(\newcommand \shl {\ll }\) \(\newcommand \shr {\ggg }\) \(\newcommand \asr {\gg }\) \(\newcommand \NOT {\ensuremath {\mathord {\sim }}}\) \(\newcommand {\isep }{\mathrel {{.}\,{.}}}\) \(\newcommand {\Id }[1]{\mathit {#1}}\) \(\newcommand {\const }[1]{\mathsf {#1}}\) \(\newcommand {\algorithmname }[1]{\text {\textsc {#1}}}\) \(\newcommand {\bits }[1]{\text {#1}}\) \(\newcommand {\hexa }[1]{\mathtt {0x#1}}\) \(\newcommand {\num }[1]{#1}\) \(\newcommand {\qed }{\quad \square }\) \(\newcommand {\idiv }[2]{\lfloor #1/#2\rfloor }\) \(\newcommand \attribdot {\ensuremath {\mkern 1.5mu.\mkern 1.5mu}}\) \(\newcommand \attribxr [2]{#1\attribdot \text {#2}}\) \(\newcommand \attribir [2]{\Id {#1}\attribdot \text {#2}}\) \(\newcommand \attribii [2]{\Id {#1}\attribdot \Id {#2}}\) \(\newcommand \textsc [1]{#1}\) \(\require {colortbl}\) \(\let \LWRorigcolumncolor \columncolor \) \(\renewcommand {\columncolor }[2][named]{\LWRorigcolumncolor [#1]{#2}\LWRabsorbtwooptions }\) \(\let \LWRorigrowcolor \rowcolor \) \(\renewcommand {\rowcolor }[2][named]{\LWRorigrowcolor [#1]{#2}\LWRabsorbtwooptions }\) \(\let \LWRorigcellcolor \cellcolor \) \(\renewcommand {\cellcolor }[2][named]{\LWRorigcellcolor [#1]{#2}\LWRabsorbtwooptions }\) \(\newcommand {\tcbset }[1]{}\) \(\newcommand {\tcbsetforeverylayer }[1]{}\) \(\newcommand {\tcbox }[2][]{\boxed {\text {#2}}}\) \(\newcommand {\tcboxfit }[2][]{\boxed {#2}}\) \(\newcommand {\tcblower }{}\) \(\newcommand {\tcbline }{}\) \(\newcommand {\tcbtitle }{}\) \(\newcommand {\tcbsubtitle [2][]{\mathrm {#2}}}\) \(\newcommand {\tcboxmath }[2][]{\boxed {#2}}\) \(\newcommand {\tcbhighmath }[2][]{\boxed {#2}}\) \(\newcommand {\toprule }[1][]{\hline }\) \(\let \midrule \toprule \) \(\let \bottomrule \toprule \) \(\def \LWRbooktabscmidruleparen (#1)#2{}\) \(\newcommand {\LWRbooktabscmidrulenoparen }[1]{}\) \(\newcommand {\cmidrule }[1][]{\ifnextchar (\LWRbooktabscmidruleparen \LWRbooktabscmidrulenoparen }\) \(\newcommand {\morecmidrules }{}\) \(\newcommand {\specialrule }[3]{\hline }\) \(\newcommand {\addlinespace }[1][]{}\) \(\newcommand {\LWRsubmultirow }[2][]{#2}\) \(\newcommand {\LWRmultirow }[2][]{\LWRsubmultirow }\) \(\newcommand {\multirow }[2][]{\LWRmultirow }\) \(\newcommand {\mrowcell }{}\) \(\newcommand {\mcolrowcell }{}\) \(\newcommand {\STneed }[1]{}\) \(\newcommand {\LWRldelimtwo }[1][]{\text {#1}~\LWRbigdelim }\) \(\newcommand {\LWRldelimone }[2][]{\LWRldelimtwo }\) \(\def \ldelim #1#2{\def \LWRbigdelim {#1}\LWRldelimone }\) \(\newcommand {\LWRrdelimtwo }[1][]{\LWRbigdelim ~\text {#1}}\) \(\newcommand {\LWRrdelimone }[2][]{\LWRrdelimtwo }\) \(\def \rdelim #1#2{\def \LWRbigdelim {#1}\LWRrdelimone }\) \(\let \symnormal \mathit \) \(\let \symliteral \mathrm \) \(\let \symbb \mathbb \) \(\let \symbbit \mathbb \) \(\let \symcal \mathcal \) \(\let \symscr \mathscr \) \(\let \symfrak \mathfrak \) \(\let \symsfup \mathsf \) \(\let \symsfit \mathit \) \(\let \symbfsf \mathbf \) \(\let \symbfup \mathbf \) \(\newcommand {\symbfit }[1]{\boldsymbol {#1}}\) \(\let \symbfcal \mathcal \) \(\let \symbfscr \mathscr \) \(\let \symbffrak \mathfrak \) \(\let \symbfsfup \mathbf \) \(\newcommand {\symbfsfit }[1]{\boldsymbol {#1}}\) \(\let \symup \mathrm \) \(\let \symbf \mathbf \) \(\let \symit \mathit \) \(\let \symsf \symsfit \) \(\let \symtt \mathtt \) \(\let \symbffrac \mathbffrac \) \(\newcommand {\mathfence }[1]{\mathord {#1}}\) \(\newcommand {\mathover }[1]{#1}\) \(\newcommand {\mathunder }[1]{#1}\) \(\newcommand {\mathaccent }[1]{#1}\) \(\newcommand {\mathbotaccent }[1]{#1}\) \(\newcommand {\mathalpha }[1]{\mathord {#1}}\) \(\def\Alpha{\unicode{x1D6E2}}\) \(\def\Beta{\unicode{x1D6E3}}\) \(\def\Gamma{\unicode{x1D6E4}}\) \(\def\Digamma{\mathit{\unicode{x03DC}}}\) \(\def\Delta{\unicode{x1D6E5}}\) \(\def\Epsilon{\unicode{x1D6E6}}\) \(\def\Zeta{\unicode{x1D6E7}}\) \(\def\Eta{\unicode{x1D6E8}}\) \(\def\Theta{\unicode{x1D6E9}}\) \(\def\Vartheta{\unicode{x1D6F3}}\) \(\def\Iota{\unicode{x1D6EA}}\) \(\def\Kappa{\unicode{x1D6EB}}\) \(\def\Lambda{\unicode{x1D6EC}}\) \(\def\Mu{\unicode{x1D6ED}}\) \(\def\Nu{\unicode{x1D6EE}}\) \(\def\Xi{\unicode{x1D6EF}}\) \(\def\Omicron{\unicode{x1D6F0}}\) \(\def\Pi{\unicode{x1D6F1}}\) \(\def\Rho{\unicode{x1D6F2}}\) \(\def\Sigma{\unicode{x1D6F4}}\) \(\def\Tau{\unicode{x1D6F5}}\) \(\def\Upsilon{\unicode{x1D6F6}}\) \(\def\Phi{\unicode{x1D6F7}}\) \(\def\Chi{\unicode{x1D6F8}}\) \(\def\Psi{\unicode{x1D6F9}}\) \(\def\Omega{\unicode{x1D6FA}}\) \(\def\alpha{\unicode{x1D6FC}}\) \(\def\beta{\unicode{x1D6FD}}\) \(\def\varbeta{\unicode{x03D0}}\) \(\def\gamma{\unicode{x1D6FE}}\) \(\def\digamma{\mathit{\unicode{x03DD}}}\) \(\def\delta{\unicode{x1D6FF}}\) \(\def\epsilon{\unicode{x1D716}}\) \(\def\varepsilon{\unicode{x1D700}}\) \(\def\zeta{\unicode{x1D701}}\) \(\def\eta{\unicode{x1D702}}\) \(\def\theta{\unicode{x1D703}}\) \(\def\vartheta{\unicode{x1D717}}\) \(\def\iota{\unicode{x1D704}}\) \(\def\kappa{\unicode{x1D705}}\) \(\def\varkappa{\unicode{x1D718}}\) \(\def\lambda{\unicode{x1D706}}\) \(\def\mu{\unicode{x1D707}}\) \(\def\nu{\unicode{x1D708}}\) \(\def\xi{\unicode{x1D709}}\) \(\def\omicron{\unicode{x1D70A}}\) \(\def\pi{\unicode{x1D70B}}\) \(\def\varpi{\unicode{x1D71B}}\) \(\def\rho{\unicode{x1D70C}}\) \(\def\varrho{\unicode{x1D71A}}\) \(\def\sigma{\unicode{x1D70E}}\) \(\def\varsigma{\unicode{x1D70D}}\) \(\def\tau{\unicode{x1D70F}}\) \(\def\upsilon{\unicode{x1D710}}\) \(\def\phi{\unicode{x1D719}}\) \(\def\varphi{\unicode{x1D711}}\) \(\def\chi{\unicode{x1D712}}\) \(\def\psi{\unicode{x1D713}}\) \(\def\omega{\unicode{x1D714}}\) \(\def\upAlpha{\unicode{x0391}}\) \(\def\upBeta{\unicode{x0392}}\) \(\def\upGamma{\unicode{x0393}}\) \(\def\upDigamma{\unicode{x03DC}}\) \(\def\upDelta{\unicode{x0394}}\) \(\def\upEpsilon{\unicode{x0395}}\) \(\def\upZeta{\unicode{x0396}}\) \(\def\upEta{\unicode{x0397}}\) \(\def\upTheta{\unicode{x0398}}\) \(\def\upVartheta{\unicode{x03F4}}\) \(\def\upIota{\unicode{x0399}}\) \(\def\upKappa{\unicode{x039A}}\) \(\def\upLambda{\unicode{x039B}}\) \(\def\upMu{\unicode{x039C}}\) \(\def\upNu{\unicode{x039D}}\) \(\def\upXi{\unicode{x039E}}\) \(\def\upOmicron{\unicode{x039F}}\) \(\def\upPi{\unicode{x03A0}}\) \(\def\upVarpi{\unicode{x03D6}}\) \(\def\upRho{\unicode{x03A1}}\) \(\def\upSigma{\unicode{x03A3}}\) \(\def\upTau{\unicode{x03A4}}\) \(\def\upUpsilon{\unicode{x03A5}}\) \(\def\upPhi{\unicode{x03A6}}\) \(\def\upChi{\unicode{x03A7}}\) \(\def\upPsi{\unicode{x03A8}}\) \(\def\upOmega{\unicode{x03A9}}\) \(\def\itAlpha{\unicode{x1D6E2}}\) \(\def\itBeta{\unicode{x1D6E3}}\) \(\def\itGamma{\unicode{x1D6E4}}\) \(\def\itDigamma{\mathit{\unicode{x03DC}}}\) \(\def\itDelta{\unicode{x1D6E5}}\) \(\def\itEpsilon{\unicode{x1D6E6}}\) \(\def\itZeta{\unicode{x1D6E7}}\) \(\def\itEta{\unicode{x1D6E8}}\) \(\def\itTheta{\unicode{x1D6E9}}\) \(\def\itVartheta{\unicode{x1D6F3}}\) \(\def\itIota{\unicode{x1D6EA}}\) \(\def\itKappa{\unicode{x1D6EB}}\) \(\def\itLambda{\unicode{x1D6EC}}\) \(\def\itMu{\unicode{x1D6ED}}\) \(\def\itNu{\unicode{x1D6EE}}\) \(\def\itXi{\unicode{x1D6EF}}\) \(\def\itOmicron{\unicode{x1D6F0}}\) \(\def\itPi{\unicode{x1D6F1}}\) \(\def\itRho{\unicode{x1D6F2}}\) \(\def\itSigma{\unicode{x1D6F4}}\) \(\def\itTau{\unicode{x1D6F5}}\) \(\def\itUpsilon{\unicode{x1D6F6}}\) \(\def\itPhi{\unicode{x1D6F7}}\) \(\def\itChi{\unicode{x1D6F8}}\) \(\def\itPsi{\unicode{x1D6F9}}\) \(\def\itOmega{\unicode{x1D6FA}}\) \(\def\upalpha{\unicode{x03B1}}\) \(\def\upbeta{\unicode{x03B2}}\) \(\def\upvarbeta{\unicode{x03D0}}\) \(\def\upgamma{\unicode{x03B3}}\) \(\def\updigamma{\unicode{x03DD}}\) \(\def\updelta{\unicode{x03B4}}\) \(\def\upepsilon{\unicode{x03F5}}\) \(\def\upvarepsilon{\unicode{x03B5}}\) \(\def\upzeta{\unicode{x03B6}}\) \(\def\upeta{\unicode{x03B7}}\) \(\def\uptheta{\unicode{x03B8}}\) \(\def\upvartheta{\unicode{x03D1}}\) \(\def\upiota{\unicode{x03B9}}\) \(\def\upkappa{\unicode{x03BA}}\) \(\def\upvarkappa{\unicode{x03F0}}\) \(\def\uplambda{\unicode{x03BB}}\) \(\def\upmu{\unicode{x03BC}}\) \(\def\upnu{\unicode{x03BD}}\) \(\def\upxi{\unicode{x03BE}}\) \(\def\upomicron{\unicode{x03BF}}\) \(\def\uppi{\unicode{x03C0}}\) \(\def\upvarpi{\unicode{x03D6}}\) \(\def\uprho{\unicode{x03C1}}\) \(\def\upvarrho{\unicode{x03F1}}\) \(\def\upsigma{\unicode{x03C3}}\) \(\def\upvarsigma{\unicode{x03C2}}\) \(\def\uptau{\unicode{x03C4}}\) \(\def\upupsilon{\unicode{x03C5}}\) \(\def\upphi{\unicode{x03D5}}\) \(\def\upvarphi{\unicode{x03C6}}\) \(\def\upchi{\unicode{x03C7}}\) \(\def\uppsi{\unicode{x03C8}}\) \(\def\upomega{\unicode{x03C9}}\) \(\def\italpha{\unicode{x1D6FC}}\) \(\def\itbeta{\unicode{x1D6FD}}\) \(\def\itvarbeta{\unicode{x03D0}}\) \(\def\itgamma{\unicode{x1D6FE}}\) \(\def\itdigamma{\mathit{\unicode{x03DD}}}\) \(\def\itdelta{\unicode{x1D6FF}}\) \(\def\itepsilon{\unicode{x1D716}}\) \(\def\itvarepsilon{\unicode{x1D700}}\) \(\def\itzeta{\unicode{x1D701}}\) \(\def\iteta{\unicode{x1D702}}\) \(\def\ittheta{\unicode{x1D703}}\) \(\def\itvartheta{\unicode{x1D717}}\) \(\def\itiota{\unicode{x1D704}}\) \(\def\itkappa{\unicode{x1D705}}\) \(\def\itvarkappa{\unicode{x1D718}}\) \(\def\itlambda{\unicode{x1D706}}\) \(\def\itmu{\unicode{x1D707}}\) \(\def\itnu{\unicode{x1D708}}\) \(\def\itxi{\unicode{x1D709}}\) \(\def\itomicron{\unicode{x1D70A}}\) \(\def\itpi{\unicode{x1D70B}}\) \(\def\itvarpi{\unicode{x1D71B}}\) \(\def\itrho{\unicode{x1D70C}}\) \(\def\itvarrho{\unicode{x1D71A}}\) \(\def\itsigma{\unicode{x1D70E}}\) \(\def\itvarsigma{\unicode{x1D70D}}\) \(\def\ittau{\unicode{x1D70F}}\) \(\def\itupsilon{\unicode{x1D710}}\) \(\def\itphi{\unicode{x1D719}}\) \(\def\itvarphi{\unicode{x1D711}}\) \(\def\itchi{\unicode{x1D712}}\) \(\def\itpsi{\unicode{x1D713}}\) \(\def\itomega{\unicode{x1D714}}\) \(\let \lparen (\) \(\let \rparen )\) \(\newcommand {\cuberoot }[1]{\,{}^3\!\!\sqrt {#1}}\,\) \(\newcommand {\fourthroot }[1]{\,{}^4\!\!\sqrt {#1}}\,\) \(\newcommand {\longdivision }[1]{\mathord {\unicode {x027CC}#1}}\) \(\newcommand {\mathcomma }{,}\) \(\newcommand {\mathcolon }{:}\) \(\newcommand {\mathsemicolon }{;}\) \(\newcommand {\overbracket }[1]{\mathinner {\overline {\ulcorner {#1}\urcorner }}}\) \(\newcommand {\underbracket }[1]{\mathinner {\underline {\llcorner {#1}\lrcorner }}}\) \(\newcommand {\overbar }[1]{\mathord {#1\unicode {x00305}}}\) \(\newcommand {\ovhook }[1]{\mathord {#1\unicode {x00309}}}\) \(\newcommand {\ocirc }[1]{\mathord {#1\unicode {x0030A}}}\) \(\newcommand {\candra }[1]{\mathord {#1\unicode {x00310}}}\) \(\newcommand {\oturnedcomma }[1]{\mathord {#1\unicode {x00312}}}\) \(\newcommand {\ocommatopright }[1]{\mathord {#1\unicode {x00315}}}\) \(\newcommand {\droang }[1]{\mathord {#1\unicode {x0031A}}}\) \(\newcommand {\leftharpoonaccent }[1]{\mathord {#1\unicode {x020D0}}}\) \(\newcommand {\rightharpoonaccent }[1]{\mathord {#1\unicode {x020D1}}}\) \(\newcommand {\vertoverlay }[1]{\mathord {#1\unicode {x020D2}}}\) \(\newcommand {\leftarrowaccent }[1]{\mathord {#1\unicode {x020D0}}}\) \(\newcommand {\annuity }[1]{\mathord {#1\unicode {x020E7}}}\) \(\newcommand {\widebridgeabove }[1]{\mathord {#1\unicode {x020E9}}}\) \(\newcommand {\asteraccent }[1]{\mathord {#1\unicode {x020F0}}}\) \(\newcommand {\threeunderdot }[1]{\mathord {#1\unicode {x020E8}}}\) \(\newcommand {\Bbbsum }{\mathop {\unicode {x2140}}\limits }\) \(\newcommand {\oiint }{\mathop {\unicode {x222F}}\limits }\) \(\newcommand {\oiiint }{\mathop {\unicode {x2230}}\limits }\) \(\newcommand {\intclockwise }{\mathop {\unicode {x2231}}\limits }\) \(\newcommand {\ointclockwise }{\mathop {\unicode {x2232}}\limits }\) \(\newcommand {\ointctrclockwise }{\mathop {\unicode {x2233}}\limits }\) \(\newcommand {\varointclockwise }{\mathop {\unicode {x2232}}\limits }\) \(\newcommand {\leftouterjoin }{\mathop {\unicode {x27D5}}\limits }\) \(\newcommand {\rightouterjoin }{\mathop {\unicode {x27D6}}\limits }\) \(\newcommand {\fullouterjoin }{\mathop {\unicode {x27D7}}\limits }\) \(\newcommand {\bigbot }{\mathop {\unicode {x27D8}}\limits }\) \(\newcommand {\bigtop }{\mathop {\unicode {x27D9}}\limits }\) \(\newcommand {\xsol }{\mathop {\unicode {x29F8}}\limits }\) \(\newcommand {\xbsol }{\mathop {\unicode {x29F9}}\limits }\) \(\newcommand {\bigcupdot }{\mathop {\unicode {x2A03}}\limits }\) \(\newcommand {\bigsqcap }{\mathop {\unicode {x2A05}}\limits }\) \(\newcommand {\conjquant }{\mathop {\unicode {x2A07}}\limits }\) \(\newcommand {\disjquant }{\mathop {\unicode {x2A08}}\limits }\) \(\newcommand {\bigtimes }{\mathop {\unicode {x2A09}}\limits }\) \(\newcommand {\modtwosum }{\mathop {\unicode {x2A0A}}\limits }\) \(\newcommand {\sumint }{\mathop {\unicode {x2A0B}}\limits }\) \(\newcommand {\intbar }{\mathop {\unicode {x2A0D}}\limits }\) \(\newcommand {\intBar }{\mathop {\unicode {x2A0E}}\limits }\) \(\newcommand {\fint }{\mathop {\unicode {x2A0F}}\limits }\) \(\newcommand {\cirfnint }{\mathop {\unicode {x2A10}}\limits }\) \(\newcommand {\awint }{\mathop {\unicode {x2A11}}\limits }\) \(\newcommand {\rppolint }{\mathop {\unicode {x2A12}}\limits }\) \(\newcommand {\scpolint }{\mathop {\unicode {x2A13}}\limits }\) \(\newcommand {\npolint }{\mathop {\unicode {x2A14}}\limits }\) \(\newcommand {\pointint }{\mathop {\unicode {x2A15}}\limits }\) \(\newcommand {\sqint }{\mathop {\unicode {x2A16}}\limits }\) \(\newcommand {\intlarhk }{\mathop {\unicode {x2A17}}\limits }\) \(\newcommand {\intx }{\mathop {\unicode {x2A18}}\limits }\) \(\newcommand {\intcap }{\mathop {\unicode {x2A19}}\limits }\) \(\newcommand {\intcup }{\mathop {\unicode {x2A1A}}\limits }\) \(\newcommand {\upint }{\mathop {\unicode {x2A1B}}\limits }\) \(\newcommand {\lowint }{\mathop {\unicode {x2A1C}}\limits }\) \(\newcommand {\bigtriangleleft }{\mathop {\unicode {x2A1E}}\limits }\) \(\newcommand {\zcmp }{\mathop {\unicode {x2A1F}}\limits }\) \(\newcommand {\zpipe }{\mathop {\unicode {x2A20}}\limits }\) \(\newcommand {\zproject }{\mathop {\unicode {x2A21}}\limits }\) \(\newcommand {\biginterleave }{\mathop {\unicode {x2AFC}}\limits }\) \(\newcommand {\bigtalloblong }{\mathop {\unicode {x2AFF}}\limits }\) \(\newcommand {\arabicmaj }{\mathop {\unicode {x1EEF0}}\limits }\) \(\newcommand {\arabichad }{\mathop {\unicode {x1EEF1}}\limits }\)

Chapter 10

Solution to Exercise 10.1

a)It’s easy to see that the algorithm performs exactly the same steps in both cases. For a single Match token, the inner for loop is executed once and copies \(l\) bytes before incrementing \(p\) by \(l\):

\begin{align*} \Id {output}[p+0] &= \Id {output}[p-\Id {offset}+0]\\ \Id {output}[p+1] &= \Id {output}[p-\Id {offset}+1]\\ &\dots \\ \Id {output}[p+l-1] &= \Id {output}[p-\Id {offset}+l-1]\\ p &= p + l \end{align*} For multiple Match tokens, the inner for loop is executed multiple times, each time copying a single byte and incrementing \(p\) by 1:

\begin{align*} \Id {output}[p+0] &= \Id {output}[p-\Id {offset}+0]\\ p &= p + 1\\ \Id {output}[p+0] &= \Id {output}[p-\Id {offset}+0]\\ p &= p + 1\\ &\dots \\ \Id {output}[p+0] &= \Id {output}[p-\Id {offset}+0]\\ p &= p + 1 \end{align*}

b)The token represents multiple repetition of the previous offset bytes. For instance, the Match token in the sequence

  • Byte(A), Byte(B), Match(offset=2, length=5)

produces \(2.5\) additional copies of “AB”, which results in the final string “ABABABA”.

Solution to Exercise 10.2

Listing C.92 shows direct translation of LZ77-Compress and LZ77-Decompress. During decompression, we use the instanceof operator to determine the type of each token.

Listing C.92ch10β€―/β€―SimpleLZ77

static List<SimpleToken> compress(byte[] input, int maxOffset,
        int minLength, int maxLength) {
    var tokens = new ArrayList<SimpleToken>();
    for (int k = 0; k < input.length; ) {
        int bestLength = 0, bestOffset = 0;
        for (int off = 1; off <= Math.min(k, maxOffset); off++) {
            int len = 0;
            while (len < Math.min(maxLength, input.length - k)
                    && input[k - off + len] == input[k + len]) {
                len++;
            }
            if (len > bestLength) {
                bestLength = len;
                bestOffset = off;
            }
        }
        if (bestLength >= minLength) {
            tokens.add(new SimpleToken.Match(bestOffset, bestLength));
            k += bestLength;
        } else {
            tokens.add(new SimpleToken.Byte(input[k]));
            k++;
        }
    }
    return tokens;
}

static int decompress(List<SimpleToken> tokens, byte[] output) {
    int k = 0;
    for (SimpleToken token : tokens) {
        if (token instanceof SimpleToken.Byte b) {
            output[k++] = b.value();
        } else if (token instanceof SimpleToken.Match m) {
            for (int i = 0; i < m.length(); i++)
                output[k + i] = output[k - m.offset() + i];
            k += m.length();
        }
    }
    return k;
}

Solution to Exercise 10.3

See Table C.2 for a table of integers encoded using the Elias gamma code. The advantages of the code are that small integers are encoded very efficiently and that it can handle numbers of arbitrary size. Its main disadvantage is that large integers are encoded using many bits.

Table C.2 Encoding of integers using the Elias gamma code
.
\(n\) \(n\) in binary \(\bitlen (n)-1\) codeword
\(1\) \(1_2\) \(0\) 1
\(2\) \(10_2\) \(1\) 01 0
\(3\) \(11_2\) \(1\) 01 1
\(4\) \(100_2\) \(2\) 001 00
\(5\) \(101_2\) \(2\) 001 01
\(6\) \(110_2\) \(2\) 001 10
\(7\) \(111_2\) \(2\) 001 11
\(8\) \(1000_2\) \(3\) 0001 000
\(\vdots \) \(\vdots \) \(\vdots \) \(\vdots \)
\(3410\) \(110101010010_2\) 11 000000000001 10101010010
\(\vdots \) \(\vdots \) \(\vdots \) \(\vdots \)

Solution to Exercise 10.4

Listing C.93 shows the outline of class LZHDecoder. The main constructor takes two arguments: the input data, which is a bit stream produced by LZHEncoder, and the output stream to which the uncompressed sequence of bytes will be written. As with other Lempel-Ziv decoders, we store a certain number of previously decoded bytes in a cyclic buffer dictionary. The outLength field holds the number of bytes that have been decoded so far. We start the decompression process in decompress() by reading the two parameters of the algorithm from the stream: maxOffset is the largest offset field that can occur and blockSize the number of tokens per block. We then initialize dictionary to a cyclic buffer of size maxOffset and read all blocks until we reach the end of the input.

Listing C.93ch10β€―/β€―LZHDecoder

public class LZHDecoder {
    private final BitInputStream input;
    private final OutputStream out;
    private CyclicBuffer dictionary;  // current dictionary region
    private int outLength = 0;  // number of bytes decoded so far

    public LZHDecoder(BitInputStream in, OutputStream out) {
        this.input = in;
        this.out = out;
    }

    public void decompress() throws IOException {
        int maxOffset = (int) input.readBits(32);
        int blockSize = (int) input.readBits(32);
        dictionary = new CyclicBuffer(maxOffset);
        while (decodeBlock(blockSize)) {
        }
    }

    // ...
}

For each block, we first recover the two Huffman codes for tags and offsets and then decode one tag after the other until the entire block has been recovered (Listing C.94). If the tag is \(256\), we have reached the end of the input. If it is less than \(256\), it represents a BYTE token that we write directly to the output; the write() method writes a single byte to the output stream and to dictionary. Every other tag represents a MATCH token, which we decode by recovering the offset and length fields and copying the requisite number of bytes from dictionary.

Listing C.94ch10β€―/β€―LZHDecoder

private boolean decodeBlock(int blockSize) throws IOException {
    var tagCode = PrefixCode.readCode(input);
    var offsetCode = PrefixCode.readCode(input);
    for (int k = 0; k < blockSize; k++) {
        int tag = tagCode.decodeSymbol(input);
        if (tag == 256) {
            return false;  // end of input
        } else if (tag < 256) {
            write((byte) tag);
        } else {
            final int minLength = 3;
            int length = decodeInteger(tag - 257) + minLength;
            int offset = decodeInteger(offsetCode.decodeSymbol(input));
            for (int i = 0; i < length; i++)
                write(dictionary.get(outLength - offset));
        }
    }
    return true;
}

private void write(byte b) throws IOException {
    out.write(b);
    dictionary.set(outLength++, b);
}

private int decodeInteger(int bitLength) throws IOException {
    if (bitLength <= 1)
        return bitLength;
    return (1 << (bitLength - 1))
            | (int) input.readBits(bitLength - 1);
}

The decodeInteger() method that is used to read the offset and length fields decodes a single variable-length integer. Given the integer’s bit length \(n\), the number is recovered by reading the least significant \(n-1\) bits from input and then adding the most significant bit.

Solution to Exercise 10.5

Since Huffman’s algorithm only cares about frequencies and not the objects associated with them, a Huffman tree of tokens is constructed in the same way as a Huffman tree of characters or bytes. One possible result is shown in Fig. C.19.

Figure C.19 Huffman tree for LZ77 tokens.

Solution to Exercise 10.6

a)Two sequences are sufficient:

  • LZ4(“Around the world, a”, offset=18, length=15)
    LZ4(0xA, offset=35, length=105)

The first sequence encodes a single line without the terminating newline character. The second sequence adds the newline and three copies of the first line, each of which consists of 35 bytes.

b)The first sequence is encoded using 10 bytes. The header contains two 4-bit numbers: The first is the length of literal part (0111) and the second the length of the match 6 reduced by the minimal match length 4 (0010). The next 7 bytes contain the literal part of the sequence, followed by 2 bytes for the offset of the match (0x0006, but in little-endian order).

  • .
    Position 0 1–7 8–9
    Bytes 01110010 YABBA␣D 0x06 0x00

The second sequence is similar, but since the match length 40 is too large for the header, an additional byte is used to encode the remainder, which is

\begin{equation*} 40-15-(\text {minimal match length}) = 21. \end{equation*}

The result is

  • .
    Position 0 1 2–3 4
    Bytes 00011111 O 0x01 0x00 21

c)The output consists of a single sequence that contains all \(n\) bytes of the input. In addition to the \(n\) bytes required to encode the literal part of this sequence, the main contributor to the size of the output is the encoding of \(n\) itself, which requires \(\bigl \lceil (n-15)/255\bigr \rceil \) bytes, or approximately \(n/255\) bytes. This corresponds to a \(100/255=0.39\,\%\) increase in file size.

d)The implementation shown in Listing C.95 includes additional error checking to ensure that the program doesn’t crash even if the input data isn’t well-formed. The ensure() method verifies that a certain condition is met and throws a DecodeException if it isn’t. The top-level decode() method reads the header of the following sequence and then decodes its literal and match parts. The match part is ignored if the end of the input is reached first.

Listing C.95ch10β€―/β€―LZ4Decoder

public static class DecodeException extends Exception {
}

private void ensure(boolean condition) throws DecodeException {
    if (!condition)
        throw new DecodeException();
}

public int decode() throws DecodeException {
    while (inPos < inLength) {
        int token = in[inPos++];
        decodeLiteral(token);
        if (inPos < inLength)
            decodeMatch(token);
    }
    return outPos;
}

To decode the literal part of the sequence, the decodeLiteral() method in Listing C.96 first reads the remainder of the literal’s llength field and then copies the requested number of bytes from in[] to out[]. The length field is decoded using decodeLength(). This method takes a single parameter startLength, which is either the mlength or the llength field stored in the sequence’s header. If startLength is 15, the method reads additional bytes and add them to the length until it encounters a byte whose value is less than 255. Since bytes are signed values in Java, the expression in[inPos++] & 0xff is used to convert each byte to an unsigned integer.

Listing C.96ch10β€―/β€―LZ4Decoder

private void decodeLiteral(int header) throws DecodeException {
    int literalLength = decodeLength((header >> 4) & 0xf);
    ensure(inPos + literalLength <= inLength
            && outPos + literalLength <= out.length);
    System.arraycopy(in, inPos, out, outPos, literalLength);
    inPos += literalLength;
    outPos += literalLength;
}

private int decodeLength(int startLength) throws DecodeException {
    if (startLength != 15)
        return startLength;
    int length = startLength;
    while (inPos < inLength) {
        int k = in[inPos++] & 0xff;
        length += k;
        if (k != 255)
            return length;
    }
    throw new DecodeException();  // incomplete length
}

The decodeMatch() method in Listing C.97 decodes the match part of a sequence. It first reads two bytes for the offset and then decodes the remainder of the match length using decodeLength(). Afterwards, it copies the matching bytes from a previous position in out to the current position; this can usually be done using System.arraycopy(). However, if the length is greater than the offset — that is, if the match extends beyond the current position — the bytes must be copied one by one because arraycopy()’s handling of overlapping regions is incompatible with LZ4.

Listing C.97ch10β€―/β€―LZ4Decoder

private void decodeMatch(int header) throws DecodeException {
    ensure(inPos + 2 <= inLength);
    int offset =
            (in[inPos] & 0xff) | ((in[inPos + 1] & 0xff) << 8);
    inPos += 2;
    if (offset == 0)    // empty match
        return;
    ensure(outPos - offset >= 0);
    int length = decodeLength(header & 0xf) + LZ4.MIN_MATCH;
    ensure(outPos + length < out.length);
    if (length > offset) {
        for (int i = 0; i < length; i++)
            out[outPos + i] = out[outPos - offset + i];
    } else {
        System.arraycopy(out, outPos - offset, out, outPos,
                length);
    }
    outPos += length;
}