mpi.c revision 31de2854
1/*
2 * Copyright (c) 2002 by The XFree86 Project, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 *
22 * Except as contained in this notice, the name of the XFree86 Project shall
23 * not be used in advertising or otherwise to promote the sale, use or other
24 * dealings in this Software without prior written authorization from the
25 * XFree86 Project.
26 *
27 * Author: Paulo César Pereira de Andrade
28 */
29
30/* $XFree86: xc/programs/xedit/lisp/mp/mpi.c,v 1.12 2002/11/20 07:44:43 paulo Exp $ */
31
32#include "mp.h"
33
34#ifdef __UNIXOS2__
35# define finite(x) isfinite(x)
36#endif
37
38/*
39 * Prototypes
40 */
41	/* do the hard work of mpi_add and mpi_sub */
42static void mpi_addsub(mpi *rop, mpi *op1, mpi *op2, int sub);
43
44	/* logical functions implementation */
45static INLINE BNS mpi_logic(BNS op1, BNS op2, BNS op);
46static void mpi_log(mpi *rop, mpi *op1, mpi *op2,  BNS op);
47
48	/* internal mpi_seti, whithout memory allocation */
49static void _mpi_seti(mpi *rop, long si);
50
51/*
52 * Initialization
53 */
54static BNS onedig[1] = { 1 };
55static mpi mpone = { 1, 1, 0, (BNS*)&onedig };
56
57/*
58 * Implementation
59 */
60void
61mpi_init(mpi *op)
62{
63    op->sign = 0;
64    op->size = op->alloc = 1;
65    op->digs = mp_malloc(sizeof(BNS));
66    op->digs[0] = 0;
67}
68
69void
70mpi_clear(mpi *op)
71{
72    op->sign = 0;
73    op->size = op->alloc = 0;
74    mp_free(op->digs);
75}
76
77void
78mpi_set(mpi *rop, mpi *op)
79{
80    if (rop != op) {
81	if (rop->alloc < op->size) {
82	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op->size);
83	    rop->alloc = op->size;
84	}
85	rop->size = op->size;
86	memcpy(rop->digs, op->digs, sizeof(BNS) * op->size);
87	rop->sign = op->sign;
88    }
89}
90
91void
92mpi_seti(mpi *rop, long si)
93{
94    unsigned long ui;
95    int sign = si < 0;
96    int size;
97
98    if (si == MINSLONG) {
99	ui = MINSLONG;
100	size = 2;
101    }
102    else {
103	if (sign)
104	    ui = -si;
105	else
106	    ui = si;
107	if (ui < CARRY)
108	    size = 1;
109	else
110	    size = 2;
111    }
112
113    if (rop->alloc < size) {
114	rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size);
115	rop->alloc = size;
116    }
117    rop->size = size;
118
119    /* store data in small mp integer */
120    rop->digs[0] = (BNS)ui;
121    if (size > 1)
122	rop->digs[1] = (BNS)(ui >> BNSBITS);
123    rop->size = size;
124
125    /* adjust result sign */
126    rop->sign = sign;
127}
128
129static void
130_mpi_seti(mpi *rop, long si)
131{
132    unsigned long ui;
133    int sign = si < 0;
134    int size;
135
136    if (si == MINSLONG) {
137	ui = MINSLONG;
138	size = 2;
139    }
140    else {
141	if (sign)
142	    ui = -si;
143	else
144	    ui = si;
145	if (ui < CARRY)
146	    size = 1;
147	else
148	    size = 2;
149    }
150
151    rop->digs[0] = (BNS)ui;
152    if (size > 1)
153	rop->digs[1] = (BNS)(ui >> BNSBITS);
154    rop->size = size;
155
156    rop->sign = sign;
157}
158
159void
160mpi_setd(mpi *rop, double d)
161{
162    long i;
163    double mantissa;
164    int shift, exponent;
165    BNI size;
166
167    if (isnan(d))
168	d = 0.0;
169    else if (!finite(d))
170	d = copysign(1.0, d) * DBL_MAX;
171
172    /* check if number is larger than 1 */
173    if (fabs(d) < 1.0) {
174	rop->digs[0] = 0;
175	rop->size = 1;
176	rop->sign = d < 0.0;
177
178	return;
179    }
180
181    mantissa = frexp(d, &exponent);
182    if (mantissa < 0)
183	mantissa = -mantissa;
184
185    size = (exponent + (BNSBITS - 1)) / BNSBITS;
186    shift = BNSBITS - (exponent & (BNSBITS - 1));
187
188    /* adjust amount of memory */
189    if (rop->alloc < size) {
190	rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size);
191	rop->alloc = size;
192    }
193    rop->size = size;
194
195    /* adjust the exponent */
196    if (shift < BNSBITS)
197	mantissa = ldexp(mantissa, -shift);
198
199    /* convert double */
200    for (i = size - 1; i >= 0 && mantissa != 0.0; i--) {
201	mantissa = ldexp(mantissa, BNSBITS);
202	rop->digs[i] = (BNS)mantissa;
203	mantissa -= rop->digs[i];
204    }
205    for (; i >= 0; i--)
206	rop->digs[i] = 0;
207
208    /* normalize */
209    if (size > 1 && rop->digs[size - 1] == 0)
210	--rop->size;
211
212    rop->sign = d < 0.0;
213}
214
215/* how many BNS in the given base, log(base) / log(CARRY) */
216#ifdef LONG64
217static double str_bases[37] = {
218    0.0000000000000000, 0.0000000000000000, 0.0312500000000000,
219    0.0495300781475362, 0.0625000000000000, 0.0725602529652301,
220    0.0807800781475362, 0.0877298413143002, 0.0937500000000000,
221    0.0990601562950723, 0.1038102529652301, 0.1081072380824156,
222    0.1120300781475362, 0.1156387411919092, 0.1189798413143002,
223    0.1220903311127662, 0.1250000000000000, 0.1277332137890731,
224    0.1303101562950723, 0.1327477347951120, 0.1350602529652300,
225    0.1372599194618363, 0.1393572380824156, 0.1413613111267817,
226    0.1432800781475362, 0.1451205059304602, 0.1468887411919092,
227    0.1485902344426084, 0.1502298413143002, 0.1518119060977367,
228    0.1533403311127662, 0.1548186346995899, 0.1562500000000000,
229    0.1576373162299517, 0.1589832137890731, 0.1602900942795302,
230    0.1615601562950723,
231};
232#else
233static double str_bases[37] = {
234    0.0000000000000000, 0.0000000000000000, 0.0625000000000000,
235    0.0990601562950723, 0.1250000000000000, 0.1451205059304602,
236    0.1615601562950723, 0.1754596826286003, 0.1875000000000000,
237    0.1981203125901446, 0.2076205059304602, 0.2162144761648311,
238    0.2240601562950723, 0.2312774823838183, 0.2379596826286003,
239    0.2441806622255325, 0.2500000000000000, 0.2554664275781462,
240    0.2606203125901445, 0.2654954695902241, 0.2701205059304602,
241    0.2745198389236725, 0.2787144761648311, 0.2827226222535633,
242    0.2865601562950723, 0.2902410118609203, 0.2937774823838183,
243    0.2971804688852168, 0.3004596826286003, 0.3036238121954733,
244    0.3066806622255324, 0.3096372693991797, 0.3125000000000000,
245    0.3152746324599034, 0.3179664275781462, 0.3205801885590604,
246    0.3231203125901446,
247};
248#endif
249
250void
251mpi_setstr(mpi *rop, char *str, int base)
252{
253    long i;			/* counter */
254    int sign;			/* result sign */
255    BNI carry;			/* carry value */
256    BNI value;			/* temporary value */
257    BNI size;			/* size of result */
258    char *ptr;			/* end of valid input */
259
260    /* initialization */
261    sign = 0;
262    carry = 0;
263
264    /* skip leading spaces */
265    while (isspace(*str))
266	++str;
267
268    /* check if sign supplied */
269    if (*str == '-') {
270	sign = 1;
271	++str;
272    }
273    else if (*str == '+')
274	++str;
275
276    /* skip leading zeros */
277    while (*str == '0')
278	++str;
279
280    ptr = str;
281    while (*ptr) {
282	if (*ptr >= '0' && *ptr <= '9') {
283	    if (*ptr - '0' >= base)
284		break;
285	}
286	else if (*ptr >= 'A' && *ptr <= 'Z') {
287	    if (*ptr - 'A' + 10 >= base)
288		break;
289	}
290	else if (*ptr >= 'a' && *ptr <= 'z') {
291	    if (*ptr - 'a' + 10 >= base)
292		break;
293	}
294	else
295	    break;
296	++ptr;
297    }
298
299    /* resulting size */
300    size = (ptr - str) * str_bases[base] + 1;
301
302    /* make sure rop has enough storage */
303    if (rop->alloc < size) {
304	rop->digs = mp_realloc(rop->digs, size * sizeof(BNS));
305	rop->alloc = size;
306    }
307    rop->size = size;
308
309    /* initialize rop to zero */
310    memset(rop->digs, '\0', size * sizeof(BNS));
311
312    /* set result sign */
313    rop->sign = sign;
314
315    /* convert string */
316    for (; str < ptr; str++) {
317	value = *str;
318	if (islower(value))
319	    value = toupper(value);
320	value = value > '9' ? value - 'A' + 10 : value - '0';
321	value += (BNI)rop->digs[0] * base;
322	carry = value >> BNSBITS;
323	rop->digs[0] = (BNS)value;
324	for (i = 1; i < size; i++) {
325	    value = (BNI)rop->digs[i] * base + carry;
326	    carry = value >> BNSBITS;
327	    rop->digs[i] = (BNS)value;
328	}
329    }
330
331    /* normalize */
332    if (rop->size > 1 && rop->digs[rop->size - 1] == 0)
333	--rop->size;
334}
335
336void
337mpi_add(mpi *rop, mpi *op1, mpi *op2)
338{
339    mpi_addsub(rop, op1, op2, 0);
340}
341
342void
343mpi_addi(mpi *rop, mpi *op1, long op2)
344{
345    BNS digs[2];
346    mpi op;
347
348    op.digs = (BNS*)digs;
349    _mpi_seti(&op, op2);
350
351    mpi_addsub(rop, op1, &op, 0);
352}
353
354void
355mpi_sub(mpi *rop, mpi *op1, mpi *op2)
356{
357    mpi_addsub(rop, op1, op2, 1);
358}
359
360void
361mpi_subi(mpi *rop, mpi *op1, long op2)
362{
363    BNS digs[2];
364    mpi op;
365
366    op.digs = (BNS*)digs;
367    _mpi_seti(&op, op2);
368
369    mpi_addsub(rop, op1, &op, 1);
370}
371
372static void
373mpi_addsub(mpi *rop, mpi *op1, mpi *op2, int sub)
374{
375    long xlen;				/* maximum result size */
376
377    if (sub ^ (op1->sign == op2->sign)) {
378	/* plus one for possible carry */
379	xlen = MAX(op1->size, op2->size) + 1;
380	if (rop->alloc < xlen) {
381	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xlen);
382	    rop->alloc = xlen;
383	}
384	rop->size = mp_add(rop->digs, op1->digs, op2->digs,
385			   op1->size, op2->size);
386	rop->sign = op1->sign;
387    }
388    else {
389	long cmp;			/* check for larger operator */
390
391	cmp = mpi_cmpabs(op1, op2);
392	if (cmp == 0) {
393	    rop->digs[0] = 0;
394	    rop->size = 1;
395	    rop->sign = 0;
396	}
397	else {
398	    xlen = MAX(op1->size, op2->size);
399	    if (rop->alloc < xlen) {
400		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xlen);
401		rop->alloc = xlen;
402	    }
403	    if (cmp > 0) {
404		rop->size = mp_sub(rop->digs, op1->digs, op2->digs,
405				   op1->size, op2->size);
406		rop->sign = op1->sign;
407	    }
408	    else {
409		rop->size = mp_sub(rop->digs, op2->digs, op1->digs,
410				   op2->size, op1->size);
411		rop->sign = sub ^ op2->sign;
412	    }
413	}
414    }
415}
416
417void
418mpi_mul(mpi *rop, mpi *op1, mpi *op2)
419{
420    int sign;				/* sign flag */
421    BNS *digs;				/* result data */
422    long xsize;				/* result size */
423
424    /* get result sign */
425    sign = op1->sign ^ op2->sign;
426
427    /* check for special cases */
428    if (op1->size == 1) {
429	if (*op1->digs == 0) {
430	    /* multiply by 0 */
431	    mpi_seti(rop, 0);
432	    return;
433	}
434	else if (*op1->digs == 1) {
435	    /* multiply by +-1 */
436	    if (rop->alloc < op2->size) {
437		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op2->size);
438		rop->alloc = op2->size;
439	    }
440	    rop->size = op2->size;
441	    memmove(rop->digs, op2->digs, sizeof(BNS) * op2->size);
442	    rop->sign = op2->size > 1 || *op2->digs ? sign : 0;
443
444	    return;
445	}
446    }
447    else if (op2->size == 1) {
448	if (*op2->digs == 0) {
449	    /* multiply by 0 */
450	    mpi_seti(rop, 0);
451	    return;
452	}
453	else if (*op2->digs == 1) {
454	    /* multiply by +-1 */
455	    if (rop->alloc < op1->size) {
456		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op1->size);
457		rop->alloc = op1->size;
458	    }
459	    rop->size = op1->size;
460	    memmove(rop->digs, op1->digs, sizeof(BNS) * op1->size);
461	    rop->sign = op1->size > 1 || *op1->digs ? sign : 0;
462
463	    return;
464	}
465    }
466
467    /* allocate result data and set it to zero */
468    xsize = op1->size + op2->size;
469    if (rop->digs == op1->digs || rop->digs == op2->digs)
470	/* rop is also an operand */
471	digs = mp_calloc(1, sizeof(BNS) * xsize);
472    else {
473	if (rop->alloc < xsize) {
474	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xsize);
475	    rop->alloc = xsize;
476	}
477	digs = rop->digs;
478	memset(digs, '\0', sizeof(BNS) * xsize);
479    }
480
481    /* multiply operands */
482    xsize = mp_mul(digs, op1->digs, op2->digs, op1->size, op2->size);
483
484    /* store result in rop */
485    if (digs != rop->digs) {
486	/* if rop was an operand, free old data */
487	mp_free(rop->digs);
488	rop->digs = digs;
489    }
490    rop->size = xsize;
491
492    /* set result sign */
493    rop->sign = sign;
494}
495
496void
497mpi_muli(mpi *rop, mpi *op1, long op2)
498{
499    BNS digs[2];
500    mpi op;
501
502    op.digs = (BNS*)digs;
503    _mpi_seti(&op, op2);
504
505    mpi_mul(rop, op1, &op);
506}
507
508void
509mpi_div(mpi *rop, mpi *num, mpi *den)
510{
511    mpi_divqr(rop, NULL, num, den);
512}
513
514void
515mpi_rem(mpi *rop, mpi *num, mpi *den)
516{
517    mpi_divqr(NULL, rop, num, den);
518}
519
520/*
521 * Could/should be changed to not allocate qdigs if qrop is NULL
522 * Performance wouldn't suffer too much with a test on every loop iteration.
523 */
524void
525mpi_divqr(mpi *qrop, mpi *rrop, mpi *num, mpi *den)
526{
527    long i, j;			/* counters */
528    int qsign;			/* sign of quotient */
529    int rsign;			/* sign of remainder */
530    BNI qsize;			/* size of quotient */
531    BNI rsize;			/* size of remainder */
532    BNS qest;			/* estimative of quotient value */
533    BNS *qdigs, *rdigs;		/* work copy or result */
534    BNS *ndigs, *ddigs;		/* work copy or divisor and dividend */
535    BNI value;			/* temporary result */
536    long svalue;		/* signed temporary result (2's complement) */
537    BNS carry, scarry, denorm;	/* carry and normalization */
538    BNI dpos, npos;		/* offsets in data */
539
540    /* get signs */
541    rsign = num->sign;
542    qsign = rsign ^ den->sign;
543
544    /* check for special case */
545    if (num->size < den->size) {
546	/* quotient is zero and remainder is numerator */
547	if (rrop && rrop->digs != num->digs) {
548	    if (rrop->alloc < num->size) {
549		rrop->digs = mp_realloc(rrop->digs, sizeof(BNS) * num->size);
550		rrop->alloc = num->size;
551	    }
552	    rrop->size = num->size;
553	    memcpy(rrop->digs, num->digs, sizeof(BNS) * num->size);
554	    rrop->sign = rsign;
555	}
556	if (qrop)
557	    mpi_seti(qrop, 0);
558
559	return;
560    }
561
562    /* estimate result sizes */
563    rsize = den->size;
564    qsize = num->size - den->size + 1;
565
566    /* offsets */
567    npos = num->size - 1;
568    dpos = den->size - 1;
569
570    /* allocate space for quotient and remainder */
571    if (qrop == NULL || qrop->digs == num->digs || qrop->digs == den->digs)
572	qdigs = mp_calloc(1, sizeof(BNS) * qsize);
573    else {
574	if (qrop->alloc < qsize) {
575	    qrop->digs = mp_realloc(qrop->digs, sizeof(BNS) * qsize);
576	    qrop->alloc = qsize;
577	}
578	memset(qrop->digs, '\0', sizeof(BNS) * qsize);
579	qdigs = qrop->digs;
580    }
581    if (rrop) {
582	if (rrop->digs == num->digs || rrop->digs == den->digs)
583	    rdigs = mp_calloc(1, sizeof(BNS) * rsize);
584	else {
585	    if (rrop->alloc < rsize) {
586		rrop->digs = mp_realloc(rrop->digs, sizeof(BNS) * rsize);
587		rrop->alloc = rsize;
588	    }
589	    memset(rrop->digs, '\0', sizeof(BNS) * rsize);
590	    rdigs = rrop->digs;
591	}
592    }
593    else
594	rdigs = NULL;	/* fix gcc warning */
595
596    /* special case, only one word in divisor */
597    if (dpos == 0) {
598	for (carry = 0, i = npos; i >= 0; i--) {
599	    value = ((BNI)carry << BNSBITS) + num->digs[i];
600	    qdigs[i] = (BNS)(value / den->digs[0]);
601	    carry = (BNS)(value % den->digs[0]);
602	}
603	if (rrop)
604	    rdigs[0] = carry;
605
606	goto mpi_divqr_done;
607    }
608
609    /* make work copy of numerator */
610    ndigs = mp_malloc(sizeof(BNS) * (num->size + 1));
611    /* allocate one extra word an update offset */
612    memcpy(ndigs, num->digs, sizeof(BNS) * num->size);
613    ndigs[num->size] = 0;
614    ++npos;
615
616    /* normalize */
617    denorm = (BNS)((BNI)CARRY / ((BNI)(den->digs[dpos]) + 1));
618
619    if (denorm > 1) {
620	/* i <= num->size because ndigs has an extra word */
621	for (carry = 0, i = 0; i <= num->size; i++) {
622	    value = ndigs[i] * (BNI)denorm + carry;
623	    ndigs[i] = (BNS)value;
624	    carry = (BNS)(value >> BNSBITS);
625	}
626	/* make work copy of denominator */
627	ddigs = mp_malloc(sizeof(BNS) * den->size);
628	memcpy(ddigs, den->digs, sizeof(BNS) * den->size);
629	for (carry = 0, i = 0; i < den->size; i++) {
630	    value = ddigs[i] * (BNI)denorm + carry;
631	    ddigs[i] = (BNS)value;
632	    carry = (BNS)(value >> BNSBITS);
633	}
634    }
635    else
636	/* only allocate copy of denominator if going to change it */
637	ddigs = den->digs;
638
639    /* divide mp integers */
640    for (j = qsize - 1; j >= 0; j--, npos--) {
641	/* estimate quotient */
642	if (ndigs[npos] == ddigs[dpos])
643	    qest = (BNS)SMASK;
644	else
645	    qest = (BNS)((((BNI)(ndigs[npos]) << BNSBITS) + ndigs[npos - 1]) /
646			 ddigs[dpos]);
647
648	while ((value = ((BNI)(ndigs[npos]) << BNSBITS) + ndigs[npos - 1] -
649	        qest * (BNI)(ddigs[dpos])) < CARRY &&
650		ddigs[dpos - 1] * (BNI)qest >
651		(value << BNSBITS) + ndigs[npos - 2])
652	       --qest;
653
654	/* multiply and subtract */
655	carry = scarry = 0;
656	for (i = 0; i < den->size; i++) {
657	    value = qest * (BNI)ddigs[i] + carry;
658	    carry = (BNS)(value >> BNSBITS);
659	    svalue = (long)ndigs[npos - dpos + i - 1] - (long)(value & SMASK) -
660		     (long)scarry;
661	    ndigs[npos - dpos + i - 1] = (BNS)svalue;
662	    scarry = svalue < 0;
663	}
664
665	svalue = (long)ndigs[npos] - (long)(carry & SMASK) - (long)scarry;
666	ndigs[npos] = (BNS)svalue;
667
668	if (svalue & LMASK) {
669	    /* quotient too big */
670	    --qest;
671	    carry = 0;
672	    for (i = 0; i < den->size; i++) {
673		value = ndigs[npos - dpos + i - 1] + (BNI)carry + (BNI)ddigs[i];
674		ndigs[npos - dpos + i - 1] = (BNS)value;
675		carry = (BNS)(value >> BNSBITS);
676	    }
677	    ndigs[npos] += carry;
678	}
679
680	qdigs[j] = qest;
681    }
682
683    /* calculate remainder */
684    if (rrop) {
685	for (carry = 0, j = dpos; j >= 0; j--) {
686	    value = ((BNI)carry << BNSBITS) + ndigs[j];
687	    rdigs[j] = (BNS)(value / denorm);
688	    carry = (BNS)(value % denorm);
689	}
690    }
691
692    mp_free(ndigs);
693    if (ddigs != den->digs)
694	mp_free(ddigs);
695
696mpi_divqr_done:
697    if (rrop) {
698	if (rrop->digs != rdigs)
699	    mp_free(rrop->digs);
700	/* normalize remainder */
701	for (i = rsize - 1; i >= 0; i--)
702	    if (rdigs[i] != 0)
703		break;
704	if (i != rsize - 1) {
705	    if (i < 0) {
706		rsign = 0;
707		rsize = 1;
708	    }
709	    else
710		rsize = i + 1;
711	}
712	rrop->digs = rdigs;
713	rrop->sign = rsign;
714	rrop->size = rsize;
715    }
716
717    /* normalize quotient */
718    if (qrop) {
719	if (qrop->digs != qdigs)
720	    mp_free(qrop->digs);
721	for (i = qsize - 1; i >= 0; i--)
722	    if (qdigs[i] != 0)
723		break;
724	if (i != qsize - 1) {
725	    if (i < 0) {
726		qsign = 0;
727		qsize = 1;
728	    }
729	    else
730		qsize = i + 1;
731	}
732	qrop->digs = qdigs;
733	qrop->sign = qsign;
734	qrop->size = qsize;
735    }
736    else
737	mp_free(qdigs);
738}
739
740long
741mpi_divqri(mpi *qrop, mpi *num, long den)
742{
743    BNS ddigs[2];
744    mpi dop, rrop;
745    long remainder;
746
747    dop.digs = (BNS*)ddigs;
748    _mpi_seti(&dop, den);
749
750    memset(&rrop, '\0', sizeof(mpi));
751    mpi_init(&rrop);
752    mpi_divqr(qrop, &rrop, num, &dop);
753    remainder = rrop.digs[0];
754    if (rrop.size > 1)
755	remainder |= (BNI)(rrop.digs[1]) << BNSBITS;
756    if (rrop.sign)
757	remainder = -remainder;
758    mpi_clear(&rrop);
759
760    return (remainder);
761}
762
763void
764mpi_divi(mpi *rop, mpi *num, long den)
765{
766    BNS ddigs[2];
767    mpi dop;
768
769    dop.digs = (BNS*)ddigs;
770    _mpi_seti(&dop, den);
771
772    mpi_divqr(rop, NULL, num, &dop);
773}
774
775long
776mpi_remi(mpi *num, long den)
777{
778    return (mpi_divqri(NULL, num, den));
779}
780
781void
782mpi_mod(mpi *rop, mpi *num, mpi *den)
783{
784    mpi_rem(rop, num, den);
785    if (num->sign ^ den->sign)
786	mpi_add(rop, rop, den);
787}
788
789long
790mpi_modi(mpi *num, long den)
791{
792    long remainder;
793
794    remainder = mpi_remi(num, den);
795    if (num->sign ^ (den < 0))
796	remainder += den;
797
798    return (remainder);
799}
800
801void
802mpi_gcd(mpi *rop, mpi *num, mpi *den)
803{
804    long cmp;
805    mpi rem;
806
807    /* check if result already given */
808    cmp = mpi_cmpabs(num, den);
809
810    /* check if num is equal to den or if num is zero */
811    if (cmp == 0 || (num->size == 1 && num->digs[0] == 0)) {
812	mpi_set(rop, den);
813	rop->sign = 0;
814	return;
815    }
816    /* check if den is not zero */
817    if (den->size == 1 && den->digs[0] == 0) {
818	mpi_set(rop, num);
819	rop->sign = 0;
820	return;
821    }
822
823    /* don't call mpi_init, relies on realloc(0, size) == malloc(size) */
824    memset(&rem, '\0', sizeof(mpi));
825
826    /* if num larger than den */
827    if (cmp > 0) {
828	mpi_rem(&rem, num, den);
829	if (rem.size == 1 && rem.digs[0] == 0) {
830	    /* exact division */
831	    mpi_set(rop, den);
832	    rop->sign = 0;
833	    mpi_clear(&rem);
834	    return;
835	}
836	mpi_set(rop, den);
837    }
838    else {
839	mpi_rem(&rem, den, num);
840	if (rem.size == 1 && rem.digs[0] == 0) {
841	    /* exact division */
842	    mpi_set(rop, num);
843	    rop->sign = 0;
844	    mpi_clear(&rem);
845	    return;
846	}
847	mpi_set(rop, num);
848    }
849
850    /* loop using positive values */
851    rop->sign = rem.sign = 0;
852
853    /* cannot optimize this inverting rem/rop assignment earlier
854     * because rop mais be an operand */
855    mpi_swap(rop, &rem);
856
857    /* Euclides algorithm */
858    for (;;) {
859	mpi_rem(&rem, &rem, rop);
860	if (rem.size == 1 && rem.digs[0] == 0)
861	    break;
862	mpi_swap(rop, &rem);
863    }
864    mpi_clear(&rem);
865}
866
867void
868mpi_lcm(mpi *rop, mpi *num, mpi *den)
869{
870    mpi gcd;
871
872    /* check for zero operand */
873    if ((num->size == 1 && num->digs[0] == 0) ||
874	(den->size == 1 && den->digs[0] == 0)) {
875	rop->digs[0] = 0;
876	rop->sign = 0;
877	return;
878    }
879
880    /* don't call mpi_init, relies on realloc(0, size) == malloc(size) */
881    memset(&gcd, '\0', sizeof(mpi));
882
883    mpi_gcd(&gcd, num, den);
884    mpi_div(&gcd, den, &gcd);
885    mpi_mul(rop, &gcd, num);
886    rop->sign = 0;
887
888    mpi_clear(&gcd);
889}
890
891void
892mpi_pow(mpi *rop, mpi *op, unsigned long exp)
893{
894    mpi zop, top;
895
896    if (exp == 2) {
897	mpi_mul(rop, op, op);
898	return;
899    }
900    /* check for op**0 */
901    else if (exp == 0) {
902	rop->digs[0] = 1;
903	rop->size = 1;
904	rop->sign = 0;
905	return;
906    }
907    else if (exp == 1) {
908	mpi_set(rop, op);
909	return;
910    }
911    else if (op->size == 1) {
912	if (op->digs[0] == 0) {
913	    mpi_seti(rop, 0);
914	    return;
915	}
916	else if (op->digs[0] == 1) {
917	    mpi_seti(rop, op->sign && (exp & 1) ? -1 : 1);
918	    return;
919	}
920    }
921
922    memset(&zop, '\0', sizeof(mpi));
923    memset(&top, '\0', sizeof(mpi));
924    mpi_set(&zop, op);
925    mpi_set(&top, op);
926    for (--exp; exp; exp >>= 1) {
927	if (exp & 1)
928	    mpi_mul(&zop, &top, &zop);
929	mpi_mul(&top, &top, &top);
930    }
931
932    mpi_clear(&top);
933    rop->sign = zop.sign;
934    mp_free(rop->digs);
935    rop->digs = zop.digs;
936    rop->size = zop.size;
937}
938
939/* Find integer root of given number using the iteration
940 *	x{n+1} = ((K-1) * x{n} + N / x{n}^(K-1)) / K
941 */
942int
943mpi_root(mpi *rop, mpi *op, unsigned long nth)
944{
945    long bits, cmp;
946    int exact;
947    int sign;
948    mpi *r, t, temp, quot, old, rem;
949
950    sign = op->sign;
951
952    /* divide by zero op**1/0 */
953    if (nth == 0) {
954	int one = 1, zero = 0;
955	one = one / zero;
956    }
957    /* result is complex */
958    if (sign && !(nth & 1)) {
959	int one = 1, zero = 0;
960	one = one / zero;
961    }
962
963    /* special case op**1/1 = op */
964    if (nth == 1) {
965	mpi_set(rop, op);
966	return (1);
967    }
968
969    bits = mpi_getsize(op, 2) - 2;
970
971    if (bits < 0 || bits / nth == 0) {
972	/* integral root is surely less than 2 */
973	exact = op->size == 1 && (op->digs[0] == 1 || op->digs[0] == 0);
974	mpi_seti(rop, sign ? -1 : op->digs[0] == 0 ? 0 : 1);
975
976	return (exact == 1);
977    }
978
979    /* initialize */
980    if (rop != op)
981	r = rop;
982    else {
983	r = &t;
984	memset(r, '\0', sizeof(mpi));
985    }
986    memset(&temp, '\0', sizeof(mpi));
987    memset(&quot, '\0', sizeof(mpi));
988    memset(&old, '\0', sizeof(mpi));
989    memset(&rem, '\0', sizeof(mpi));
990
991    if (sign)
992	r->sign = 0;
993
994    /* root aproximation */
995    mpi_ash(r, op, -(bits - (bits / nth)));
996
997    for (;;) {
998	mpi_pow(&temp, r, nth - 1);
999	mpi_divqr(&quot, &rem, op, &temp);
1000	cmp = mpi_cmpabs(r, &quot);
1001	if (cmp == 0) {
1002	    exact = mpi_cmpi(&rem, 0) == 0;
1003	    break;
1004	}
1005	else if (cmp < 0) {
1006	    if (mpi_cmpabs(r, &old) == 0) {
1007		exact = 0;
1008		break;
1009	    }
1010	    mpi_set(&old, r);
1011	}
1012	mpi_muli(&temp, r, nth - 1);
1013	mpi_add(&quot, &quot, &temp);
1014	mpi_divi(r, &quot, nth);
1015    }
1016
1017    mpi_clear(&temp);
1018    mpi_clear(&quot);
1019    mpi_clear(&old);
1020    mpi_clear(&rem);
1021    if (r != rop) {
1022	mpi_set(rop, r);
1023	mpi_clear(r);
1024    }
1025    rop->sign = sign;
1026
1027    return (exact);
1028}
1029
1030/*
1031 * Find square root using the iteration:
1032 *	x{n+1} = (x{n}+N/x{n})/2
1033 */
1034int
1035mpi_sqrt(mpi *rop, mpi *op)
1036{
1037    long bits, cmp;
1038    int exact;
1039    mpi *r, t, quot, rem, old;
1040
1041    /* result is complex */
1042    if (op->sign) {
1043	int one = 1, zero = 0;
1044	one = one / zero;
1045    }
1046
1047    bits = mpi_getsize(op, 2) - 2;
1048
1049    if (bits < 2) {
1050	/* integral root is surely less than 2 */
1051	exact = op->size == 1 && (op->digs[0] == 1 || op->digs[0] == 0);
1052	mpi_seti(rop, op->digs[0] == 0 ? 0 : 1);
1053
1054	return (exact == 1);
1055    }
1056
1057    /* initialize */
1058    if (rop != op)
1059	r = rop;
1060    else {
1061	r = &t;
1062	memset(r, '\0', sizeof(mpi));
1063    }
1064    memset(&quot, '\0', sizeof(mpi));
1065    memset(&rem, '\0', sizeof(mpi));
1066    memset(&old, '\0', sizeof(mpi));
1067
1068    /* root aproximation */
1069    mpi_ash(r, op, -(bits - (bits / 2)));
1070
1071    for (;;) {
1072	if (mpi_cmpabs(r, &old) == 0) {
1073	    exact = 0;
1074	    break;
1075	}
1076	mpi_divqr(&quot, &rem, op, r);
1077	cmp = mpi_cmpabs(&quot, r);
1078	if (cmp == 0) {
1079	    exact = mpi_cmpi(&rem, 0) == 0;
1080	    break;
1081	}
1082	else if (cmp > 0 && rem.size == 1 && rem.digs[0] == 0)
1083	    mpi_subi(&quot, &quot, 1);
1084	mpi_set(&old, r);
1085	mpi_add(r, r, &quot);
1086	mpi_ash(r, r, -1);
1087    }
1088    mpi_clear(&quot);
1089    mpi_clear(&rem);
1090    mpi_clear(&old);
1091    if (r != rop) {
1092	mpi_set(rop, r);
1093	mpi_clear(r);
1094    }
1095
1096    return (exact);
1097}
1098
1099void
1100mpi_ash(mpi *rop, mpi *op, long shift)
1101{
1102    long i;			/* counter */
1103    long xsize;			/* maximum result size */
1104    BNS *digs;
1105
1106    /* check for 0 shift, multiply/divide by 1 */
1107    if (shift == 0) {
1108	if (rop != op) {
1109	    if (rop->alloc < op->size) {
1110		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op->size);
1111		rop->alloc = op->size;
1112	    }
1113	    rop->size = op->size;
1114	    memcpy(rop->digs, op->digs, sizeof(BNS) * op->size);
1115	}
1116
1117	return;
1118    }
1119    else if (op->size == 1 && op->digs[0] == 0) {
1120	rop->sign = 0;
1121	rop->size = 1;
1122	rop->digs[0] = 0;
1123
1124	return;
1125    }
1126
1127    /* check shift and initialize */
1128    if (shift > 0)
1129	xsize = op->size + (shift / BNSBITS) + 1;
1130    else {
1131	xsize = op->size - ((-shift) / BNSBITS);
1132	if (xsize <= 0) {
1133	    rop->size = 1;
1134	    rop->sign = op->sign;
1135	    rop->digs[0] = op->sign ? 1 : 0;
1136
1137	    return;
1138	}
1139    }
1140
1141    /* allocate/adjust memory for result */
1142    if (rop == op)
1143	digs = mp_malloc(sizeof(BNS) * xsize);
1144    else {
1145	if (rop->alloc < xsize) {
1146	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xsize);
1147	    rop->alloc = xsize;
1148	}
1149	digs = rop->digs;
1150    }
1151
1152    /* left shift, multiply by power of two */
1153    if (shift > 0)
1154	rop->size = mp_lshift(digs, op->digs, op->size, shift);
1155    /* right shift, divide by power of two */
1156    else {
1157	long carry = 0;
1158
1159	if (op->sign) {
1160	    BNI words, bits;
1161
1162	    words = -shift / BNSBITS;
1163	    bits = -shift % BNSBITS;
1164	    for (i = 0; i < words; i++)
1165		carry |= op->digs[xsize + i];
1166	    if (!carry) {
1167		for (i = 0; i < bits; i++)
1168		    if (op->digs[op->size - xsize] & (1 << i)) {
1169			carry = 1;
1170			break;
1171		    }
1172	    }
1173	}
1174	rop->size = mp_rshift(digs, op->digs, op->size, -shift);
1175
1176	if (carry)
1177	    /* emulates two's complement subtracting 1 from the result */
1178	    rop->size = mp_add(digs, digs, mpone.digs, rop->size, 1);
1179    }
1180
1181    if (rop->digs != digs) {
1182	mp_free(rop->digs);
1183	rop->alloc = rop->size;
1184	rop->digs = digs;
1185    }
1186    rop->sign = op->sign;
1187}
1188
1189static INLINE BNS
1190mpi_logic(BNS op1, BNS op2, BNS op)
1191{
1192    switch (op) {
1193	case '&':
1194	    return (op1 & op2);
1195	case '|':
1196	    return (op1 | op2);
1197	case '^':
1198	    return (op1 ^ op2);
1199    }
1200
1201    return (SMASK);
1202}
1203
1204static void
1205mpi_log(mpi *rop, mpi *op1, mpi *op2, BNS op)
1206{
1207    long i;			/* counter */
1208    long c, c1, c2;		/* carry */
1209    BNS *digs, *digs1, *digs2;	/* pointers to mp data */
1210    BNI size, size1, size2;
1211    BNS sign, sign1, sign2;
1212    BNS n, n1, n2;		/* logical operands */
1213    BNI sum;
1214
1215    /* initialize */
1216    size1 = op1->size;
1217    size2 = op2->size;
1218
1219    sign1 = op1->sign ? SMASK : 0;
1220    sign2 = op2->sign ? SMASK : 0;
1221
1222    sign = mpi_logic(sign1, sign2, op);
1223
1224    size = MAX(size1, size2);
1225    if (sign)
1226	++size;
1227    if (rop->alloc < size) {
1228	rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size);
1229	rop->alloc = size;
1230    }
1231
1232    digs = rop->digs;
1233    digs1 = op1->digs;
1234    digs2 = op2->digs;
1235
1236    c = c1 = c2 = 1;
1237
1238    /* apply logical operation */
1239    for (i = 0; i < size; i++) {
1240	if (i >= size1)
1241	    n1 = sign1;
1242	else if (sign1) {
1243	    sum = (BNI)(BNS)(~digs1[i]) + c1;
1244	    c1 = (long)(sum >> BNSBITS);
1245	    n1 = (BNS)sum;
1246	}
1247	else
1248	    n1 = digs1[i];
1249
1250	if (i >= size2)
1251	    n2 = sign2;
1252	else if (sign2) {
1253	    sum = (BNI)(BNS)(~digs2[i]) + c2;
1254	    c2 = (long)(sum >> BNSBITS);
1255	    n2 = (BNS)sum;
1256	}
1257	else
1258	    n2 = digs2[i];
1259
1260	n = mpi_logic(n1, n2, op);
1261	if (sign) {
1262	    sum = (BNI)(BNS)(~n) + c;
1263	    c = (long)(sum >> BNSBITS);
1264	    digs[i] = (BNS)sum;
1265	}
1266	else
1267	    digs[i] = n;
1268    }
1269
1270    /* normalize */
1271    for (i = size - 1; i >= 0; i--)
1272	if (digs[i] != 0)
1273	    break;
1274    if (i != size - 1) {
1275	if (i < 0) {
1276	    sign = 0;
1277	    size = 1;
1278	}
1279	else
1280	    size = i + 1;
1281    }
1282
1283    rop->sign = sign != 0;
1284    rop->size = size;
1285}
1286
1287void
1288mpi_and(mpi *rop, mpi *op1, mpi *op2)
1289{
1290    mpi_log(rop, op1, op2, '&');
1291}
1292
1293void
1294mpi_ior(mpi *rop, mpi *op1, mpi *op2)
1295{
1296    mpi_log(rop, op1, op2, '|');
1297}
1298
1299void
1300mpi_xor(mpi *rop, mpi *op1, mpi *op2)
1301{
1302    mpi_log(rop, op1, op2, '^');
1303}
1304
1305void
1306mpi_com(mpi *rop, mpi *op)
1307{
1308    static BNS digs[1] = { 1 };
1309    static mpi one = { 0, 1, 1, (BNS*)&digs };
1310
1311    mpi_log(rop, rop, &one, '^');
1312}
1313
1314void
1315mpi_neg(mpi *rop, mpi *op)
1316{
1317    int sign = op->sign ^ 1;
1318
1319    if (rop->digs != op->digs) {
1320	if (rop->alloc < op->size) {
1321	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * rop->size);
1322	    rop->alloc = op->size;
1323	}
1324	rop->size = op->size;
1325	memcpy(rop->digs, op->digs, sizeof(BNS) * rop->size);
1326    }
1327
1328    rop->sign = sign;
1329}
1330
1331void
1332mpi_abs(mpi *rop, mpi *op)
1333{
1334    if (rop->digs != op->digs) {
1335	if (rop->alloc < op->size) {
1336	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * rop->size);
1337	    rop->alloc = op->size;
1338	}
1339	rop->size = op->size;
1340	memcpy(rop->digs, op->digs, sizeof(BNS) * rop->size);
1341    }
1342
1343    rop->sign = 0;
1344}
1345
1346int
1347mpi_cmp(mpi *op1, mpi *op2)
1348{
1349    if (op1->sign ^ op2->sign)
1350	return (op1->sign ? -1 : 1);
1351
1352    if (op1->size == op2->size) {
1353	long i, cmp = 0;
1354
1355	for (i = op1->size - 1; i >= 0; i--)
1356	    if ((cmp = (long)op1->digs[i] - (long)op2->digs[i]) != 0)
1357		break;
1358
1359	return (cmp == 0 ? 0 : (cmp < 0) ^ op1->sign ? -1 : 1);
1360    }
1361
1362    return ((op1->size < op2->size) ^ op1->sign ? -1 : 1);
1363}
1364
1365int
1366mpi_cmpi(mpi *op1, long op2)
1367{
1368    long cmp;
1369
1370    if (op1->size > 2)
1371	return (op1->sign ? -1 : 1);
1372
1373    cmp = op1->digs[0];
1374    if (op1->size == 2) {
1375	cmp |= (long)op1->digs[1] << BNSBITS;
1376	if (cmp == MINSLONG)
1377	    return (op2 == cmp && op1->sign ? 0 : op1->sign ? -1 : 1);
1378    }
1379    if (op1->sign)
1380	cmp = -cmp;
1381
1382    return (cmp - op2);
1383}
1384
1385int
1386mpi_cmpabs(mpi *op1, mpi *op2)
1387{
1388    if (op1->size == op2->size) {
1389	long i, cmp = 0;
1390
1391	for (i = op1->size - 1; i >= 0; i--)
1392	    if ((cmp = (long)op1->digs[i] - (long)op2->digs[i]) != 0)
1393		break;
1394
1395	return (cmp);
1396    }
1397
1398    return ((op1->size < op2->size) ? -1 : 1);
1399}
1400
1401int
1402mpi_cmpabsi(mpi *op1, long op2)
1403{
1404    unsigned long cmp;
1405
1406    if (op1->size > 2)
1407	return (1);
1408
1409    cmp = op1->digs[0];
1410    if (op1->size == 2)
1411	cmp |= (unsigned long)op1->digs[1] << BNSBITS;
1412
1413    return (cmp > op2 ? 1 : cmp == op2 ? 0 : -1);
1414}
1415
1416int
1417mpi_sgn(mpi *op)
1418{
1419    return (op->sign ? -1 : op->size > 1 || op->digs[0] ? 1 : 0);
1420}
1421
1422void
1423mpi_swap(mpi *op1, mpi *op2)
1424{
1425    if (op1 != op2) {
1426	mpi swap;
1427
1428	memcpy(&swap, op1, sizeof(mpi));
1429	memcpy(op1, op2, sizeof(mpi));
1430	memcpy(op2, &swap, sizeof(mpi));
1431    }
1432}
1433
1434int
1435mpi_fiti(mpi *op)
1436{
1437    if (op->size == 1)
1438	return (1);
1439    else if (op->size == 2) {
1440	unsigned long value = ((BNI)(op->digs[1]) << BNSBITS) | op->digs[0];
1441
1442	if (value & MINSLONG)
1443	    return (op->sign && value == MINSLONG) ? 1 : 0;
1444
1445	return (1);
1446    }
1447
1448    return (0);
1449}
1450
1451long
1452mpi_geti(mpi *op)
1453{
1454    long value;
1455
1456    value = op->digs[0];
1457    if (op->size > 1)
1458	value |= (BNI)(op->digs[1]) << BNSBITS;
1459
1460    return (op->sign && value != MINSLONG ? -value : value);
1461}
1462
1463double
1464mpi_getd(mpi *op)
1465{
1466    long i, len;
1467    double d = 0.0;
1468    int exponent;
1469
1470#define FLOATDIGS	sizeof(double) / sizeof(BNS)
1471
1472    switch (op->size) {
1473	case 2:
1474	    d = (BNI)(op->digs[1]) << BNSBITS;
1475	case 1:
1476	    d += op->digs[0];
1477	    return (op->sign ? -d : d);
1478	default:
1479	    break;
1480    }
1481
1482    for (i = 0, len = op->size; len > 0 && i < FLOATDIGS; i++)
1483	d = ldexp(d, BNSBITS) + op->digs[--len];
1484    d = frexp(d, &exponent);
1485    if (len > 0)
1486	exponent += len * BNSBITS;
1487
1488    if (d == 0.0)
1489	return (d);
1490
1491    d = ldexp(d, exponent);
1492
1493    return (op->sign ? -d : d);
1494}
1495
1496/* how many digits in a given base, floor(log(CARRY) / log(base)) */
1497#ifdef LONG64
1498static char dig_bases[37] = {
1499     0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  9,  9,  8,  8,  8,  8,
1500     8,  7,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  6,  6,
1501     6,  6,  6,  6,  6,
1502};
1503#else
1504static char dig_bases[37] = {
1505     0,  0, 16, 10,  8,  6,  6,  5,  5,  5,  4,  4,  4,  4,  4,  4,
1506     4,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
1507     3,  3,  3,  3,  3,
1508};
1509#endif
1510
1511/* how many digits per bit in a given base, log(2) / log(base) */
1512static double bit_bases[37] = {
1513    0.0000000000000000, 0.0000000000000000, 1.0000000000000000,
1514    0.6309297535714575, 0.5000000000000000, 0.4306765580733931,
1515    0.3868528072345416, 0.3562071871080222, 0.3333333333333334,
1516    0.3154648767857287, 0.3010299956639811, 0.2890648263178878,
1517    0.2789429456511298, 0.2702381544273197, 0.2626495350371936,
1518    0.2559580248098155, 0.2500000000000000, 0.2446505421182260,
1519    0.2398124665681315, 0.2354089133666382, 0.2313782131597592,
1520    0.2276702486969530, 0.2242438242175754, 0.2210647294575037,
1521    0.2181042919855316, 0.2153382790366965, 0.2127460535533632,
1522    0.2103099178571525, 0.2080145976765095, 0.2058468324604344,
1523    0.2037950470905062, 0.2018490865820999, 0.2000000000000000,
1524    0.1982398631705605, 0.1965616322328226, 0.1949590218937863,
1525    0.1934264036172708,
1526};
1527
1528/* normalization base for string conversion, pow(base, dig_bases[base]) & ~CARRY */
1529#ifdef LONG64
1530static BNS big_bases[37] = {
1531    0x00000001, 0x00000001, 0x00000000, 0xCFD41B91, 0x00000000, 0x48C27395,
1532    0x81BF1000, 0x75DB9C97, 0x40000000, 0xCFD41B91, 0x3B9ACA00, 0x8C8B6D2B,
1533    0x19A10000, 0x309F1021, 0x57F6C100, 0x98C29B81, 0x00000000, 0x18754571,
1534    0x247DBC80, 0x3547667B, 0x4C4B4000, 0x6B5A6E1D, 0x94ACE180, 0xCAF18367,
1535    0x0B640000, 0x0E8D4A51, 0x1269AE40, 0x17179149, 0x1CB91000, 0x23744899,
1536    0x2B73A840, 0x34E63B41, 0x40000000, 0x4CFA3CC1, 0x5C13D840, 0x6D91B519,
1537    0x81BF1000,
1538};
1539#else
1540static BNS big_bases[37] = {
1541    0x0001, 0x0001, 0x0000, 0xE6A9, 0x0000, 0x3D09, 0xB640, 0x41A7, 0x8000,
1542    0xE6A9, 0x2710, 0x3931, 0x5100, 0x6F91, 0x9610, 0xC5C1, 0x0000, 0x1331,
1543    0x16C8, 0x1ACB, 0x1F40, 0x242D, 0x2998, 0x2F87, 0x3600, 0x3D09, 0x44A8,
1544    0x4CE3, 0x55C0, 0x5F45, 0x6978, 0x745F, 0x8000, 0x8C61, 0x9988, 0xA77B,
1545    0xb640,
1546};
1547#endif
1548
1549unsigned long
1550mpi_getsize(mpi *op, int base)
1551{
1552    unsigned long value, bits;
1553
1554    value = op->digs[op->size - 1];
1555
1556    /* count leading bits */
1557    if (value) {
1558	unsigned long count, carry;
1559
1560	for (count = 0, carry = CARRY >> 1; carry; count++, carry >>= 1)
1561	    if (value & carry)
1562		break;
1563
1564	bits = BNSBITS - count;
1565    }
1566    else
1567	bits = 0;
1568
1569    return ((bits + (op->size - 1) * BNSBITS) * bit_bases[base] + 1);
1570}
1571
1572char *
1573mpi_getstr(char *str, mpi *op, int base)
1574{
1575    long i;			/* counter */
1576    BNS *digs, *xdigs;		/* copy of op data */
1577    BNI size;			/* size of op */
1578    BNI digits;			/* digits per word in given base */
1579    BNI bigbase;		/* big base of given base */
1580    BNI strsize;		/* size of resulting string */
1581    char *cp;			/* pointer in str for conversion */
1582
1583    /* initialize */
1584    size = op->size;
1585    strsize = mpi_getsize(op, base) + op->sign + 1;
1586
1587    if (str == NULL)
1588	str = mp_malloc(strsize);
1589
1590    /* check for zero */
1591    if (size == 1 && op->digs[0] == 0) {
1592	str[0] = '0';
1593	str[1] = '\0';
1594
1595	return (str);
1596    }
1597
1598    digits = dig_bases[base];
1599    bigbase = big_bases[base];
1600
1601    cp = str + strsize;
1602    *--cp = '\0';
1603
1604    /* make copy of op data and adjust digs */
1605    xdigs = mp_malloc(size * sizeof(BNS));
1606    memcpy(xdigs, op->digs, size * sizeof(BNS));
1607    digs = xdigs + size - 1;
1608
1609    /* convert to string */
1610    for (;;) {
1611	long count = -1;
1612	BNI value;
1613	BNS quotient, remainder = 0;
1614
1615	/* if power of two base */
1616	if ((base & (base - 1)) == 0) {
1617	    for (i = 0; i < size; i++) {
1618		quotient = remainder;
1619		remainder = digs[-i];
1620		digs[-i] = quotient;
1621		if (count < 0 && quotient)
1622		    count = i;
1623	    }
1624	}
1625	else {
1626	    for (i = 0; i < size; i++) {
1627		value = digs[-i] + ((BNI)remainder << BNSBITS);
1628		quotient = (BNS)(value / bigbase);
1629		remainder = (BNS)(value % bigbase);
1630		digs[-i] = quotient;
1631		if (count < 0 && quotient)
1632		    count = i;
1633	    }
1634	}
1635	quotient = remainder;
1636	for (i = 0; i < digits; i++) {
1637	    if (quotient == 0 && count < 0)
1638		break;
1639	    remainder = quotient % base;
1640	    quotient /= base;
1641	    *--cp = remainder < 10 ? remainder + '0' : remainder - 10 + 'A';
1642	}
1643	if (count < 0)
1644	    break;
1645	digs -= count;
1646	size -= count;
1647    }
1648
1649    /* adjust sign */
1650    if (op->sign)
1651	*--cp = '-';
1652
1653    /* remove any extra characters */
1654    if (cp > str)
1655	strcpy(str, cp);
1656
1657    mp_free(xdigs);
1658
1659    return (str);
1660}
1661