<< . .

. 30
( : 45)



. . >>


17.2. The save instruction gives ˜?™ a fresh meaning, hence ˜?™ is a numeric variable
unconnected to any other variables. When the group ends and ˜?™ is restored to its
old meaning, the value of the group expression no longer has a name. (It™s called a
“capsule” if you try to show it.) Therefore the value of the group expression is a new,
nameless variable, as desired.

17.3. It™s a nameless pair whose xpart and ypart are equal; thus it is essentially
equivalent to ˜whatever — (1, 1)™.
248 Appendix A: Answers to All the Exercises


17.4. ˜v3 := begingroup save ?; picture ?; ? endgroup™ refreshes the picture special-purpose
...
variable v3 without changing other variables like v2 . This construction works also for
pairs, pens, strings, etc.
18.1. Yes; the direction at z.j will be either left or right .
18.2. beginlogochar("A",15);
x1=.5w;
x2=x4=leftstemloc;
x3=x5=w-x2;
top y1=h+o;
(Figure A18a will be inserted here;
y2=y3=barheight; too bad you can™t see it now.)
bot y4=bot y5=-o;
draw z4--z2--z3--z5;
super_half(2,1,3);
labels(1,2,3,4,5);
endchar;
Notice that all three calls of super_half in logo.mf are of the form ˜super half (2, j, 3)™.
But it would not be good style to eliminate parameters i and k, even though super_half
is a special-purpose subroutine; that would make it too too special.
18.3. If bracket = 0 or serif darkness = 0. (It™s probably not a good idea to make
serif darkness = 0, because this would lead to an extreme case of the ˜. . .™ triangle,
which might not be numerically stable in the presence of rounding errors.) Another
case, not really desirable, is left jut = right jut = 0.
18.4. That™s a strange question. The serif routine includes a penpos that de¬nes
z$l , z$ , and z$r relative to each other, and it de¬nes the other six points relative to
them. Outside the routine the user ought to specify just one x coordinate and one
y coordinate, in order to position all of the points. This can be done either before or
after serif is called, but has an easier job if it™s done beforehand.
18.5. Yes; see the previous exercise. (But in the program for "A" it™s necessary to
de¬ne y4l and y5r , so that theta 4 and theta 5 can be calculated.)
18.6. beginchar ("H", 13u#, ht #, 0);
x1 = x2 = x5 = 3u;
x3 = x4 = x6 = w ’ x1 ;
y1c = y3c = h; y2c = y4c = 0;
serif (1, thick , ’90, jut , jut );
serif (2, thick , 90, jut , jut ); (Figure A18b will be inserted here; too bad
you can™t see it now.)
serif (3, thick , ’90, jut , jut );
serif (4, thick , 90, jut , jut );
¬ll serif edge 2
- - reverse serif edge 1 - - cycle;
¬ll serif edge 4
- - reverse serif edge 3 - - cycle;
penpos5 (thin , 90); penpos6 (thin , 90);
y5 = y6 = .52h; penstroke z5e - - z6e ;
penlabels(1, 2, 3, 4, 5, 6); endchar.
Appendix A: Answers to All the Exercises 249


18.7. def top serif (su¬x $)(expr xx , theta , left jut , right jut ) = future pen
penpos$ (xx , 0); z$a ’ z$l = z$f ’ z$r = (bracket /abs sind theta ) — dir theta ;
y$c = y$d = y$ ; x$c = x$l ’ left jut ; x$d = x$r + right jut ;
z$b = z$l + whatever — dir theta = z$c + whatever — dir ’phi ;
z$e = z$r + whatever — dir theta = z$d + whatever — dir phi ;
labels($a, $b, $c, $d, $e, $f ) enddef ;
def top serif edge su¬x $ =
(z$a . . controls z$b . . z$c
- - (¬‚ex (z$c , .5[z$c , z$d ] ’ dishing , z$d )) shifted (0, +epsilon )
- - z$d . . controls z$e . . z$f ) enddef ;

18.8. Assuming that py = 0, the e¬ective right stroke weight would be px ·sin(θ5 ’φ)
if it were drawn with one stroke of broad pen , and xxx · sin θ5 is the additional weight
corresponding to separate strokes xxx apart. The right-hand side of the equation is
the same calculation in the case of vertical strokes (θ = 90—¦ ), when the stroke weight
of "I" is considered. (Since a similar calculation needs to be done for the letters K,
V, W, X, Y, and Z, it would be a good idea to embed these details in another macro.)

18.9. beginchar ("H", 13u#, ht #, 0);
x1 = x2 = x5 = 3u;
x3 = x4 = x6 = w ’ x1 ;
y1 = y3 = h; y2 = y4 = 0;
top serif (1, xx , ’90, jut , jut );
bot serif (2, xx , 90, jut , jut ); (Figure A18c will be inserted here; too bad

top serif (3, xx , ’90, jut , jut );
you can™t see it now.)


bot serif (4, xx , 90, jut , jut );
¬lldraw bot serif edge 2
- - reverse top serif edge 1 - - cycle;
¬ll bot serif edge 4
- - reverse top serif edge 3 - - cycle;
y5 = y6 = .52h; draw z5 - - z6 ;
penlabels(1, 2, 3, 4, 5, 6); endchar.

18.10. The replacement text contains ten tokens,

t e p
def = enddef ; def t =

where t , e , and p are placeholders for argument insertion. When this macro is
expanded with tracingmacros > 0, will type

foo(TEXT0)<expr>of<primary>->def(TEXT0)=(EXPR1)enddef;def.t=(EXPR2)

followed by the arguments (TEXT0), (EXPR1), and (EXPR2).

18.11. According to the rule just stated, the ¬rst comma is an abbreviation for ˜}} {{™.
Hence the ¬rst argument is a capsule containing the value of x; the second is the text
˜(,™ ; the third is the text ˜(}})™.

18.12. This snares future pens before they™re converted to pens, because pickup
wants to yscale by aspect ratio before ellipses change to polygons.
250 Appendix A: Answers to All the Exercises


18.13. The construction ˜hide ( statement list )™ expands into ˜gobble begingroup vacuous
endfor
statement list ; endgroup™, so the argument to gobble must be evaluated. The
show
begingroup causes to start executing statements. When that has been str
done, the ¬nal statement turns out to be empty , so the argument to gobble turns
out to be a vacuous expression (cf. Chapter 25). Finally, gobble ™s replacement text is
empty, so the hidden text has indeed disappeared. (The hide macro in Appendix B is
actually a bit more e¬cient, but a bit trickier.)

™s “stomach” would see ˜;™ if mag is known, but there would
19.1. Then
be no change if mag is unknown. An extra semicolon is harmless, since
statements can be empty . But it™s wise to get in the habit of putting ˜;™ before ¬,
because it saves a wee bit of time and because ˜;™ de¬nitely belongs before endfor.

19.2. No; that would be shocking.
1
19.3. Yes, if and only if n ’ is an even integer. (Because ambiguous values are
2
rounded up.)

19.4. No.

19.5. def even = not odd enddef .

19.6. The ¬rst is 5, because the pair is not considered to be a path. The second and
third are 0, because the pair is forced to become a path.

19.7. (a) The loop text is never executed. (b) It™s executed only once, for x = 1.
(c) It™s executed in¬nitely often, for x = 1, 1, 1, . . . . (d) Since ten times -
™s internal representation of .1 is slightly larger than 1, the answer is not what
you probably expect! The loop text is executed for x = 0, 0.1, 0.20001, 0.30002,
0.40002, 0.50003, 0.60004, 0.70004, 0.80005, and 0.90005 only. (If you want the values
(0, .1, .2, . . . , 1), say ˜ for xx = 0 upto 10: x := xx /10; text endfor™ instead.)

19.8. m = 1, n = 0.

19.9. def exitunless expr b = exitif not b enddef . (The simpler alternative
˜def exitunless = exitif not enddef ™ wouldn™t work, since ˜not™ applies only to the
following primary .)

19.10. numeric p[]; boolean n_is_prime; p[1]=2; k:=1;
for n=3 step 2 until infinity:
n_is_prime:=true;
for j=2 upto k: if n mod p[j]=0: n_is_prime:=false; fi
exitif n/p[j]<p[j]; endfor
if n_is_prime: p[incr k]:=n; exitif k=30; fi
endfor fi
show for k=1 upto 30: str p[k]&"="&decimal p[k], endfor "done" end.

19.11. ˜0; exitif true;™.

20.1. False; consider ˜a1(2)™.

20.2. A value very close to z2 .
Appendix A: Answers to All the Exercises 251


20.3. vardef lo_cube(expr x)=x*x*x<10 enddef; **
tolerance
show solve lo_cube(0,10), 10**1/3; end.
str
(EXPR
With the default tolerance of 0.1, this will show the respective values 2.14844 and (SUFFIX
(TEXT
2.1544. A more general routine could also be written, with ˜10™ as a parameter:
at sharp
at
vardef lo_cube[](expr x)=x*x*x<@ enddef;
sharp at
show solve lo_cube10(0,10); origin
skyline
if we ask for minimum tolerance (tolerance := epsilon ), the result is 2.15445; the true histogram
value is ≈ 2.15443469.

20.4. begingroup(p5dx,p5dy)endgroup.

20.5. Say ˜first#@™ after de¬ning ˜vardef first.a[]@#=@ enddef™. (There are
other solutions, e.g., using substrings of str #@, but this one is perhaps the most
instructive.)

20.6. The machine answers thus:
incr=macro:<suffix>->
begingroup(SUFFIX2):=(SUFFIX2)+1;(SUFFIX2)endgroup
z@#=macro:->begingroup(x(SUFFIX2),y(SUFFIX2))endgroup

Parameters to a macro are numbered sequentially, starting with zero, and classi¬ed as
either (EXPRn ), (SUFFIXn ), or (TEXTn ). In a vardef, (SUFFIX0) and (SUFFIX1) are
always reserved for the implicit parameters #@ and @; (SUFFIX2) will be @#, if it is used
in the parameter heading, otherwise it will be the ¬rst explicit parameter, if it happens
to be a su¬x parameter.

20.7. secondarydef t transum tt =
begingroup save T; transform T;
for z=origin,up,right:
z transformed t + z transformed tt = z transformed T; endfor
T endgroup enddef.

21.1. False; about twice as often (2/3 versus 1/3).

21.2. 1+floor uniformdeviate n.

21.3. A random point on the straight line segment from z1 to z2 . (The point z1
itself will occur with probability about 1/65536; but point z2 will never occur.)

21.4. A random “skyline” texture, 100 pt wide — 10 pt tall:
The density decreases uniformly as you go up in altitude.

21.5. A more-or-less bell-shaped histogram:

22.1. (a) I¬ n is an integer between 0 and 255. (b) I¬ s is a string of length 1.

22.2. Whoever says that there™s no such primitive operation has forgotten about
scantokens.
252 Appendix A: Answers to All the Exercises


22.3. vardef octal primary n = Hobby
save m,s; m:=abs round n; string s; s=decimal(m mod 8);
forever: m:=m div 8; exitif m=0;
s:=decimal(m mod 8) & s; endfor
s enddef;
˜str[m mod 8]™ could also be used instead of ˜decimal(m mod 8)™.
23.1. Point (x, y) is the upper left corner, (x + c1 ’ c0 , y) is the upper right corner,
(x, y ’ r1 + r0 ) is the lower left corner, and (x + c1 ’ c0 , y ’ r1 + r0 ) is the lower right
corner. (Pixels outside this rectangle will not be displayed.)
23.2. Rede¬ne openit so that it puts the top left at (’50, 280).
23.3. (This routine is due to John Hobby.)
newinternal n_windows; % the number of windows allocated so far
newinternal screen_bot; % the first untouched screen row
pair screen_corner; % the upper left corner of next window
def wipescreen = % do this to initialize or reinitialize
for i:=1 upto n_windows: display blankpicture inwindow i; endfor
n_windows := screen_bot := 0; screen_corner := origin enddef;
wipescreen;
vardef new_window@#(expr u,v) = save r,c,up_lft; pair up_lft;
if n_windows=15: errmessage "No more windows left"
else: window@# := incr n_windows;
up_lft = (min(xpart u,xpart v), max(ypart u, ypart v));
(r,c) = (u+v-2up_lft) rotated 90;
if ypart screen_corner + c > screen_cols:
screen_corner:=(screen_bot,0); fi
openwindow window@# from screen_corner
to screen_corner+(r,c) at up_lft;
screen_bot := max(screen_bot,xpart screen_corner + r);
screen_corner := screen_corner + (0,c) fi; enddef;

24.1. The entire path now has negative y coordinates except at point (0, 0), so
the outline of the ¬lled region is (0, ’1) - - (10, ’1) - - (10, 0) - - (0, 0) - - (0, 1) - - cycle.
(Notice that the digitized outline actually goes up to (0, 1) before coming straight down
again. This ¬lls no pixels, but correctly puts “cancelling” edges from (0, 0)
to (0, 1) and back to (0, 0) into its edge structure, because the point (0, .5) is on the
boundary and rounds to (0, 1).)
24.2. The horizontal tangents are already taken care of by the equations top y1 =
h + o and bot y4 = ’o, so nothing needs to be done there. We should, however, say
x2 = w ’ x3 = good.x (1.5u + s)
so that vertical tangents will occur in good places. Since w is an integer, and since the
logo pen has left-right symmetry, w ’ x3 will be good if and only if x3 is.
24.3. Let b be the pen breadth. Then .5w is a good x value if and only if lft .5w is
an integer; but lft .5w = .5w ’ .5b, and this is an integer if and only if w ’ b is even.
Appendix A: Answers to All the Exercises 253


24.4. There are no ambiguous points on the outlines of this stroke, except perhaps draw
¬‚oor
on the top and bottom edges; the latter can occur only if round py is odd. Hence
there is always left-right symmetry, but top-bottom symmetry might fail because of a
missing row at the bottom (e.g., when px = py = 3). In a case like the ˜ ™ we do have
both symmetries, because y1 and x4 are in good positions.
24.5. No matter where you place the octagon so that it isn™t touching any ambiguous
points, exactly seven ambiguous points are inside it; hence every one-point draw ¬lls
exactly seven pixels. (In fact, you always get one of the patterns , , , or .)
24.6. f = .5(x4 ’x3 ); the desired equation is ˜x1 ’x2 = round(x1 ’x2 +.5(x4 ’x3 ))™.
24.7. Let x3 = n + 1 + θ, where n is an integer and 0 ¤ θ < 1. By drawing lines of
2
slope 30—¦ from the pixel centers, we ¬nd that there are three cases for the rightmost
four columns:
Case A, ; Case B, ; Case C, .
√ √ √
Case A occurs for 0 ¤ θ < 2 3 ’ 3; Case B occurs for 2 3 ’ 3 ¤ θ < 3 ’ 1; Case C

occurs for 3 ’ 1 ¤ θ < 1. The tip in Case A looks a bit too sharp, and Case C looks
too blunt, so Case B seems best. This case occurs when x3 is near an integer, so it™s
OK to let x3 be an integer.
√ √
24.8. Let y1 = n + θ. If θ lies between 1 3 ’ 1 and 1 3 + 1 , the top row after
6√ √
2 2 2
digitization will contain two black pixels. If θ lies between 1 3 + 1 and 5 3 ’ 1 , we
6 2 6 2
get the desired shape. Otherwise we get ˜ ™.

24.9. (We choose θ = 1 3 in the previous exercise, since this is the midpoint of the
2
desirable interval.) The equations are changed to
x1 = x2 = w ’ x3 = round s;
y3 = .5 + ¬‚oor .5h;
z1 ’ z2 = (z3 ’ z2 ) rotated 60;
y1 := .5 sqrt 3 + round(y1 ’ .5 sqrt 3);
y2 := h ’ y1 ;
and then we ¬ll z1 - - z2 - - z3 - - cycle as before.
24.10. vardef vround primary v =
¬‚oor(v — aspect ratio + .5)/aspect ratio enddef ;
vardef good.y primary y =
vround (y + pen top ) ’ pen top enddef .
24.11. (m + 1/2, (n + 1/2)/aspect ratio ). These are the points that currenttransform
maps into pixel centers.
25.1. By looking at the syntax rules, we ¬nd, for example,
boolean expression true
numeric expression 0
pair expression (0,0)
path expression makepath pencircle
pen expression nullpen
254 Appendix A: Answers to All the Exercises


picture expression nullpicture delimiter
Missing token has been inserted
string expression ""
capsule
transform expression Impossible!
vacuous expression begingroup endgroup

Every transform expression includes either a variable or a capsule. Incidentally, there
are some amusing alternative 5-token solutions for pair expression :
postcontrol 0 of makepath nullpen
makepath pencircle intersectiontimes makepath nullpen

26.1. The responses are
> a=left delimiter that matches ::
> b=(outer) a
> c=a

because: a has been rede¬ned from internal quantity to delimiter; b is still an internal
quantity (named a), and it has been stamped outer; c denotes the same internal
quantity, but it hasn™t got outerness.

27.1. We want to delete

0 [ 1 + sqrt 43 ]

from the sequence of tokens that is about to read next, in order to get
rid of the right bracket, which we can see is going to be just as erroneous as the left
bracket was. However, there is another way to proceed (and indeed, this alternative
would be preferable to counting tokens, if the bracketed expression were longer): We
could simply delete 2 tokens, then ˜I(™. This would produce another error stop,
! Missing ˜)™ has been inserted.
<to be read again>
]
<*> show round[1 + sqrt43]
;
?h
I found no right delimiter to match a left one. So I™ve
put one in, behind the scenes; this may fix the problem.
?

after which it™s easy to delete the ˜]™ and continue successfully.

27.2. looked ahead, to see if the expression being evaluated was going
to be something like ˜round 0[1+sqrt43,x]™. But when it found no comma, it put
back several tokens so that they could be read again. (The subexpression 1+sqrt43
had already been evaluated, so a “capsule” for its value, 7.55743, was inserted among
the tokens to be reread.) The expression ended with ˜0™, and ˜round 0™ was shown.
Then found extra tokens following the show command; a semicolon should
have come next. To continue, the user should just plunge ahead recklessly once again,
letting delete those unwanted tokens.
Appendix A: Answers to All the Exercises 255


27.3. The little program counterclockwise
SHAKESPEARE
path p,q; p=flex((-32,481),(-42,455),(-62,430)); KNUTH
q=flex((-62,430),(-20,452),(42,448));
show p intersectiontimes q, p intersectionpoint q,
angle -direction 2 of p, angle direction 0 of q; end
gives the following results:
>> (1.88403,0.07692)
>> (-59.32149,432.59523)
>> 43.14589
>> 45.47263
(Actually, the paths would also cross if 452 were 451, but it™s such a close call that
doesn™t call the path strange; prefers to turn counterclockwise
—¦
when the amount of turn is close enough to 180 , even if it™s slightly more.)
27.4. If this exercise isn™t just a joke, the title of this appendix is a lie. (When
you™ve solved this exercise you might also try to ¬nd all the lies and/or jokes that are
the same in both this book and The TEXbook.)


<< . .

. 30
( : 45)



. . >>