1/* 2 See license.txt in the root of this project. 3*/ 4 5# include "luametatex.h" 6 7/*tex 8 9 The principal computations performed by \TEX\ are done entirely in terms of integers less than 10 $2^{31}$ in magnitude; and divisions are done only when both dividend and divisor are 11 nonnegative. Thus, the arithmetic specified in this program can be carried out in exactly the 12 same way on a wide variety of computers, including some small ones. Why? Because the arithmetic 13 calculations need to be spelled out precisely in order to guarantee that \TEX\ will produce 14 identical output on different machines. 15 16 If some quantities were rounded differently in different implementations, we would find that 17 line breaks and even page breaks might occur in different places. Hence the arithmetic of \TEX\ 18 has been designed with care, and systems that claim to be implementations of \TEX82 should 19 follow precisely the \TEX82\ calculations as they appear in the present program. 20 21 Actually there are three places where \TEX\ uses |div| with a possibly negative numerator. 22 These are harmless; see |div| in the index. Also if the user sets the |\time| or the |\year| to 23 a negative value, some diagnostic information will involve negative|-|numerator division. The 24 same remarks apply for |mod| as well as for |div|. 25 26 The |half| routine, defined in the header file, calculates half of an integer, using an 27 unambiguous convention with respect to signed odd numbers. 28 29 The |round_decimals| function, defined in the header file, is used to create a scaled integer 30 from a given decimal fraction $(.d_0d_1 \ldots d_{k-1})$, where |0 <= k <= 17|. The digit $d_i$ 31 is given in |dig[i]|, and the calculation produces a correctly rounded result. 32 33 Keep in mind that in spite of these precautions results can be different over time. For 34 instance, fonts and hyphenation patterns do evolve over, and actually did in the many decades 35 that \TEX\ has been around. Also, delegating work to \LUA, which uses doubles, can have 36 consequences. 37 38*/ 39 40/*tex 41 42 Physical sizes that a \TEX\ user specifies for portions of documents are represented internally 43 as scaled points. Thus, if we define an |sp| (scaled point) as a unit equal to $2^{-16}$ 44 printer's points, every dimension inside of \TEX\ is an integer number of sp. There are exactly 45 4,736,286.72 sp per inch. Users are not allowed to specify dimensions larger than $2^{30} - 1$ 46 sp, which is a distance of about 18.892 feet (5.7583 meters); two such quantities can be added 47 without overflow on a 32-bit computer. 48 49 The present implementation of \TEX\ does not check for overflow when dimensions are added or 50 subtracted. This could be done by inserting a few dozen tests of the form |if x >= 010000000000| 51 then |report_overflow|, but the chance of overflow is so remote that such tests do not seem 52 worthwhile. 53 54 \TEX\ needs to do only a few arithmetic operations on scaled quantities, other than addition and 55 subtraction, and the following subroutines do most of the work. A single computation might use 56 several subroutine calls, and it is desirable to avoid producing multiple error messages in case 57 of arithmetic overflow; so the routines set the global variable |arith_error| to |true| instead 58 of reporting errors directly to the user. Another global variable, |tex_remainder|, holds the 59 remainder after a division. 60 61 The first arithmetical subroutine we need computes $nx+y$, where |x| and~|y| are |scaled| and 62 |n| is an integer. We will also use it to multiply integers. 63 64*/ 65 66inline static scaled tex_aux_m_and_a(int n, scaled x, scaled y, scaled max_answer) 67{ 68 if (n == 0) { 69 return y; 70 } else { 71 if (n < 0) { 72 x = -x; 73 n = -n; 74 } 75 if (((x <= (max_answer - y) / n) && (-x <= (max_answer + y) / n))) { 76 return n * x + y; 77 } else { 78 lmt_scanner_state.arithmic_error = 1; 79 return 0; 80 } 81 } 82} 83 84scaled tex_multiply_and_add (int n, scaled x, scaled y, scaled max_answer) { return tex_aux_m_and_a(n, x, y, max_answer); } 85scaled tex_nx_plus_y (int n, scaled x, scaled y) { return tex_aux_m_and_a(n, x, y, 0x3FFFFFFF); } // 07777777777 86scaled tex_multiply_integers (int n, scaled x) { return tex_aux_m_and_a(n, x, 0, 0x7FFFFFFF); } // 017777777777 87 88/*tex We also need to divide scaled dimensions by integers. */ 89 90/* 91scaled tex_x_over_n_r(scaled x, int n, int *remainder) 92{ 93 if (n == 0) { 94 lmt_scanner_state.arithmic_error = 1; 95 if (remainder) { 96 *remainder = x; 97 } 98 return 0; 99 } else { 100 int negative = 0; 101 if (n < 0) { 102 x = -x; 103 n = -n; 104 negative = 1; 105 } 106 if (x >= 0) { 107 int r = x % n; 108 if (remainder) { 109 if (negative) { 110 r = -r; 111 } 112 *remainder = r; 113 } 114 return (x / n); 115 } else { 116 int r = -((-x) % n); 117 if (remainder) { 118 if (negative) { 119 r = -r; 120 } 121 *remainder = r; 122 } 123 return -((-x) / n); 124 } 125 } 126} 127*/ 128 129scaled tex_x_over_n_r(scaled x, int n, int *remainder) 130{ 131 /*tex Should |tex_remainder| be negated? */ 132 if (n == 0) { 133 lmt_scanner_state.arithmic_error = 1; 134 *remainder = x; 135 return 0; 136 } else { 137 *remainder = x % n; 138 return x/n; 139 } 140} 141 142/* 143scaled tex_x_over_n(scaled x, int n) 144{ 145 if (n == 0) { 146 lmt_scanner_state.arithmic_error = 1; 147 return 0; 148 } else { 149 if (n < 0) { 150 x = -x; 151 n = -n; 152 } 153 if (x >= 0) { 154 return (x / n); 155 } else { 156 return -((-x) / n); 157 } 158 } 159} 160*/ 161 162scaled tex_x_over_n(scaled x, int n) 163{ 164 if (n == 0) { 165 lmt_scanner_state.arithmic_error = 1; 166 return 0; 167 } else { 168 return x/n; 169 } 170} 171 172/*tex 173 174 Then comes the multiplication of a scaled number by a fraction |n/d|, where |n| and |d| are 175 nonnegative integers |<= 2^16| and |d| is positive. It would be too dangerous to multiply by~|n| 176 and then divide by~|d|, in separate operations, since overflow might well occur; and it would 177 be too inaccurate to divide by |d| and then multiply by |n|. Hence this subroutine simulates 178 1.5-precision arithmetic. 179 180*/ 181 182/* 183scaled tex_xn_over_d_r(scaled x, int n, int d, int *remainder) 184{ 185 if (x == 0) { 186 if (remainder) { 187 *remainder = 0; 188 } 189 return 0; 190 } else { 191 int positive = 1; 192 unsigned int t, u, v, xx, dd; 193 if (x < 0) { 194 x = -x; 195 positive = 0; 196 } 197 xx = (unsigned int) x; 198 dd = (unsigned int) d; 199 t = ((xx % 0x8000) * (unsigned int) n); 200 u = ((xx / 0x8000) * (unsigned int) n + (t / 0x8000)); 201 v = (u % dd) * 0x8000 + (t % 0x8000); 202 if (u / dd >= 0x8000) { 203 lmt_scanner_state.arithmic_error = 1; 204 } else { 205 u = 0x8000 * (u / dd) + (v / dd); 206 } 207 if (positive) { 208 if (remainder) { 209 *remainder = (int) (v % dd); 210 } 211 return (scaled) u; 212 } else { 213 if (remainder) { 214 *remainder = - (int) (v % dd); 215 } 216 return - (scaled) u; 217 } 218 } 219} 220*/ 221 222scaled tex_xn_over_d_r(scaled x, int n, int d, int *remainder) 223{ 224 if (x == 0) { 225 *remainder = 0; 226 return 0; 227 } else { 228 long long v = (long long) x * (long long) n; 229 *remainder = (scaled) (v % d); 230 return (scaled) (v / d); 231 } 232} 233 234/* 235scaled tex_xn_over_d(scaled x, int n, int d) 236{ 237 if (x == 0) { 238 return 0; 239 } else { 240 int positive = 1; 241 unsigned int t, u, v, xx, dd; 242 if (x < 0) { 243 x = -x; 244 positive = 0; 245 } 246 xx = (unsigned int) x; 247 dd = (unsigned int) d; 248 t = ((xx % 0x8000) * (unsigned int) n); 249 u = ((xx / 0x8000) * (unsigned int) n + (t / 0x8000)); 250 v = (u % dd) * 0x8000 + (t % 0x8000); 251 if (u / dd >= 0x8000) { 252 lmt_scanner_state.arithmic_error = 1; 253 } else { 254 u = 0x8000 * (u / dd) + (v / dd); 255 } 256 if (positive) { 257 return (scaled) u; 258 } else { 259 return - (scaled) u; 260 } 261 } 262} 263*/ 264 265scaled tex_xn_over_d(scaled x, int n, int d) 266{ 267 if (x == 0) { 268 return 0; 269 } else { 270 long long v = (long long) x * (long long) n; 271 return (scaled) (v / d); 272 } 273} 274 275/*tex 276 277 When \TEX\ packages a list into a box, it needs to calculate the proportionality ratio by which 278 the glue inside the box should stretch or shrink. This calculation does not affect \TEX's 279 decision making, so the precise details of rounding, etc., in the glue calculation are not of 280 critical importance for the consistency of results on different computers. 281 282 We shall use the type |glue_ratio| for such proportionality ratios. A glue ratio should take the 283 same amount of memory as an |integer| (usually 32 bits) if it is to blend smoothly with \TEX's 284 other data structures. Thus |glue_ratio| should be equivalent to |short_real| in some 285 implementations of \PASCAL. Alternatively, it is possible to deal with glue ratios using nothing 286 but fixed-point arithmetic; see {\em TUGboat \bf3},1 (March 1982), 10--27. (But the routines 287 cited there must be modified to allow negative glue ratios.) 288 289*/ 290 291/* 292scaled tex_round_xn_over_d(scaled x, int n, unsigned int d) 293{ 294 if (x == 0) { 295 return 0; 296 } else if (n == d) { 297 return x; 298 } else { 299 int positive = 1; 300 unsigned t, u, v; 301 if (x < 0) { 302 positive = ! positive; 303 x = -x; 304 } 305 if (n < 0) { 306 positive = ! positive; 307 n = -n; 308 } 309 t = (unsigned) ((x % 0x8000) * n); 310 u = (unsigned) (((unsigned) (x) / 0x8000) * (unsigned) n + (t / 0x8000)); 311 v = (u % d) * 0x8000 + (t % 0x8000); 312 if (u / d >= 0x8000) { 313 lmt_scanner_state.arithmic_error = 1; 314 } else { 315 u = 0x8000 * (u / d) + (v / d); 316 } 317 v = v % d; 318 if (2 * v >= d) { 319 u++; 320 } 321 return positive ? (scaled) u : - (scaled) u; 322 } 323} 324*/ 325 326/* 327scaled tex_round_xn_over_d(scaled x, int n, unsigned int d) 328{ 329 if (x == 0|| n == d) { 330 return x; 331 } else { 332 double v = (1.0 / d) * n * x; 333 return (v < 0.0) ? (int) (v - 0.5) : (int) (v + 0.5); 334 } 335} 336*/ 337 338scaled tex_round_xn_over_d(scaled x, int n, unsigned int d) 339{ 340 if (x == 0 || (unsigned int) n == d) { 341 return x; 342 } else { 343 return scaledround((1.0 / d) * n * x); 344 } 345} 346 347/*tex 348 349 The return value is a decimal number with the point |dd| places from the back, |scaled_out| is 350 the number of scaled points corresponding to that. 351 352*/ 353 354/* not used: 355 356scaled tex_divide_scaled(scaled s, scaled m, int dd) 357{ 358 if (s == 0) { 359 return 0; 360 } else { 361 scaled q, r; 362 int sign = 1; 363 if (s < 0) { 364 sign = -sign; 365 s = -s; 366 } 367 if (m < 0) { 368 sign = -sign; 369 m = -m; 370 } 371 if (m == 0) { 372 normal_error("arithmetic", "divided by zero"); 373 } else if (m >= (max_integer / 10)) { 374 normal_error("arithmetic", "number too big"); 375 } 376 q = s / m; 377 r = s % m; 378 for (int i = 1; i <= (int) dd; i++) { 379 q = 10 * q + (10 * r) / m; 380 r = (10 * r) % m; 381 } 382 if (2 * r >= m) { 383 q++; // rounding 384 } 385 return sign * q; 386 } 387} 388*/ 389 390/* 391scaled divide_scaled_n(double sd, double md, double n) 392{ 393 scaled di = 0; 394 double dd = sd / md * n; 395 if (dd > 0.0) { 396 di = ifloor( dd + 0.5); 397 } else if (dd < 0.0) { 398 di = -ifloor((-dd) + 0.5); 399 } 400 return di; 401} 402*/ 403 404scaled tex_divide_scaled_n(double sd, double md, double n) 405{ 406 return scaledround(sd / md * n); 407} 408 409/* 410scaled tex_ext_xn_over_d(scaled x, scaled n, scaled d) 411{ 412 double r = (((double) x) * ((double) n)) / ((double) d); 413 if (r > DBL_EPSILON) { 414 r += 0.5; 415 } else { 416 r -= 0.5; 417 } 418 if (r >= (double) max_integer || r <= -(double) max_integer) { 419 tex_normal_warning("internal", "arithmetic number too big"); 420 } 421 return (scaled) r; 422} 423*/ 424 425scaled tex_ext_xn_over_d(scaled x, scaled n, scaled d) 426{ 427 double r = (((double) x) * ((double) n)) / ((double) d); 428 if (r >= (double) max_integer || r <= -(double) max_integer) { 429 /* can we really run into this? */ 430 tex_normal_warning("internal", "arithmetic number too big"); 431 } 432 return scaledround(r); 433} 434 |