15dfecf96Smrg/*
25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc.
35dfecf96Smrg *
45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a
55dfecf96Smrg * copy of this software and associated documentation files (the "Software"),
65dfecf96Smrg * to deal in the Software without restriction, including without limitation
75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the
95dfecf96Smrg * Software is furnished to do so, subject to the following conditions:
105dfecf96Smrg *
115dfecf96Smrg * The above copyright notice and this permission notice shall be included in
125dfecf96Smrg * all copies or substantial portions of the Software.
135dfecf96Smrg *
145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
205dfecf96Smrg * SOFTWARE.
215dfecf96Smrg *
225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall
235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other
245dfecf96Smrg * dealings in this Software without prior written authorization from the
255dfecf96Smrg * XFree86 Project.
265dfecf96Smrg *
275dfecf96Smrg * Author: Paulo César Pereira de Andrade
285dfecf96Smrg */
295dfecf96Smrg
305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/mp/mpi.c,v 1.12 2002/11/20 07:44:43 paulo Exp $ */
315dfecf96Smrg
325dfecf96Smrg#include "mp.h"
335dfecf96Smrg
34c2cbb186Smrg#ifdef __APPLE__
355dfecf96Smrg# define finite(x) isfinite(x)
365dfecf96Smrg#endif
375dfecf96Smrg
385dfecf96Smrg/*
395dfecf96Smrg * Prototypes
405dfecf96Smrg */
415dfecf96Smrg	/* do the hard work of mpi_add and mpi_sub */
425dfecf96Smrgstatic void mpi_addsub(mpi *rop, mpi *op1, mpi *op2, int sub);
435dfecf96Smrg
445dfecf96Smrg	/* logical functions implementation */
455dfecf96Smrgstatic INLINE BNS mpi_logic(BNS op1, BNS op2, BNS op);
465dfecf96Smrgstatic void mpi_log(mpi *rop, mpi *op1, mpi *op2,  BNS op);
475dfecf96Smrg
485dfecf96Smrg	/* internal mpi_seti, whithout memory allocation */
495dfecf96Smrgstatic void _mpi_seti(mpi *rop, long si);
505dfecf96Smrg
515dfecf96Smrg/*
525dfecf96Smrg * Initialization
535dfecf96Smrg */
545dfecf96Smrgstatic BNS onedig[1] = { 1 };
555dfecf96Smrgstatic mpi mpone = { 1, 1, 0, (BNS*)&onedig };
565dfecf96Smrg
575dfecf96Smrg/*
585dfecf96Smrg * Implementation
595dfecf96Smrg */
605dfecf96Smrgvoid
615dfecf96Smrgmpi_init(mpi *op)
625dfecf96Smrg{
635dfecf96Smrg    op->sign = 0;
645dfecf96Smrg    op->size = op->alloc = 1;
655dfecf96Smrg    op->digs = mp_malloc(sizeof(BNS));
665dfecf96Smrg    op->digs[0] = 0;
675dfecf96Smrg}
685dfecf96Smrg
695dfecf96Smrgvoid
705dfecf96Smrgmpi_clear(mpi *op)
715dfecf96Smrg{
725dfecf96Smrg    op->sign = 0;
735dfecf96Smrg    op->size = op->alloc = 0;
745dfecf96Smrg    mp_free(op->digs);
755dfecf96Smrg}
765dfecf96Smrg
775dfecf96Smrgvoid
785dfecf96Smrgmpi_set(mpi *rop, mpi *op)
795dfecf96Smrg{
805dfecf96Smrg    if (rop != op) {
815dfecf96Smrg	if (rop->alloc < op->size) {
825dfecf96Smrg	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op->size);
835dfecf96Smrg	    rop->alloc = op->size;
845dfecf96Smrg	}
855dfecf96Smrg	rop->size = op->size;
865dfecf96Smrg	memcpy(rop->digs, op->digs, sizeof(BNS) * op->size);
875dfecf96Smrg	rop->sign = op->sign;
885dfecf96Smrg    }
895dfecf96Smrg}
905dfecf96Smrg
915dfecf96Smrgvoid
925dfecf96Smrgmpi_seti(mpi *rop, long si)
935dfecf96Smrg{
945dfecf96Smrg    unsigned long ui;
955dfecf96Smrg    int sign = si < 0;
965dfecf96Smrg    int size;
975dfecf96Smrg
985dfecf96Smrg    if (si == MINSLONG) {
995dfecf96Smrg	ui = MINSLONG;
1005dfecf96Smrg	size = 2;
1015dfecf96Smrg    }
1025dfecf96Smrg    else {
1035dfecf96Smrg	if (sign)
1045dfecf96Smrg	    ui = -si;
1055dfecf96Smrg	else
1065dfecf96Smrg	    ui = si;
1075dfecf96Smrg	if (ui < CARRY)
1085dfecf96Smrg	    size = 1;
1095dfecf96Smrg	else
1105dfecf96Smrg	    size = 2;
1115dfecf96Smrg    }
1125dfecf96Smrg
1135dfecf96Smrg    if (rop->alloc < size) {
1145dfecf96Smrg	rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size);
1155dfecf96Smrg	rop->alloc = size;
1165dfecf96Smrg    }
1175dfecf96Smrg    rop->size = size;
1185dfecf96Smrg
1195dfecf96Smrg    /* store data in small mp integer */
1205dfecf96Smrg    rop->digs[0] = (BNS)ui;
1215dfecf96Smrg    if (size > 1)
1225dfecf96Smrg	rop->digs[1] = (BNS)(ui >> BNSBITS);
1235dfecf96Smrg    rop->size = size;
1245dfecf96Smrg
1255dfecf96Smrg    /* adjust result sign */
1265dfecf96Smrg    rop->sign = sign;
1275dfecf96Smrg}
1285dfecf96Smrg
1295dfecf96Smrgstatic void
1305dfecf96Smrg_mpi_seti(mpi *rop, long si)
1315dfecf96Smrg{
1325dfecf96Smrg    unsigned long ui;
1335dfecf96Smrg    int sign = si < 0;
1345dfecf96Smrg    int size;
1355dfecf96Smrg
1365dfecf96Smrg    if (si == MINSLONG) {
1375dfecf96Smrg	ui = MINSLONG;
1385dfecf96Smrg	size = 2;
1395dfecf96Smrg    }
1405dfecf96Smrg    else {
1415dfecf96Smrg	if (sign)
1425dfecf96Smrg	    ui = -si;
1435dfecf96Smrg	else
1445dfecf96Smrg	    ui = si;
1455dfecf96Smrg	if (ui < CARRY)
1465dfecf96Smrg	    size = 1;
1475dfecf96Smrg	else
1485dfecf96Smrg	    size = 2;
1495dfecf96Smrg    }
1505dfecf96Smrg
1515dfecf96Smrg    rop->digs[0] = (BNS)ui;
1525dfecf96Smrg    if (size > 1)
1535dfecf96Smrg	rop->digs[1] = (BNS)(ui >> BNSBITS);
1545dfecf96Smrg    rop->size = size;
1555dfecf96Smrg
1565dfecf96Smrg    rop->sign = sign;
1575dfecf96Smrg}
1585dfecf96Smrg
1595dfecf96Smrgvoid
1605dfecf96Smrgmpi_setd(mpi *rop, double d)
1615dfecf96Smrg{
1625dfecf96Smrg    long i;
1635dfecf96Smrg    double mantissa;
1645dfecf96Smrg    int shift, exponent;
1655dfecf96Smrg    BNI size;
1665dfecf96Smrg
1675dfecf96Smrg    if (isnan(d))
1685dfecf96Smrg	d = 0.0;
1695dfecf96Smrg    else if (!finite(d))
1705dfecf96Smrg	d = copysign(1.0, d) * DBL_MAX;
1715dfecf96Smrg
1725dfecf96Smrg    /* check if number is larger than 1 */
1735dfecf96Smrg    if (fabs(d) < 1.0) {
1745dfecf96Smrg	rop->digs[0] = 0;
1755dfecf96Smrg	rop->size = 1;
1765dfecf96Smrg	rop->sign = d < 0.0;
1775dfecf96Smrg
1785dfecf96Smrg	return;
1795dfecf96Smrg    }
1805dfecf96Smrg
1815dfecf96Smrg    mantissa = frexp(d, &exponent);
1825dfecf96Smrg    if (mantissa < 0)
1835dfecf96Smrg	mantissa = -mantissa;
1845dfecf96Smrg
1855dfecf96Smrg    size = (exponent + (BNSBITS - 1)) / BNSBITS;
1865dfecf96Smrg    shift = BNSBITS - (exponent & (BNSBITS - 1));
1875dfecf96Smrg
1885dfecf96Smrg    /* adjust amount of memory */
1895dfecf96Smrg    if (rop->alloc < size) {
1905dfecf96Smrg	rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size);
1915dfecf96Smrg	rop->alloc = size;
1925dfecf96Smrg    }
1935dfecf96Smrg    rop->size = size;
1945dfecf96Smrg
1955dfecf96Smrg    /* adjust the exponent */
1965dfecf96Smrg    if (shift < BNSBITS)
1975dfecf96Smrg	mantissa = ldexp(mantissa, -shift);
1985dfecf96Smrg
1995dfecf96Smrg    /* convert double */
2005dfecf96Smrg    for (i = size - 1; i >= 0 && mantissa != 0.0; i--) {
2015dfecf96Smrg	mantissa = ldexp(mantissa, BNSBITS);
2025dfecf96Smrg	rop->digs[i] = (BNS)mantissa;
2035dfecf96Smrg	mantissa -= rop->digs[i];
2045dfecf96Smrg    }
2055dfecf96Smrg    for (; i >= 0; i--)
2065dfecf96Smrg	rop->digs[i] = 0;
2075dfecf96Smrg
2085dfecf96Smrg    /* normalize */
2095dfecf96Smrg    if (size > 1 && rop->digs[size - 1] == 0)
2105dfecf96Smrg	--rop->size;
2115dfecf96Smrg
2125dfecf96Smrg    rop->sign = d < 0.0;
2135dfecf96Smrg}
2145dfecf96Smrg
2155dfecf96Smrg/* how many BNS in the given base, log(base) / log(CARRY) */
2165dfecf96Smrg#ifdef LONG64
2175dfecf96Smrgstatic double str_bases[37] = {
2185dfecf96Smrg    0.0000000000000000, 0.0000000000000000, 0.0312500000000000,
2195dfecf96Smrg    0.0495300781475362, 0.0625000000000000, 0.0725602529652301,
2205dfecf96Smrg    0.0807800781475362, 0.0877298413143002, 0.0937500000000000,
2215dfecf96Smrg    0.0990601562950723, 0.1038102529652301, 0.1081072380824156,
2225dfecf96Smrg    0.1120300781475362, 0.1156387411919092, 0.1189798413143002,
2235dfecf96Smrg    0.1220903311127662, 0.1250000000000000, 0.1277332137890731,
2245dfecf96Smrg    0.1303101562950723, 0.1327477347951120, 0.1350602529652300,
2255dfecf96Smrg    0.1372599194618363, 0.1393572380824156, 0.1413613111267817,
2265dfecf96Smrg    0.1432800781475362, 0.1451205059304602, 0.1468887411919092,
2275dfecf96Smrg    0.1485902344426084, 0.1502298413143002, 0.1518119060977367,
2285dfecf96Smrg    0.1533403311127662, 0.1548186346995899, 0.1562500000000000,
2295dfecf96Smrg    0.1576373162299517, 0.1589832137890731, 0.1602900942795302,
2305dfecf96Smrg    0.1615601562950723,
2315dfecf96Smrg};
2325dfecf96Smrg#else
2335dfecf96Smrgstatic double str_bases[37] = {
2345dfecf96Smrg    0.0000000000000000, 0.0000000000000000, 0.0625000000000000,
2355dfecf96Smrg    0.0990601562950723, 0.1250000000000000, 0.1451205059304602,
2365dfecf96Smrg    0.1615601562950723, 0.1754596826286003, 0.1875000000000000,
2375dfecf96Smrg    0.1981203125901446, 0.2076205059304602, 0.2162144761648311,
2385dfecf96Smrg    0.2240601562950723, 0.2312774823838183, 0.2379596826286003,
2395dfecf96Smrg    0.2441806622255325, 0.2500000000000000, 0.2554664275781462,
2405dfecf96Smrg    0.2606203125901445, 0.2654954695902241, 0.2701205059304602,
2415dfecf96Smrg    0.2745198389236725, 0.2787144761648311, 0.2827226222535633,
2425dfecf96Smrg    0.2865601562950723, 0.2902410118609203, 0.2937774823838183,
2435dfecf96Smrg    0.2971804688852168, 0.3004596826286003, 0.3036238121954733,
2445dfecf96Smrg    0.3066806622255324, 0.3096372693991797, 0.3125000000000000,
2455dfecf96Smrg    0.3152746324599034, 0.3179664275781462, 0.3205801885590604,
2465dfecf96Smrg    0.3231203125901446,
2475dfecf96Smrg};
2485dfecf96Smrg#endif
2495dfecf96Smrg
2505dfecf96Smrgvoid
2515dfecf96Smrgmpi_setstr(mpi *rop, char *str, int base)
2525dfecf96Smrg{
2535dfecf96Smrg    long i;			/* counter */
2545dfecf96Smrg    int sign;			/* result sign */
2555dfecf96Smrg    BNI carry;			/* carry value */
2565dfecf96Smrg    BNI value;			/* temporary value */
2575dfecf96Smrg    BNI size;			/* size of result */
2585dfecf96Smrg    char *ptr;			/* end of valid input */
2595dfecf96Smrg
2605dfecf96Smrg    /* initialization */
2615dfecf96Smrg    sign = 0;
2625dfecf96Smrg    carry = 0;
2635dfecf96Smrg
2645dfecf96Smrg    /* skip leading spaces */
2655dfecf96Smrg    while (isspace(*str))
2665dfecf96Smrg	++str;
2675dfecf96Smrg
2685dfecf96Smrg    /* check if sign supplied */
2695dfecf96Smrg    if (*str == '-') {
2705dfecf96Smrg	sign = 1;
2715dfecf96Smrg	++str;
2725dfecf96Smrg    }
2735dfecf96Smrg    else if (*str == '+')
2745dfecf96Smrg	++str;
2755dfecf96Smrg
2765dfecf96Smrg    /* skip leading zeros */
2775dfecf96Smrg    while (*str == '0')
2785dfecf96Smrg	++str;
2795dfecf96Smrg
2805dfecf96Smrg    ptr = str;
2815dfecf96Smrg    while (*ptr) {
2825dfecf96Smrg	if (*ptr >= '0' && *ptr <= '9') {
2835dfecf96Smrg	    if (*ptr - '0' >= base)
2845dfecf96Smrg		break;
2855dfecf96Smrg	}
2865dfecf96Smrg	else if (*ptr >= 'A' && *ptr <= 'Z') {
2875dfecf96Smrg	    if (*ptr - 'A' + 10 >= base)
2885dfecf96Smrg		break;
2895dfecf96Smrg	}
2905dfecf96Smrg	else if (*ptr >= 'a' && *ptr <= 'z') {
2915dfecf96Smrg	    if (*ptr - 'a' + 10 >= base)
2925dfecf96Smrg		break;
2935dfecf96Smrg	}
2945dfecf96Smrg	else
2955dfecf96Smrg	    break;
2965dfecf96Smrg	++ptr;
2975dfecf96Smrg    }
2985dfecf96Smrg
2995dfecf96Smrg    /* resulting size */
3005dfecf96Smrg    size = (ptr - str) * str_bases[base] + 1;
3015dfecf96Smrg
3025dfecf96Smrg    /* make sure rop has enough storage */
3035dfecf96Smrg    if (rop->alloc < size) {
3045dfecf96Smrg	rop->digs = mp_realloc(rop->digs, size * sizeof(BNS));
3055dfecf96Smrg	rop->alloc = size;
3065dfecf96Smrg    }
3075dfecf96Smrg    rop->size = size;
3085dfecf96Smrg
3095dfecf96Smrg    /* initialize rop to zero */
3105dfecf96Smrg    memset(rop->digs, '\0', size * sizeof(BNS));
3115dfecf96Smrg
3125dfecf96Smrg    /* set result sign */
3135dfecf96Smrg    rop->sign = sign;
3145dfecf96Smrg
3155dfecf96Smrg    /* convert string */
3165dfecf96Smrg    for (; str < ptr; str++) {
3175dfecf96Smrg	value = *str;
3185dfecf96Smrg	if (islower(value))
3195dfecf96Smrg	    value = toupper(value);
3205dfecf96Smrg	value = value > '9' ? value - 'A' + 10 : value - '0';
32131de2854Smrg	value += (BNI)rop->digs[0] * base;
3225dfecf96Smrg	carry = value >> BNSBITS;
3235dfecf96Smrg	rop->digs[0] = (BNS)value;
3245dfecf96Smrg	for (i = 1; i < size; i++) {
3255dfecf96Smrg	    value = (BNI)rop->digs[i] * base + carry;
3265dfecf96Smrg	    carry = value >> BNSBITS;
3275dfecf96Smrg	    rop->digs[i] = (BNS)value;
3285dfecf96Smrg	}
3295dfecf96Smrg    }
3305dfecf96Smrg
3315dfecf96Smrg    /* normalize */
3325dfecf96Smrg    if (rop->size > 1 && rop->digs[rop->size - 1] == 0)
3335dfecf96Smrg	--rop->size;
3345dfecf96Smrg}
3355dfecf96Smrg
3365dfecf96Smrgvoid
3375dfecf96Smrgmpi_add(mpi *rop, mpi *op1, mpi *op2)
3385dfecf96Smrg{
3395dfecf96Smrg    mpi_addsub(rop, op1, op2, 0);
3405dfecf96Smrg}
3415dfecf96Smrg
3425dfecf96Smrgvoid
3435dfecf96Smrgmpi_addi(mpi *rop, mpi *op1, long op2)
3445dfecf96Smrg{
3455dfecf96Smrg    BNS digs[2];
3465dfecf96Smrg    mpi op;
3475dfecf96Smrg
3485dfecf96Smrg    op.digs = (BNS*)digs;
3495dfecf96Smrg    _mpi_seti(&op, op2);
3505dfecf96Smrg
3515dfecf96Smrg    mpi_addsub(rop, op1, &op, 0);
3525dfecf96Smrg}
3535dfecf96Smrg
3545dfecf96Smrgvoid
3555dfecf96Smrgmpi_sub(mpi *rop, mpi *op1, mpi *op2)
3565dfecf96Smrg{
3575dfecf96Smrg    mpi_addsub(rop, op1, op2, 1);
3585dfecf96Smrg}
3595dfecf96Smrg
3605dfecf96Smrgvoid
3615dfecf96Smrgmpi_subi(mpi *rop, mpi *op1, long op2)
3625dfecf96Smrg{
3635dfecf96Smrg    BNS digs[2];
3645dfecf96Smrg    mpi op;
3655dfecf96Smrg
3665dfecf96Smrg    op.digs = (BNS*)digs;
3675dfecf96Smrg    _mpi_seti(&op, op2);
3685dfecf96Smrg
3695dfecf96Smrg    mpi_addsub(rop, op1, &op, 1);
3705dfecf96Smrg}
3715dfecf96Smrg
3725dfecf96Smrgstatic void
3735dfecf96Smrgmpi_addsub(mpi *rop, mpi *op1, mpi *op2, int sub)
3745dfecf96Smrg{
3755dfecf96Smrg    long xlen;				/* maximum result size */
3765dfecf96Smrg
3775dfecf96Smrg    if (sub ^ (op1->sign == op2->sign)) {
3785dfecf96Smrg	/* plus one for possible carry */
3795dfecf96Smrg	xlen = MAX(op1->size, op2->size) + 1;
3805dfecf96Smrg	if (rop->alloc < xlen) {
3815dfecf96Smrg	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xlen);
3825dfecf96Smrg	    rop->alloc = xlen;
3835dfecf96Smrg	}
3845dfecf96Smrg	rop->size = mp_add(rop->digs, op1->digs, op2->digs,
3855dfecf96Smrg			   op1->size, op2->size);
3865dfecf96Smrg	rop->sign = op1->sign;
3875dfecf96Smrg    }
3885dfecf96Smrg    else {
3895dfecf96Smrg	long cmp;			/* check for larger operator */
3905dfecf96Smrg
3915dfecf96Smrg	cmp = mpi_cmpabs(op1, op2);
3925dfecf96Smrg	if (cmp == 0) {
3935dfecf96Smrg	    rop->digs[0] = 0;
3945dfecf96Smrg	    rop->size = 1;
3955dfecf96Smrg	    rop->sign = 0;
3965dfecf96Smrg	}
3975dfecf96Smrg	else {
3985dfecf96Smrg	    xlen = MAX(op1->size, op2->size);
3995dfecf96Smrg	    if (rop->alloc < xlen) {
4005dfecf96Smrg		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xlen);
4015dfecf96Smrg		rop->alloc = xlen;
4025dfecf96Smrg	    }
4035dfecf96Smrg	    if (cmp > 0) {
4045dfecf96Smrg		rop->size = mp_sub(rop->digs, op1->digs, op2->digs,
4055dfecf96Smrg				   op1->size, op2->size);
4065dfecf96Smrg		rop->sign = op1->sign;
4075dfecf96Smrg	    }
4085dfecf96Smrg	    else {
4095dfecf96Smrg		rop->size = mp_sub(rop->digs, op2->digs, op1->digs,
4105dfecf96Smrg				   op2->size, op1->size);
4115dfecf96Smrg		rop->sign = sub ^ op2->sign;
4125dfecf96Smrg	    }
4135dfecf96Smrg	}
4145dfecf96Smrg    }
4155dfecf96Smrg}
4165dfecf96Smrg
4175dfecf96Smrgvoid
4185dfecf96Smrgmpi_mul(mpi *rop, mpi *op1, mpi *op2)
4195dfecf96Smrg{
4205dfecf96Smrg    int sign;				/* sign flag */
4215dfecf96Smrg    BNS *digs;				/* result data */
4225dfecf96Smrg    long xsize;				/* result size */
4235dfecf96Smrg
4245dfecf96Smrg    /* get result sign */
4255dfecf96Smrg    sign = op1->sign ^ op2->sign;
4265dfecf96Smrg
4275dfecf96Smrg    /* check for special cases */
4285dfecf96Smrg    if (op1->size == 1) {
4295dfecf96Smrg	if (*op1->digs == 0) {
4305dfecf96Smrg	    /* multiply by 0 */
4315dfecf96Smrg	    mpi_seti(rop, 0);
4325dfecf96Smrg	    return;
4335dfecf96Smrg	}
4345dfecf96Smrg	else if (*op1->digs == 1) {
4355dfecf96Smrg	    /* multiply by +-1 */
4365dfecf96Smrg	    if (rop->alloc < op2->size) {
4375dfecf96Smrg		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op2->size);
4385dfecf96Smrg		rop->alloc = op2->size;
4395dfecf96Smrg	    }
4405dfecf96Smrg	    rop->size = op2->size;
4415dfecf96Smrg	    memmove(rop->digs, op2->digs, sizeof(BNS) * op2->size);
4425dfecf96Smrg	    rop->sign = op2->size > 1 || *op2->digs ? sign : 0;
4435dfecf96Smrg
4445dfecf96Smrg	    return;
4455dfecf96Smrg	}
4465dfecf96Smrg    }
4475dfecf96Smrg    else if (op2->size == 1) {
4485dfecf96Smrg	if (*op2->digs == 0) {
4495dfecf96Smrg	    /* multiply by 0 */
4505dfecf96Smrg	    mpi_seti(rop, 0);
4515dfecf96Smrg	    return;
4525dfecf96Smrg	}
4535dfecf96Smrg	else if (*op2->digs == 1) {
4545dfecf96Smrg	    /* multiply by +-1 */
4555dfecf96Smrg	    if (rop->alloc < op1->size) {
4565dfecf96Smrg		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op1->size);
4575dfecf96Smrg		rop->alloc = op1->size;
4585dfecf96Smrg	    }
4595dfecf96Smrg	    rop->size = op1->size;
4605dfecf96Smrg	    memmove(rop->digs, op1->digs, sizeof(BNS) * op1->size);
4615dfecf96Smrg	    rop->sign = op1->size > 1 || *op1->digs ? sign : 0;
4625dfecf96Smrg
4635dfecf96Smrg	    return;
4645dfecf96Smrg	}
4655dfecf96Smrg    }
4665dfecf96Smrg
4675dfecf96Smrg    /* allocate result data and set it to zero */
4685dfecf96Smrg    xsize = op1->size + op2->size;
4695dfecf96Smrg    if (rop->digs == op1->digs || rop->digs == op2->digs)
4705dfecf96Smrg	/* rop is also an operand */
4715dfecf96Smrg	digs = mp_calloc(1, sizeof(BNS) * xsize);
4725dfecf96Smrg    else {
4735dfecf96Smrg	if (rop->alloc < xsize) {
4745dfecf96Smrg	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xsize);
4755dfecf96Smrg	    rop->alloc = xsize;
4765dfecf96Smrg	}
4775dfecf96Smrg	digs = rop->digs;
4785dfecf96Smrg	memset(digs, '\0', sizeof(BNS) * xsize);
4795dfecf96Smrg    }
4805dfecf96Smrg
4815dfecf96Smrg    /* multiply operands */
4825dfecf96Smrg    xsize = mp_mul(digs, op1->digs, op2->digs, op1->size, op2->size);
4835dfecf96Smrg
4845dfecf96Smrg    /* store result in rop */
4855dfecf96Smrg    if (digs != rop->digs) {
4865dfecf96Smrg	/* if rop was an operand, free old data */
4875dfecf96Smrg	mp_free(rop->digs);
4885dfecf96Smrg	rop->digs = digs;
4895dfecf96Smrg    }
4905dfecf96Smrg    rop->size = xsize;
4915dfecf96Smrg
4925dfecf96Smrg    /* set result sign */
4935dfecf96Smrg    rop->sign = sign;
4945dfecf96Smrg}
4955dfecf96Smrg
4965dfecf96Smrgvoid
4975dfecf96Smrgmpi_muli(mpi *rop, mpi *op1, long op2)
4985dfecf96Smrg{
4995dfecf96Smrg    BNS digs[2];
5005dfecf96Smrg    mpi op;
5015dfecf96Smrg
5025dfecf96Smrg    op.digs = (BNS*)digs;
5035dfecf96Smrg    _mpi_seti(&op, op2);
5045dfecf96Smrg
5055dfecf96Smrg    mpi_mul(rop, op1, &op);
5065dfecf96Smrg}
5075dfecf96Smrg
5085dfecf96Smrgvoid
5095dfecf96Smrgmpi_div(mpi *rop, mpi *num, mpi *den)
5105dfecf96Smrg{
5115dfecf96Smrg    mpi_divqr(rop, NULL, num, den);
5125dfecf96Smrg}
5135dfecf96Smrg
5145dfecf96Smrgvoid
5155dfecf96Smrgmpi_rem(mpi *rop, mpi *num, mpi *den)
5165dfecf96Smrg{
5175dfecf96Smrg    mpi_divqr(NULL, rop, num, den);
5185dfecf96Smrg}
5195dfecf96Smrg
5205dfecf96Smrg/*
5215dfecf96Smrg * Could/should be changed to not allocate qdigs if qrop is NULL
5225dfecf96Smrg * Performance wouldn't suffer too much with a test on every loop iteration.
5235dfecf96Smrg */
5245dfecf96Smrgvoid
5255dfecf96Smrgmpi_divqr(mpi *qrop, mpi *rrop, mpi *num, mpi *den)
5265dfecf96Smrg{
5275dfecf96Smrg    long i, j;			/* counters */
5285dfecf96Smrg    int qsign;			/* sign of quotient */
5295dfecf96Smrg    int rsign;			/* sign of remainder */
5305dfecf96Smrg    BNI qsize;			/* size of quotient */
5315dfecf96Smrg    BNI rsize;			/* size of remainder */
5325dfecf96Smrg    BNS qest;			/* estimative of quotient value */
5335dfecf96Smrg    BNS *qdigs, *rdigs;		/* work copy or result */
5345dfecf96Smrg    BNS *ndigs, *ddigs;		/* work copy or divisor and dividend */
5355dfecf96Smrg    BNI value;			/* temporary result */
5365dfecf96Smrg    long svalue;		/* signed temporary result (2's complement) */
5375dfecf96Smrg    BNS carry, scarry, denorm;	/* carry and normalization */
5385dfecf96Smrg    BNI dpos, npos;		/* offsets in data */
5395dfecf96Smrg
5405dfecf96Smrg    /* get signs */
5415dfecf96Smrg    rsign = num->sign;
5425dfecf96Smrg    qsign = rsign ^ den->sign;
5435dfecf96Smrg
5445dfecf96Smrg    /* check for special case */
5455dfecf96Smrg    if (num->size < den->size) {
5465dfecf96Smrg	/* quotient is zero and remainder is numerator */
5475dfecf96Smrg	if (rrop && rrop->digs != num->digs) {
5485dfecf96Smrg	    if (rrop->alloc < num->size) {
5495dfecf96Smrg		rrop->digs = mp_realloc(rrop->digs, sizeof(BNS) * num->size);
5505dfecf96Smrg		rrop->alloc = num->size;
5515dfecf96Smrg	    }
5525dfecf96Smrg	    rrop->size = num->size;
5535dfecf96Smrg	    memcpy(rrop->digs, num->digs, sizeof(BNS) * num->size);
5545dfecf96Smrg	    rrop->sign = rsign;
5555dfecf96Smrg	}
5565dfecf96Smrg	if (qrop)
5575dfecf96Smrg	    mpi_seti(qrop, 0);
5585dfecf96Smrg
5595dfecf96Smrg	return;
5605dfecf96Smrg    }
5615dfecf96Smrg
5625dfecf96Smrg    /* estimate result sizes */
5635dfecf96Smrg    rsize = den->size;
5645dfecf96Smrg    qsize = num->size - den->size + 1;
5655dfecf96Smrg
5665dfecf96Smrg    /* offsets */
5675dfecf96Smrg    npos = num->size - 1;
5685dfecf96Smrg    dpos = den->size - 1;
5695dfecf96Smrg
5705dfecf96Smrg    /* allocate space for quotient and remainder */
5715dfecf96Smrg    if (qrop == NULL || qrop->digs == num->digs || qrop->digs == den->digs)
5725dfecf96Smrg	qdigs = mp_calloc(1, sizeof(BNS) * qsize);
5735dfecf96Smrg    else {
5745dfecf96Smrg	if (qrop->alloc < qsize) {
5755dfecf96Smrg	    qrop->digs = mp_realloc(qrop->digs, sizeof(BNS) * qsize);
5765dfecf96Smrg	    qrop->alloc = qsize;
5775dfecf96Smrg	}
5785dfecf96Smrg	memset(qrop->digs, '\0', sizeof(BNS) * qsize);
5795dfecf96Smrg	qdigs = qrop->digs;
5805dfecf96Smrg    }
5815dfecf96Smrg    if (rrop) {
5825dfecf96Smrg	if (rrop->digs == num->digs || rrop->digs == den->digs)
5835dfecf96Smrg	    rdigs = mp_calloc(1, sizeof(BNS) * rsize);
5845dfecf96Smrg	else {
5855dfecf96Smrg	    if (rrop->alloc < rsize) {
5865dfecf96Smrg		rrop->digs = mp_realloc(rrop->digs, sizeof(BNS) * rsize);
5875dfecf96Smrg		rrop->alloc = rsize;
5885dfecf96Smrg	    }
5895dfecf96Smrg	    memset(rrop->digs, '\0', sizeof(BNS) * rsize);
5905dfecf96Smrg	    rdigs = rrop->digs;
5915dfecf96Smrg	}
5925dfecf96Smrg    }
5935dfecf96Smrg    else
5945dfecf96Smrg	rdigs = NULL;	/* fix gcc warning */
5955dfecf96Smrg
5965dfecf96Smrg    /* special case, only one word in divisor */
5975dfecf96Smrg    if (dpos == 0) {
5985dfecf96Smrg	for (carry = 0, i = npos; i >= 0; i--) {
5995dfecf96Smrg	    value = ((BNI)carry << BNSBITS) + num->digs[i];
6005dfecf96Smrg	    qdigs[i] = (BNS)(value / den->digs[0]);
6015dfecf96Smrg	    carry = (BNS)(value % den->digs[0]);
6025dfecf96Smrg	}
6035dfecf96Smrg	if (rrop)
6045dfecf96Smrg	    rdigs[0] = carry;
6055dfecf96Smrg
6065dfecf96Smrg	goto mpi_divqr_done;
6075dfecf96Smrg    }
6085dfecf96Smrg
6095dfecf96Smrg    /* make work copy of numerator */
6105dfecf96Smrg    ndigs = mp_malloc(sizeof(BNS) * (num->size + 1));
6115dfecf96Smrg    /* allocate one extra word an update offset */
6125dfecf96Smrg    memcpy(ndigs, num->digs, sizeof(BNS) * num->size);
6135dfecf96Smrg    ndigs[num->size] = 0;
6145dfecf96Smrg    ++npos;
6155dfecf96Smrg
6165dfecf96Smrg    /* normalize */
6175dfecf96Smrg    denorm = (BNS)((BNI)CARRY / ((BNI)(den->digs[dpos]) + 1));
6185dfecf96Smrg
6195dfecf96Smrg    if (denorm > 1) {
6205dfecf96Smrg	/* i <= num->size because ndigs has an extra word */
6215dfecf96Smrg	for (carry = 0, i = 0; i <= num->size; i++) {
6225dfecf96Smrg	    value = ndigs[i] * (BNI)denorm + carry;
6235dfecf96Smrg	    ndigs[i] = (BNS)value;
6245dfecf96Smrg	    carry = (BNS)(value >> BNSBITS);
6255dfecf96Smrg	}
6265dfecf96Smrg	/* make work copy of denominator */
6275dfecf96Smrg	ddigs = mp_malloc(sizeof(BNS) * den->size);
6285dfecf96Smrg	memcpy(ddigs, den->digs, sizeof(BNS) * den->size);
6295dfecf96Smrg	for (carry = 0, i = 0; i < den->size; i++) {
6305dfecf96Smrg	    value = ddigs[i] * (BNI)denorm + carry;
6315dfecf96Smrg	    ddigs[i] = (BNS)value;
6325dfecf96Smrg	    carry = (BNS)(value >> BNSBITS);
6335dfecf96Smrg	}
6345dfecf96Smrg    }
6355dfecf96Smrg    else
6365dfecf96Smrg	/* only allocate copy of denominator if going to change it */
6375dfecf96Smrg	ddigs = den->digs;
6385dfecf96Smrg
6395dfecf96Smrg    /* divide mp integers */
6405dfecf96Smrg    for (j = qsize - 1; j >= 0; j--, npos--) {
6415dfecf96Smrg	/* estimate quotient */
6425dfecf96Smrg	if (ndigs[npos] == ddigs[dpos])
6435dfecf96Smrg	    qest = (BNS)SMASK;
6445dfecf96Smrg	else
64531de2854Smrg	    qest = (BNS)((((BNI)(ndigs[npos]) << BNSBITS) + ndigs[npos - 1]) /
6465dfecf96Smrg			 ddigs[dpos]);
6475dfecf96Smrg
64831de2854Smrg	while ((value = ((BNI)(ndigs[npos]) << BNSBITS) + ndigs[npos - 1] -
6495dfecf96Smrg	        qest * (BNI)(ddigs[dpos])) < CARRY &&
6505dfecf96Smrg		ddigs[dpos - 1] * (BNI)qest >
6515dfecf96Smrg		(value << BNSBITS) + ndigs[npos - 2])
6525dfecf96Smrg	       --qest;
6535dfecf96Smrg
6545dfecf96Smrg	/* multiply and subtract */
6555dfecf96Smrg	carry = scarry = 0;
6565dfecf96Smrg	for (i = 0; i < den->size; i++) {
6575dfecf96Smrg	    value = qest * (BNI)ddigs[i] + carry;
6585dfecf96Smrg	    carry = (BNS)(value >> BNSBITS);
6595dfecf96Smrg	    svalue = (long)ndigs[npos - dpos + i - 1] - (long)(value & SMASK) -
6605dfecf96Smrg		     (long)scarry;
6615dfecf96Smrg	    ndigs[npos - dpos + i - 1] = (BNS)svalue;
6625dfecf96Smrg	    scarry = svalue < 0;
6635dfecf96Smrg	}
6645dfecf96Smrg
6655dfecf96Smrg	svalue = (long)ndigs[npos] - (long)(carry & SMASK) - (long)scarry;
6665dfecf96Smrg	ndigs[npos] = (BNS)svalue;
6675dfecf96Smrg
6685dfecf96Smrg	if (svalue & LMASK) {
6695dfecf96Smrg	    /* quotient too big */
6705dfecf96Smrg	    --qest;
6715dfecf96Smrg	    carry = 0;
6725dfecf96Smrg	    for (i = 0; i < den->size; i++) {
6735dfecf96Smrg		value = ndigs[npos - dpos + i - 1] + (BNI)carry + (BNI)ddigs[i];
6745dfecf96Smrg		ndigs[npos - dpos + i - 1] = (BNS)value;
6755dfecf96Smrg		carry = (BNS)(value >> BNSBITS);
6765dfecf96Smrg	    }
6775dfecf96Smrg	    ndigs[npos] += carry;
6785dfecf96Smrg	}
6795dfecf96Smrg
6805dfecf96Smrg	qdigs[j] = qest;
6815dfecf96Smrg    }
6825dfecf96Smrg
6835dfecf96Smrg    /* calculate remainder */
6845dfecf96Smrg    if (rrop) {
6855dfecf96Smrg	for (carry = 0, j = dpos; j >= 0; j--) {
6865dfecf96Smrg	    value = ((BNI)carry << BNSBITS) + ndigs[j];
6875dfecf96Smrg	    rdigs[j] = (BNS)(value / denorm);
6885dfecf96Smrg	    carry = (BNS)(value % denorm);
6895dfecf96Smrg	}
6905dfecf96Smrg    }
6915dfecf96Smrg
6925dfecf96Smrg    mp_free(ndigs);
6935dfecf96Smrg    if (ddigs != den->digs)
6945dfecf96Smrg	mp_free(ddigs);
6955dfecf96Smrg
6965dfecf96Smrgmpi_divqr_done:
6975dfecf96Smrg    if (rrop) {
6985dfecf96Smrg	if (rrop->digs != rdigs)
6995dfecf96Smrg	    mp_free(rrop->digs);
7005dfecf96Smrg	/* normalize remainder */
7015dfecf96Smrg	for (i = rsize - 1; i >= 0; i--)
7025dfecf96Smrg	    if (rdigs[i] != 0)
7035dfecf96Smrg		break;
7045dfecf96Smrg	if (i != rsize - 1) {
7055dfecf96Smrg	    if (i < 0) {
7065dfecf96Smrg		rsign = 0;
7075dfecf96Smrg		rsize = 1;
7085dfecf96Smrg	    }
7095dfecf96Smrg	    else
7105dfecf96Smrg		rsize = i + 1;
7115dfecf96Smrg	}
7125dfecf96Smrg	rrop->digs = rdigs;
7135dfecf96Smrg	rrop->sign = rsign;
7145dfecf96Smrg	rrop->size = rsize;
7155dfecf96Smrg    }
7165dfecf96Smrg
7175dfecf96Smrg    /* normalize quotient */
7185dfecf96Smrg    if (qrop) {
7195dfecf96Smrg	if (qrop->digs != qdigs)
7205dfecf96Smrg	    mp_free(qrop->digs);
7215dfecf96Smrg	for (i = qsize - 1; i >= 0; i--)
7225dfecf96Smrg	    if (qdigs[i] != 0)
7235dfecf96Smrg		break;
7245dfecf96Smrg	if (i != qsize - 1) {
7255dfecf96Smrg	    if (i < 0) {
7265dfecf96Smrg		qsign = 0;
7275dfecf96Smrg		qsize = 1;
7285dfecf96Smrg	    }
7295dfecf96Smrg	    else
7305dfecf96Smrg		qsize = i + 1;
7315dfecf96Smrg	}
7325dfecf96Smrg	qrop->digs = qdigs;
7335dfecf96Smrg	qrop->sign = qsign;
7345dfecf96Smrg	qrop->size = qsize;
7355dfecf96Smrg    }
7365dfecf96Smrg    else
7375dfecf96Smrg	mp_free(qdigs);
7385dfecf96Smrg}
7395dfecf96Smrg
7405dfecf96Smrglong
7415dfecf96Smrgmpi_divqri(mpi *qrop, mpi *num, long den)
7425dfecf96Smrg{
7435dfecf96Smrg    BNS ddigs[2];
7445dfecf96Smrg    mpi dop, rrop;
7455dfecf96Smrg    long remainder;
7465dfecf96Smrg
7475dfecf96Smrg    dop.digs = (BNS*)ddigs;
7485dfecf96Smrg    _mpi_seti(&dop, den);
7495dfecf96Smrg
7505dfecf96Smrg    memset(&rrop, '\0', sizeof(mpi));
7515dfecf96Smrg    mpi_init(&rrop);
7525dfecf96Smrg    mpi_divqr(qrop, &rrop, num, &dop);
7535dfecf96Smrg    remainder = rrop.digs[0];
7545dfecf96Smrg    if (rrop.size > 1)
7555dfecf96Smrg	remainder |= (BNI)(rrop.digs[1]) << BNSBITS;
7565dfecf96Smrg    if (rrop.sign)
7575dfecf96Smrg	remainder = -remainder;
7585dfecf96Smrg    mpi_clear(&rrop);
7595dfecf96Smrg
7605dfecf96Smrg    return (remainder);
7615dfecf96Smrg}
7625dfecf96Smrg
7635dfecf96Smrgvoid
7645dfecf96Smrgmpi_divi(mpi *rop, mpi *num, long den)
7655dfecf96Smrg{
7665dfecf96Smrg    BNS ddigs[2];
7675dfecf96Smrg    mpi dop;
7685dfecf96Smrg
7695dfecf96Smrg    dop.digs = (BNS*)ddigs;
7705dfecf96Smrg    _mpi_seti(&dop, den);
7715dfecf96Smrg
7725dfecf96Smrg    mpi_divqr(rop, NULL, num, &dop);
7735dfecf96Smrg}
7745dfecf96Smrg
7755dfecf96Smrglong
7765dfecf96Smrgmpi_remi(mpi *num, long den)
7775dfecf96Smrg{
7785dfecf96Smrg    return (mpi_divqri(NULL, num, den));
7795dfecf96Smrg}
7805dfecf96Smrg
7815dfecf96Smrgvoid
7825dfecf96Smrgmpi_mod(mpi *rop, mpi *num, mpi *den)
7835dfecf96Smrg{
7845dfecf96Smrg    mpi_rem(rop, num, den);
7855dfecf96Smrg    if (num->sign ^ den->sign)
7865dfecf96Smrg	mpi_add(rop, rop, den);
7875dfecf96Smrg}
7885dfecf96Smrg
7895dfecf96Smrglong
7905dfecf96Smrgmpi_modi(mpi *num, long den)
7915dfecf96Smrg{
7925dfecf96Smrg    long remainder;
7935dfecf96Smrg
7945dfecf96Smrg    remainder = mpi_remi(num, den);
7955dfecf96Smrg    if (num->sign ^ (den < 0))
7965dfecf96Smrg	remainder += den;
7975dfecf96Smrg
7985dfecf96Smrg    return (remainder);
7995dfecf96Smrg}
8005dfecf96Smrg
8015dfecf96Smrgvoid
8025dfecf96Smrgmpi_gcd(mpi *rop, mpi *num, mpi *den)
8035dfecf96Smrg{
8045dfecf96Smrg    long cmp;
8055dfecf96Smrg    mpi rem;
8065dfecf96Smrg
8075dfecf96Smrg    /* check if result already given */
8085dfecf96Smrg    cmp = mpi_cmpabs(num, den);
8095dfecf96Smrg
8105dfecf96Smrg    /* check if num is equal to den or if num is zero */
8115dfecf96Smrg    if (cmp == 0 || (num->size == 1 && num->digs[0] == 0)) {
8125dfecf96Smrg	mpi_set(rop, den);
8135dfecf96Smrg	rop->sign = 0;
8145dfecf96Smrg	return;
8155dfecf96Smrg    }
8165dfecf96Smrg    /* check if den is not zero */
8175dfecf96Smrg    if (den->size == 1 && den->digs[0] == 0) {
8185dfecf96Smrg	mpi_set(rop, num);
8195dfecf96Smrg	rop->sign = 0;
8205dfecf96Smrg	return;
8215dfecf96Smrg    }
8225dfecf96Smrg
8235dfecf96Smrg    /* don't call mpi_init, relies on realloc(0, size) == malloc(size) */
8245dfecf96Smrg    memset(&rem, '\0', sizeof(mpi));
8255dfecf96Smrg
8265dfecf96Smrg    /* if num larger than den */
8275dfecf96Smrg    if (cmp > 0) {
8285dfecf96Smrg	mpi_rem(&rem, num, den);
8295dfecf96Smrg	if (rem.size == 1 && rem.digs[0] == 0) {
8305dfecf96Smrg	    /* exact division */
8315dfecf96Smrg	    mpi_set(rop, den);
8325dfecf96Smrg	    rop->sign = 0;
8335dfecf96Smrg	    mpi_clear(&rem);
8345dfecf96Smrg	    return;
8355dfecf96Smrg	}
8365dfecf96Smrg	mpi_set(rop, den);
8375dfecf96Smrg    }
8385dfecf96Smrg    else {
8395dfecf96Smrg	mpi_rem(&rem, den, num);
8405dfecf96Smrg	if (rem.size == 1 && rem.digs[0] == 0) {
8415dfecf96Smrg	    /* exact division */
8425dfecf96Smrg	    mpi_set(rop, num);
8435dfecf96Smrg	    rop->sign = 0;
8445dfecf96Smrg	    mpi_clear(&rem);
8455dfecf96Smrg	    return;
8465dfecf96Smrg	}
8475dfecf96Smrg	mpi_set(rop, num);
8485dfecf96Smrg    }
8495dfecf96Smrg
8505dfecf96Smrg    /* loop using positive values */
8515dfecf96Smrg    rop->sign = rem.sign = 0;
8525dfecf96Smrg
8535dfecf96Smrg    /* cannot optimize this inverting rem/rop assignment earlier
8545dfecf96Smrg     * because rop mais be an operand */
8555dfecf96Smrg    mpi_swap(rop, &rem);
8565dfecf96Smrg
8575dfecf96Smrg    /* Euclides algorithm */
8585dfecf96Smrg    for (;;) {
8595dfecf96Smrg	mpi_rem(&rem, &rem, rop);
8605dfecf96Smrg	if (rem.size == 1 && rem.digs[0] == 0)
8615dfecf96Smrg	    break;
8625dfecf96Smrg	mpi_swap(rop, &rem);
8635dfecf96Smrg    }
8645dfecf96Smrg    mpi_clear(&rem);
8655dfecf96Smrg}
8665dfecf96Smrg
8675dfecf96Smrgvoid
8685dfecf96Smrgmpi_lcm(mpi *rop, mpi *num, mpi *den)
8695dfecf96Smrg{
8705dfecf96Smrg    mpi gcd;
8715dfecf96Smrg
8725dfecf96Smrg    /* check for zero operand */
8735dfecf96Smrg    if ((num->size == 1 && num->digs[0] == 0) ||
8745dfecf96Smrg	(den->size == 1 && den->digs[0] == 0)) {
8755dfecf96Smrg	rop->digs[0] = 0;
8765dfecf96Smrg	rop->sign = 0;
8775dfecf96Smrg	return;
8785dfecf96Smrg    }
8795dfecf96Smrg
8805dfecf96Smrg    /* don't call mpi_init, relies on realloc(0, size) == malloc(size) */
8815dfecf96Smrg    memset(&gcd, '\0', sizeof(mpi));
8825dfecf96Smrg
8835dfecf96Smrg    mpi_gcd(&gcd, num, den);
8845dfecf96Smrg    mpi_div(&gcd, den, &gcd);
8855dfecf96Smrg    mpi_mul(rop, &gcd, num);
8865dfecf96Smrg    rop->sign = 0;
8875dfecf96Smrg
8885dfecf96Smrg    mpi_clear(&gcd);
8895dfecf96Smrg}
8905dfecf96Smrg
8915dfecf96Smrgvoid
8925dfecf96Smrgmpi_pow(mpi *rop, mpi *op, unsigned long exp)
8935dfecf96Smrg{
8945dfecf96Smrg    mpi zop, top;
8955dfecf96Smrg
8965dfecf96Smrg    if (exp == 2) {
8975dfecf96Smrg	mpi_mul(rop, op, op);
8985dfecf96Smrg	return;
8995dfecf96Smrg    }
9005dfecf96Smrg    /* check for op**0 */
9015dfecf96Smrg    else if (exp == 0) {
9025dfecf96Smrg	rop->digs[0] = 1;
9035dfecf96Smrg	rop->size = 1;
9045dfecf96Smrg	rop->sign = 0;
9055dfecf96Smrg	return;
9065dfecf96Smrg    }
9075dfecf96Smrg    else if (exp == 1) {
9085dfecf96Smrg	mpi_set(rop, op);
9095dfecf96Smrg	return;
9105dfecf96Smrg    }
9115dfecf96Smrg    else if (op->size == 1) {
9125dfecf96Smrg	if (op->digs[0] == 0) {
9135dfecf96Smrg	    mpi_seti(rop, 0);
9145dfecf96Smrg	    return;
9155dfecf96Smrg	}
9165dfecf96Smrg	else if (op->digs[0] == 1) {
9175dfecf96Smrg	    mpi_seti(rop, op->sign && (exp & 1) ? -1 : 1);
9185dfecf96Smrg	    return;
9195dfecf96Smrg	}
9205dfecf96Smrg    }
9215dfecf96Smrg
9225dfecf96Smrg    memset(&zop, '\0', sizeof(mpi));
9235dfecf96Smrg    memset(&top, '\0', sizeof(mpi));
9245dfecf96Smrg    mpi_set(&zop, op);
9255dfecf96Smrg    mpi_set(&top, op);
9265dfecf96Smrg    for (--exp; exp; exp >>= 1) {
9275dfecf96Smrg	if (exp & 1)
9285dfecf96Smrg	    mpi_mul(&zop, &top, &zop);
9295dfecf96Smrg	mpi_mul(&top, &top, &top);
9305dfecf96Smrg    }
9315dfecf96Smrg
9325dfecf96Smrg    mpi_clear(&top);
9335dfecf96Smrg    rop->sign = zop.sign;
9345dfecf96Smrg    mp_free(rop->digs);
9355dfecf96Smrg    rop->digs = zop.digs;
9365dfecf96Smrg    rop->size = zop.size;
9375dfecf96Smrg}
9385dfecf96Smrg
9395dfecf96Smrg/* Find integer root of given number using the iteration
9405dfecf96Smrg *	x{n+1} = ((K-1) * x{n} + N / x{n}^(K-1)) / K
9415dfecf96Smrg */
9425dfecf96Smrgint
9435dfecf96Smrgmpi_root(mpi *rop, mpi *op, unsigned long nth)
9445dfecf96Smrg{
9455dfecf96Smrg    long bits, cmp;
9465dfecf96Smrg    int exact;
9475dfecf96Smrg    int sign;
9485dfecf96Smrg    mpi *r, t, temp, quot, old, rem;
9495dfecf96Smrg
9505dfecf96Smrg    sign = op->sign;
9515dfecf96Smrg
9525dfecf96Smrg    /* divide by zero op**1/0 */
9535dfecf96Smrg    if (nth == 0) {
9545dfecf96Smrg	int one = 1, zero = 0;
9555dfecf96Smrg	one = one / zero;
9565dfecf96Smrg    }
9575dfecf96Smrg    /* result is complex */
9585dfecf96Smrg    if (sign && !(nth & 1)) {
9595dfecf96Smrg	int one = 1, zero = 0;
9605dfecf96Smrg	one = one / zero;
9615dfecf96Smrg    }
9625dfecf96Smrg
9635dfecf96Smrg    /* special case op**1/1 = op */
9645dfecf96Smrg    if (nth == 1) {
9655dfecf96Smrg	mpi_set(rop, op);
9665dfecf96Smrg	return (1);
9675dfecf96Smrg    }
9685dfecf96Smrg
9695dfecf96Smrg    bits = mpi_getsize(op, 2) - 2;
9705dfecf96Smrg
9715dfecf96Smrg    if (bits < 0 || bits / nth == 0) {
9725dfecf96Smrg	/* integral root is surely less than 2 */
9735dfecf96Smrg	exact = op->size == 1 && (op->digs[0] == 1 || op->digs[0] == 0);
9745dfecf96Smrg	mpi_seti(rop, sign ? -1 : op->digs[0] == 0 ? 0 : 1);
9755dfecf96Smrg
9765dfecf96Smrg	return (exact == 1);
9775dfecf96Smrg    }
9785dfecf96Smrg
9795dfecf96Smrg    /* initialize */
9805dfecf96Smrg    if (rop != op)
9815dfecf96Smrg	r = rop;
9825dfecf96Smrg    else {
9835dfecf96Smrg	r = &t;
9845dfecf96Smrg	memset(r, '\0', sizeof(mpi));
9855dfecf96Smrg    }
9865dfecf96Smrg    memset(&temp, '\0', sizeof(mpi));
9875dfecf96Smrg    memset(&quot, '\0', sizeof(mpi));
9885dfecf96Smrg    memset(&old, '\0', sizeof(mpi));
9895dfecf96Smrg    memset(&rem, '\0', sizeof(mpi));
9905dfecf96Smrg
9915dfecf96Smrg    if (sign)
9925dfecf96Smrg	r->sign = 0;
9935dfecf96Smrg
9945dfecf96Smrg    /* root aproximation */
9955dfecf96Smrg    mpi_ash(r, op, -(bits - (bits / nth)));
9965dfecf96Smrg
9975dfecf96Smrg    for (;;) {
9985dfecf96Smrg	mpi_pow(&temp, r, nth - 1);
9995dfecf96Smrg	mpi_divqr(&quot, &rem, op, &temp);
10005dfecf96Smrg	cmp = mpi_cmpabs(r, &quot);
10015dfecf96Smrg	if (cmp == 0) {
10025dfecf96Smrg	    exact = mpi_cmpi(&rem, 0) == 0;
10035dfecf96Smrg	    break;
10045dfecf96Smrg	}
10055dfecf96Smrg	else if (cmp < 0) {
10065dfecf96Smrg	    if (mpi_cmpabs(r, &old) == 0) {
10075dfecf96Smrg		exact = 0;
10085dfecf96Smrg		break;
10095dfecf96Smrg	    }
10105dfecf96Smrg	    mpi_set(&old, r);
10115dfecf96Smrg	}
10125dfecf96Smrg	mpi_muli(&temp, r, nth - 1);
10135dfecf96Smrg	mpi_add(&quot, &quot, &temp);
10145dfecf96Smrg	mpi_divi(r, &quot, nth);
10155dfecf96Smrg    }
10165dfecf96Smrg
10175dfecf96Smrg    mpi_clear(&temp);
10185dfecf96Smrg    mpi_clear(&quot);
10195dfecf96Smrg    mpi_clear(&old);
10205dfecf96Smrg    mpi_clear(&rem);
10215dfecf96Smrg    if (r != rop) {
10225dfecf96Smrg	mpi_set(rop, r);
10235dfecf96Smrg	mpi_clear(r);
10245dfecf96Smrg    }
10255dfecf96Smrg    rop->sign = sign;
10265dfecf96Smrg
10275dfecf96Smrg    return (exact);
10285dfecf96Smrg}
10295dfecf96Smrg
10305dfecf96Smrg/*
10315dfecf96Smrg * Find square root using the iteration:
10325dfecf96Smrg *	x{n+1} = (x{n}+N/x{n})/2
10335dfecf96Smrg */
10345dfecf96Smrgint
10355dfecf96Smrgmpi_sqrt(mpi *rop, mpi *op)
10365dfecf96Smrg{
10375dfecf96Smrg    long bits, cmp;
10385dfecf96Smrg    int exact;
10395dfecf96Smrg    mpi *r, t, quot, rem, old;
10405dfecf96Smrg
10415dfecf96Smrg    /* result is complex */
10425dfecf96Smrg    if (op->sign) {
10435dfecf96Smrg	int one = 1, zero = 0;
10445dfecf96Smrg	one = one / zero;
10455dfecf96Smrg    }
10465dfecf96Smrg
10475dfecf96Smrg    bits = mpi_getsize(op, 2) - 2;
10485dfecf96Smrg
10495dfecf96Smrg    if (bits < 2) {
10505dfecf96Smrg	/* integral root is surely less than 2 */
10515dfecf96Smrg	exact = op->size == 1 && (op->digs[0] == 1 || op->digs[0] == 0);
10525dfecf96Smrg	mpi_seti(rop, op->digs[0] == 0 ? 0 : 1);
10535dfecf96Smrg
10545dfecf96Smrg	return (exact == 1);
10555dfecf96Smrg    }
10565dfecf96Smrg
10575dfecf96Smrg    /* initialize */
10585dfecf96Smrg    if (rop != op)
10595dfecf96Smrg	r = rop;
10605dfecf96Smrg    else {
10615dfecf96Smrg	r = &t;
10625dfecf96Smrg	memset(r, '\0', sizeof(mpi));
10635dfecf96Smrg    }
10645dfecf96Smrg    memset(&quot, '\0', sizeof(mpi));
10655dfecf96Smrg    memset(&rem, '\0', sizeof(mpi));
10665dfecf96Smrg    memset(&old, '\0', sizeof(mpi));
10675dfecf96Smrg
10685dfecf96Smrg    /* root aproximation */
10695dfecf96Smrg    mpi_ash(r, op, -(bits - (bits / 2)));
10705dfecf96Smrg
10715dfecf96Smrg    for (;;) {
10725dfecf96Smrg	if (mpi_cmpabs(r, &old) == 0) {
10735dfecf96Smrg	    exact = 0;
10745dfecf96Smrg	    break;
10755dfecf96Smrg	}
10765dfecf96Smrg	mpi_divqr(&quot, &rem, op, r);
10775dfecf96Smrg	cmp = mpi_cmpabs(&quot, r);
10785dfecf96Smrg	if (cmp == 0) {
10795dfecf96Smrg	    exact = mpi_cmpi(&rem, 0) == 0;
10805dfecf96Smrg	    break;
10815dfecf96Smrg	}
10825dfecf96Smrg	else if (cmp > 0 && rem.size == 1 && rem.digs[0] == 0)
10835dfecf96Smrg	    mpi_subi(&quot, &quot, 1);
10845dfecf96Smrg	mpi_set(&old, r);
10855dfecf96Smrg	mpi_add(r, r, &quot);
10865dfecf96Smrg	mpi_ash(r, r, -1);
10875dfecf96Smrg    }
10885dfecf96Smrg    mpi_clear(&quot);
10895dfecf96Smrg    mpi_clear(&rem);
10905dfecf96Smrg    mpi_clear(&old);
10915dfecf96Smrg    if (r != rop) {
10925dfecf96Smrg	mpi_set(rop, r);
10935dfecf96Smrg	mpi_clear(r);
10945dfecf96Smrg    }
10955dfecf96Smrg
10965dfecf96Smrg    return (exact);
10975dfecf96Smrg}
10985dfecf96Smrg
10995dfecf96Smrgvoid
11005dfecf96Smrgmpi_ash(mpi *rop, mpi *op, long shift)
11015dfecf96Smrg{
11025dfecf96Smrg    long i;			/* counter */
11035dfecf96Smrg    long xsize;			/* maximum result size */
11045dfecf96Smrg    BNS *digs;
11055dfecf96Smrg
11065dfecf96Smrg    /* check for 0 shift, multiply/divide by 1 */
11075dfecf96Smrg    if (shift == 0) {
11085dfecf96Smrg	if (rop != op) {
11095dfecf96Smrg	    if (rop->alloc < op->size) {
11105dfecf96Smrg		rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op->size);
11115dfecf96Smrg		rop->alloc = op->size;
11125dfecf96Smrg	    }
11135dfecf96Smrg	    rop->size = op->size;
11145dfecf96Smrg	    memcpy(rop->digs, op->digs, sizeof(BNS) * op->size);
11155dfecf96Smrg	}
11165dfecf96Smrg
11175dfecf96Smrg	return;
11185dfecf96Smrg    }
11195dfecf96Smrg    else if (op->size == 1 && op->digs[0] == 0) {
11205dfecf96Smrg	rop->sign = 0;
11215dfecf96Smrg	rop->size = 1;
11225dfecf96Smrg	rop->digs[0] = 0;
11235dfecf96Smrg
11245dfecf96Smrg	return;
11255dfecf96Smrg    }
11265dfecf96Smrg
11275dfecf96Smrg    /* check shift and initialize */
11285dfecf96Smrg    if (shift > 0)
11295dfecf96Smrg	xsize = op->size + (shift / BNSBITS) + 1;
11305dfecf96Smrg    else {
11315dfecf96Smrg	xsize = op->size - ((-shift) / BNSBITS);
11325dfecf96Smrg	if (xsize <= 0) {
11335dfecf96Smrg	    rop->size = 1;
11345dfecf96Smrg	    rop->sign = op->sign;
11355dfecf96Smrg	    rop->digs[0] = op->sign ? 1 : 0;
11365dfecf96Smrg
11375dfecf96Smrg	    return;
11385dfecf96Smrg	}
11395dfecf96Smrg    }
11405dfecf96Smrg
11415dfecf96Smrg    /* allocate/adjust memory for result */
11425dfecf96Smrg    if (rop == op)
11435dfecf96Smrg	digs = mp_malloc(sizeof(BNS) * xsize);
11445dfecf96Smrg    else {
11455dfecf96Smrg	if (rop->alloc < xsize) {
11465dfecf96Smrg	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xsize);
11475dfecf96Smrg	    rop->alloc = xsize;
11485dfecf96Smrg	}
11495dfecf96Smrg	digs = rop->digs;
11505dfecf96Smrg    }
11515dfecf96Smrg
11525dfecf96Smrg    /* left shift, multiply by power of two */
11535dfecf96Smrg    if (shift > 0)
11545dfecf96Smrg	rop->size = mp_lshift(digs, op->digs, op->size, shift);
11555dfecf96Smrg    /* right shift, divide by power of two */
11565dfecf96Smrg    else {
11575dfecf96Smrg	long carry = 0;
11585dfecf96Smrg
11595dfecf96Smrg	if (op->sign) {
11605dfecf96Smrg	    BNI words, bits;
11615dfecf96Smrg
11625dfecf96Smrg	    words = -shift / BNSBITS;
11635dfecf96Smrg	    bits = -shift % BNSBITS;
11645dfecf96Smrg	    for (i = 0; i < words; i++)
11655dfecf96Smrg		carry |= op->digs[xsize + i];
11665dfecf96Smrg	    if (!carry) {
11675dfecf96Smrg		for (i = 0; i < bits; i++)
11685dfecf96Smrg		    if (op->digs[op->size - xsize] & (1 << i)) {
11695dfecf96Smrg			carry = 1;
11705dfecf96Smrg			break;
11715dfecf96Smrg		    }
11725dfecf96Smrg	    }
11735dfecf96Smrg	}
11745dfecf96Smrg	rop->size = mp_rshift(digs, op->digs, op->size, -shift);
11755dfecf96Smrg
11765dfecf96Smrg	if (carry)
11775dfecf96Smrg	    /* emulates two's complement subtracting 1 from the result */
11785dfecf96Smrg	    rop->size = mp_add(digs, digs, mpone.digs, rop->size, 1);
11795dfecf96Smrg    }
11805dfecf96Smrg
11815dfecf96Smrg    if (rop->digs != digs) {
11825dfecf96Smrg	mp_free(rop->digs);
11835dfecf96Smrg	rop->alloc = rop->size;
11845dfecf96Smrg	rop->digs = digs;
11855dfecf96Smrg    }
11865dfecf96Smrg    rop->sign = op->sign;
11875dfecf96Smrg}
11885dfecf96Smrg
11895dfecf96Smrgstatic INLINE BNS
11905dfecf96Smrgmpi_logic(BNS op1, BNS op2, BNS op)
11915dfecf96Smrg{
11925dfecf96Smrg    switch (op) {
11935dfecf96Smrg	case '&':
11945dfecf96Smrg	    return (op1 & op2);
11955dfecf96Smrg	case '|':
11965dfecf96Smrg	    return (op1 | op2);
11975dfecf96Smrg	case '^':
11985dfecf96Smrg	    return (op1 ^ op2);
11995dfecf96Smrg    }
12005dfecf96Smrg
12015dfecf96Smrg    return (SMASK);
12025dfecf96Smrg}
12035dfecf96Smrg
12045dfecf96Smrgstatic void
12055dfecf96Smrgmpi_log(mpi *rop, mpi *op1, mpi *op2, BNS op)
12065dfecf96Smrg{
12075dfecf96Smrg    long i;			/* counter */
12085dfecf96Smrg    long c, c1, c2;		/* carry */
12095dfecf96Smrg    BNS *digs, *digs1, *digs2;	/* pointers to mp data */
12105dfecf96Smrg    BNI size, size1, size2;
12115dfecf96Smrg    BNS sign, sign1, sign2;
12125dfecf96Smrg    BNS n, n1, n2;		/* logical operands */
12135dfecf96Smrg    BNI sum;
12145dfecf96Smrg
12155dfecf96Smrg    /* initialize */
12165dfecf96Smrg    size1 = op1->size;
12175dfecf96Smrg    size2 = op2->size;
12185dfecf96Smrg
12195dfecf96Smrg    sign1 = op1->sign ? SMASK : 0;
12205dfecf96Smrg    sign2 = op2->sign ? SMASK : 0;
12215dfecf96Smrg
12225dfecf96Smrg    sign = mpi_logic(sign1, sign2, op);
12235dfecf96Smrg
12245dfecf96Smrg    size = MAX(size1, size2);
12255dfecf96Smrg    if (sign)
12265dfecf96Smrg	++size;
12275dfecf96Smrg    if (rop->alloc < size) {
12285dfecf96Smrg	rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size);
12295dfecf96Smrg	rop->alloc = size;
12305dfecf96Smrg    }
12315dfecf96Smrg
12325dfecf96Smrg    digs = rop->digs;
12335dfecf96Smrg    digs1 = op1->digs;
12345dfecf96Smrg    digs2 = op2->digs;
12355dfecf96Smrg
12365dfecf96Smrg    c = c1 = c2 = 1;
12375dfecf96Smrg
12385dfecf96Smrg    /* apply logical operation */
12395dfecf96Smrg    for (i = 0; i < size; i++) {
12405dfecf96Smrg	if (i >= size1)
12415dfecf96Smrg	    n1 = sign1;
12425dfecf96Smrg	else if (sign1) {
12435dfecf96Smrg	    sum = (BNI)(BNS)(~digs1[i]) + c1;
12445dfecf96Smrg	    c1 = (long)(sum >> BNSBITS);
12455dfecf96Smrg	    n1 = (BNS)sum;
12465dfecf96Smrg	}
12475dfecf96Smrg	else
12485dfecf96Smrg	    n1 = digs1[i];
12495dfecf96Smrg
12505dfecf96Smrg	if (i >= size2)
12515dfecf96Smrg	    n2 = sign2;
12525dfecf96Smrg	else if (sign2) {
12535dfecf96Smrg	    sum = (BNI)(BNS)(~digs2[i]) + c2;
12545dfecf96Smrg	    c2 = (long)(sum >> BNSBITS);
12555dfecf96Smrg	    n2 = (BNS)sum;
12565dfecf96Smrg	}
12575dfecf96Smrg	else
12585dfecf96Smrg	    n2 = digs2[i];
12595dfecf96Smrg
12605dfecf96Smrg	n = mpi_logic(n1, n2, op);
12615dfecf96Smrg	if (sign) {
12625dfecf96Smrg	    sum = (BNI)(BNS)(~n) + c;
12635dfecf96Smrg	    c = (long)(sum >> BNSBITS);
12645dfecf96Smrg	    digs[i] = (BNS)sum;
12655dfecf96Smrg	}
12665dfecf96Smrg	else
12675dfecf96Smrg	    digs[i] = n;
12685dfecf96Smrg    }
12695dfecf96Smrg
12705dfecf96Smrg    /* normalize */
12715dfecf96Smrg    for (i = size - 1; i >= 0; i--)
12725dfecf96Smrg	if (digs[i] != 0)
12735dfecf96Smrg	    break;
12745dfecf96Smrg    if (i != size - 1) {
12755dfecf96Smrg	if (i < 0) {
12765dfecf96Smrg	    sign = 0;
12775dfecf96Smrg	    size = 1;
12785dfecf96Smrg	}
12795dfecf96Smrg	else
12805dfecf96Smrg	    size = i + 1;
12815dfecf96Smrg    }
12825dfecf96Smrg
12835dfecf96Smrg    rop->sign = sign != 0;
12845dfecf96Smrg    rop->size = size;
12855dfecf96Smrg}
12865dfecf96Smrg
12875dfecf96Smrgvoid
12885dfecf96Smrgmpi_and(mpi *rop, mpi *op1, mpi *op2)
12895dfecf96Smrg{
12905dfecf96Smrg    mpi_log(rop, op1, op2, '&');
12915dfecf96Smrg}
12925dfecf96Smrg
12935dfecf96Smrgvoid
12945dfecf96Smrgmpi_ior(mpi *rop, mpi *op1, mpi *op2)
12955dfecf96Smrg{
12965dfecf96Smrg    mpi_log(rop, op1, op2, '|');
12975dfecf96Smrg}
12985dfecf96Smrg
12995dfecf96Smrgvoid
13005dfecf96Smrgmpi_xor(mpi *rop, mpi *op1, mpi *op2)
13015dfecf96Smrg{
13025dfecf96Smrg    mpi_log(rop, op1, op2, '^');
13035dfecf96Smrg}
13045dfecf96Smrg
13055dfecf96Smrgvoid
13065dfecf96Smrgmpi_com(mpi *rop, mpi *op)
13075dfecf96Smrg{
13085dfecf96Smrg    static BNS digs[1] = { 1 };
13095dfecf96Smrg    static mpi one = { 0, 1, 1, (BNS*)&digs };
13105dfecf96Smrg
13115dfecf96Smrg    mpi_log(rop, rop, &one, '^');
13125dfecf96Smrg}
13135dfecf96Smrg
13145dfecf96Smrgvoid
13155dfecf96Smrgmpi_neg(mpi *rop, mpi *op)
13165dfecf96Smrg{
13175dfecf96Smrg    int sign = op->sign ^ 1;
13185dfecf96Smrg
13195dfecf96Smrg    if (rop->digs != op->digs) {
13205dfecf96Smrg	if (rop->alloc < op->size) {
13215dfecf96Smrg	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * rop->size);
13225dfecf96Smrg	    rop->alloc = op->size;
13235dfecf96Smrg	}
13245dfecf96Smrg	rop->size = op->size;
13255dfecf96Smrg	memcpy(rop->digs, op->digs, sizeof(BNS) * rop->size);
13265dfecf96Smrg    }
13275dfecf96Smrg
13285dfecf96Smrg    rop->sign = sign;
13295dfecf96Smrg}
13305dfecf96Smrg
13315dfecf96Smrgvoid
13325dfecf96Smrgmpi_abs(mpi *rop, mpi *op)
13335dfecf96Smrg{
13345dfecf96Smrg    if (rop->digs != op->digs) {
13355dfecf96Smrg	if (rop->alloc < op->size) {
13365dfecf96Smrg	    rop->digs = mp_realloc(rop->digs, sizeof(BNS) * rop->size);
13375dfecf96Smrg	    rop->alloc = op->size;
13385dfecf96Smrg	}
13395dfecf96Smrg	rop->size = op->size;
13405dfecf96Smrg	memcpy(rop->digs, op->digs, sizeof(BNS) * rop->size);
13415dfecf96Smrg    }
13425dfecf96Smrg
13435dfecf96Smrg    rop->sign = 0;
13445dfecf96Smrg}
13455dfecf96Smrg
13465dfecf96Smrgint
13475dfecf96Smrgmpi_cmp(mpi *op1, mpi *op2)
13485dfecf96Smrg{
13495dfecf96Smrg    if (op1->sign ^ op2->sign)
13505dfecf96Smrg	return (op1->sign ? -1 : 1);
13515dfecf96Smrg
13525dfecf96Smrg    if (op1->size == op2->size) {
13535dfecf96Smrg	long i, cmp = 0;
13545dfecf96Smrg
13555dfecf96Smrg	for (i = op1->size - 1; i >= 0; i--)
13565dfecf96Smrg	    if ((cmp = (long)op1->digs[i] - (long)op2->digs[i]) != 0)
13575dfecf96Smrg		break;
13585dfecf96Smrg
13595dfecf96Smrg	return (cmp == 0 ? 0 : (cmp < 0) ^ op1->sign ? -1 : 1);
13605dfecf96Smrg    }
13615dfecf96Smrg
13625dfecf96Smrg    return ((op1->size < op2->size) ^ op1->sign ? -1 : 1);
13635dfecf96Smrg}
13645dfecf96Smrg
13655dfecf96Smrgint
13665dfecf96Smrgmpi_cmpi(mpi *op1, long op2)
13675dfecf96Smrg{
13685dfecf96Smrg    long cmp;
13695dfecf96Smrg
13705dfecf96Smrg    if (op1->size > 2)
13715dfecf96Smrg	return (op1->sign ? -1 : 1);
13725dfecf96Smrg
13735dfecf96Smrg    cmp = op1->digs[0];
13745dfecf96Smrg    if (op1->size == 2) {
13755dfecf96Smrg	cmp |= (long)op1->digs[1] << BNSBITS;
13765dfecf96Smrg	if (cmp == MINSLONG)
13775dfecf96Smrg	    return (op2 == cmp && op1->sign ? 0 : op1->sign ? -1 : 1);
13785dfecf96Smrg    }
13795dfecf96Smrg    if (op1->sign)
13805dfecf96Smrg	cmp = -cmp;
13815dfecf96Smrg
13825dfecf96Smrg    return (cmp - op2);
13835dfecf96Smrg}
13845dfecf96Smrg
13855dfecf96Smrgint
13865dfecf96Smrgmpi_cmpabs(mpi *op1, mpi *op2)
13875dfecf96Smrg{
13885dfecf96Smrg    if (op1->size == op2->size) {
13895dfecf96Smrg	long i, cmp = 0;
13905dfecf96Smrg
13915dfecf96Smrg	for (i = op1->size - 1; i >= 0; i--)
13925dfecf96Smrg	    if ((cmp = (long)op1->digs[i] - (long)op2->digs[i]) != 0)
13935dfecf96Smrg		break;
13945dfecf96Smrg
13955dfecf96Smrg	return (cmp);
13965dfecf96Smrg    }
13975dfecf96Smrg
13985dfecf96Smrg    return ((op1->size < op2->size) ? -1 : 1);
13995dfecf96Smrg}
14005dfecf96Smrg
14015dfecf96Smrgint
14025dfecf96Smrgmpi_cmpabsi(mpi *op1, long op2)
14035dfecf96Smrg{
14045dfecf96Smrg    unsigned long cmp;
14055dfecf96Smrg
14065dfecf96Smrg    if (op1->size > 2)
14075dfecf96Smrg	return (1);
14085dfecf96Smrg
14095dfecf96Smrg    cmp = op1->digs[0];
14105dfecf96Smrg    if (op1->size == 2)
14115dfecf96Smrg	cmp |= (unsigned long)op1->digs[1] << BNSBITS;
14125dfecf96Smrg
14135dfecf96Smrg    return (cmp > op2 ? 1 : cmp == op2 ? 0 : -1);
14145dfecf96Smrg}
14155dfecf96Smrg
14165dfecf96Smrgint
14175dfecf96Smrgmpi_sgn(mpi *op)
14185dfecf96Smrg{
14195dfecf96Smrg    return (op->sign ? -1 : op->size > 1 || op->digs[0] ? 1 : 0);
14205dfecf96Smrg}
14215dfecf96Smrg
14225dfecf96Smrgvoid
14235dfecf96Smrgmpi_swap(mpi *op1, mpi *op2)
14245dfecf96Smrg{
14255dfecf96Smrg    if (op1 != op2) {
14265dfecf96Smrg	mpi swap;
14275dfecf96Smrg
14285dfecf96Smrg	memcpy(&swap, op1, sizeof(mpi));
14295dfecf96Smrg	memcpy(op1, op2, sizeof(mpi));
14305dfecf96Smrg	memcpy(op2, &swap, sizeof(mpi));
14315dfecf96Smrg    }
14325dfecf96Smrg}
14335dfecf96Smrg
14345dfecf96Smrgint
14355dfecf96Smrgmpi_fiti(mpi *op)
14365dfecf96Smrg{
14375dfecf96Smrg    if (op->size == 1)
14385dfecf96Smrg	return (1);
14395dfecf96Smrg    else if (op->size == 2) {
14405dfecf96Smrg	unsigned long value = ((BNI)(op->digs[1]) << BNSBITS) | op->digs[0];
14415dfecf96Smrg
14425dfecf96Smrg	if (value & MINSLONG)
14435dfecf96Smrg	    return (op->sign && value == MINSLONG) ? 1 : 0;
14445dfecf96Smrg
14455dfecf96Smrg	return (1);
14465dfecf96Smrg    }
14475dfecf96Smrg
14485dfecf96Smrg    return (0);
14495dfecf96Smrg}
14505dfecf96Smrg
14515dfecf96Smrglong
14525dfecf96Smrgmpi_geti(mpi *op)
14535dfecf96Smrg{
14545dfecf96Smrg    long value;
14555dfecf96Smrg
14565dfecf96Smrg    value = op->digs[0];
14575dfecf96Smrg    if (op->size > 1)
14585dfecf96Smrg	value |= (BNI)(op->digs[1]) << BNSBITS;
14595dfecf96Smrg
14605dfecf96Smrg    return (op->sign && value != MINSLONG ? -value : value);
14615dfecf96Smrg}
14625dfecf96Smrg
14635dfecf96Smrgdouble
14645dfecf96Smrgmpi_getd(mpi *op)
14655dfecf96Smrg{
14665dfecf96Smrg    long i, len;
14675dfecf96Smrg    double d = 0.0;
14685dfecf96Smrg    int exponent;
14695dfecf96Smrg
14705dfecf96Smrg#define FLOATDIGS	sizeof(double) / sizeof(BNS)
14715dfecf96Smrg
14725dfecf96Smrg    switch (op->size) {
14735dfecf96Smrg	case 2:
14745dfecf96Smrg	    d = (BNI)(op->digs[1]) << BNSBITS;
14755dfecf96Smrg	case 1:
14765dfecf96Smrg	    d += op->digs[0];
14775dfecf96Smrg	    return (op->sign ? -d : d);
14785dfecf96Smrg	default:
14795dfecf96Smrg	    break;
14805dfecf96Smrg    }
14815dfecf96Smrg
14825dfecf96Smrg    for (i = 0, len = op->size; len > 0 && i < FLOATDIGS; i++)
14835dfecf96Smrg	d = ldexp(d, BNSBITS) + op->digs[--len];
14845dfecf96Smrg    d = frexp(d, &exponent);
14855dfecf96Smrg    if (len > 0)
14865dfecf96Smrg	exponent += len * BNSBITS;
14875dfecf96Smrg
14885dfecf96Smrg    if (d == 0.0)
14895dfecf96Smrg	return (d);
14905dfecf96Smrg
14915dfecf96Smrg    d = ldexp(d, exponent);
14925dfecf96Smrg
14935dfecf96Smrg    return (op->sign ? -d : d);
14945dfecf96Smrg}
14955dfecf96Smrg
14965dfecf96Smrg/* how many digits in a given base, floor(log(CARRY) / log(base)) */
14975dfecf96Smrg#ifdef LONG64
14985dfecf96Smrgstatic char dig_bases[37] = {
14995dfecf96Smrg     0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  9,  9,  8,  8,  8,  8,
15005dfecf96Smrg     8,  7,  7,  7,  7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  6,  6,
15015dfecf96Smrg     6,  6,  6,  6,  6,
15025dfecf96Smrg};
15035dfecf96Smrg#else
15045dfecf96Smrgstatic char dig_bases[37] = {
15055dfecf96Smrg     0,  0, 16, 10,  8,  6,  6,  5,  5,  5,  4,  4,  4,  4,  4,  4,
15065dfecf96Smrg     4,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
15075dfecf96Smrg     3,  3,  3,  3,  3,
15085dfecf96Smrg};
15095dfecf96Smrg#endif
15105dfecf96Smrg
15115dfecf96Smrg/* how many digits per bit in a given base, log(2) / log(base) */
15125dfecf96Smrgstatic double bit_bases[37] = {
15135dfecf96Smrg    0.0000000000000000, 0.0000000000000000, 1.0000000000000000,
15145dfecf96Smrg    0.6309297535714575, 0.5000000000000000, 0.4306765580733931,
15155dfecf96Smrg    0.3868528072345416, 0.3562071871080222, 0.3333333333333334,
15165dfecf96Smrg    0.3154648767857287, 0.3010299956639811, 0.2890648263178878,
15175dfecf96Smrg    0.2789429456511298, 0.2702381544273197, 0.2626495350371936,
15185dfecf96Smrg    0.2559580248098155, 0.2500000000000000, 0.2446505421182260,
15195dfecf96Smrg    0.2398124665681315, 0.2354089133666382, 0.2313782131597592,
15205dfecf96Smrg    0.2276702486969530, 0.2242438242175754, 0.2210647294575037,
15215dfecf96Smrg    0.2181042919855316, 0.2153382790366965, 0.2127460535533632,
15225dfecf96Smrg    0.2103099178571525, 0.2080145976765095, 0.2058468324604344,
15235dfecf96Smrg    0.2037950470905062, 0.2018490865820999, 0.2000000000000000,
15245dfecf96Smrg    0.1982398631705605, 0.1965616322328226, 0.1949590218937863,
15255dfecf96Smrg    0.1934264036172708,
15265dfecf96Smrg};
15275dfecf96Smrg
15285dfecf96Smrg/* normalization base for string conversion, pow(base, dig_bases[base]) & ~CARRY */
15295dfecf96Smrg#ifdef LONG64
15305dfecf96Smrgstatic BNS big_bases[37] = {
15315dfecf96Smrg    0x00000001, 0x00000001, 0x00000000, 0xCFD41B91, 0x00000000, 0x48C27395,
15325dfecf96Smrg    0x81BF1000, 0x75DB9C97, 0x40000000, 0xCFD41B91, 0x3B9ACA00, 0x8C8B6D2B,
15335dfecf96Smrg    0x19A10000, 0x309F1021, 0x57F6C100, 0x98C29B81, 0x00000000, 0x18754571,
15345dfecf96Smrg    0x247DBC80, 0x3547667B, 0x4C4B4000, 0x6B5A6E1D, 0x94ACE180, 0xCAF18367,
15355dfecf96Smrg    0x0B640000, 0x0E8D4A51, 0x1269AE40, 0x17179149, 0x1CB91000, 0x23744899,
15365dfecf96Smrg    0x2B73A840, 0x34E63B41, 0x40000000, 0x4CFA3CC1, 0x5C13D840, 0x6D91B519,
15375dfecf96Smrg    0x81BF1000,
15385dfecf96Smrg};
15395dfecf96Smrg#else
15405dfecf96Smrgstatic BNS big_bases[37] = {
15415dfecf96Smrg    0x0001, 0x0001, 0x0000, 0xE6A9, 0x0000, 0x3D09, 0xB640, 0x41A7, 0x8000,
15425dfecf96Smrg    0xE6A9, 0x2710, 0x3931, 0x5100, 0x6F91, 0x9610, 0xC5C1, 0x0000, 0x1331,
15435dfecf96Smrg    0x16C8, 0x1ACB, 0x1F40, 0x242D, 0x2998, 0x2F87, 0x3600, 0x3D09, 0x44A8,
15445dfecf96Smrg    0x4CE3, 0x55C0, 0x5F45, 0x6978, 0x745F, 0x8000, 0x8C61, 0x9988, 0xA77B,
15455dfecf96Smrg    0xb640,
15465dfecf96Smrg};
15475dfecf96Smrg#endif
15485dfecf96Smrg
15495dfecf96Smrgunsigned long
15505dfecf96Smrgmpi_getsize(mpi *op, int base)
15515dfecf96Smrg{
15525dfecf96Smrg    unsigned long value, bits;
15535dfecf96Smrg
15545dfecf96Smrg    value = op->digs[op->size - 1];
15555dfecf96Smrg
15565dfecf96Smrg    /* count leading bits */
15575dfecf96Smrg    if (value) {
15585dfecf96Smrg	unsigned long count, carry;
15595dfecf96Smrg
15605dfecf96Smrg	for (count = 0, carry = CARRY >> 1; carry; count++, carry >>= 1)
15615dfecf96Smrg	    if (value & carry)
15625dfecf96Smrg		break;
15635dfecf96Smrg
15645dfecf96Smrg	bits = BNSBITS - count;
15655dfecf96Smrg    }
15665dfecf96Smrg    else
15675dfecf96Smrg	bits = 0;
15685dfecf96Smrg
15695dfecf96Smrg    return ((bits + (op->size - 1) * BNSBITS) * bit_bases[base] + 1);
15705dfecf96Smrg}
15715dfecf96Smrg
15725dfecf96Smrgchar *
15735dfecf96Smrgmpi_getstr(char *str, mpi *op, int base)
15745dfecf96Smrg{
15755dfecf96Smrg    long i;			/* counter */
15765dfecf96Smrg    BNS *digs, *xdigs;		/* copy of op data */
15775dfecf96Smrg    BNI size;			/* size of op */
15785dfecf96Smrg    BNI digits;			/* digits per word in given base */
15795dfecf96Smrg    BNI bigbase;		/* big base of given base */
15805dfecf96Smrg    BNI strsize;		/* size of resulting string */
15815dfecf96Smrg    char *cp;			/* pointer in str for conversion */
15825dfecf96Smrg
15835dfecf96Smrg    /* initialize */
15845dfecf96Smrg    size = op->size;
15855dfecf96Smrg    strsize = mpi_getsize(op, base) + op->sign + 1;
15865dfecf96Smrg
15875dfecf96Smrg    if (str == NULL)
15885dfecf96Smrg	str = mp_malloc(strsize);
15895dfecf96Smrg
15905dfecf96Smrg    /* check for zero */
15915dfecf96Smrg    if (size == 1 && op->digs[0] == 0) {
15925dfecf96Smrg	str[0] = '0';
15935dfecf96Smrg	str[1] = '\0';
15945dfecf96Smrg
15955dfecf96Smrg	return (str);
15965dfecf96Smrg    }
15975dfecf96Smrg
15985dfecf96Smrg    digits = dig_bases[base];
15995dfecf96Smrg    bigbase = big_bases[base];
16005dfecf96Smrg
16015dfecf96Smrg    cp = str + strsize;
16025dfecf96Smrg    *--cp = '\0';
16035dfecf96Smrg
16045dfecf96Smrg    /* make copy of op data and adjust digs */
16055dfecf96Smrg    xdigs = mp_malloc(size * sizeof(BNS));
160631de2854Smrg    memcpy(xdigs, op->digs, size * sizeof(BNS));
16075dfecf96Smrg    digs = xdigs + size - 1;
16085dfecf96Smrg
16095dfecf96Smrg    /* convert to string */
16105dfecf96Smrg    for (;;) {
16115dfecf96Smrg	long count = -1;
16125dfecf96Smrg	BNI value;
16135dfecf96Smrg	BNS quotient, remainder = 0;
16145dfecf96Smrg
16155dfecf96Smrg	/* if power of two base */
16165dfecf96Smrg	if ((base & (base - 1)) == 0) {
16175dfecf96Smrg	    for (i = 0; i < size; i++) {
16185dfecf96Smrg		quotient = remainder;
16195dfecf96Smrg		remainder = digs[-i];
16205dfecf96Smrg		digs[-i] = quotient;
16215dfecf96Smrg		if (count < 0 && quotient)
16225dfecf96Smrg		    count = i;
16235dfecf96Smrg	    }
16245dfecf96Smrg	}
16255dfecf96Smrg	else {
16265dfecf96Smrg	    for (i = 0; i < size; i++) {
16275dfecf96Smrg		value = digs[-i] + ((BNI)remainder << BNSBITS);
16285dfecf96Smrg		quotient = (BNS)(value / bigbase);
16295dfecf96Smrg		remainder = (BNS)(value % bigbase);
16305dfecf96Smrg		digs[-i] = quotient;
16315dfecf96Smrg		if (count < 0 && quotient)
16325dfecf96Smrg		    count = i;
16335dfecf96Smrg	    }
16345dfecf96Smrg	}
16355dfecf96Smrg	quotient = remainder;
16365dfecf96Smrg	for (i = 0; i < digits; i++) {
16375dfecf96Smrg	    if (quotient == 0 && count < 0)
16385dfecf96Smrg		break;
16395dfecf96Smrg	    remainder = quotient % base;
16405dfecf96Smrg	    quotient /= base;
16415dfecf96Smrg	    *--cp = remainder < 10 ? remainder + '0' : remainder - 10 + 'A';
16425dfecf96Smrg	}
16435dfecf96Smrg	if (count < 0)
16445dfecf96Smrg	    break;
16455dfecf96Smrg	digs -= count;
16465dfecf96Smrg	size -= count;
16475dfecf96Smrg    }
16485dfecf96Smrg
16495dfecf96Smrg    /* adjust sign */
16505dfecf96Smrg    if (op->sign)
16515dfecf96Smrg	*--cp = '-';
16525dfecf96Smrg
16535dfecf96Smrg    /* remove any extra characters */
16545dfecf96Smrg    if (cp > str)
16555dfecf96Smrg	strcpy(str, cp);
16565dfecf96Smrg
16575dfecf96Smrg    mp_free(xdigs);
16585dfecf96Smrg
16595dfecf96Smrg    return (str);
16605dfecf96Smrg}
1661