modernc.org/knuth@v0.0.4/web/testdata/ctan.org/tex-archive/systems/knuth/dist/tex/glue.web (about) 1 % This program by D. E. Knuth is not copyrighted and can be used freely. 2 % It was written on 18 Dec 1981 and revised on 24 May 1991. 3 4 % Here is TeX material that gets inserted after \input webmac 5 \def\PASCAL{Pascal} 6 \font\eightrm=cmr8 7 8 \def\title{GLUE} 9 \def\topofcontents{\null 10 \titlefalse % include headline on the contents page 11 \def\rheader{\mainfont\hfil \contentspagenumber} 12 \vfill 13 \centerline{\titlefont Fixed-Point Glue Setting} 14 \vfill} 15 \def\botofcontents{\vfill 16 \centerline{\hsize 6in\baselineskip9pt 17 \vbox{\eightrm\baselineskip9pt\noindent 18 The preparation of this report 19 was supported in part by the National Science 20 Foundation under grants IST-7921977 and MCS-7723728; 21 by Office of Naval Research grant N00014-81-K-0330; 22 and by the IBM Corporation. `\TeX' is a 23 trademark of the American Mathematical Society.}}} 24 25 @* Introduction. 26 If \TeX\ is being implemented on a microcomputer that does 32-bit 27 addition and subtraction, but with multiplication and division restricted to 28 multipliers and divisors that are either powers of~2 or positive 29 integers less than~$2^{15}$, it can still do the computations associated 30 with the setting of glue in a suitable way. This program illustrates one 31 solution to the problem. 32 33 Another purpose of this program is to provide the first ``short'' example 34 of the use of \.{WEB}. 35 36 @ The program itself is written in standard \PASCAL. It begins with a 37 normal program header, most of which will be filled in with other parts of this 38 ``web'' as we are ready to introduce them. 39 @^program header@> 40 41 @p program GLUE(@!input,@!output); 42 type @<Types in the outer block@>@; 43 var @<Globals in the outer block@>@; 44 procedure initialize; {this procedure gets things started} 45 var @<Local variables for initialization@>@; 46 begin @<Set initial values@>; 47 end; 48 49 @ Here are two macros for common programming idioms. 50 51 @d incr(#) == #:=#+1 {increase a variable by unity} 52 @d decr(#) == #:=#-1 {decrease a variable by unity} 53 54 @* The problem and a solution. 55 We are concerned here with the ``setting of glue'' that occurs when a 56 \TeX\ box is being packaged. Let $x_1$, \dots,~$x_n$ be integers whose sum 57 $s=x_1+\cdots+x_n$ is positive, and let $t$ be another positive integer. 58 These $x_i$ represent scaled amounts of glue in units of sp (scaled 59 points), where one sp is $2^{-16}$ of a printer's point. The other 60 quantity $t$ represents the total by which the glue should stretch or 61 shrink. Following the conventions of \TeX82, we will assume that the 62 integers we deal with are less than $2^{31}$ in absolute value. 63 64 After the glue has been set, the actual amounts of incremental glue space 65 (in~sp) will be the integers $f(x_1)$, \dots,~$f(x_n)$, where $f$ is a 66 function that we wish to compute. We want $f(x)$ to be nearly proportional 67 to~$x$, and we also want the sum $f(x_1)+\cdots+f(x_n)$ to be nearly 68 equal to~$t$. If we were using floating-point arithmetic, we would simply 69 compute $f(x)\equiv(t/s)\cdot x$ and hope for the best; but the goal here 70 is to compute a suitable~$f$ using only the fixed-point arithmetic operations 71 of a typical ``16-bit microcomputer.'' 72 73 The solution adopted here is to determine integers $a$, $b$, $c$ such that 74 $$f(x)=\bigl\lfloor 2^{-b}c\lfloor 2^{-a}x\rfloor\bigr\rfloor$$ 75 if $x$ is nonnegative. Thus, we take $x$ and shift it right by $a$~bits, 76 then multiply by~$c$ (which is $2^{15}$ or less), and shift the product 77 right by $b$~bits. The quantities $a$, $b$, and~$c$ are to be chosen 78 so that this calculation doesn't cause overflow and so that $f(x_1)+\cdots 79 +f(x_n)$ is reasonably close to~$t$. 80 81 The following method is used to calculate $a$ and~$b$: 82 Suppose $$y=\max_{1\le i\le n}\vert x_i\vert\,.$$ 83 Let $d$ and $e$ be the smallest integers such that $t<2^ds$ and $y<2^e$. 84 Since $s$ and~$t$ are less than~$2^{31}$, we have $-30\le d\le31$ and 85 $1\le e\le31$. An error message is given if $d+e\ge31$; in such a case 86 some $x_m$ has $\vert x_m\vert\ge 2^{e-1}$ and we are trying to change 87 $\vert x_m\vert$ to $\vert(t/s)x_m\vert\ge2^{d+e-2}\ge2^{30}$~sp, which 88 \TeX\ does not permit. (Consider, for example, the ``worst case'' situation 89 $x_1=2^{30}+1$, $x_2=-2^{30}$, $t=2^{31}-1$; surely we need not bother 90 trying to accommodate such anomalous combinations of values.) On the other 91 hand if $d+e\le31$, we set $a=e-16$ and $b=31-d-e$. Notice that this choice 92 of~$a$ guarantees that $\lfloor2^{-a}\vert x_i\vert\rfloor<2^{16}$. We will 93 choose~$c$ to be at most~$2^{15}$, so that the product will be less 94 than~$2^{31}$. 95 96 The computation of $c$ is the tricky part. 97 @^hairy mathematics@> 98 The ``ideal'' value for $c$ would be $\rho=2^{a+b}t/s$, since $f(x)$ should 99 be approximately $(t/s)\cdot x$. Furthermore it is better to have $c$ slightly 100 larger than~$\rho$, instead of slightly smaller, since the other operations 101 in $f(x)$ have a downward bias. Therefore we shall compute $c=\lceil\rho\rceil$. 102 Since $2^{a+b}t/s<2^{a+b+d}=2^{15}$, we have $c\le2^{15}$ as desired. 103 104 We want to compute $c=\lceil\rho\rceil$ exactly in all cases. There is no 105 difficulty if $s<2^{15}$, since $c$ can be computed directly using the 106 formula $c=\bigl\lfloor(2^{a+b}t+s-1)/s\bigr\rfloor$; overflow will not 107 occur since $2^{a+b}t<2^{15}s<2^{30}$. 108 109 Otherwise let $s=s_12^l+s_2$, where $2^{14}\le s_1<2^{15}$ and $0\le s_2<2^l$. 110 We will essentially carry out a long division. Let $t$ be ``normalized'' 111 so that $2^{30}\le2^ht<2^{31}$ for some~$h$. Then we form the quotient and 112 remainder of $2^ht$ divided by~$s_1$, 113 $$ 2^ht=qs_1+r_0, \qquad 0\le r_0<s_1.$$ 114 It follows that $2^{h+l}t-qs=2^lr_0-qs_2=r$, say. If $0\ge r>-s$ we have 115 $q=\lceil2^{h+l}t/s\rceil$; otherwise we can replace $(q,r)$ by 116 $(q\pm1,r\mp s)$ repeatedly until $r$ is in the correct range. It is not 117 difficult to prove that $q$ needs to be increased at most once and decreased 118 at most seven times, since $2^lr_0-qs_2<2^ls_1\le s$ and since 119 $qs_2/s\le(2^ht/s_1)(s_2/2^ls_1)<2^{31}/s_1^2\le8$. Finally, we have 120 $a+b-h-l=-1$ or~$-2$, since $2^{28+l}\le2^{14}s=2^{a+b+d-1}s\le2^{a+b}t< 121 2^{a+b+d}s=2^{15}s<2^{30+l}$ and $2^{30}\le2^ht<2^{31}$. Hence 122 $c=\lceil2^{a+b-h-l}q\rceil=\lceil{1\over2}q\rceil$ or~$\lceil{1\over4}q\rceil$. 123 124 An error analysis shows that these values of $a$, $b$, and $c$ work 125 satisfactorily, except in unusual cases where we wouldn't expect them to. 126 @^error analysis@> 127 When $x\ge0$ we have 128 $$\eqalign{f(x)&=2^{-b}(2^{a+b}t/s+\theta_0)(2^{-a}x-\theta_1)-\theta_2\cr 129 &=(t/s)x+\theta_02^{-a-b}x-\theta_12^at/s-2^{-b}\theta_0\theta_1-\theta_2\cr}$$ 130 where $0\le\theta_0,\theta_1,\theta_2<1$. Now $0\le\theta_02^{-a-b}x 131 <2^{e-a-b}=2^{d+e-15}$ and $0\le\theta_12^at/s<2^{a+d}=2^{d+e-16}$, and 132 the other two terms are negligible. Therefore $f(x_1)+\cdots+f(x_n)$ differs 133 from~$t$ by at most about $2^{d+e-15}n$. Since $2^{d+e}$ is larger than 134 $(t/s)y$, which is the largest stretching or shrinking of glue after expansion, 135 the error is at worst about $n/32000$ times as much as this, so it is quite 136 reasonable. For example, even if fill glue is being used to stretch 137 20 inches, the error will still be less than $1\over1600$ of an inch. 138 139 @ To sum up: Given the positive integers $s$, $t$, and $y$ as above, we 140 set $$a\gets\lfloor\lg y\rfloor-15,\qquad b\gets29-\lfloor\lg y\rfloor- 141 \lfloor\lg t/s\rfloor,\qquad\hbox{and}\qquad c\gets\lceil2^{a+b}t/s\rceil.$$ 142 The implementation below shows how to do the job in \PASCAL\ without using 143 large numbers. 144 145 @ \TeX\ wants to have the glue-setting information in a 32-bit data type 146 called |glue_ratio|. The \PASCAL\ implementation of \TeX82 has |glue_ratio 147 =real|, but alternative definitions of |glue_ratio| are explicitly allowed. 148 149 For our purposes we shall let |glue_ratio| be a record that is packed with 150 three fields: The |a_part| will hold the positive integer |a+16|, the 151 |b_part| will hold the nonnegative integer~|b|, and the |c_part| will hold 152 the nonnegative integer~|c|. When the formulas above tell us to take 153 |b>30|, we might as well set |c:=0| instead, because |f(x)| will be 154 zero in all cases when |b>30|. Note that we have only about 25 bits of 155 information in all, so it should fit in 32 bits with ease. 156 157 @<Types...@>= 158 @!glue_ratio=packed record 159 @!a_part: 1..31; {the quantity |e=a+16| in our derivation} 160 @!b_part: 0..30; {the quantity |b| in our derivation} 161 @!c_part: 0..@'100000; {the quantity |c| in our derivation} 162 end; 163 @!scaled = integer; {this data type is used for quantities in sp units} 164 165 @ The real problem is to define the procedures that \TeX\ needs to 166 deal with such |glue_ratio| values: 167 (a)~Given scaled numbers |s|, |t|, and~|y| as above, to compute the 168 corresponding |glue_ratio|. 169 (b)~Given a nonnegative scaled number~|x| and a |glue_ratio|~|g|, to 170 compute the scaled number~|f(x)|. 171 (c)~Given a |glue_ratio|~|g|, to print out a decimal equivalent of 172 |g| for diagnostic purposes. 173 174 The procedures below can be incorporated into \TeX82 via a change file 175 without great difficulty. A few modifications will be needed, because 176 \TeX's |glue_ratio| values can be negative in unusual cases---when the 177 amount of stretchability or shrinkability is less than zero. Negative 178 values in the |c_part| will handle such problems, if proper care is 179 taken. The error message below should either become a warning message 180 or a call to \TeX's |print_err| routine; in the latter case, an 181 @^error message@> 182 appropriate help message should be given, stating that glue cannot 183 stretch to more than 18~feet long, but that it's OK to proceed with 184 fingers crossed. 185 186 @*Glue multiplication. 187 The easiest procedure of the three just mentioned is the one that is 188 needed most often, namely, the computation of~|f(x)|. 189 190 \PASCAL\ doesn't have built-in binary shift commands or built-in exponentiation, 191 although many computers do have this capability. Therefore our arithmetic 192 routines use an array called `|two_to_the|', containing powers of~two. 193 Divisions by powers of two are never done in the programs below when the 194 dividend is negative, so the operations can safely be replaced by right 195 shifts on machines for which this is most appropriate. (Contrary to popular 196 opinion, the operation `|x div 2|' is not the same as shifting |x| 197 right one binary place, on a machine with two's complement arithmetic, 198 when |x| is a negative odd integer. But division 199 {\it is\/} equivalent to shifting when |x| is nonnegative.) 200 201 @<Globals...@>= 202 @!two_to_the: array[0..30] of integer; {$|two_to_the|[k]=2^k$} 203 204 @ @<Local variables for init...@>= 205 @!k:1..30; {an index for initializing |two_to_the|} 206 207 @ @<Set init...@>= 208 two_to_the[0]:=1; 209 for k:=1 to 30 do two_to_the[k]:=two_to_the[k-1]+two_to_the[k-1]; 210 211 @ We will use the abbreviations |ga|, |gb|, and |gc| as convenient 212 alternatives to \PASCAL's \&{with} statement. The glue-multiplication 213 function |f|, which replaces several occurrences of the `|float|' macro 214 in \TeX82, is now easy to state: 215 216 @d ga==g.a_part 217 @d gb==g.b_part 218 @d gc==g.c_part 219 220 @p function glue_mult(@!x:scaled;@!g:glue_ratio):integer; 221 {returns |f(x)| as above, assuming that |x>=0|} 222 begin if ga>16 then x:=x div two_to_the[ga-16] {right shift by |a| places} 223 else x:=x*two_to_the[16-ga]; {left shift by |-a| places} 224 glue_mult:=(x*gc) div two_to_the[gb]; {right shift by |b| places} 225 end; {note that |b| may be as large as 30} 226 227 @*Glue setting. 228 The |glue_fix| procedure computes |a|, |b|, and |c| by the method 229 explained above. \TeX\ does not normally compute the quantity~|y|, but 230 it could be made to do so without great difficulty. 231 232 This procedure replaces several occurrences of the `|unfloat|' macro in 233 \TeX82. It would be written as a function that returns a |glue_ratio|, 234 if \PASCAL\ would allow functions to produce records as values. 235 236 @p procedure glue_fix(@!s,@!t,@!y:scaled; var@!g:glue_ratio); 237 var @!a,@!b,@!c:integer; {components of the desired ratio} 238 @!k,@!h:integer; {$30-\lfloor\lg s\rfloor$, $30-\lfloor\lg t\rfloor$} 239 @!s0:integer; {original (unnormalized) value of |s|} 240 @!q,@!r,@!s1:integer; {quotient, remainder, divisor} 241 @!w:integer; {$2^l$, where $l=16-k$} 242 begin @<Normalize |s|, |t|, and |y|, computing |a|, |k|, and |h|@>; 243 if t<s then b:=15-a-k+h@+else b:=14-a-k+h; 244 if (b<0) or (b>30) then 245 begin if b<0 then write_ln('! Excessive glue.'); {error message} 246 @^error message@> 247 b:=0; c:=0; {make |f(x)| identically zero} 248 end 249 else begin if k>=16 then {easy case, $s_0<2^{15}$} 250 c:=(t div two_to_the[h-a-b]+s0-1) div s0 {here |1<=h-a-b<=k-14<=16|} 251 else @<Compute |c| by long division@>; 252 end; 253 ga:=a+16; gb:=b; gc:=c; 254 end; 255 256 @ @<Normalize |s|, |t|, and |y|, computing |a|, |k|, and |h|@>= 257 begin a:=15; k:=0; h:=0; s0:=s; 258 while y<@'10000000000 do {|y| is known to be positive} 259 begin decr(a); y:=y+y; 260 end; 261 while s<@'10000000000 do {|s| is known to be positive} 262 begin incr(k); s:=s+s; 263 end; 264 while t<@'10000000000 do {|t| is known to be positive} 265 begin incr(h); t:=t+t; 266 end; 267 end {now $2^{30}\le t=2^ht_0<2^{31}$ and $2^{30}\le s=2^ks_0<2^{31}$, 268 hence $d=k-h$ if $t/s<1$} 269 270 @ @<Compute |c| by long division@>= 271 begin w:=two_to_the[16-k]; 272 s1:=s0 div w; 273 q:=t div s1; 274 r:=((t mod s1)*w)-((s0 mod w)*q); 275 if r>0 then 276 begin incr(q); r:=r-s0; 277 end 278 else while r<=-s0 do 279 begin decr(q); r:=r+s0; 280 end; 281 if a+b+k-h=15 then c:=(q+1) div 2 @+else c:=(q+3) div 4; 282 end 283 284 @*Glue-set printing. 285 The last of the three procedures we need is |print_gr|, which displays a 286 |glue_ratio| in symbolic decimal form. Before constructing such a procedure, 287 we shall consider some simpler routines, copying them from an early 288 draft of the program \TeX82. 289 290 @d unity==@'200000 {$2^{16}$, represents 1.0000} 291 292 @<Glob...@>= 293 @!dig:array[0..15] of 0..9; {for storing digits} 294 295 @ An array of digits is printed out by |print_digs|. 296 297 @p procedure print_digs(@!k:integer); {prints |dig[k-1]| \dots |dig[0]|} 298 begin while k>0 do 299 begin decr(k); write(chr(ord('0')+dig[k])); 300 end; 301 end; 302 303 @ A nonnegative integer is printed out by |print_int|. 304 305 @p procedure print_int(@!n:integer); {prints an integer in decimal form} 306 var @!k:0..12; {index to current digit; we assume that $0\le n<10^{12}$} 307 begin k:=0; 308 repeat dig[k]:=n mod 10; n:=n div 10; incr(k); 309 until n=0; 310 print_digs(k); 311 end; 312 313 @ And here is a procedure to print a nonnegative |scaled| number. 314 315 @p procedure print_scaled(s:scaled); 316 {prints a scaled real, truncated to four digits} 317 var k:0..3; {index to current digit of the fraction part} 318 begin print_int(s div unity); {print the integer part} 319 s:=((s mod unity)*10000) div unity; 320 for k:=0 to 3 do 321 begin dig[k]:=s mod 10; s:=s div 10; 322 end; 323 write('.'); print_digs(4); 324 end; 325 326 @ Now we're ready to print a |glue_ratio|. Since the effective multiplier 327 is $2^{-a-b}c$, we will display the scaled integer $2^{16-a-b}c$, taking 328 care to print something special if this quantity is terribly large. 329 330 @p procedure print_gr(@!g:glue_ratio); {prints a glue multiplier} 331 var @!j:-29..31; {the amount to shift |c|} 332 begin j:=32-ga-gb; 333 while j>15 do 334 begin write('2x'); decr(j); {indicate multiples of 2 for BIG cases} 335 end; 336 if j<0 then print_scaled(gc div two_to_the[-j]) {shift right} 337 else print_scaled(gc*two_to_the[j]); {shift left} 338 end; 339 340 @* The driver program. 341 In order to test these routines, we will assume that the |input| file 342 contains a sequence of test cases, where each test case consists of the 343 integer numbers $t$, $x_1$, \dots,~$x_n$, 0. The final test case should 344 be followed by an additional zero. 345 346 @<Glob...@>= 347 @!x:array[1..1000] of scaled; {the $x_i$} 348 @!t:scaled; {the desired total} 349 @!m:integer; {the test case number} 350 351 @ Each case will be processed by the following routine, which assumes 352 that |t| has already been read. 353 354 @p procedure test; {processes the next data set, given |t| and~|m|} 355 var @!n: 0..1000; {the number of items} 356 k:0..1000; {runs through the items} 357 y:scaled; {$\max_{1\le i\le n}\vert x_i\vert$} 358 @!g:glue_ratio; {the computed glue multiplier} 359 @!s:scaled; {the sum $x_1+\cdots+x_n$} 360 @!ts:scaled; {the sum $f(x_1)+\cdots+f(x_n)$} 361 begin write_ln('Test data set number ',m:1,':'); 362 @<Read $x_1,\ldots,x_n$@>; 363 @<Compute |s| and |y|@>; 364 if s<=0 then write_ln('Invalid data (nonpositive sum); this set rejected.') 365 else begin @<Compute |g| and print it@>; 366 @<Print the values of $x_i$, $f(x_i)$, and the totals@>; 367 end; 368 end; 369 370 @ @<Read $x_1,\ldots,x_n$@>= 371 begin n:=0; 372 repeat incr(n); read(x[n]); 373 until x[n]=0; 374 decr(n); 375 end 376 377 @ @<Compute |s| and |y|@>= 378 begin s:=0; y:=0; 379 for k:=1 to n do 380 begin s:=s+x[k]; 381 if y<abs(x[k]) then y:=abs(x[k]); 382 end; 383 end 384 385 @ @<Compute |g| and print it@>= 386 begin glue_fix(s,t,y,g); {set |g|, perhaps print an error message} 387 write(' Glue ratio is '); print_gr(g); 388 write_ln(' (',ga-16:1,',',gb:1,',',gc:1,')'); 389 end 390 391 @ @<Print the values of $x_i$, $f(x_i)$, and the totals@>= 392 begin ts:=0; 393 for k:=1 to n do 394 begin write(x[k]:20); 395 if x[k]>=0 then y:=glue_mult(x[k],g) 396 else y:=-glue_mult(-x[k],g); 397 write_ln(y:15); 398 ts:=ts+y; 399 end; 400 write_ln(' Totals',s:13,ts:15,' (versus ',t:1,')'); 401 end 402 403 @ Here is the main program. 404 @^main program@> 405 406 @p begin initialize; 407 m:=1; 408 read(t); 409 while t>0 do 410 begin test; 411 incr(m); read(t); 412 end; 413 end. 414 415 @*Index. Here are the section numbers where various identifiers are used in the 416 program, and where various topics are discussed. 417 418 419 420 421