3 * $Id: mpx.c,v 1.3 1999/11/13 01:57:31 mdw Exp $
5 * Low-level multiprecision arithmetic
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.3 1999/11/13 01:57:31 mdw
34 * Remove stray debugging code.
36 * Revision 1.2 1999/11/13 01:50:59 mdw
37 * Multiprecision routines finished and tested.
39 * Revision 1.1 1999/09/03 08:41:12 mdw
44 /*----- Header files ------------------------------------------------------*/
51 #include <mLib/bits.h>
56 /*----- Loading and storing -----------------------------------------------*/
58 /* --- @mpx_storel@ --- *
60 * Arguments: @const mpw *v, *vl@ = base and limit of source vector
61 * @void *pp@ = pointer to octet array
62 * @size_t sz@ = size of octet array
66 * Use: Stores an MP in an octet array, least significant octet
67 * first. High-end octets are silently discarded if there
68 * isn't enough space for them.
71 void mpx_storel(const mpw *v, const mpw *vl, void *pp, size_t sz)
74 octet *p = pp, *q = p + sz;
84 *p++ = U8(w | n << bits);
96 /* --- @mpx_loadl@ --- *
98 * Arguments: @mpw *v, *vl@ = base and limit of destination vector
99 * @const void *pp@ = pointer to octet array
100 * @size_t sz@ = size of octet array
104 * Use: Loads an MP in an octet array, least significant octet
105 * first. High-end octets are ignored if there isn't enough
109 void mpx_loadl(mpw *v, mpw *vl, const void *pp, size_t sz)
113 const octet *p = pp, *q = p + sz;
122 if (bits >= MPW_BITS) {
124 w = n >> (MPW_BITS - bits + 8);
134 /* --- @mpx_storeb@ --- *
136 * Arguments: @const mpw *v, *vl@ = base and limit of source vector
137 * @void *pp@ = pointer to octet array
138 * @size_t sz@ = size of octet array
142 * Use: Stores an MP in an octet array, most significant octet
143 * first. High-end octets are silently discarded if there
144 * isn't enough space for them.
147 void mpx_storeb(const mpw *v, const mpw *vl, void *pp, size_t sz)
150 octet *p = pp, *q = p + sz;
160 *--q = U8(w | n << bits);
162 bits += MPW_BITS - 8;
172 /* --- @mpx_loadb@ --- *
174 * Arguments: @mpw *v, *vl@ = base and limit of destination vector
175 * @const void *pp@ = pointer to octet array
176 * @size_t sz@ = size of octet array
180 * Use: Loads an MP in an octet array, most significant octet
181 * first. High-end octets are ignored if there isn't enough
185 void mpx_loadb(mpw *v, mpw *vl, const void *pp, size_t sz)
189 const octet *p = pp, *q = p + sz;
198 if (bits >= MPW_BITS) {
200 w = n >> (MPW_BITS - bits + 8);
210 /*----- Logical shifting --------------------------------------------------*/
212 /* --- @mpx_lsl@ --- *
214 * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
215 * @const mpw *av, *avl@ = source vector base and limit
216 * @size_t n@ = number of bit positions to shift by
220 * Use: Performs a logical shift left operation on an integer.
223 void mpx_lsl(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n)
228 /* --- Trivial special case --- */
231 MPX_COPY(dv, dvl, av, avl);
233 /* --- Single bit shifting --- */
242 *dv++ = MPW((t << 1) | w);
243 w = t >> (MPW_BITS - 1);
252 /* --- Break out word and bit shifts for more sophisticated work --- */
257 /* --- Handle a shift by a multiple of the word size --- */
260 MPX_COPY(dv + nw, dvl, av, avl);
261 memset(dv, 0, MPWS(nw));
264 /* --- And finally the difficult case --- *
266 * This is a little convoluted, because I have to start from the end and
267 * work backwards to avoid overwriting the source, if they're both the same
273 size_t nr = MPW_BITS - nb;
274 size_t dvn = dvl - dv;
275 size_t avn = avl - av;
282 if (dvn > avn + nw) {
283 size_t off = avn + nw + 1;
284 MPX_ZERO(dv + off, dvl);
294 *--dvl = (t >> nr) | w;
305 /* --- @mpx_lsr@ --- *
307 * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
308 * @const mpw *av, *avl@ = source vector base and limit
309 * @size_t n@ = number of bit positions to shift by
313 * Use: Performs a logical shift right operation on an integer.
316 void mpx_lsr(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n)
321 /* --- Trivial special case --- */
324 MPX_COPY(dv, dvl, av, avl);
326 /* --- Single bit shifting --- */
335 *dv++ = MPW((t << (MPW_BITS - 1)) | w);
345 /* --- Break out word and bit shifts for more sophisticated work --- */
350 /* --- Handle a shift by a multiple of the word size --- */
353 MPX_COPY(dv, dvl, av + nw, avl);
355 /* --- And finally the difficult case --- */
359 size_t nr = MPW_BITS - nb;
368 *dv++ = MPW((w >> nb) | (t << nr));
372 *dv++ = MPW(w >> nb);
380 /*----- Unsigned arithmetic -----------------------------------------------*/
382 /* --- @mpx_ucmp@ --- *
384 * Arguments: @const mpw *av, *avl@ = first argument vector base and limit
385 * @const mpw *bv, *bvl@ = second argument vector base and limit
387 * Returns: Less than, equal to, or greater than zero depending on
388 * whether @a@ is less than, equal to or greater than @b@,
391 * Use: Performs an unsigned integer comparison.
394 int mpx_ucmp(const mpw *av, const mpw *avl, const mpw *bv, const mpw *bvl)
399 if (avl - av > bvl - bv)
401 else if (avl - av < bvl - bv)
403 else while (avl > av) {
404 mpw a = *--avl, b = *--bvl;
413 /* --- @mpx_uadd@ --- *
415 * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
416 * @const mpw *av, *avl@ = first addend vector base and limit
417 * @const mpw *bv, *bvl@ = second addend vector base and limit
421 * Use: Performs unsigned integer addition. If the result overflows
422 * the destination vector, high-order bits are discarded. This
423 * means that two's complement addition happens more or less for
424 * free, although that's more a side-effect than anything else.
425 * The result vector may be equal to either or both source
426 * vectors, but may not otherwise overlap them.
429 void mpx_uadd(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
430 const mpw *bv, const mpw *bvl)
434 while (av < avl || bv < bvl) {
439 a = (av < avl) ? *av++ : 0;
440 b = (bv < bvl) ? *bv++ : 0;
441 x = (mpd)a + (mpd)b + c;
451 /* --- @mpx_usub@ --- *
453 * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
454 * @const mpw *av, *avl@ = first argument vector base and limit
455 * @const mpw *bv, *bvl@ = second argument vector base and limit
459 * Use: Performs unsigned integer subtraction. If the result
460 * overflows the destination vector, high-order bits are
461 * discarded. This means that two's complement subtraction
462 * happens more or less for free, althuogh that's more a side-
463 * effect than anything else. The result vector may be equal to
464 * either or both source vectors, but may not otherwise overlap
468 void mpx_usub(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
469 const mpw *bv, const mpw *bvl)
473 while (av < avl || bv < bvl) {
478 a = (av < avl) ? *av++ : 0;
479 b = (bv < bvl) ? *bv++ : 0;
480 x = (mpd)a - (mpd)b - c;
493 /* --- @mpx_umul@ --- *
495 * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
496 * @const mpw *av, *avl@ = multiplicand vector base and limit
497 * @const mpw *bv, *bvl@ = multiplier vector base and limit
501 * Use: Performs unsigned integer multiplication. If the result
502 * overflows the desination vector, high-order bits are
503 * discarded. The result vector may not overlap the argument
504 * vectors in any way.
507 void mpx_umul(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
508 const mpw *bv, const mpw *bvl)
510 /* --- This is probably worthwhile on a multiply --- */
515 /* --- Deal with a multiply by zero --- */
522 /* --- Do the initial multiply and initialize the accumulator --- */
524 MPX_UMULN(dv, dvl, av, avl, *bv++);
526 /* --- Do the remaining multiply/accumulates --- */
528 while (dv < dvl && bv < bvl) {
538 x = (mpd)*dvv + (mpd)m * (mpd)*avv++ + c;
542 MPX_UADDN(dvv, dvl, c);
547 /* --- @mpx_usqr@ --- *
549 * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
550 * @const mpw *av, *av@ = source vector base and limit
554 * Use: Performs unsigned integer squaring. The result vector must
555 * not overlap the source vector in any way.
558 void mpx_usqr(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl)
562 /* --- Main loop --- */
570 /* --- Stop if I've run out of destination --- */
575 /* --- Work out the square at this point in the proceedings --- */
578 mpd x = (mpd)a * (mpd)a + *dvv;
580 c = MPW(x >> MPW_BITS);
583 /* --- Now fix up the rest of the vector upwards --- */
586 while (dvv < dvl && avv < avl) {
587 mpd x = (mpd)a * (mpd)*avv++;
588 mpd y = ((x << 1) & MPW_MAX) + c + *dvv;
589 c = (x >> (MPW_BITS - 1)) + (y >> MPW_BITS);
592 while (dvv < dvl && c) {
598 /* --- Get ready for the next round --- */
605 /* --- @mpx_udiv@ --- *
607 * Arguments: @mpw *qv, *qvl@ = quotient vector base and limit
608 * @mpw *rv, *rvl@ = dividend/remainder vector base and limit
609 * @const mpw *dv, *dvl@ = divisor vector base and limit
610 * @mpw *sv, *svl@ = scratch workspace
614 * Use: Performs unsigned integer division. If the result overflows
615 * the quotient vector, high-order bits are discarded. (Clearly
616 * the remainder vector can't overflow.) The various vectors
617 * may not overlap in any way. Yes, I know it's a bit odd
618 * requiring the dividend to be in the result position but it
619 * does make some sense really. The remainder must have
620 * headroom for at least two extra words. The scratch space
621 * must be at least two words larger than twice the size of the
625 void mpx_udiv(mpw *qv, mpw *qvl, mpw *rv, mpw *rvl,
626 const mpw *dv, const mpw *dvl,
633 /* --- Initialize the quotient --- */
637 /* --- Perform some sanity checks --- */
640 assert(((void)"division by zero in mpx_udiv", dv < dvl));
642 /* --- Normalize the divisor --- *
644 * The algorithm requires that the divisor be at least two digits long.
645 * This is easy to fix.
652 for (b = MPW_BITS / 2; b; b >>= 1) {
653 if (d < (MPW_MAX >> b)) {
662 /* --- Normalize the dividend/remainder to match --- */
665 mpw *svvl = sv + (dvl - dv) + 1;
666 mpx_lsl(rv, rvl, rv, rvl, norm);
667 mpx_lsl(sv, svvl, dv, dvl, norm);
678 /* --- Work out the relative scales --- */
681 size_t rvn = rvl - rv;
682 size_t dvn = dvl - dv;
684 /* --- If the divisor is clearly larger, notice this --- */
687 mpx_lsr(rv, rvl, rv, rvl, norm);
694 /* --- Calculate the most significant quotient digit --- *
696 * Because the divisor has its top bit set, this can only happen once. The
697 * pointer arithmetic is a little contorted, to make sure that the
698 * behaviour is defined.
701 if (MPX_UCMP(rv + scale, rvl, >=, dv, dvl)) {
702 mpx_usub(rv + scale, rvl, rv + scale, rvl, dv, dvl);
703 if (qvl - qv > scale)
707 /* --- Now for the main loop --- */
716 /* --- Get an estimate for the next quotient digit --- */
723 rh = ((mpd)r << MPW_BITS) | rr;
729 /* --- Refine the estimate --- */
733 mpd yl = (mpd)dd * q;
736 yh += yl >> MPW_BITS;
740 while (yh > rh || (yh == rh && yl > rrr)) {
751 /* --- Remove a chunk from the dividend --- */
758 /* --- Calculate the size of the chunk --- */
760 for (svv = sv, dvv = dv; dvv < dvl; svv++, dvv++) {
761 mpd x = (mpd)*dvv * (mpd)q + c;
768 /* --- Now make sure that we can cope with the difference --- *
770 * Take advantage of the fact that subtraction works two's-
774 mpx_usub(rv + scale, rvl, rv + scale, rvl, sv, svv);
775 if (rvl[-1] > MPW_MAX / 2) {
776 mpx_uadd(rv + scale, rvl, rv + scale, rvl, dv, dvl);
781 /* --- Done for another iteration --- */
783 if (qvl - qv > scale)
790 /* --- Now fiddle with unnormalizing and things --- */
792 mpx_lsr(rv, rvl, rv, rvl, norm);
795 /*----- That's all, folks -------------------------------------------------*/