home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / calc / part05 < prev    next >
Encoding:
Text File  |  1992-05-09  |  56.8 KB  |  2,761 lines

  1. Newsgroups: comp.sources.unix
  2. From: dbell@pdact.pd.necisa.oz.au (David I. Bell)
  3. Subject: v26i031: CALC - An arbitrary precision C-like calculator, Part05/21
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: dbell@pdact.pd.necisa.oz.au (David I. Bell)
  8. Posting-Number: Volume 26, Issue 31
  9. Archive-Name: calc/part05
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 5 (of 21)."
  18. # Contents:  comfunc.c commath.c file.c listfunc.c qmod.c
  19. # Wrapped by dbell@elm on Tue Feb 25 15:20:59 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'comfunc.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'comfunc.c'\"
  23. else
  24. echo shar: Extracting \"'comfunc.c'\" \(10332 characters\)
  25. sed "s/^X//" >'comfunc.c' <<'END_OF_FILE'
  26. X/*
  27. X * Copyright (c) 1992 David I. Bell
  28. X * Permission is granted to use, distribute, or modify this source,
  29. X * provided that this copyright notice remains intact.
  30. X *
  31. X * Extended precision complex arithmetic non-primitive routines
  32. X */
  33. X
  34. X#include "calc.h"
  35. X
  36. X
  37. X/*
  38. X * Round a complex number to the specified number of decimal places.
  39. X * This simply means to round each of the components of the number.
  40. X * Zero decimal places means round to the nearest complex integer.
  41. X */
  42. XCOMPLEX *
  43. Xcround(c, places)
  44. X    COMPLEX *c;
  45. X    long places;
  46. X{
  47. X    COMPLEX *res;        /* result */
  48. X
  49. X    res = comalloc();
  50. X    res->real = qround(c->real, places);
  51. X    res->imag = qround(c->imag, places);
  52. X    return res;
  53. X}
  54. X
  55. X
  56. X/*
  57. X * Round a complex number to the specified number of binary decimal places.
  58. X * This simply means to round each of the components of the number.
  59. X * Zero binary places means round to the nearest complex integer.
  60. X */
  61. XCOMPLEX *
  62. Xcbround(c, places)
  63. X    COMPLEX *c;
  64. X    long places;
  65. X{
  66. X    COMPLEX *res;        /* result */
  67. X
  68. X    res = comalloc();
  69. X    res->real = qbround(c->real, places);
  70. X    res->imag = qbround(c->imag, places);
  71. X    return res;
  72. X}
  73. X
  74. X
  75. X/*
  76. X * Compute the result of raising a complex number to an integer power.
  77. X */
  78. XCOMPLEX *
  79. Xcpowi(c, q)
  80. X    COMPLEX *c;        /* complex number to be raised */
  81. X    NUMBER *q;        /* power to raise it to */
  82. X{
  83. X    COMPLEX *tmp, *res;    /* temporary values */
  84. X    long power;        /* power to raise to */
  85. X    unsigned long bit;    /* current bit value */
  86. X    int sign;
  87. X
  88. X    if (qisfrac(q))
  89. X        error("Raising number to non-integral power");
  90. X    if (isbig(q->num))
  91. X        error("Raising number to very large power");
  92. X    power = (istiny(q->num) ? z1tol(q->num) : z2tol(q->num));
  93. X    if (ciszero(c) && (power == 0))
  94. X        error("Raising zero to zeroth power");
  95. X    sign = 1;
  96. X    if (qisneg(q))
  97. X        sign = -1;
  98. X    /*
  99. X     * Handle some low powers specially
  100. X     */
  101. X    if (power <= 4) {
  102. X        switch ((int) (power * sign)) {
  103. X            case 0:
  104. X                return clink(&_cone_);
  105. X            case 1:
  106. X                return clink(c);
  107. X            case -1:
  108. X                return cinv(c);
  109. X            case 2:
  110. X                return csquare(c);
  111. X            case -2:
  112. X                tmp = csquare(c);
  113. X                res = cinv(tmp);
  114. X                comfree(tmp);
  115. X                return res;
  116. X            case 3:
  117. X                tmp = csquare(c);
  118. X                res = cmul(c, tmp);
  119. X                comfree(tmp);
  120. X                return res;
  121. X            case 4:
  122. X                tmp = csquare(c);
  123. X                res = csquare(tmp);
  124. X                comfree(tmp);
  125. X                return res;
  126. X        }
  127. X    }
  128. X    /*
  129. X     * Compute the power by squaring and multiplying.
  130. X     * This uses the left to right method of power raising.
  131. X     */
  132. X    bit = TOPFULL;
  133. X    while ((bit & power) == 0)
  134. X        bit >>= 1L;
  135. X    bit >>= 1L;
  136. X    res = csquare(c);
  137. X    if (bit & power) {
  138. X        tmp = cmul(res, c);
  139. X        comfree(res);
  140. X        res = tmp;
  141. X    }
  142. X    bit >>= 1L;
  143. X    while (bit) {
  144. X        tmp = csquare(res);
  145. X        comfree(res);
  146. X        res = tmp;
  147. X        if (bit & power) {
  148. X            tmp = cmul(res, c);
  149. X            comfree(res);
  150. X            res = tmp;
  151. X        }
  152. X        bit >>= 1L;
  153. X    }
  154. X    if (sign < 0) {
  155. X        tmp = cinv(res);
  156. X        comfree(res);
  157. X        res = tmp;
  158. X    }
  159. X    return res;
  160. X}
  161. X
  162. X
  163. X/*
  164. X * Calculate the square root of a complex number, with each component
  165. X * within the specified error. This uses the formula:
  166. X *    sqrt(a+bi) = sqrt((a+sqrt(a^2+b^2))/2) + sqrt((-a+sqrt(a^2+b^2))/2)i.
  167. X */
  168. XCOMPLEX *
  169. Xcsqrt(c, epsilon)
  170. X    COMPLEX *c;
  171. X    NUMBER *epsilon;
  172. X{
  173. X    COMPLEX *r;
  174. X    NUMBER *hypot, *tmp1, *tmp2;
  175. X
  176. X    if (ciszero(c) || cisone(c))
  177. X        return clink(c);
  178. X    r = comalloc();
  179. X    if (cisreal(c)) {
  180. X        if (!qisneg(c->real)) {
  181. X            r->real = qsqrt(c->real, epsilon);
  182. X            return r;
  183. X        }
  184. X        tmp1 = qneg(c->real);
  185. X        r->imag = qsqrt(tmp1, epsilon);
  186. X        qfree(tmp1);
  187. X        return r;
  188. X    }
  189. X    hypot = qhypot(c->real, c->imag, epsilon);
  190. X    tmp1 = qadd(hypot, c->real);
  191. X    tmp2 = qscale(tmp1, -1L);
  192. X    qfree(tmp1);
  193. X    r->real = qsqrt(tmp2, epsilon);
  194. X    qfree(tmp2);
  195. X    tmp1 = qsub(hypot, c->real);
  196. X    qfree(hypot);
  197. X    tmp2 = qscale(tmp1, -1L);
  198. X    qfree(tmp1);
  199. X    tmp1 = qsqrt(tmp2, epsilon);
  200. X    qfree(tmp2);
  201. X    if (qisneg(c->imag)) {
  202. X        tmp2 = qneg(tmp1);
  203. X        qfree(tmp1);
  204. X        tmp1 = tmp2;
  205. X    }
  206. X    r->imag = tmp1;
  207. X    return r;
  208. X}
  209. X
  210. X
  211. X/*
  212. X * Take the Nth root of a complex number, where N is a positive integer.
  213. X * Each component of the result is within the specified error.
  214. X */
  215. XCOMPLEX *
  216. Xcroot(c, q, epsilon)
  217. X    COMPLEX *c;
  218. X    NUMBER *q, *epsilon;
  219. X{
  220. X    COMPLEX *r;
  221. X    NUMBER *a2pb2, *root, *tmp1, *tmp2, *epsilon2;
  222. X
  223. X    if (qisneg(q) || qiszero(q) || qisfrac(q))
  224. X        error("Taking bad root of complex number");
  225. X    if (cisone(c) || qisone(q))
  226. X        return clink(c);
  227. X    if (qistwo(q))
  228. X        return csqrt(c, epsilon);
  229. X    r = comalloc();
  230. X    if (cisreal(c) && !qisneg(c->real)) {
  231. X        r->real = qroot(c->real, q, epsilon);
  232. X        return r;
  233. X    }
  234. X    /*
  235. X     * Calculate the root using the formula:
  236. X     *    croot(a + bi, n) =
  237. X     *        cpolar(qroot(a^2 + b^2, 2 * n), qatan2(b, a) / n).
  238. X     */
  239. X    epsilon2 = qscale(epsilon, -8L);
  240. X    tmp1 = qsquare(c->real);
  241. X    tmp2 = qsquare(c->imag);
  242. X    a2pb2 = qadd(tmp1, tmp2);
  243. X    qfree(tmp1);
  244. X    qfree(tmp2);
  245. X    tmp1 = qscale(q, 1L);
  246. X    root = qroot(a2pb2, tmp1, epsilon2);
  247. X    qfree(a2pb2);
  248. X    qfree(tmp1);
  249. X    tmp1 = qatan2(c->imag, c->real, epsilon2);
  250. X    qfree(epsilon2);
  251. X    tmp2 = qdiv(tmp1, q);
  252. X    qfree(tmp1);
  253. X    r = cpolar(root, tmp2, epsilon);
  254. X    qfree(root);
  255. X    qfree(tmp2);
  256. X    return r;
  257. X}
  258. X
  259. X
  260. X/*
  261. X * Calculate the complex exponential function to the desired accuracy.
  262. X * We use the formula:
  263. X *    exp(a + bi) = exp(a) * (cos(b) + i * sin(b)).
  264. X */
  265. XCOMPLEX *
  266. Xcexp(c, epsilon)
  267. X    COMPLEX *c;
  268. X    NUMBER *epsilon;
  269. X{
  270. X    COMPLEX *r;
  271. X    NUMBER *tmp1, *tmp2, *epsilon2;
  272. X
  273. X    if (ciszero(c))
  274. X        return clink(&_cone_);
  275. X    r = comalloc();
  276. X    if (cisreal(c)) {
  277. X        r->real = qexp(c->real, epsilon);
  278. X        return r;
  279. X    }
  280. X    epsilon2 = qscale(epsilon, -2L);
  281. X    r->real = qcos(c->imag, epsilon2);
  282. X    r->imag = qlegtoleg(r->real, epsilon2, _sinisneg_);
  283. X    if (qiszero(c->real)) {
  284. X        qfree(epsilon2);
  285. X        return r;
  286. X    }
  287. X    tmp1 = qexp(c->real, epsilon2);
  288. X    qfree(epsilon2);
  289. X    tmp2 = qmul(r->real, tmp1);
  290. X    qfree(r->real);
  291. X    r->real = tmp2;
  292. X    tmp2 = qmul(r->imag, tmp1);
  293. X    qfree(r->imag);
  294. X    qfree(tmp1);
  295. X    r->imag = tmp2;
  296. X    return r;
  297. X}
  298. X
  299. X
  300. X/*
  301. X * Calculate the natural logarithm of a complex number within the specified
  302. X * error.  We use the formula:
  303. X *    ln(a + bi) = ln(a^2 + b^2) / 2 + i * atan2(b, a).
  304. X */
  305. XCOMPLEX *
  306. Xcln(c, epsilon)
  307. X    COMPLEX *c;
  308. X    NUMBER *epsilon;
  309. X{
  310. X    COMPLEX *r;
  311. X    NUMBER *a2b2, *tmp1, *tmp2;
  312. X
  313. X    if (ciszero(c))
  314. X        error("Logarithm of zero");
  315. X    if (cisone(c))
  316. X        return clink(&_czero_);
  317. X    r = comalloc();
  318. X    if (cisreal(c) && !qisneg(c->real)) {
  319. X        r->real = qln(c->real, epsilon);
  320. X        return r;
  321. X    }
  322. X    tmp1 = qsquare(c->real);
  323. X    tmp2 = qsquare(c->imag);
  324. X    a2b2 = qadd(tmp1, tmp2);
  325. X    qfree(tmp1);
  326. X    qfree(tmp2);
  327. X    tmp1 = qln(a2b2, epsilon);
  328. X    qfree(a2b2);
  329. X    r->real = qscale(tmp1, -1L);
  330. X    qfree(tmp1);
  331. X    r->imag = qatan2(c->imag, c->real, epsilon);
  332. X    return r;
  333. X}
  334. X
  335. X
  336. X/*
  337. X * Calculate the complex cosine within the specified accuracy.
  338. X * This uses the formula:
  339. X *    cos(a + bi) = cos(a) * cosh(b) - sin(a) * sinh(b) * i.
  340. X */
  341. XCOMPLEX *
  342. Xccos(c, epsilon)
  343. X    COMPLEX *c;
  344. X    NUMBER *epsilon;
  345. X{
  346. X    COMPLEX *r;
  347. X    NUMBER *cosval, *coshval, *tmp1, *tmp2, *tmp3, *epsilon2;
  348. X    int negimag;
  349. X
  350. X    if (ciszero(c))
  351. X        return clink(&_cone_);
  352. X    r = comalloc();
  353. X    if (cisreal(c)) {
  354. X        r->real = qcos(c->real, epsilon);
  355. X        return r;
  356. X    }
  357. X    if (qiszero(c->real)) {
  358. X        r->real = qcosh(c->imag, epsilon);
  359. X        return r;
  360. X    }
  361. X    epsilon2 = qscale(epsilon, -2L);
  362. X    coshval = qcosh(c->imag, epsilon2);
  363. X    cosval = qcos(c->real, epsilon2);
  364. X    negimag = !_sinisneg_;
  365. X    if (qisneg(c->imag))
  366. X        negimag = !negimag;
  367. X    r->real = qmul(cosval, coshval);
  368. X    /*
  369. X     * Calculate the imaginary part using the formula:
  370. X     *    sin(a) * sinh(b) = sqrt((1 - a^2) * (b^2 - 1)).
  371. X     */
  372. X    tmp1 = qsquare(cosval);
  373. X    qfree(cosval);
  374. X    tmp2 = qdec(tmp1);
  375. X    qfree(tmp1);
  376. X    tmp1 = qneg(tmp2);
  377. X    qfree(tmp2);
  378. X    tmp2 = qsquare(coshval);
  379. X    qfree(coshval);
  380. X    tmp3 = qdec(tmp2);
  381. X    qfree(tmp2);
  382. X    tmp2 = qmul(tmp1, tmp3);
  383. X    qfree(tmp1);
  384. X    qfree(tmp3);
  385. X    r->imag = qsqrt(tmp2, epsilon2);
  386. X    qfree(tmp2);
  387. X    qfree(epsilon2);
  388. X    if (negimag) {
  389. X        tmp1 = qneg(r->imag);
  390. X        qfree(r->imag);
  391. X        r->imag = tmp1;
  392. X    }
  393. X    return r;
  394. X}
  395. X
  396. X
  397. X/*
  398. X * Calculate the complex sine within the specified accuracy.
  399. X * This uses the formula:
  400. X *    sin(a + bi) = sin(a) * cosh(b) + cos(a) * sinh(b) * i.
  401. X */
  402. XCOMPLEX *
  403. Xcsin(c, epsilon)
  404. X    COMPLEX *c;
  405. X    NUMBER *epsilon;
  406. X{
  407. X    COMPLEX *r;
  408. X
  409. X    NUMBER *cosval, *coshval, *tmp1, *tmp2, *epsilon2;
  410. X
  411. X    if (ciszero(c))
  412. X        return clink(&_czero_);
  413. X    r = comalloc();
  414. X    if (cisreal(c)) {
  415. X        r->real = qsin(c->real, epsilon);
  416. X        return r;
  417. X    }
  418. X    if (qiszero(c->real)) {
  419. X        r->imag = qsinh(c->imag, epsilon);
  420. X        return r;
  421. X    }
  422. X    epsilon2 = qscale(epsilon, -2L);
  423. X    coshval = qcosh(c->imag, epsilon2);
  424. X    cosval = qcos(c->real, epsilon2);
  425. X    tmp1 = qlegtoleg(cosval, epsilon2, _sinisneg_);
  426. X    r->real = qmul(tmp1, coshval);
  427. X    qfree(tmp1);
  428. X    tmp1 = qsquare(coshval);
  429. X    qfree(coshval);
  430. X    tmp2 = qdec(tmp1);
  431. X    qfree(tmp1);
  432. X    tmp1 = qsqrt(tmp2, epsilon2);
  433. X    qfree(tmp2);
  434. X    r->imag = qmul(tmp1, cosval);
  435. X    qfree(tmp1);
  436. X    qfree(cosval);
  437. X    if (qisneg(c->imag)) {
  438. X        tmp1 = qneg(r->imag);
  439. X        qfree(r->imag);
  440. X        r->imag = tmp1;
  441. X    }
  442. X    return r;
  443. X}
  444. X
  445. X
  446. X/*
  447. X * Convert a number from polar coordinates to normal complex number form
  448. X * within the specified accuracy.  This produces the value:
  449. X *    q1 * cos(q2) + q1 * sin(q2) * i.
  450. X */
  451. XCOMPLEX *
  452. Xcpolar(q1, q2, epsilon)
  453. X    NUMBER *q1, *q2, *epsilon;
  454. X{
  455. X    COMPLEX *r;
  456. X    NUMBER *tmp, *epsilon2;
  457. X    long scale;
  458. X
  459. X    r = comalloc();
  460. X    if (qiszero(q1) || qiszero(q2)) {
  461. X        r->real = qlink(q1);
  462. X        return r;
  463. X    }
  464. X    epsilon2 = epsilon;
  465. X    if (!qisunit(q1)) {
  466. X        scale = zhighbit(q1->num) - zhighbit(q1->den) + 1;
  467. X        if (scale > 0)
  468. X            epsilon2 = qscale(epsilon, -scale);
  469. X    }
  470. X    r->real = qcos(q2, epsilon2);
  471. X    r->imag = qlegtoleg(r->real, epsilon2, _sinisneg_);
  472. X    if (epsilon2 != epsilon)
  473. X        qfree(epsilon2);
  474. X    if (qisone(q1))
  475. X        return r;
  476. X    tmp = qmul(r->real, q1);
  477. X    qfree(r->real);
  478. X    r->real = tmp;
  479. X    tmp = qmul(r->imag, q1);
  480. X    qfree(r->imag);
  481. X    r->imag = tmp;
  482. X    return r;
  483. X}
  484. X
  485. X
  486. X/*
  487. X * Raise one complex number to the power of another one to within the
  488. X * specified error.
  489. X */
  490. XCOMPLEX *
  491. Xcpower(c1, c2, epsilon)
  492. X    COMPLEX *c1, *c2;
  493. X    NUMBER *epsilon;
  494. X{
  495. X    COMPLEX *tmp1, *tmp2;
  496. X    NUMBER *epsilon2;
  497. X
  498. X    if (cisreal(c2) && qisint(c2->real))
  499. X        return cpowi(c1, c2->real);
  500. X    if (cisone(c1) || ciszero(c1))
  501. X        return clink(c1);
  502. X    epsilon2 = qscale(epsilon, -4L);
  503. X    tmp1 = cln(c1, epsilon2);
  504. X    tmp2 = cmul(tmp1, c2);
  505. X    comfree(tmp1);
  506. X    tmp1 = cexp(tmp2, epsilon);
  507. X    comfree(tmp2);
  508. X    qfree(epsilon2);
  509. X    return tmp1;
  510. X}
  511. X
  512. X
  513. X/*
  514. X * Print a complex number.
  515. X */
  516. Xvoid
  517. Xcomprint(c)
  518. X    COMPLEX *c;
  519. X{
  520. X    NUMBER qtmp;
  521. X
  522. X    if (_outmode_ == MODE_FRAC) {
  523. X        cprintfr(c);
  524. X        return;
  525. X    }
  526. X    if (!qiszero(c->real) || qiszero(c->imag))
  527. X        qprintnum(c->real, MODE_DEFAULT);
  528. X    qtmp = c->imag[0];
  529. X    if (qiszero(&qtmp))
  530. X        return;
  531. X    if (!qiszero(c->real) && !qisneg(&qtmp))
  532. X        math_chr('+');
  533. X    if (qisneg(&qtmp)) {
  534. X        math_chr('-');
  535. X        qtmp.num.sign = 0;
  536. X    }
  537. X    qprintnum(&qtmp, MODE_DEFAULT);
  538. X    math_chr('i');
  539. X}
  540. X
  541. X/* END CODE */
  542. END_OF_FILE
  543. if test 10332 -ne `wc -c <'comfunc.c'`; then
  544.     echo shar: \"'comfunc.c'\" unpacked with wrong size!
  545. fi
  546. # end of 'comfunc.c'
  547. fi
  548. if test -f 'commath.c' -a "${1}" != "-c" ; then 
  549.   echo shar: Will not clobber existing file \"'commath.c'\"
  550. else
  551. echo shar: Extracting \"'commath.c'\" \(9654 characters\)
  552. sed "s/^X//" >'commath.c' <<'END_OF_FILE'
  553. X/*
  554. X * Copyright (c) 1992 David I. Bell
  555. X * Permission is granted to use, distribute, or modify this source,
  556. X * provided that this copyright notice remains intact.
  557. X *
  558. X * Extended precision complex arithmetic primitive routines
  559. X */
  560. X
  561. X#include <stdio.h>
  562. X#include "math.h"
  563. X
  564. X
  565. XCOMPLEX _czero_ =        { &_qzero_, &_qzero_, 1 };
  566. XCOMPLEX _cone_ =        { &_qone_, &_qzero_, 1 };
  567. Xstatic COMPLEX _cnegone_ =    { &_qnegone_, &_qzero_, 1 };
  568. X
  569. X#if 0
  570. XCOMPLEX _conei_ =    { &_qzero_, &_qone_, 1 };
  571. X#endif
  572. X
  573. X
  574. X/*
  575. X * Free list for complex numbers.
  576. X */
  577. Xstatic FREELIST freelist = {
  578. X    sizeof(COMPLEX),    /* size of an item */
  579. X    100            /* number of free items to keep */
  580. X};
  581. X
  582. X
  583. X/*
  584. X * Add two complex numbers.
  585. X */
  586. XCOMPLEX *
  587. Xcadd(c1, c2)
  588. X    COMPLEX *c1, *c2;
  589. X{
  590. X    COMPLEX *r;
  591. X
  592. X    if (ciszero(c1))
  593. X        return clink(c2);
  594. X    if (ciszero(c2))
  595. X        return clink(c1);
  596. X    r = comalloc();
  597. X    if (!qiszero(c1->real) || !qiszero(c2->real))
  598. X        r->real = qadd(c1->real, c2->real);
  599. X    if (!qiszero(c1->imag) || !qiszero(c2->imag))
  600. X        r->imag = qadd(c1->imag, c2->imag);
  601. X    return r;
  602. X}
  603. X
  604. X
  605. X/*
  606. X * Subtract two complex numbers.
  607. X */
  608. XCOMPLEX *
  609. Xcsub(c1, c2)
  610. X    COMPLEX *c1, *c2;
  611. X{
  612. X    COMPLEX *r;
  613. X
  614. X    if ((c1->real == c2->real) && (c1->imag == c2->imag))
  615. X        return clink(&_czero_);
  616. X    if (ciszero(c2))
  617. X        return clink(c1);
  618. X    r = comalloc();
  619. X    if (!qiszero(c1->real) || !qiszero(c2->real))
  620. X        r->real = qsub(c1->real, c2->real);
  621. X    if (!qiszero(c1->imag) || !qiszero(c2->imag))
  622. X        r->imag = qsub(c1->imag, c2->imag);
  623. X    return r;
  624. X}
  625. X
  626. X
  627. X/*
  628. X * Multiply two complex numbers.
  629. X * This saves one multiplication over the obvious algorithm by
  630. X * trading it for several extra additions, as follows.  Let
  631. X *    q1 = (a + b) * (c + d)
  632. X *    q2 = a * c
  633. X *    q3 = b * d
  634. X * Then (a+bi) * (c+di) = (q2 - q3) + (q1 - q2 - q3)i.
  635. X */
  636. XCOMPLEX *
  637. Xcmul(c1, c2)
  638. X    COMPLEX *c1, *c2;
  639. X{
  640. X    COMPLEX *r;
  641. X    NUMBER *q1, *q2, *q3, *q4;
  642. X
  643. X    if (ciszero(c1) || ciszero(c2))
  644. X        return clink(&_czero_);
  645. X    if (cisone(c1))
  646. X        return clink(c2);
  647. X    if (cisone(c2))
  648. X        return clink(c1);
  649. X    if (cisreal(c2))
  650. X        return cmulq(c1, c2->real);
  651. X    if (cisreal(c1))
  652. X        return cmulq(c2, c1->real);
  653. X    /*
  654. X     * Need to do the full calculation.
  655. X     */
  656. X    r = comalloc();
  657. X    q2 = qadd(c1->real, c1->imag);
  658. X    q3 = qadd(c2->real, c2->imag);
  659. X    q1 = qmul(q2, q3);
  660. X    qfree(q2);
  661. X    qfree(q3);
  662. X    q2 = qmul(c1->real, c2->real);
  663. X    q3 = qmul(c1->imag, c2->imag);
  664. X    q4 = qadd(q2, q3);
  665. X    r->real = qsub(q2, q3);
  666. X    r->imag = qsub(q1, q4);
  667. X    qfree(q1);
  668. X    qfree(q2);
  669. X    qfree(q3);
  670. X    qfree(q4);
  671. X    return r;
  672. X}
  673. X
  674. X
  675. X/*
  676. X * Square a complex number.
  677. X */
  678. XCOMPLEX *
  679. Xcsquare(c)
  680. X    COMPLEX *c;
  681. X{
  682. X    COMPLEX *r;
  683. X    NUMBER *q1, *q2;
  684. X
  685. X    if (ciszero(c))
  686. X        return clink(&_czero_);
  687. X    if (cisrunit(c))
  688. X        return clink(&_cone_);
  689. X    if (cisiunit(c))
  690. X        return clink(&_cnegone_);
  691. X    r = comalloc();
  692. X    if (cisreal(c)) {
  693. X        r->real = qsquare(c->real);
  694. X        return r;
  695. X    }
  696. X    if (cisimag(c)) {
  697. X        q1 = qsquare(c->imag);
  698. X        r->real = qneg(q1);
  699. X        qfree(q1);
  700. X        return r;
  701. X    }
  702. X    q1 = qsquare(c->real);
  703. X    q2 = qsquare(c->imag);
  704. X    r->real = qsub(q1, q2);
  705. X    qfree(q1);
  706. X    qfree(q2);
  707. X    q1 = qmul(c->real, c->imag);
  708. X    r->imag = qscale(q1, 1L);
  709. X    qfree(q1);
  710. X    return r;
  711. X}
  712. X
  713. X
  714. X/*
  715. X * Divide two complex numbers.
  716. X */
  717. XCOMPLEX *
  718. Xcdiv(c1, c2)
  719. X    COMPLEX *c1, *c2;
  720. X{
  721. X    COMPLEX *r;
  722. X    NUMBER *q1, *q2, *q3, *den;
  723. X
  724. X    if (ciszero(c2))
  725. X        error("Division by zero");
  726. X    if ((c1->real == c2->real) && (c1->imag == c2->imag))
  727. X        return clink(&_cone_);
  728. X    r = comalloc();
  729. X    if (cisreal(c1) && cisreal(c2)) {
  730. X        r->real = qdiv(c1->real, c2->real);
  731. X        return r;
  732. X    }
  733. X    if (cisimag(c1) && cisimag(c2)) {
  734. X        r->real = qdiv(c1->imag, c2->imag);
  735. X        return r;
  736. X    }
  737. X    if (cisimag(c1) && cisreal(c2)) {
  738. X        r->imag = qdiv(c1->imag, c2->real);
  739. X        return r;
  740. X    }
  741. X    if (cisreal(c1) && cisimag(c2)) {
  742. X        q1 = qdiv(c1->real, c2->imag);
  743. X        r->imag = qneg(q1);
  744. X        qfree(q1);
  745. X        return r;
  746. X    }
  747. X    if (cisreal(c2)) {
  748. X        r->real = qdiv(c1->real, c2->real);
  749. X        r->imag = qdiv(c1->imag, c2->real);
  750. X        return r;
  751. X    }
  752. X    q1 = qsquare(c2->real);
  753. X    q2 = qsquare(c2->imag);
  754. X    den = qadd(q1, q2);
  755. X    qfree(q1);
  756. X    qfree(q2);
  757. X    q1 = qmul(c1->real, c2->real);
  758. X    q2 = qmul(c1->imag, c2->imag);
  759. X    q3 = qadd(q1, q2);
  760. X    qfree(q1);
  761. X    qfree(q2);
  762. X    r->real = qdiv(q3, den);
  763. X    qfree(q3);
  764. X    q1 = qmul(c1->real, c2->imag);
  765. X    q2 = qmul(c1->imag, c2->real);
  766. X    q3 = qsub(q2, q1);
  767. X    qfree(q1);
  768. X    qfree(q2);
  769. X    r->imag = qdiv(q3, den);
  770. X    qfree(q3);
  771. X    qfree(den);
  772. X    return r;
  773. X}
  774. X
  775. X
  776. X/*
  777. X * Invert a complex number.
  778. X */
  779. XCOMPLEX *
  780. Xcinv(c)
  781. X    COMPLEX *c;
  782. X{
  783. X    COMPLEX *r;
  784. X    NUMBER *q1, *q2, *den;
  785. X
  786. X    if (ciszero(c))
  787. X        error("Inverting zero");
  788. X    r = comalloc();
  789. X    if (cisreal(c)) {
  790. X        r->real = qinv(c->real);
  791. X        return r;
  792. X    }
  793. X    if (cisimag(c)) {
  794. X        q1 = qinv(c->imag);
  795. X        r->imag = qneg(q1);
  796. X        qfree(q1);
  797. X        return r;
  798. X    }
  799. X    q1 = qsquare(c->real);
  800. X    q2 = qsquare(c->imag);
  801. X    den = qadd(q1, q2);
  802. X    qfree(q1);
  803. X    qfree(q2);
  804. X    r->real = qdiv(c->real, den);
  805. X    q1 = qdiv(c->imag, den);
  806. X    r->imag = qneg(q1);
  807. X    qfree(q1);
  808. X    qfree(den);
  809. X    return r;
  810. X}
  811. X
  812. X
  813. X/*
  814. X * Negate a complex number.
  815. X */
  816. XCOMPLEX *
  817. Xcneg(c)
  818. X    COMPLEX *c;
  819. X{
  820. X    COMPLEX *r;
  821. X
  822. X    if (ciszero(c))
  823. X        return clink(&_czero_);
  824. X    r = comalloc();
  825. X    if (!qiszero(c->real))
  826. X        r->real = qneg(c->real);
  827. X    if (!qiszero(c->imag))
  828. X        r->imag = qneg(c->imag);
  829. X    return r;
  830. X}
  831. X
  832. X
  833. X/*
  834. X * Take the integer part of a complex number.
  835. X * This means take the integer part of both components.
  836. X */
  837. XCOMPLEX *
  838. Xcint(c)
  839. X    COMPLEX *c;
  840. X{
  841. X    COMPLEX *r;
  842. X
  843. X    if (cisint(c))
  844. X        return clink(c);
  845. X    r = comalloc();
  846. X    r->real = qint(c->real);
  847. X    r->imag = qint(c->imag);
  848. X    return r;
  849. X}
  850. X
  851. X
  852. X/*
  853. X * Take the fractional part of a complex number.
  854. X * This means take the fractional part of both components.
  855. X */
  856. XCOMPLEX *
  857. Xcfrac(c)
  858. X    COMPLEX *c;
  859. X{
  860. X    COMPLEX *r;
  861. X
  862. X    if (cisint(c))
  863. X        return clink(&_czero_);
  864. X    r = comalloc();
  865. X    r->real = qfrac(c->real);
  866. X    r->imag = qfrac(c->imag);
  867. X    return r;
  868. X}
  869. X
  870. X
  871. X#if 0
  872. X/*
  873. X * Take the conjugate of a complex number.
  874. X * This negates the complex part.
  875. X */
  876. XCOMPLEX *
  877. Xcconj(c)
  878. X    COMPLEX *c;
  879. X{
  880. X    COMPLEX *r;
  881. X
  882. X    if (cisreal(c))
  883. X        return clink(c);
  884. X    r = comalloc();
  885. X    if (!qiszero(c->real))
  886. X        r->real = qlink(c->real);
  887. X    r->imag = qneg(c->imag);
  888. X    return r;
  889. X}
  890. X
  891. X
  892. X/*
  893. X * Return the real part of a complex number.
  894. X */
  895. XCOMPLEX *
  896. Xcreal(c)
  897. X    COMPLEX *c;
  898. X{
  899. X    COMPLEX *r;
  900. X
  901. X    if (cisreal(c))
  902. X        return clink(c);
  903. X    r = comalloc();
  904. X    if (!qiszero(c->real))
  905. X        r->real = qlink(c->real);
  906. X    return r;
  907. X}
  908. X
  909. X
  910. X/*
  911. X * Return the imaginary part of a complex number as a real.
  912. X */
  913. XCOMPLEX *
  914. Xcimag(c)
  915. X    COMPLEX *c;
  916. X{
  917. X    COMPLEX *r;
  918. X
  919. X    if (cisreal(c))
  920. X        return clink(&_czero_);
  921. X    r = comalloc();
  922. X    r->real = qlink(c->imag);
  923. X    return r;
  924. X}
  925. X#endif
  926. X
  927. X
  928. X/*
  929. X * Add a real number to a complex number.
  930. X */
  931. XCOMPLEX *
  932. Xcaddq(c, q)
  933. X    COMPLEX *c;
  934. X    NUMBER *q;
  935. X{
  936. X    COMPLEX *r;
  937. X
  938. X    if (qiszero(q))
  939. X        return clink(c);
  940. X    r = comalloc();
  941. X    r->real = qadd(c->real, q);
  942. X    r->imag = qlink(c->imag);
  943. X    return r;
  944. X}
  945. X
  946. X
  947. X/*
  948. X * Subtract a real number from a complex number.
  949. X */
  950. XCOMPLEX *
  951. Xcsubq(c, q)
  952. X    COMPLEX *c;
  953. X    NUMBER *q;
  954. X{
  955. X    COMPLEX *r;
  956. X
  957. X    if (qiszero(q))
  958. X        return clink(c);
  959. X    r = comalloc();
  960. X    r->real = qsub(c->real, q);
  961. X    r->imag = qlink(c->imag);
  962. X    return r;
  963. X}
  964. X
  965. X
  966. X/*
  967. X * Shift the components of a complex number left by the specified
  968. X * number of bits.  Negative values shift to the right.
  969. X */
  970. XCOMPLEX *
  971. Xcshift(c, n)
  972. X    COMPLEX *c;
  973. X    long n;
  974. X{
  975. X    COMPLEX *r;
  976. X
  977. X    if (ciszero(c) || (n == 0))
  978. X        return clink(c);
  979. X    r = comalloc();
  980. X    r->real = qshift(c->real, n);
  981. X    r->imag = qshift(c->imag, n);
  982. X    return r;
  983. X}
  984. X
  985. X
  986. X/*
  987. X * Scale a complex number by a power of two.
  988. X */
  989. XCOMPLEX *
  990. Xcscale(c, n)
  991. X    COMPLEX *c;
  992. X    long n;
  993. X{
  994. X    COMPLEX *r;
  995. X
  996. X    if (ciszero(c) || (n == 0))
  997. X        return clink(c);
  998. X    r = comalloc();
  999. X    r->real = qscale(c->real, n);
  1000. X    r->imag = qscale(c->imag, n);
  1001. X    return r;
  1002. X}
  1003. X
  1004. X
  1005. X/*
  1006. X * Multiply a complex number by a real number.
  1007. X */
  1008. XCOMPLEX *
  1009. Xcmulq(c, q)
  1010. X    COMPLEX *c;
  1011. X    NUMBER *q;
  1012. X{
  1013. X    COMPLEX *r;
  1014. X
  1015. X    if (qiszero(q))
  1016. X        return clink(&_czero_);
  1017. X    if (qisone(q))
  1018. X        return clink(c);
  1019. X    if (qisnegone(q))
  1020. X        return cneg(c);
  1021. X    r = comalloc();
  1022. X    r->real = qmul(c->real, q);
  1023. X    r->imag = qmul(c->imag, q);
  1024. X    return r;
  1025. X}
  1026. X
  1027. X
  1028. X/*
  1029. X * Divide a complex number by a real number.
  1030. X */
  1031. XCOMPLEX *
  1032. Xcdivq(c, q)
  1033. X    COMPLEX *c;
  1034. X    NUMBER *q;
  1035. X{
  1036. X    COMPLEX *r;
  1037. X
  1038. X    if (qiszero(q))
  1039. X        error("Division by zero");
  1040. X    if (qisone(q))
  1041. X        return clink(c);
  1042. X    if (qisnegone(q))
  1043. X        return cneg(c);
  1044. X    r = comalloc();
  1045. X    r->real = qdiv(c->real, q);
  1046. X    r->imag = qdiv(c->imag, q);
  1047. X    return r;
  1048. X}
  1049. X
  1050. X
  1051. X/*
  1052. X * Take the integer quotient of a complex number by a real number.
  1053. X * This is defined to be the result of doing the quotient for each component.
  1054. X */
  1055. XCOMPLEX *
  1056. Xcquoq(c, q)
  1057. X    COMPLEX *c;
  1058. X    NUMBER *q;
  1059. X{
  1060. X    COMPLEX *r;
  1061. X
  1062. X    if (qiszero(q))
  1063. X        error("Division by zero");
  1064. X    r = comalloc();
  1065. X    r->real = qquo(c->real, q);
  1066. X    r->imag = qquo(c->imag, q);
  1067. X    return r;
  1068. X}
  1069. X
  1070. X
  1071. X/*
  1072. X * Take the modulus of a complex number by a real number.
  1073. X * This is defined to be the result of doing the modulo for each component.
  1074. X */
  1075. XCOMPLEX *
  1076. Xcmodq(c, q)
  1077. X    COMPLEX *c;
  1078. X    NUMBER *q;
  1079. X{
  1080. X    COMPLEX *r;
  1081. X
  1082. X    if (qiszero(q))
  1083. X        error("Division by zero");
  1084. X    r = comalloc();
  1085. X    r->real = qmod(c->real, q);
  1086. X    r->imag = qmod(c->imag, q);
  1087. X    return r;
  1088. X}
  1089. X
  1090. X
  1091. X#if 0
  1092. X/*
  1093. X * Construct a complex number given the real and imaginary components.
  1094. X */
  1095. XCOMPLEX *
  1096. Xqqtoc(q1, q2)
  1097. X    NUMBER *q1, *q2;
  1098. X{
  1099. X    COMPLEX *r;
  1100. X
  1101. X    if (qiszero(q1) && qiszero(q2))
  1102. X        return clink(&_czero_);
  1103. X    r = comalloc();
  1104. X    if (!qiszero(q1))
  1105. X        r->real = qlink(q1);
  1106. X    if (!qiszero(q2))
  1107. X        r->imag = qlink(q2);
  1108. X    return r;
  1109. X}
  1110. X#endif
  1111. X
  1112. X
  1113. X/*
  1114. X * Compare two complex numbers for equality, returning FALSE if they are equal,
  1115. X * and TRUE if they differ.
  1116. X */
  1117. XBOOL
  1118. Xccmp(c1, c2)
  1119. X    COMPLEX *c1, *c2;
  1120. X{
  1121. X    BOOL i;
  1122. X
  1123. X    i = qcmp(c1->real, c2->real);
  1124. X    if (!i)
  1125. X        i = qcmp(c1->imag, c2->imag);
  1126. X    return i;
  1127. X}
  1128. X
  1129. X
  1130. X/*
  1131. X * Allocate a new complex number.
  1132. X */
  1133. XCOMPLEX *
  1134. Xcomalloc()
  1135. X{
  1136. X    COMPLEX *r;
  1137. X
  1138. X    r = (COMPLEX *) allocitem(&freelist);
  1139. X    if (r == NULL)
  1140. X        error("Cannot allocate complex number");
  1141. X    r->links = 1;
  1142. X    r->real = qlink(&_qzero_);
  1143. X    r->imag = qlink(&_qzero_);
  1144. X    return r;
  1145. X}
  1146. X
  1147. X
  1148. X/*
  1149. X * Free a complex number.
  1150. X */
  1151. Xvoid
  1152. Xcomfree(c)
  1153. X    COMPLEX *c;
  1154. X{
  1155. X    if (--(c->links) > 0)
  1156. X        return;
  1157. X    qfree(c->real);
  1158. X    qfree(c->imag);
  1159. X    freeitem(&freelist, (FREEITEM *) c);
  1160. X}
  1161. X
  1162. X/* END CODE */
  1163. END_OF_FILE
  1164. if test 9654 -ne `wc -c <'commath.c'`; then
  1165.     echo shar: \"'commath.c'\" unpacked with wrong size!
  1166. fi
  1167. # end of 'commath.c'
  1168. fi
  1169. if test -f 'file.c' -a "${1}" != "-c" ; then 
  1170.   echo shar: Will not clobber existing file \"'file.c'\"
  1171. else
  1172. echo shar: Extracting \"'file.c'\" \(10407 characters\)
  1173. sed "s/^X//" >'file.c' <<'END_OF_FILE'
  1174. X/*
  1175. X * Copyright (c) 1992 David I. Bell
  1176. X * Permission is granted to use, distribute, or modify this source,
  1177. X * provided that this copyright notice remains intact.
  1178. X *
  1179. X * File I/O routines callable by users.
  1180. X */
  1181. X
  1182. X#include "stdarg.h"
  1183. X#include "calc.h"
  1184. X
  1185. X
  1186. X#define    READSIZE    1024    /* buffer size for reading */
  1187. X
  1188. X/*
  1189. X * Definition of opened files.
  1190. X */
  1191. Xtypedef struct {
  1192. X    FILEID id;        /* id to identify this file */
  1193. X    FILE *fp;        /* real file structure for I/O */
  1194. X    char *name;        /* file name */
  1195. X    BOOL reading;        /* TRUE if opened for reading */
  1196. X    BOOL writing;        /* TRUE if opened for writing */
  1197. X    char *mode;        /* open mode */
  1198. X} FILEIO;
  1199. X
  1200. X
  1201. X/*
  1202. X * Table of opened files.
  1203. X * The first three entries always correspond to stdin, stdout, and stderr,
  1204. X * and cannot be closed.  Their file ids are always 0, 1, and 2.
  1205. X */
  1206. Xstatic FILEIO files[MAXFILES] = {
  1207. X    FILEID_STDIN,  stdin,  "(stdin)",  TRUE, FALSE, "reading",
  1208. X    FILEID_STDOUT, stdout, "(stdout)", FALSE, TRUE, "writing",
  1209. X    FILEID_STDERR, stderr, "(stderr)", FALSE, TRUE, "writing"
  1210. X};
  1211. X
  1212. Xstatic FILEID lastid = FILEID_STDERR;        /* last allocated file id */
  1213. X
  1214. X
  1215. X
  1216. X/*
  1217. X * Open the specified file name for reading or writing as determined by
  1218. X * the specified mode ("r", "w", or "a").  Returns a file id which can be
  1219. X * used to do I/O to the file, or else FILEID_NONE if the open failed.
  1220. X * Aborts with an error if too many files are opened or the mode is illegal.
  1221. X */
  1222. XFILEID
  1223. Xopenid(name, mode)
  1224. X    char *name;        /* file name */
  1225. X    char *mode;        /* open mode */
  1226. X{
  1227. X    FILEIO *fiop;        /* file structure */
  1228. X    FILEID id;        /* new file id */
  1229. X    int count;
  1230. X
  1231. X    if (((*mode != 'r') && (*mode != 'w') && (*mode != 'a')) || mode[1])
  1232. X        error("Illegal mode for fopen");
  1233. X
  1234. X    count = MAXFILES;
  1235. X    do {
  1236. X        if (--count < 0)
  1237. X            error("Too many open files");
  1238. X        id = ++lastid;
  1239. X        fiop = &files[id % MAXFILES];
  1240. X
  1241. X    } while (fiop->reading || fiop->writing);
  1242. X
  1243. X    fiop->name = (char *)malloc(strlen(name) + 1);
  1244. X    if (fiop->name == NULL) {
  1245. X        lastid--;
  1246. X        error("No memory for filename");
  1247. X    }
  1248. X    strcpy(fiop->name, name);
  1249. X
  1250. X    fiop->fp = f_open(name, mode);
  1251. X    if (fiop->fp == NULL) {
  1252. X        free(fiop->name);
  1253. X        fiop->name = NULL;
  1254. X        lastid--;
  1255. X        return FILEID_NONE;
  1256. X    }
  1257. X
  1258. X    switch (*mode) {
  1259. X        case 'r':
  1260. X            fiop->mode = "reading";
  1261. X            fiop->reading = TRUE;
  1262. X            break;
  1263. X        case 'w':
  1264. X            fiop->mode = "writing";
  1265. X            fiop->writing = TRUE;
  1266. X            break;
  1267. X        case 'a':
  1268. X            fiop->mode = "appending";
  1269. X            fiop->writing = TRUE;
  1270. X            break;
  1271. X    }
  1272. X
  1273. X    fiop->id = id;
  1274. X
  1275. X    return id;
  1276. X}
  1277. X
  1278. X
  1279. X/*
  1280. X * Find the file I/O structure for the specified file id, and verify that
  1281. X * it is opened in the required manner ('r' for reading or 'w' for writing).
  1282. X * If mode is 0, then no open checks are made at all, and NULL is then
  1283. X * returned if the id represents a closed file.
  1284. X */
  1285. Xstatic FILEIO *
  1286. Xfindid(id, mode)
  1287. X    FILEID id;
  1288. X{
  1289. X    FILEIO *fiop;        /* file structure */
  1290. X    char *msg;
  1291. X    BOOL flag;
  1292. X
  1293. X    if ((id < 0) || (id > lastid))
  1294. X        error("Illegal file id");
  1295. X
  1296. X    fiop = &files[id % MAXFILES];
  1297. X
  1298. X    switch (mode) {
  1299. X        case 'r':
  1300. X            msg = "Reading from";
  1301. X            flag = fiop->reading;
  1302. X            break;
  1303. X        case 'w':
  1304. X            msg = "Writing to";
  1305. X            flag = fiop->writing;
  1306. X            break;
  1307. X        case 0:
  1308. X            msg = NULL;
  1309. X            break;
  1310. X        default:
  1311. X            error("Unknown findid mode");
  1312. X    }
  1313. X
  1314. X    if (fiop->id != id) {
  1315. X        if (msg)
  1316. X            error("%s closed file", msg);
  1317. X        return NULL;
  1318. X    }
  1319. X
  1320. X    if (msg && !flag)
  1321. X        error("%s file not opened that way", msg);
  1322. X    
  1323. X    return fiop;
  1324. X}
  1325. X
  1326. X
  1327. X/*
  1328. X * Return whether or not a file id is valid.  This is used for if tests.
  1329. X */
  1330. XBOOL
  1331. Xvalidid(id)
  1332. X    FILEID id;
  1333. X{
  1334. X    return (findid(id, 0) != NULL);
  1335. X}
  1336. X
  1337. X
  1338. X/*
  1339. X * Return the file id for the entry in the file table at the specified index.
  1340. X * Returns FILEID_NONE if the index is illegal or the file is closed.
  1341. X */
  1342. XFILEID
  1343. Xindexid(index)
  1344. X    long index;
  1345. X{
  1346. X    FILEIO *fiop;        /* file structure */
  1347. X
  1348. X    if ((index < 0) || (index >= MAXFILES))
  1349. X        return FILEID_NONE;
  1350. X
  1351. X    fiop = &files[index];
  1352. X    if (fiop->reading || fiop->writing)
  1353. X        return fiop->id;
  1354. X
  1355. X    return FILEID_NONE;
  1356. X}
  1357. X
  1358. X
  1359. X/*
  1360. X * Close the specified file id.  Returns TRUE if there was an error.
  1361. X * Closing of stdin, stdout, or stderr is illegal, but closing of already
  1362. X * closed files is allowed.
  1363. X */
  1364. XBOOL
  1365. Xcloseid(id)
  1366. X    FILEID id;
  1367. X{
  1368. X    FILEIO *fiop;        /* file structure */
  1369. X    int err;
  1370. X
  1371. X    if ((id == FILEID_STDIN) || (id == FILEID_STDOUT) ||
  1372. X        (id == FILEID_STDERR))
  1373. X            error("Cannot close stdin, stdout, or stderr");
  1374. X
  1375. X    fiop = findid(id, 0);
  1376. X    if (fiop == NULL)
  1377. X        return FALSE;
  1378. X
  1379. X    fiop->id = FILEID_NONE;
  1380. X    if (!fiop->reading && !fiop->writing)
  1381. X        error("Closing non-opened file");
  1382. X    fiop->reading = FALSE;
  1383. X    fiop->writing = FALSE;
  1384. X
  1385. X    if (fiop->name)
  1386. X        free(fiop->name);
  1387. X    fiop->name = NULL;
  1388. X
  1389. X    err = ferror(fiop->fp);
  1390. X    err |= fclose(fiop->fp);
  1391. X    fiop->fp = NULL;
  1392. X
  1393. X    return (err != 0);
  1394. X}
  1395. X
  1396. X
  1397. X/*
  1398. X * Return whether or not an error occurred to a file.
  1399. X */
  1400. XBOOL
  1401. Xerrorid(id)
  1402. X    FILEID id;
  1403. X{
  1404. X    FILEIO *fiop;        /* file structure */
  1405. X
  1406. X    fiop = findid(id, 0);
  1407. X    if (fiop == NULL)
  1408. X        error("Closed file for ferror");
  1409. X    return (ferror(fiop->fp) != 0);
  1410. X}
  1411. X
  1412. X
  1413. X/*
  1414. X * Return whether or not end of file occurred to a file.
  1415. X */
  1416. XBOOL
  1417. Xeofid(id)
  1418. X    FILEID id;
  1419. X{
  1420. X    FILEIO *fiop;        /* file structure */
  1421. X
  1422. X    fiop = findid(id, 0);
  1423. X    if (fiop == NULL)
  1424. X        error("Closed file for feof");
  1425. X    return (feof(fiop->fp) != 0);
  1426. X}
  1427. X
  1428. X
  1429. X/*
  1430. X * Flush output to an opened file.
  1431. X */
  1432. Xvoid
  1433. Xflushid(id)
  1434. X    FILEID id;
  1435. X{
  1436. X    FILEIO *fiop;        /* file structure */
  1437. X
  1438. X    fiop = findid(id, 'w');
  1439. X    fflush(fiop->fp);
  1440. X}
  1441. X
  1442. X
  1443. X/*
  1444. X * Read the next line from an opened file.
  1445. X * Returns a pointer to an allocated string holding the null-terminated
  1446. X * line (without any terminating newline), or else a NULL pointer on an
  1447. X * end of file or error.
  1448. X */
  1449. Xvoid
  1450. Xreadid(id, retptr)
  1451. X    FILEID    id;        /* file to read from */
  1452. X    char **retptr;        /* returned pointer to string */
  1453. X{
  1454. X    FILEIO *fiop;        /* file structure */
  1455. X    char *str;        /* current string */
  1456. X    int len;        /* current length of string */
  1457. X    int totlen;        /* total length of string */
  1458. X    char buf[READSIZE];    /* temporary buffer */
  1459. X
  1460. X    totlen = 0;
  1461. X    str = NULL;
  1462. X
  1463. X    fiop = findid(id, 'r');
  1464. X
  1465. X    while (fgets(buf, READSIZE, fiop->fp) && buf[0]) {
  1466. X        len = strlen(buf);
  1467. X        if (totlen)
  1468. X            str = (char *)realloc(str, totlen + len + 1);
  1469. X        else
  1470. X            str = (char *)malloc(len + 1);
  1471. X        if (str == NULL)
  1472. X            error("No memory in freadline");
  1473. X        strcpy(&str[totlen], buf);
  1474. X        totlen += len;
  1475. X        if (buf[len - 1] == '\n') {
  1476. X            str[totlen - 1] = '\0';
  1477. X            *retptr = str;
  1478. X            return;
  1479. X        }
  1480. X    }
  1481. X    if (totlen && ferror(fiop->fp)) {
  1482. X        free(str);
  1483. X        str = NULL;
  1484. X    }
  1485. X    *retptr = str;
  1486. X}
  1487. X
  1488. X
  1489. X/*
  1490. X * Return the next character from an opened file.
  1491. X * Returns EOF if there was an error or end of file.
  1492. X */
  1493. Xint
  1494. Xgetcharid(id)
  1495. X    FILEID id;
  1496. X{
  1497. X    return fgetc(findid(id, 'r')->fp);
  1498. X}
  1499. X
  1500. X
  1501. X/*
  1502. X * Print out the name of an opened file.
  1503. X * If the file has been closed, a null name is printed.
  1504. X * If flags contain PRINT_UNAMBIG then extra information is printed
  1505. X * identifying the output as a file and some data about it.
  1506. X */
  1507. Xvoid
  1508. Xprintid(id, flags)
  1509. X    FILEID id;
  1510. X{
  1511. X    FILEIO *fiop;        /* file structure */
  1512. X    FILE *fp;
  1513. X
  1514. X    fiop = findid(id, 0);
  1515. X    if (fiop == NULL) {
  1516. X        math_str((flags & PRINT_UNAMBIG) ? "FILE (closed)" : "\"\"");
  1517. X        return;
  1518. X    }
  1519. X    if ((flags & PRINT_UNAMBIG) == 0) {
  1520. X        math_chr('"');
  1521. X        math_str(fiop->name);
  1522. X        math_chr('"');
  1523. X        return;
  1524. X    }
  1525. X
  1526. X    fp = fiop->fp;
  1527. X    math_fmt("FILE \"%s\" (%s, pos %ld", fiop->name,  fiop->mode,
  1528. X        ftell(fp));
  1529. X    if (ferror(fp))
  1530. X        math_str(", error");
  1531. X    if (feof(fp))
  1532. X        math_str(", eof");
  1533. X    math_chr(')');
  1534. X}
  1535. X
  1536. X
  1537. X/*
  1538. X * Print a formatted string similar to printf.  Various formats of output
  1539. X * are possible, depending on the format string AND the actual types of the
  1540. X * values.  Mismatches do not cause errors, instead something reasonable is
  1541. X * printed instead.  The output goes to the file with the specified id.
  1542. X */
  1543. Xvoid
  1544. Xidprintf(id, fmt, count, vals)
  1545. X    FILEID id;            /* file id to print to */
  1546. X    char *fmt;            /* standard format string */
  1547. X    VALUE **vals;            /* table of values to print */
  1548. X{
  1549. X    FILEIO *fiop;
  1550. X    VALUE *vp;
  1551. X    char *str;
  1552. X    int ch, len;
  1553. X    int oldmode, newmode;
  1554. X    long olddigits, newdigits;
  1555. X    long width, precision;
  1556. X    BOOL didneg, didprecision;
  1557. X
  1558. X    fiop = findid(id, 'w');
  1559. X
  1560. X    setfp(fiop->fp);
  1561. X
  1562. X    while ((ch = *fmt++) != '\0') {
  1563. X        if (ch == '\\') {
  1564. X            ch = *fmt++;
  1565. X            switch (ch) {
  1566. X                case 'n': ch = '\n'; break;
  1567. X                case 'r': ch = '\r'; break;
  1568. X                case 't': ch = '\t'; break;
  1569. X                case 'f': ch = '\f'; break;
  1570. X                case 'v': ch = '\v'; break;
  1571. X                case 'b': ch = '\b'; break;
  1572. X                case 0:
  1573. X                    setfp(stdout);
  1574. X                    return;
  1575. X            }
  1576. X            math_chr(ch);
  1577. X            continue;
  1578. X        }
  1579. X
  1580. X        if (ch != '%') {
  1581. X            math_chr(ch);
  1582. X            continue;
  1583. X        }
  1584. X
  1585. X        /*
  1586. X         * Here to handle formats.
  1587. X         */
  1588. X        didneg = FALSE;
  1589. X        didprecision = FALSE;
  1590. X        width = 0;
  1591. X        precision = 0;
  1592. X
  1593. X        ch = *fmt++;
  1594. X        if (ch == '-') {
  1595. X            didneg = TRUE;
  1596. X            ch = *fmt++;
  1597. X        }
  1598. X        while ((ch >= '0') && (ch <= '9')) {
  1599. X            width = width * 10 + (ch - '0');
  1600. X            ch = *fmt++;
  1601. X        }
  1602. X        if (ch == '.') {
  1603. X            didprecision = TRUE;
  1604. X            ch = *fmt++;
  1605. X            while ((ch >= '0') && (ch <= '9')) {
  1606. X                precision = precision * 10 + (ch - '0');
  1607. X                ch = *fmt++;
  1608. X            }
  1609. X        }
  1610. X        if (ch == 'l')
  1611. X            ch = *fmt++;
  1612. X
  1613. X        oldmode = _outmode_;
  1614. X        newmode = oldmode;
  1615. X        olddigits = _outdigits_;
  1616. X        newdigits = olddigits;
  1617. X        if (didprecision)
  1618. X            newdigits = precision;
  1619. X
  1620. X        switch (ch) {
  1621. X            case 'd':
  1622. X            case 's':
  1623. X            case 'c':
  1624. X                break;
  1625. X            case 'f':
  1626. X                newmode = MODE_REAL;
  1627. X                break;
  1628. X            case 'e':
  1629. X                newmode = MODE_EXP;
  1630. X                break;
  1631. X            case 'r':
  1632. X                newmode = MODE_FRAC;
  1633. X                break;
  1634. X            case 'o':
  1635. X                newmode = MODE_OCTAL;
  1636. X                break;
  1637. X            case 'x':
  1638. X                newmode = MODE_HEX;
  1639. X                break;
  1640. X            case 'b':
  1641. X                newmode = MODE_BINARY;
  1642. X                break;
  1643. X            case 0:
  1644. X                setfp(stdout);
  1645. X                return;
  1646. X            default:
  1647. X                math_chr(ch);
  1648. X                continue;
  1649. X        }
  1650. X
  1651. X        if (--count < 0)
  1652. X            error("Not enough arguments for fprintf");
  1653. X        vp = *vals++;
  1654. X
  1655. X        setdigits(newdigits);
  1656. X        setmode(newmode);
  1657. X
  1658. X        /*
  1659. X         * If there is no width specification, or if the type of
  1660. X         * value requires multiple lines, then just output the
  1661. X         * value directly.
  1662. X         */
  1663. X        if ((width == 0) ||
  1664. X            (vp->v_type == V_MAT) || (vp->v_type == V_LIST))
  1665. X        {
  1666. X            printvalue(vp, PRINT_NORMAL);
  1667. X            setmode(oldmode);
  1668. X            setdigits(olddigits);
  1669. X            continue;
  1670. X        }
  1671. X
  1672. X        /*
  1673. X         * There is a field width.  Collect the output in a string,
  1674. X         * print it padded appropriately with spaces, and free it.
  1675. X         * However, if the output contains a newline, then ignore
  1676. X         * the field width.
  1677. X         */
  1678. X        divertio();
  1679. X        printvalue(vp, PRINT_NORMAL);
  1680. X        str = getdivertedio();
  1681. X        if (strchr(str, '\n'))
  1682. X            width = 0;
  1683. X        len = strlen(str);
  1684. X        while (!didneg && (width > len)) {
  1685. X            width--;
  1686. X            math_chr(' ');
  1687. X        }
  1688. X        math_str(str);
  1689. X        free(str);
  1690. X        while (didneg && (width > len)) {
  1691. X            width--;
  1692. X            math_chr(' ');
  1693. X        }
  1694. X        setmode(oldmode);
  1695. X        setdigits(olddigits);
  1696. X    }
  1697. X    setfp(stdout);
  1698. X}
  1699. X
  1700. X/* END CODE */
  1701. END_OF_FILE
  1702. if test 10407 -ne `wc -c <'file.c'`; then
  1703.     echo shar: \"'file.c'\" unpacked with wrong size!
  1704. fi
  1705. # end of 'file.c'
  1706. fi
  1707. if test -f 'listfunc.c' -a "${1}" != "-c" ; then 
  1708.   echo shar: Will not clobber existing file \"'listfunc.c'\"
  1709. else
  1710. echo shar: Extracting \"'listfunc.c'\" \(11116 characters\)
  1711. sed "s/^X//" >'listfunc.c' <<'END_OF_FILE'
  1712. X/*
  1713. X * Copyright (c) 1992 David I. Bell
  1714. X * Permission is granted to use, distribute, or modify this source,
  1715. X * provided that this copyright notice remains intact.
  1716. X *
  1717. X * List handling routines.
  1718. X * Lists can be composed of any types of values, mixed if desired.
  1719. X * Lists are doubly linked so that elements can be inserted or
  1720. X * deleted efficiently at any point in the list.  A pointer is
  1721. X * kept to the most recently indexed element so that sequential
  1722. X * accesses are fast.
  1723. X */
  1724. X
  1725. X#include "calc.h"
  1726. X
  1727. X
  1728. Xstatic LISTELEM *elemalloc();
  1729. Xstatic LISTELEM *listelement();
  1730. Xstatic void elemfree();
  1731. Xstatic void removelistelement();
  1732. X
  1733. X
  1734. X/*
  1735. X * Free lists for list headers and list elements.
  1736. X */
  1737. Xstatic FREELIST    headerfreelist = {
  1738. X    sizeof(LIST),        /* size of list header */
  1739. X    20            /* number of free headers to keep */
  1740. X};
  1741. X
  1742. Xstatic FREELIST elementfreelist = {
  1743. X    sizeof(LISTELEM),    /* size of list element */
  1744. X    1000            /* number of free list elements to keep */
  1745. X};
  1746. X
  1747. X
  1748. X/*
  1749. X * Insert an element before the first element of a list.
  1750. X */
  1751. Xvoid
  1752. Xinsertlistfirst(lp, vp)
  1753. X    LIST *lp;        /* list to put element onto */
  1754. X    VALUE *vp;        /* value to be inserted */
  1755. X{
  1756. X    LISTELEM *ep;        /* list element */
  1757. X
  1758. X    ep = elemalloc();
  1759. X    copyvalue(vp, &ep->e_value);
  1760. X    if (lp->l_count == 0)
  1761. X        lp->l_last = ep;
  1762. X    else {
  1763. X        lp->l_cacheindex++;
  1764. X        lp->l_first->e_prev = ep;
  1765. X        ep->e_next = lp->l_first;
  1766. X    }
  1767. X    lp->l_first = ep;
  1768. X    lp->l_count++;
  1769. X}
  1770. X
  1771. X
  1772. X/*
  1773. X * Insert an element after the last element of a list.
  1774. X */
  1775. Xvoid
  1776. Xinsertlistlast(lp, vp)
  1777. X    LIST *lp;        /* list to put element onto */
  1778. X    VALUE *vp;        /* value to be inserted */
  1779. X{
  1780. X    LISTELEM *ep;        /* list element */
  1781. X
  1782. X    ep = elemalloc();
  1783. X    copyvalue(vp, &ep->e_value);
  1784. X    if (lp->l_count == 0)
  1785. X        lp->l_first = ep;
  1786. X    else {
  1787. X        lp->l_last->e_next = ep;
  1788. X        ep->e_prev = lp->l_last;
  1789. X    }
  1790. X    lp->l_last = ep;
  1791. X    lp->l_count++;
  1792. X}
  1793. X
  1794. X
  1795. X/*
  1796. X * Insert an element into the middle of list at the given index (zero based).
  1797. X * The specified index will select the new element, so existing elements
  1798. X * at or beyond the index will be shifted down one position.  It is legal
  1799. X * to specify an index which is right at the end of the list, in which
  1800. X * case the element is appended to the list.
  1801. X */
  1802. Xvoid
  1803. Xinsertlistmiddle(lp, index, vp)
  1804. X    LIST *lp;        /* list to put element onto */
  1805. X    long index;        /* element number to insert in front of */
  1806. X    VALUE *vp;        /* value to be inserted */
  1807. X{
  1808. X    LISTELEM *ep;        /* list element */
  1809. X    LISTELEM *oldep;    /* old list element at desired index */
  1810. X
  1811. X    if (index == 0) {
  1812. X        insertlistfirst(lp, vp);
  1813. X        return;
  1814. X    }
  1815. X    if (index == lp->l_count) {
  1816. X        insertlistlast(lp, vp);
  1817. X        return;
  1818. X    }
  1819. X    oldep = NULL;
  1820. X    if ((index >= 0) && (index < lp->l_count))
  1821. X        oldep = listelement(lp, index);
  1822. X    if (oldep == NULL)
  1823. X        error("Index out of bounds for list insertion");
  1824. X    ep = elemalloc();
  1825. X    copyvalue(vp, &ep->e_value);
  1826. X    ep->e_next = oldep;
  1827. X    ep->e_prev = oldep->e_prev;
  1828. X    ep->e_prev->e_next = ep;
  1829. X    oldep->e_prev = ep;
  1830. X    lp->l_cache = ep;
  1831. X    lp->l_cacheindex = index;
  1832. X    lp->l_count++;
  1833. X}
  1834. X
  1835. X
  1836. X/*
  1837. X * Remove the first element from a list, returning its value.
  1838. X * Returns the null value if no more elements exist.
  1839. X */
  1840. Xvoid
  1841. Xremovelistfirst(lp, vp)
  1842. X    LIST *lp;        /* list to have element removed */
  1843. X    VALUE *vp;        /* location of the value */
  1844. X{
  1845. X    if (lp->l_count == 0) {
  1846. X        vp->v_type = V_NULL;
  1847. X        return;
  1848. X    }
  1849. X    *vp = lp->l_first->e_value;
  1850. X    lp->l_first->e_value.v_type = V_NULL;
  1851. X    removelistelement(lp, lp->l_first);
  1852. X}
  1853. X
  1854. X
  1855. X/*
  1856. X * Remove the last element from a list, returning its value.
  1857. X * Returns the null value if no more elements exist.
  1858. X */
  1859. Xvoid
  1860. Xremovelistlast(lp, vp)
  1861. X    LIST *lp;        /* list to have element removed */
  1862. X    VALUE *vp;        /* location of the value */
  1863. X{
  1864. X    if (lp->l_count == 0) {
  1865. X        vp->v_type = V_NULL;
  1866. X        return;
  1867. X    }
  1868. X    *vp = lp->l_last->e_value;
  1869. X    lp->l_last->e_value.v_type = V_NULL;
  1870. X    removelistelement(lp, lp->l_last);
  1871. X}
  1872. X
  1873. X
  1874. X/*
  1875. X * Remove the element with the given index from a list, returning its value.
  1876. X */
  1877. Xvoid
  1878. Xremovelistmiddle(lp, index, vp)
  1879. X    LIST *lp;        /* list to have element removed */
  1880. X    long index;        /* list element to be removed */
  1881. X    VALUE *vp;        /* location of the value */
  1882. X{
  1883. X    LISTELEM *ep;        /* element being removed */
  1884. X
  1885. X    ep = NULL;
  1886. X    if ((index >= 0) && (index < lp->l_count))
  1887. X        ep = listelement(lp, index);
  1888. X    if (ep == NULL)
  1889. X        error("Index out of bounds for list deletion");
  1890. X    *vp = ep->e_value;
  1891. X    ep->e_value.v_type = V_NULL;
  1892. X    removelistelement(lp, ep);
  1893. X}
  1894. X
  1895. X
  1896. X/*
  1897. X * Remove an arbitrary element from a list.
  1898. X * The value contained in the element is freed.
  1899. X */
  1900. Xstatic void
  1901. Xremovelistelement(lp, ep)
  1902. X    register LIST *lp;        /* list header */
  1903. X    register LISTELEM *ep;        /* list element to remove */
  1904. X{
  1905. X    if ((ep == lp->l_cache) || ((ep != lp->l_first) && (ep != lp->l_last)))
  1906. X        lp->l_cache = NULL;
  1907. X    if (ep->e_next)
  1908. X        ep->e_next->e_prev = ep->e_prev;
  1909. X    if (ep->e_prev)
  1910. X        ep->e_prev->e_next = ep->e_next;
  1911. X    if (ep == lp->l_first) {
  1912. X        lp->l_first = ep->e_next;
  1913. X        lp->l_cacheindex--;
  1914. X    }
  1915. X    if (ep == lp->l_last)
  1916. X        lp->l_last = ep->e_prev;
  1917. X    lp->l_count--;
  1918. X    elemfree(ep);
  1919. X}
  1920. X
  1921. X
  1922. X/*
  1923. X * Search a list for the specified value starting at the specified index.
  1924. X * Returns the element number (zero based) of the found value, or -1 if
  1925. X * the value was not found.
  1926. X */
  1927. Xlong
  1928. Xlistsearch(lp, vp, index)
  1929. X    LIST *lp;
  1930. X    VALUE *vp;
  1931. X    long index;
  1932. X{
  1933. X    register LISTELEM *ep;
  1934. X
  1935. X    if (index < 0)
  1936. X        index = 0;
  1937. X    ep = listelement(lp, index);
  1938. X    while (ep) {
  1939. X        if (!comparevalue(&ep->e_value, vp)) {
  1940. X            lp->l_cache = ep;
  1941. X            lp->l_cacheindex = index;
  1942. X            return index;
  1943. X        }
  1944. X        ep = ep->e_next;
  1945. X        index++;
  1946. X    }
  1947. X    return -1;
  1948. X}
  1949. X
  1950. X
  1951. X/*
  1952. X * Search a list backwards for the specified value starting at the
  1953. X * specified index.  Returns the element number (zero based) of the
  1954. X * found value, or -1 if the value was not found.
  1955. X */
  1956. Xlong
  1957. Xlistrsearch(lp, vp, index)
  1958. X    LIST *lp;
  1959. X    VALUE *vp;
  1960. X    long index;
  1961. X{
  1962. X    register LISTELEM *ep;
  1963. X
  1964. X    if (index >= lp->l_count)
  1965. X        index = lp->l_count - 1;
  1966. X    ep = listelement(lp, index);
  1967. X    while (ep) {
  1968. X        if (!comparevalue(&ep->e_value, vp)) {
  1969. X            lp->l_cache = ep;
  1970. X            lp->l_cacheindex = index;
  1971. X            return index;
  1972. X        }
  1973. X        ep = ep->e_prev;
  1974. X        index--;
  1975. X    }
  1976. X    return -1;
  1977. X}
  1978. X
  1979. X
  1980. X/*
  1981. X * Index into a list and return the address for the value corresponding
  1982. X * to that index.  Returns NULL if the element does not exist.
  1983. X */
  1984. XVALUE *
  1985. Xlistindex(lp, index)
  1986. X    LIST *lp;        /* list to index into */
  1987. X    long index;        /* index of desired element */
  1988. X{
  1989. X    LISTELEM *ep;
  1990. X
  1991. X    ep = listelement(lp, index);
  1992. X    if (ep == NULL)
  1993. X        return NULL;
  1994. X    return &ep->e_value;
  1995. X}
  1996. X
  1997. X
  1998. X/*
  1999. X * Return the element at a specified index number of a list.
  2000. X * The list is indexed starting at zero, and negative indices
  2001. X * indicate to index from the end of the list.  This routine finds
  2002. X * the element by chaining through the list from the closest one
  2003. X * of the first, last, and cached elements.  Returns NULL if the
  2004. X * element does not exist.
  2005. X */
  2006. Xstatic LISTELEM *
  2007. Xlistelement(lp, index)
  2008. X    register LIST *lp;    /* list to index into */
  2009. X    long index;        /* index of desired element */
  2010. X{
  2011. X    register LISTELEM *ep;    /* current list element */
  2012. X    long dist;        /* distance to element */
  2013. X    long temp;        /* temporary distance */
  2014. X    BOOL forward;        /* TRUE if need to walk forwards */
  2015. X
  2016. X    if (index < 0)
  2017. X        index += lp->l_count;
  2018. X    if ((index < 0) || (index >= lp->l_count))
  2019. X        return NULL;
  2020. X    /*
  2021. X     * Check quick special cases first.
  2022. X     */
  2023. X    if (index == 0)
  2024. X        return lp->l_first;
  2025. X    if (index == 1)
  2026. X        return lp->l_first->e_next;
  2027. X    if (index == lp->l_count - 1)
  2028. X        return lp->l_last;
  2029. X    if ((index == lp->l_cacheindex) && lp->l_cache)
  2030. X        return lp->l_cache;
  2031. X    /*
  2032. X     * Calculate whether it is better to go forwards from
  2033. X     * the first element or backwards from the last element.
  2034. X     */
  2035. X    forward = ((index * 2) <= lp->l_count);
  2036. X    if (forward) {
  2037. X        dist = index;
  2038. X        ep = lp->l_first;
  2039. X    } else {
  2040. X        dist = (lp->l_count - 1) - index;
  2041. X        ep = lp->l_last;
  2042. X    }
  2043. X    /*
  2044. X     * Now see if we have a cached element and if so, whether or
  2045. X     * not the distance from it is better than the above distance.
  2046. X     */
  2047. X    if (lp->l_cache) {
  2048. X        temp = index - lp->l_cacheindex;
  2049. X        if ((temp >= 0) && (temp < dist)) {
  2050. X            dist = temp;
  2051. X            ep = lp->l_cache;
  2052. X            forward = TRUE;
  2053. X        }
  2054. X        if ((temp < 0) && (-temp < dist)) {
  2055. X            dist = -temp;
  2056. X            ep = lp->l_cache;
  2057. X            forward = FALSE;
  2058. X        }
  2059. X    }
  2060. X    /*
  2061. X     * Now walk forwards or backwards from the selected element
  2062. X     * until we reach the correct element.  Cache the location of
  2063. X     * the found element for future use.
  2064. X     */
  2065. X    if (forward) {
  2066. X        while (dist-- > 0)
  2067. X            ep = ep->e_next;
  2068. X    } else {
  2069. X        while (dist-- > 0)
  2070. X            ep = ep->e_prev;
  2071. X    }
  2072. X    lp->l_cache = ep;
  2073. X    lp->l_cacheindex = index;
  2074. X    return ep;
  2075. X}
  2076. X
  2077. X
  2078. X/*
  2079. X * Compare two lists to see if they are identical.
  2080. X * Returns TRUE if they are different.
  2081. X */
  2082. XBOOL
  2083. Xlistcmp(lp1, lp2)
  2084. X    LIST *lp1, *lp2;
  2085. X{
  2086. X    LISTELEM *e1, *e2;
  2087. X    long count;
  2088. X
  2089. X    if (lp1 == lp2)
  2090. X        return FALSE;
  2091. X    if (lp1->l_count != lp2->l_count)
  2092. X        return TRUE;
  2093. X    e1 = lp1->l_first;
  2094. X    e2 = lp2->l_first;
  2095. X    count = lp1->l_count;
  2096. X    while (count-- > 0) {
  2097. X        if (comparevalue(&e1->e_value, &e2->e_value))
  2098. X            return TRUE;
  2099. X        e1 = e1->e_next;
  2100. X        e2 = e2->e_next;
  2101. X    }
  2102. X    return FALSE;
  2103. X}
  2104. X
  2105. X
  2106. X/*
  2107. X * Copy a list
  2108. X */
  2109. XLIST *
  2110. Xlistcopy(oldlp)
  2111. X    LIST *oldlp;
  2112. X{
  2113. X    LIST *lp;
  2114. X    LISTELEM *oldep;
  2115. X
  2116. X    lp = listalloc();
  2117. X    oldep = oldlp->l_first;
  2118. X    while (oldep) {
  2119. X        insertlistlast(lp, &oldep->e_value);
  2120. X        oldep = oldep->e_next;
  2121. X    }
  2122. X    return lp;
  2123. X}
  2124. X
  2125. X
  2126. X/*
  2127. X * Allocate an element for a list.
  2128. X */
  2129. Xstatic LISTELEM *
  2130. Xelemalloc()
  2131. X{
  2132. X    LISTELEM *ep;
  2133. X
  2134. X    ep = (LISTELEM *) allocitem(&elementfreelist);
  2135. X    if (ep == NULL)
  2136. X        error("Cannot allocate list element");
  2137. X    ep->e_next = NULL;
  2138. X    ep->e_prev = NULL;
  2139. X    ep->e_value.v_type = V_NULL;
  2140. X    return ep;
  2141. X}
  2142. X
  2143. X
  2144. X/*
  2145. X * Free a list element, along with any contained value.
  2146. X */
  2147. Xstatic void
  2148. Xelemfree(ep)
  2149. X    LISTELEM *ep;
  2150. X{
  2151. X    if (ep->e_value.v_type != V_NULL)
  2152. X        freevalue(&ep->e_value);
  2153. X    freeitem(&elementfreelist, (FREEITEM *) ep);
  2154. X}
  2155. X
  2156. X
  2157. X/*
  2158. X * Allocate a new list header.
  2159. X */
  2160. XLIST *
  2161. Xlistalloc()
  2162. X{
  2163. X    register LIST *lp;
  2164. X
  2165. X    lp = (LIST *) allocitem(&headerfreelist);
  2166. X    if (lp == NULL)
  2167. X        error("Cannot allocate list header");
  2168. X    lp->l_first = NULL;
  2169. X    lp->l_last = NULL;
  2170. X    lp->l_cache = NULL;
  2171. X    lp->l_cacheindex = 0;
  2172. X    lp->l_count = 0;
  2173. X    return lp;
  2174. X}
  2175. X
  2176. X
  2177. X/*
  2178. X * Free a list header, along with all of its list elements.
  2179. X */
  2180. Xvoid
  2181. Xlistfree(lp)
  2182. X    register LIST *lp;
  2183. X{
  2184. X    register LISTELEM *ep;
  2185. X
  2186. X    while (lp->l_count-- > 0) {
  2187. X        ep = lp->l_first;
  2188. X        lp->l_first = ep->e_next;
  2189. X        elemfree(ep);
  2190. X    }
  2191. X    freeitem(&headerfreelist, (FREEITEM *) lp);
  2192. X}
  2193. X
  2194. X
  2195. X/*
  2196. X * Print out a list along with the specified number of its elements.
  2197. X * The elements are printed out in shortened form.
  2198. X */
  2199. Xvoid
  2200. Xlistprint(lp, maxprint)
  2201. X    LIST *lp;
  2202. X    long maxprint;
  2203. X{
  2204. X    long count;
  2205. X    long index;
  2206. X    LISTELEM *ep;
  2207. X
  2208. X    if (maxprint > lp->l_count)
  2209. X        maxprint = lp->l_count;
  2210. X    count = 0;
  2211. X    ep = lp->l_first;
  2212. X    index = lp->l_count;
  2213. X    while (index-- > 0) {
  2214. X        if ((ep->e_value.v_type != V_NUM) ||
  2215. X            (!qiszero(ep->e_value.v_num)))
  2216. X                count++;
  2217. X        ep = ep->e_next;
  2218. X    }
  2219. X    if (maxprint > 0)
  2220. X        math_str("\n");
  2221. X    math_fmt("list (%ld element%s, %ld nonzero)", lp->l_count,
  2222. X        ((lp->l_count == 1) ? "" : "s"), count);
  2223. X    if (maxprint <= 0)
  2224. X        return;
  2225. X
  2226. X    /*
  2227. X     * Walk through the first few list elements, printing their
  2228. X     * value in short and unambiguous format.
  2229. X     */
  2230. X    math_str(":\n");
  2231. X    ep = lp->l_first;
  2232. X    for (index = 0; index < maxprint; index++) {
  2233. X        math_fmt("  [[%ld]] = ", index);
  2234. X        printvalue(&ep->e_value, PRINT_SHORT | PRINT_UNAMBIG);
  2235. X        math_str("\n");
  2236. X        ep = ep->e_next;
  2237. X    }
  2238. X    if (maxprint < lp->l_count)
  2239. X        math_str("  ...\n");
  2240. X}
  2241. X
  2242. X/* END CODE */
  2243. END_OF_FILE
  2244. if test 11116 -ne `wc -c <'listfunc.c'`; then
  2245.     echo shar: \"'listfunc.c'\" unpacked with wrong size!
  2246. fi
  2247. # end of 'listfunc.c'
  2248. fi
  2249. if test -f 'qmod.c' -a "${1}" != "-c" ; then 
  2250.   echo shar: Will not clobber existing file \"'qmod.c'\"
  2251. else
  2252. echo shar: Extracting \"'qmod.c'\" \(10845 characters\)
  2253. sed "s/^X//" >'qmod.c' <<'END_OF_FILE'
  2254. X/*
  2255. X * Copyright (c) 1992 David I. Bell
  2256. X * Permission is granted to use, distribute, or modify this source,
  2257. X * provided that this copyright notice remains intact.
  2258. X *
  2259. X * Modular arithmetic routines for normal numbers, and also using
  2260. X * the faster REDC algorithm.
  2261. X */
  2262. X
  2263. X#include <stdio.h>
  2264. X#include "math.h"
  2265. X
  2266. X
  2267. X/*
  2268. X * Structure used for caching REDC information.
  2269. X */
  2270. Xtypedef struct    {
  2271. X    NUMBER    *num;        /* modulus being cached */
  2272. X    REDC    *redc;        /* REDC information for modulus */
  2273. X    long    age;        /* age counter for reallocation */
  2274. X} REDC_CACHE;
  2275. X
  2276. X
  2277. Xstatic long redc_age;            /* current age counter */
  2278. Xstatic REDC_CACHE redc_cache[MAXREDC];    /* cached REDC info */
  2279. X
  2280. X
  2281. Xstatic REDC *qfindredc();
  2282. X
  2283. X
  2284. X/*
  2285. X * Return the remainder when one number is divided by another.
  2286. X * The second argument cannot be negative.  The result is normalized
  2287. X * to lie in the range 0 to q2, and works for fractional values as:
  2288. X *    qmod(q1, q2) = q1 - (int(q1 / q2) * q2).
  2289. X */
  2290. XNUMBER *
  2291. Xqmod(q1, q2)
  2292. X    register NUMBER *q1, *q2;
  2293. X{
  2294. X    ZVALUE res;
  2295. X    NUMBER *q, *tmp;
  2296. X
  2297. X    if (qisneg(q2) || qiszero(q2))
  2298. X        error("Non-positive modulus");
  2299. X    if (qisint(q1) && qisint(q2)) {        /* easy case */
  2300. X        zmod(q1->num, q2->num, &res);
  2301. X        if (iszero(res)) {
  2302. X            freeh(res.v);
  2303. X            return qlink(&_qzero_);
  2304. X        }
  2305. X        if (isone(res)) {
  2306. X            freeh(res.v);
  2307. X            return qlink(&_qone_);
  2308. X        }
  2309. X        q = qalloc();
  2310. X        q->num = res;
  2311. X        return q;
  2312. X    }
  2313. X    q = qquo(q1, q2);
  2314. X    tmp = qmul(q, q2);
  2315. X    qfree(q);
  2316. X    q = qsub(q1, tmp);
  2317. X    qfree(tmp);
  2318. X    if (qisneg(q)) {
  2319. X        tmp = qadd(q2, q);
  2320. X        qfree(q);
  2321. X        q = tmp;
  2322. X    }
  2323. X    return q;
  2324. X}
  2325. X
  2326. X
  2327. X/*
  2328. X * Given two numbers (a and b), calculate the quotient (c) and remainder (d)
  2329. X * when a is divided by b.  This is defined so 0 <= d < b, and c is integral,
  2330. X * and a = b * c + d.  The results are returned indirectly through pointers.
  2331. X * This works for integers or fractions.  Returns whether or not there is a
  2332. X * remainder.  Examples:
  2333. X *    qquomod(11, 4, &x, &y) sets x to 2, y to 3, and returns TRUE.
  2334. X *    qquomod(-7, 3, &x, &y) sets x to -3, y to 2, and returns TRUE.
  2335. X */
  2336. XBOOL
  2337. Xqquomod(q1, q2, retqdiv, retqmod)
  2338. X    NUMBER *q1, *q2;        /* numbers to do quotient with */
  2339. X    NUMBER **retqdiv;        /* returned quotient */
  2340. X    NUMBER **retqmod;        /* returned modulo */
  2341. X{
  2342. X    NUMBER *qq, *qm, *tmp;
  2343. X
  2344. X    if (qisneg(q2) || qiszero(q2))
  2345. X        error("Non-positive modulus");
  2346. X
  2347. X    if (qisint(q1) && qisint(q2)) {        /* integer case */
  2348. X        qq = qalloc();
  2349. X        qm = qalloc();
  2350. X        zdiv(q1->num, q2->num, &qq->num, &qm->num);
  2351. X        if (!qisneg(q1) || qiszero(qm)) {
  2352. X            *retqdiv = qq;
  2353. X            *retqmod = qm;
  2354. X            return !qiszero(qm);
  2355. X        }
  2356. X
  2357. X        /*
  2358. X         * Need to fix up negative results.
  2359. X         */
  2360. X        tmp = qdec(qq);
  2361. X        qfree(qq);
  2362. X        qq = tmp;
  2363. X        tmp = qsub(q2, qm);
  2364. X        qfree(qm);
  2365. X        qm = tmp;
  2366. X        *retqdiv = qq;
  2367. X        *retqmod = qm;
  2368. X        return TRUE;
  2369. X    }
  2370. X
  2371. X    /*
  2372. X     * Fractional case.
  2373. X     */
  2374. X    qq = qquo(q1, q2);
  2375. X    tmp = qmul(qq, q2);
  2376. X    qm = qsub(q1, tmp);
  2377. X    qfree(tmp);
  2378. X    if (qisneg(qm)) {
  2379. X        tmp = qadd(qm, q2);
  2380. X        qfree(qm);
  2381. X        qm = tmp;
  2382. X        tmp = qdec(qq);
  2383. X        qfree(qq);
  2384. X        qq = tmp;
  2385. X    }
  2386. X    *retqdiv = qq;
  2387. X    *retqmod = qm;
  2388. X    return !qiszero(qm);
  2389. X}
  2390. X
  2391. X
  2392. X#if 0
  2393. X/*
  2394. X * Return the product of two integers modulo a third integer.
  2395. X * The result is in the range 0 to q3 - 1 inclusive.
  2396. X *    q4 = (q1 * q2) mod q3.
  2397. X */
  2398. XNUMBER *
  2399. Xqmulmod(q1, q2, q3)
  2400. X    NUMBER *q1, *q2, *q3;
  2401. X{
  2402. X    NUMBER *q;
  2403. X
  2404. X    if (qisneg(q3) || qiszero(q3))
  2405. X        error("Non-positive modulus");
  2406. X    if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
  2407. X        error("Non-integers for qmulmod");
  2408. X    if (qiszero(q1) || qiszero(q2) || qisunit(q3))
  2409. X        return qlink(&_qzero_);
  2410. X    q = qalloc();
  2411. X    zmulmod(q1->num, q2->num, q3->num, &q->num);
  2412. X    return q;
  2413. X}
  2414. X
  2415. X
  2416. X/*
  2417. X * Return the square of an integer modulo another integer.
  2418. X * The result is in the range 0 to q2 - 1 inclusive.
  2419. X *    q2 = (q1^2) mod q2.
  2420. X */
  2421. XNUMBER *
  2422. Xqsquaremod(q1, q2)
  2423. X    NUMBER *q1, *q2;
  2424. X{
  2425. X    NUMBER *q;
  2426. X
  2427. X    if (qisneg(q2) || qiszero(q2))
  2428. X        error("Non-positive modulus");
  2429. X    if (qisfrac(q1) || qisfrac(q2))
  2430. X        error("Non-integers for qsquaremod");
  2431. X    if (qiszero(q1) || qisunit(q2))
  2432. X        return qlink(&_qzero_);
  2433. X    if (qisunit(q1))
  2434. X        return qlink(&_qone_);
  2435. X    q = qalloc();
  2436. X    zsquaremod(q1->num, q2->num, &q->num);
  2437. X    return q;
  2438. X}
  2439. X
  2440. X
  2441. X/*
  2442. X * Return the sum of two integers modulo a third integer.
  2443. X * The result is in the range 0 to q3 - 1 inclusive.
  2444. X *    q4 = (q1 + q2) mod q3.
  2445. X */
  2446. XNUMBER *
  2447. Xqaddmod(q1, q2, q3)
  2448. X    NUMBER *q1, *q2, *q3;
  2449. X{
  2450. X    NUMBER *q;
  2451. X
  2452. X    if (qisneg(q3) || qiszero(q3))
  2453. X        error("Non-positive modulus");
  2454. X    if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
  2455. X        error("Non-integers for qaddmod");
  2456. X    q = qalloc();
  2457. X    zaddmod(q1->num, q2->num, q3->num, &q->num);
  2458. X    return q;
  2459. X}
  2460. X
  2461. X
  2462. X/*
  2463. X * Return the difference of two integers modulo a third integer.
  2464. X * The result is in the range 0 to q3 - 1 inclusive.
  2465. X *    q4 = (q1 - q2) mod q3.
  2466. X */
  2467. XNUMBER *
  2468. Xqsubmod(q1, q2, q3)
  2469. X    NUMBER *q1, *q2, *q3;
  2470. X{
  2471. X    NUMBER *q;
  2472. X
  2473. X    if (qisneg(q3) || qiszero(q3))
  2474. X        error("Non-positive modulus");
  2475. X    if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
  2476. X        error("Non-integers for qsubmod");
  2477. X    if (q1 == q2)
  2478. X        return qlink(&_qzero_);
  2479. X    q = qalloc();
  2480. X    zsubmod(q1->num, q2->num, q3->num, &q->num);
  2481. X    return q;
  2482. X}
  2483. X
  2484. X
  2485. X/*
  2486. X * Return the negative of an integer modulo another integer.
  2487. X * The result is in the range 0 to q2 - 1 inclusive.
  2488. X *    q2 = (-q1) mod q2.
  2489. X */
  2490. XNUMBER *
  2491. Xqnegmod(q1, q2)
  2492. X    NUMBER *q1, *q2;
  2493. X{
  2494. X    NUMBER *q;
  2495. X
  2496. X    if (qisneg(q2) || qiszero(q2))
  2497. X        error("Non-positive modulus");
  2498. X    if (qisfrac(q1) || qisfrac(q2))
  2499. X        error("Non-integers for qnegmod");
  2500. X    if (qiszero(q1) || qisunit(q2))
  2501. X        return qlink(&_qzero_);
  2502. X    q = qalloc();
  2503. X    znegmod(q1->num, q2->num, &q->num);
  2504. X    return q;
  2505. X}
  2506. X#endif
  2507. X
  2508. X
  2509. X/*
  2510. X * Return the integer congruent to an integer whose absolute value is smallest.
  2511. X * This is a unique integer in the range int((q2-1)/2 to int(q2/2), inclusive.
  2512. X * For example, for a modulus of 7, returned values are [-3, 3], and for a
  2513. X * modulus of 8, returned values are [-3, 4].
  2514. X */
  2515. XNUMBER *
  2516. Xqminmod(q1, q2)
  2517. X    NUMBER *q1, *q2;
  2518. X{
  2519. X    NUMBER *q;
  2520. X
  2521. X    if (qisneg(q2) || qiszero(q2))
  2522. X        error("Non-positive modulus");
  2523. X    if (qisfrac(q1) || qisfrac(q2))
  2524. X        error("Non-integers for qminmod");
  2525. X    if (qiszero(q1) || (q1->num.len < q2->num.len - 1))
  2526. X        return qlink(q1);
  2527. X    q = qalloc();
  2528. X    zminmod(q1->num, q2->num, &q->num);
  2529. X    return q;
  2530. X}
  2531. X
  2532. X
  2533. X/*
  2534. X * Return whether or not two integers are congruent modulo a third integer.
  2535. X * Returns TRUE if the numbers are not congruent, and FALSE if they are.
  2536. X */
  2537. XBOOL
  2538. Xqcmpmod(q1, q2, q3)
  2539. X    NUMBER *q1, *q2, *q3;
  2540. X{
  2541. X    if (qisneg(q3) || qiszero(q3))
  2542. X        error("Non-positive modulus");
  2543. X    if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3))
  2544. X        error("Non-integers for qcmpmod");
  2545. X    if (q1 == q2)
  2546. X        return FALSE;
  2547. X    return zcmpmod(q1->num, q2->num, q3->num);
  2548. X}
  2549. X
  2550. X
  2551. X/*
  2552. X * Convert an integer into REDC format for use in faster modular arithmetic.
  2553. X * The number can be negative or out of modulus range.
  2554. X */
  2555. XNUMBER *
  2556. Xqredcin(q1, q2)
  2557. X    NUMBER *q1;        /* number to convert into REDC format */
  2558. X    NUMBER *q2;        /* modulus */
  2559. X{
  2560. X    REDC *rp;        /* REDC information */
  2561. X    NUMBER *r;        /* result */
  2562. X
  2563. X    if (qisfrac(q1))
  2564. X        error("Non-integer for qredcin");
  2565. X    rp = qfindredc(q2);
  2566. X    if (qiszero(q1))
  2567. X        return qlink(&_qzero_);
  2568. X    r = qalloc();
  2569. X    zredcencode(rp, q1->num, &r->num);
  2570. X    return r;
  2571. X}
  2572. X
  2573. X
  2574. X/*
  2575. X * Convert a REDC format number back into a normal integer.
  2576. X * The resulting number is in the range 0 to the modulus - 1.
  2577. X */
  2578. XNUMBER *
  2579. Xqredcout(q1, q2)
  2580. X    NUMBER *q1;        /* number to convert out of REDC format */
  2581. X    NUMBER *q2;        /* modulus */
  2582. X{
  2583. X    REDC *rp;        /* REDC information */
  2584. X    NUMBER *r;        /* result */
  2585. X
  2586. X    if (qisfrac(q1) || qisneg(q1))
  2587. X        error("Non-positive integer required for qredcout");
  2588. X    rp = qfindredc(q2);
  2589. X    if (qiszero(q1))
  2590. X        return qlink(&_qzero_);
  2591. X    r = qalloc();
  2592. X    zredcdecode(rp, q1->num, &r->num);
  2593. X    if (isunit(r->num)) {
  2594. X        qfree(r);
  2595. X        r = qlink(&_qone_);
  2596. X    }
  2597. X    return r;
  2598. X}
  2599. X
  2600. X
  2601. X/*
  2602. X * Multiply two REDC format numbers together producing a REDC format result.
  2603. X * This multiplication is done modulo the specified modulus.
  2604. X */
  2605. XNUMBER *
  2606. Xqredcmul(q1, q2, q3)
  2607. X    NUMBER *q1, *q2;    /* REDC numbers to be multiplied */
  2608. X    NUMBER *q3;        /* modulus */
  2609. X{
  2610. X    REDC *rp;        /* REDC information */
  2611. X    NUMBER *r;        /* result */
  2612. X
  2613. X    if (qisfrac(q1) || qisneg(q1) || qisfrac(q2) || qisneg(q2))
  2614. X        error("Non-positive integers required for qredcmul");
  2615. X    rp = qfindredc(q3);
  2616. X    if (qiszero(q1) || qiszero(q2))
  2617. X        return qlink(&_qzero_);
  2618. X    r = qalloc();
  2619. X    zredcmul(rp, q1->num, q2->num, &r->num);
  2620. X    return r;
  2621. X}
  2622. X
  2623. X
  2624. X/*
  2625. X * Square a REDC format number to produce a REDC format result.
  2626. X * This squaring is done modulo the specified modulus.
  2627. X */
  2628. XNUMBER *
  2629. Xqredcsquare(q1, q2)
  2630. X    NUMBER *q1;        /* REDC number to be squared */
  2631. X    NUMBER *q2;        /* modulus */
  2632. X{
  2633. X    REDC *rp;        /* REDC information */
  2634. X    NUMBER *r;        /* result */
  2635. X
  2636. X    if (qisfrac(q1) || qisneg(q1))
  2637. X        error("Non-positive integer required for qredcsquare");
  2638. X    rp = qfindredc(q2);
  2639. X    if (qiszero(q1))
  2640. X        return qlink(&_qzero_);
  2641. X    r = qalloc();
  2642. X    zredcsquare(rp, q1->num, &r->num);
  2643. X    return r;
  2644. X}
  2645. X
  2646. X
  2647. X/*
  2648. X * Raise a REDC format number to the indicated power producing a REDC
  2649. X * format result.  This is done modulo the specified modulus.  The
  2650. X * power to be raised to is a normal number.
  2651. X */
  2652. XNUMBER *
  2653. Xqredcpower(q1, q2, q3)
  2654. X    NUMBER *q1;        /* REDC number to be raised */
  2655. X    NUMBER *q2;        /* power to be raised to */
  2656. X    NUMBER *q3;        /* modulus */
  2657. X{
  2658. X    REDC *rp;        /* REDC information */
  2659. X    NUMBER *r;        /* result */
  2660. X
  2661. X    if (qisfrac(q1) || qisneg(q1) || qisfrac(q2) || qisneg(q2))
  2662. X        error("Non-positive integers required for qredcpower");
  2663. X    rp = qfindredc(q3);
  2664. X    if (qiszero(q1) || qisunit(q3))
  2665. X        return qlink(&_qzero_);
  2666. X    r = qalloc();
  2667. X    zredcpower(rp, q1->num, q2->num, &r->num);
  2668. X    return r;
  2669. X}
  2670. X
  2671. X
  2672. X/*
  2673. X * Search for and return the REDC information for the specified number.
  2674. X * The information is cached into a local table so that future calls
  2675. X * for this information will be quick.  If the table fills up, then
  2676. X * the oldest cached entry is reused.
  2677. X */
  2678. Xstatic REDC *
  2679. Xqfindredc(q)
  2680. X    NUMBER *q;        /* modulus to find REDC information of */
  2681. X{
  2682. X    register REDC_CACHE *rcp;
  2683. X    REDC_CACHE *bestrcp;
  2684. X
  2685. X    /*
  2686. X     * First try for an exact pointer match in the table.
  2687. X     */
  2688. X    for (rcp = redc_cache; rcp < &redc_cache[MAXREDC]; rcp++) {
  2689. X        if (q == rcp->num) {
  2690. X            rcp->age = ++redc_age;
  2691. X            return rcp->redc;
  2692. X        }
  2693. X    }
  2694. X
  2695. X    /*
  2696. X     * Search the table again looking for a value which matches.
  2697. X     */
  2698. X    for (rcp = redc_cache; rcp < &redc_cache[MAXREDC]; rcp++) {
  2699. X        if (rcp->age && (qcmp(q, rcp->num) == 0)) {
  2700. X            rcp->age = ++redc_age;
  2701. X            return rcp->redc;
  2702. X        }
  2703. X    }
  2704. X
  2705. X    /*
  2706. X     * Must invalidate an existing entry in the table.
  2707. X     * Find the oldest (or first unused) entry.
  2708. X     * But first make sure the modulus will be reasonable.
  2709. X     */
  2710. X    if (qisfrac(q) || qiseven(q) || qisneg(q))
  2711. X        error("REDC modulus must be positive odd integer");
  2712. X
  2713. X    bestrcp = NULL;
  2714. X    for (rcp = redc_cache; rcp < &redc_cache[MAXREDC]; rcp++) {
  2715. X        if ((bestrcp == NULL) || (rcp->age < bestrcp->age))
  2716. X            bestrcp = rcp;
  2717. X    }
  2718. X
  2719. X    /*
  2720. X     * Found the best entry.
  2721. X     * Free the old information for the entry if necessary,
  2722. X     * then initialize it.
  2723. X     */
  2724. X    rcp = bestrcp;
  2725. X    if (rcp->age) {
  2726. X        rcp->age = 0;
  2727. X        qfree(rcp->num);
  2728. X        zredcfree(rcp->redc);
  2729. X    }
  2730. X
  2731. X    rcp->redc = zredcalloc(q->num);
  2732. X    rcp->num = qlink(q);
  2733. X    rcp->age = ++redc_age;
  2734. X    return rcp->redc;
  2735. X}
  2736. X
  2737. X/* END CODE */
  2738. END_OF_FILE
  2739. if test 10845 -ne `wc -c <'qmod.c'`; then
  2740.     echo shar: \"'qmod.c'\" unpacked with wrong size!
  2741. fi
  2742. # end of 'qmod.c'
  2743. fi
  2744. echo shar: End of archive 5 \(of 21\).
  2745. cp /dev/null ark5isdone
  2746. MISSING=""
  2747. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  2748.     if test ! -f ark${I}isdone ; then
  2749.     MISSING="${MISSING} ${I}"
  2750.     fi
  2751. done
  2752. if test "${MISSING}" = "" ; then
  2753.     echo You have unpacked all 21 archives.
  2754.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2755. else
  2756.     echo You still need to unpack the following archives:
  2757.     echo "        " ${MISSING}
  2758. fi
  2759. ##  End of shell archive.
  2760. exit 0
  2761.