861 lines
17 KiB
C
861 lines
17 KiB
C
/* Copyright Digital Equipment Corporation & INRIA 1988, 1989 */
|
||
/* Last modified_on Thu Feb 20 18:18:12 GMT+1:00 1992 by shand */
|
||
/* modified_on Tue Jan 15 19:32:53 GMT+1:00 1991 by herve */
|
||
|
||
|
||
/* KerN.c: the kernel written in C */
|
||
|
||
/*
|
||
* Description of types and constants.
|
||
*
|
||
* Several conventions are used in the commentary:
|
||
* A "BigNum" is the name for an infinite-precision number.
|
||
* Capital letters (e.g., "N") are used to refer to the value of BigNums.
|
||
* The word "digit" refers to a single BigNum digit.
|
||
* The notation "Size(N)" refers to the number of digits in N,
|
||
* which is typically passed to the subroutine as "nl".
|
||
* The notation "Length(N)" refers to the number of digits in N,
|
||
* not including any leading zeros.
|
||
* The word "Base" is used for the number 2 ** BN_DIGIT_SIZE, where
|
||
* BN_DIGIT_SIZE is the number of bits in a single BigNum digit.
|
||
* The expression "BBase(N)" is used for Base ** NumDigits(N).
|
||
* The term "leading zeros" refers to any zeros before the most
|
||
* significant digit of a number.
|
||
*
|
||
*
|
||
* In the code, we have:
|
||
*
|
||
* "nn" is a pointer to a big number,
|
||
* "nl" is the number of digits from nn,
|
||
* "d" is a digit.
|
||
*
|
||
*/
|
||
|
||
|
||
/**/
|
||
|
||
#define BNNMACROS_OFF
|
||
#include "BigNum.h"
|
||
#define NOMEM
|
||
|
||
/*** copyright ***/
|
||
|
||
static char copyright[]="@(#)KerN.c: copyright Digital Equipment Corporation & INRIA 1988, 1989\n";
|
||
|
||
|
||
/******* non arithmetic access to digits ********/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnSetToZero (BigNum nn, BigNumLength nl)
|
||
#else
|
||
void BnnSetToZero (nn, nl)
|
||
BigNum nn; BigNumLength nl;
|
||
#endif
|
||
|
||
/*
|
||
* Sets all the specified digits of the BigNum to 0
|
||
*/
|
||
|
||
{
|
||
BigNum nnlim;
|
||
if (nl <= 0)
|
||
return;
|
||
nnlim = nn+nl-1;
|
||
do *nn = 0; while(nn++ < nnlim);
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnAssign (BigNum mm, BigNum nn, BigNumLength nl)
|
||
#else /* _NO_PROTO */
|
||
void BnnAssign ( mm, nn, nl)
|
||
BigNum mm; BigNum nn; BigNumLength nl;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Copies N => M
|
||
*/
|
||
|
||
{
|
||
BigNum nnlim;
|
||
if (nl <= 0)
|
||
return;
|
||
nnlim = nn+nl;
|
||
#ifdef MSDOS
|
||
if (realaddr(mm) < realaddr(nn) || realaddr(mm) > realaddr(nnlim))
|
||
#else
|
||
if ((mm < nn) || ( mm > nnlim))
|
||
#endif
|
||
do *mm++ = *nn++; while(nn < nnlim);
|
||
else
|
||
#ifdef MSDOS
|
||
if (realaddr(mm) > realaddr(nn))
|
||
#else
|
||
if (mm > nn)
|
||
#endif
|
||
{
|
||
mm += nl;
|
||
do *--mm = *--nnlim; while(nn < nnlim);
|
||
}
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnSetDigit (BigNum nn, BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
void BnnSetDigit ( nn, d)
|
||
BigNum nn; BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Sets a single digit of N to the passed value
|
||
*/
|
||
|
||
{
|
||
*nn = d;
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumDigit BnnGetDigit (BigNum nn)
|
||
#else /* _NO_PROTO */
|
||
BigNumDigit BnnGetDigit ( nn)
|
||
BigNum nn;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns the single digit pointed by N
|
||
*/
|
||
|
||
{
|
||
return (*nn);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumLength BnnNumDigits (BigNum nn, BigNumLength nl)
|
||
#else /* _NO_PROTO */
|
||
BigNumLength BnnNumDigits ( nn, nl)
|
||
BigNum nn; BigNumLength nl;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns the number of digits of N, not counting leading zeros
|
||
*/
|
||
|
||
{
|
||
nn += nl;
|
||
|
||
while (nl != 0 && *--nn == 0)
|
||
nl--;
|
||
|
||
return (nl == 0 ? 1 : nl);
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumDigit BnnNumLeadingZeroBitsInDigit (BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
BigNumDigit BnnNumLeadingZeroBitsInDigit ( d)
|
||
BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns the number of leading zero bits in a digit
|
||
*/
|
||
|
||
{
|
||
register int p = 0;
|
||
if (BN_DIGIT_SIZE == 16 || BN_DIGIT_SIZE == 32 || BN_DIGIT_SIZE == 64)
|
||
{
|
||
register BigNumDigit mask = (~(BigNumDigit)0) << (BN_DIGIT_SIZE/2);
|
||
register BigNumLength maskl = BN_DIGIT_SIZE/2;
|
||
|
||
if (d == 0)
|
||
return (BN_DIGIT_SIZE);
|
||
while (maskl)
|
||
{
|
||
if ((d & mask) == 0)
|
||
{
|
||
p += maskl;
|
||
d <<= maskl;
|
||
}
|
||
maskl >>= 1;
|
||
mask <<= maskl;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
register BigNumDigit mask = ((BigNumDigit)1) << (BN_DIGIT_SIZE-1);
|
||
|
||
while ((d & mask) == 0)
|
||
{
|
||
p++;
|
||
mask >>= 1;
|
||
}
|
||
}
|
||
|
||
return (p);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
/************** Predicates on one digit ***************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
Boolean BnnDoesDigitFitInWord (BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
Boolean BnnDoesDigitFitInWord ( d)
|
||
BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns TRUE iff the digit can be represented in just BN_WORD_SIZE bits
|
||
*/
|
||
{
|
||
/* The C compiler must evaluate the predicate at compile time */
|
||
if (BN_DIGIT_SIZE > BN_WORD_SIZE)
|
||
return (d >= ((BigNumDigit)1) << BN_WORD_SIZE ? FALSE : TRUE);
|
||
else
|
||
return (TRUE);
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
Boolean BnnIsDigitZero (BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
Boolean BnnIsDigitZero ( d)
|
||
BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/* Returns TRUE iff digit = 0 */
|
||
|
||
{
|
||
return (d == 0);
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
Boolean BnnIsDigitNormalized (BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
Boolean BnnIsDigitNormalized ( d)
|
||
BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns TRUE iff Base/2 <= digit < Base
|
||
* i.e., if digit's leading bit is 1
|
||
*/
|
||
|
||
{
|
||
return (d & (((BigNumDigit)1) << (BN_DIGIT_SIZE - 1)) ? TRUE : FALSE);
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
Boolean BnnIsDigitOdd (BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
Boolean BnnIsDigitOdd ( d)
|
||
BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns TRUE iff digit is odd
|
||
*/
|
||
|
||
{
|
||
return (d & 1 ? TRUE : FALSE);
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumCmp BnnCompareDigits (BigNumDigit d1, BigNumDigit d2)
|
||
#else /* _NO_PROTO */
|
||
BigNumCmp BnnCompareDigits ( d1, d2)
|
||
BigNumDigit d1; BigNumDigit d2;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns BN_GREATER if digit1 > digit2
|
||
* BN_EQUAL if digit1 = digit2
|
||
* BN_LESS if digit1 < digit2
|
||
*/
|
||
|
||
{
|
||
return (d1 > d2 ? BN_GT : (d1 == d2 ? BN_EQ : BN_LT));
|
||
}
|
||
|
||
/***************** Logical operations ********************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnComplement (BigNum nn, BigNumLength nl)
|
||
#else /* _NO_PROTO */
|
||
void BnnComplement ( nn, nl)
|
||
BigNum nn; BigNumLength nl;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Performs the computation BBase(N) - N - 1 => N
|
||
*/
|
||
|
||
{
|
||
BigNum nnlim;
|
||
|
||
if (nl <= 0)
|
||
return;
|
||
nnlim = nn+nl;
|
||
do
|
||
{
|
||
nn++;
|
||
nn[-1] = ~nn[-1];
|
||
}
|
||
while (nn < nnlim);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnAndDigits (BigNum n, BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
void BnnAndDigits ( n, d)
|
||
BigNum n; BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns the logical computation n[0] AND d in n[0]
|
||
*/
|
||
|
||
{
|
||
*n &= d;
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnOrDigits (BigNum n, BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
void BnnOrDigits ( n, d)
|
||
BigNum n; BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns the logical computation n[0] OR d2 in n[0].
|
||
*/
|
||
|
||
{
|
||
*n |= d;
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
void BnnXorDigits (BigNum n, BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
void BnnXorDigits ( n, d)
|
||
BigNum n; BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Returns the logical computation n[0] XOR d in n[0].
|
||
*/
|
||
|
||
{
|
||
*n ^= d;
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
/****************** Shift operations *******************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumDigit BnnShiftLeft (BigNum mm, BigNumLength ml, int nbits)
|
||
#else /* _NO_PROTO */
|
||
BigNumDigit BnnShiftLeft ( mm, ml, nbits)
|
||
BigNum mm; BigNumLength ml; int nbits;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Shifts M left by "nbits", filling with 0s.
|
||
* Returns the leftmost "nbits" of M in a digit.
|
||
* Assumes 0 <= nbits < BN_DIGIT_SIZE.
|
||
*/
|
||
|
||
{
|
||
register BigNumDigit res = 0, save;
|
||
int rnbits;
|
||
|
||
|
||
if (nbits != 0)
|
||
{
|
||
rnbits = BN_DIGIT_SIZE - nbits;
|
||
|
||
while (ml-- > 0)
|
||
{
|
||
save = *mm;
|
||
*mm++ = (save << nbits) | res;
|
||
res = save >> rnbits;
|
||
}
|
||
}
|
||
|
||
return (res);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumDigit BnnShiftRight (BigNum mm, BigNumLength ml, int nbits)
|
||
#else /* _NO_PROTO */
|
||
BigNumDigit BnnShiftRight ( mm, ml, nbits)
|
||
BigNum mm; BigNumLength ml; int nbits;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Shifts M right by "nbits", filling with 0s.
|
||
* Returns the rightmost "nbits" of M in a digit.
|
||
* Assumes 0 <= nbits < BN_DIGIT_SIZE.
|
||
*/
|
||
|
||
{
|
||
register BigNumDigit res = 0, save;
|
||
int lnbits;
|
||
|
||
|
||
if (nbits != 0)
|
||
{
|
||
mm += ml;
|
||
lnbits = BN_DIGIT_SIZE - nbits;
|
||
|
||
while (ml-- > 0)
|
||
{
|
||
save = *(--mm);
|
||
*mm = (save >> nbits) | res;
|
||
res = save << lnbits;
|
||
}
|
||
}
|
||
|
||
return (res);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
/******************* Additions **************************/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumCarry BnnAddCarry (BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
||
#else /* _NO_PROTO */
|
||
BigNumCarry BnnAddCarry ( nn, nl, carryin)
|
||
BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Performs the sum N + CarryIn => N.
|
||
* Returns the CarryOut.
|
||
*/
|
||
|
||
{
|
||
if (carryin == 0)
|
||
return (0);
|
||
|
||
if (nl == 0)
|
||
return (1);
|
||
|
||
while (nl > 0 && !(++(*nn++)))
|
||
nl--;
|
||
|
||
return (nl > 0 ? 0 : 1);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumCarry BnnAdd (BigNum mm, BigNumLength ml, BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
||
#else /* _NO_PROTO */
|
||
BigNumCarry BnnAdd ( mm, ml, nn, nl, carryin)
|
||
BigNum mm; BigNumLength ml; BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Performs the sum M + N + CarryIn => M.
|
||
* Returns the CarryOut.
|
||
* Assumes Size(M) >= Size(N).
|
||
*/
|
||
|
||
{
|
||
register BigNumProduct c = carryin;
|
||
register BigNumProduct save;
|
||
|
||
|
||
ml -= nl;
|
||
|
||
while (nl > 0)
|
||
{
|
||
save = *mm;
|
||
c += save;
|
||
if (c < save)
|
||
{
|
||
*(mm++) = *(nn++);
|
||
c = 1;
|
||
}
|
||
else
|
||
{
|
||
save = *(nn++);
|
||
c += save;
|
||
*(mm++) = c;
|
||
c = (c < save) ? 1 : 0;
|
||
}
|
||
nl--;
|
||
}
|
||
|
||
return (BnnAddCarry (mm, ml, (BigNumCarry) c));
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
/****************** Subtraction *************************/
|
||
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumCarry BnnSubtractBorrow (BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
||
#else /* _NO_PROTO */
|
||
BigNumCarry BnnSubtractBorrow ( nn, nl, carryin)
|
||
BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Performs the difference N + CarryIn - 1 => N.
|
||
* Returns the CarryOut.
|
||
*/
|
||
|
||
{
|
||
if (carryin == 1)
|
||
return (1);
|
||
if (nl == 0)
|
||
return (0);
|
||
|
||
while (nl > 0 && !((*nn++)--))
|
||
nl--;
|
||
|
||
return (nl > 0 ? 1 : 0);
|
||
}
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumCarry BnnSubtract (BigNum mm, BigNumLength ml, BigNum nn, BigNumLength nl, BigNumCarry carryin)
|
||
#else /* _NO_PROTO */
|
||
BigNumCarry BnnSubtract ( mm, ml, nn, nl, carryin)
|
||
BigNum mm; BigNumLength ml; BigNum nn; BigNumLength nl; BigNumCarry carryin;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Performs the difference M - N + CarryIn - 1 => M.
|
||
* Returns the CarryOut.
|
||
* Assumes Size(M) >= Size(N).
|
||
*/
|
||
|
||
{
|
||
register BigNumProduct c = carryin;
|
||
register BigNumDigit invn;
|
||
register BigNumProduct save;
|
||
|
||
|
||
ml -= nl;
|
||
|
||
while (nl > 0)
|
||
{
|
||
save = *mm;
|
||
invn = *(nn++) ^ -1;
|
||
c += save;
|
||
|
||
if (c < save)
|
||
{
|
||
*(mm++) = invn;
|
||
c = 1;
|
||
}
|
||
else
|
||
{
|
||
c += invn;
|
||
*(mm++) = c;
|
||
c = (c < invn) ? 1 : 0;
|
||
}
|
||
nl--;
|
||
}
|
||
|
||
return (BnnSubtractBorrow (mm, ml, (BigNumCarry) c)); }
|
||
|
||
|
||
/***************************************/
|
||
/* */
|
||
|
||
/***************** Multiplication ************************/
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumCarry BnnMultiplyDigit (BigNum pp, BigNumLength pl, BigNum mm, BigNumLength ml, BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
BigNumCarry BnnMultiplyDigit ( pp, pl, mm, ml, d)
|
||
BigNum pp; BigNumLength pl; BigNum mm; BigNumLength ml; BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Performs the product:
|
||
* Q = P + M * d
|
||
* BB = BBase(P)
|
||
* Q mod BB => P
|
||
* Q div BB => CarryOut
|
||
* Returns the CarryOut.
|
||
* Assumes Size(P) >= Size(M) + 1.
|
||
*/
|
||
|
||
{
|
||
register BigNumProduct c = 0;
|
||
|
||
|
||
if (d == 0)
|
||
return (0);
|
||
|
||
if (d == 1)
|
||
return (BnnAdd (pp, pl, mm, ml, (BigNumCarry) 0));
|
||
|
||
pl -= ml;
|
||
|
||
{
|
||
/* help for stupid compilers--may actually be counter
|
||
productive on pipelined machines with decent register allocation!! */
|
||
#define m_digit X0
|
||
#define X3 Lm
|
||
#define X1 Hm
|
||
register BigNumDigit Lm, Hm, Ld, Hd, X0, X2 /*, X1, X3 */;
|
||
|
||
Ld = d & ((((BigNumDigit)1) << (BN_DIGIT_SIZE / 2)) -1);
|
||
Hd = d >> (BN_DIGIT_SIZE / 2);
|
||
while (ml != 0)
|
||
{
|
||
ml--;
|
||
m_digit = *mm++;
|
||
Lm = m_digit & ((((BigNumDigit)1) << (BN_DIGIT_SIZE / 2)) -1);
|
||
Hm = m_digit >> (BN_DIGIT_SIZE / 2);
|
||
X0 = Ld * Lm;
|
||
X2 = Hd * Lm;
|
||
X3 = Hd * Hm;
|
||
X1 = Ld * Hm;
|
||
|
||
if ((c += X0) < X0) X3++;
|
||
if ((X1 += X2) < X2) X3 += (((BigNumDigit)1)<<(BN_DIGIT_SIZE / 2));
|
||
X3 += (X1 >> (BN_DIGIT_SIZE / 2));
|
||
X1 <<= (BN_DIGIT_SIZE / 2);
|
||
if ((c += X1) < X1) X3++;
|
||
if ((*pp += c) < c) X3++;
|
||
pp++;
|
||
|
||
c = X3;
|
||
#undef m_digit
|
||
#undef X1
|
||
#undef X3
|
||
}
|
||
|
||
X0 = *pp;
|
||
c += X0;
|
||
*(pp++) = c;
|
||
|
||
if (c >= X0)
|
||
return (0);
|
||
|
||
pl--;
|
||
while (pl != 0 && !(++(*pp++)))
|
||
pl--;
|
||
|
||
return (pl != 0 ? 0 : 1);
|
||
}
|
||
}
|
||
|
||
#ifdef mips
|
||
#ifndef _NO_PROTO
|
||
BigNumCarry BnnMultiply2Digit (BigNum pp, BigNumLength pl, BigNum mm, BigNumLength ml, BigNumDigit d0, BigNumDigit d1)
|
||
#else /* _NO_PROTO */
|
||
BigNumCarry BnnMultiply2Digit ( pp, pl, mm, ml, d0, d1)
|
||
BigNum pp; BigNumLength pl; BigNum mm; BigNumLength ml; BigNumDigit d0; BigNumDigit d1;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/*
|
||
* Provided for compatibility with mips assembler implementation.
|
||
* Performs the product:
|
||
* Q = P + M * d0_d1
|
||
* BB = BBase(P)
|
||
* Q mod BB => P
|
||
* Q div BB => CarryOut
|
||
* Returns the CarryOut.
|
||
* Assumes Size(P) >= Size(M) + 1.
|
||
*/
|
||
|
||
{
|
||
return
|
||
BnnMultiplyDigit (pp, pl, mm, ml, d0)
|
||
+ BnnMultiplyDigit (pp+1, pl-1, mm, ml, d1);
|
||
}
|
||
#endif /* mips */
|
||
|
||
|
||
/***************************************/
|
||
/**/
|
||
|
||
/********************** Division *************************/
|
||
|
||
|
||
/* xh:xl -= yh:yl */
|
||
#define SUB(xh,xl,yh,yl) if (yl > xl) {xl -= yl; xh -= yh + 1;}\
|
||
else {xl -= yl; xh -= yh;}
|
||
|
||
#define LOW(x) (x & ((((BigNumDigit)1) << (BN_DIGIT_SIZE / 2)) -1))
|
||
#define HIGH(x) (x >> (BN_DIGIT_SIZE / 2))
|
||
#define L2H(x) (x << (BN_DIGIT_SIZE / 2))
|
||
|
||
|
||
#ifndef _NO_PROTO
|
||
BigNumDigit BnnDivideDigit (BigNum qq, BigNum nn, BigNumLength nl, BigNumDigit d)
|
||
#else /* _NO_PROTO */
|
||
BigNumDigit BnnDivideDigit ( qq, nn, nl, d)
|
||
BigNum qq; BigNum nn; BigNumLength nl; BigNumDigit d;
|
||
#endif /* _NO_PROTO */
|
||
|
||
/* Performs the quotient: N div d => Q
|
||
* Returns R = N mod d
|
||
* Assumes leading digit of N < d, and d > 0.
|
||
*/
|
||
|
||
{
|
||
{
|
||
int k;
|
||
BigNumLength orig_nl;
|
||
BigNumDigit rh; /* Two halves of current remainder */
|
||
BigNumDigit rl; /* Correspond to quad above */
|
||
register BigNumDigit qa; /* Current appr. to quotient */
|
||
register BigNumDigit ph, pl; /* product of c and qa */
|
||
BigNumDigit ch, cl, prev_qq;
|
||
|
||
|
||
/* Normalize divisor */
|
||
k = BnnNumLeadingZeroBitsInDigit (d);
|
||
if (k != 0)
|
||
{
|
||
prev_qq = qq[-1];
|
||
orig_nl = nl;
|
||
d <<= k;
|
||
BnnShiftLeft (nn, nl, k);
|
||
}
|
||
|
||
nn += nl;
|
||
nl--;
|
||
qq += nl;
|
||
|
||
ch = HIGH (d);
|
||
cl = LOW (d);
|
||
|
||
rl = *(--nn);
|
||
|
||
while (nl != 0)
|
||
{
|
||
nl--;
|
||
rh = rl;
|
||
rl = *(--nn);
|
||
qa = rh / ch; /* appr. quotient */
|
||
|
||
/* Compute ph, pl */
|
||
pl = cl * qa;
|
||
ph = ch * qa;
|
||
ph += HIGH (pl);
|
||
pl = L2H (pl);
|
||
|
||
/* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
|
||
while (ph > rh || ph == rh && pl > rl)
|
||
{
|
||
qa--;
|
||
SUB (ph, pl, ch, L2H (cl));
|
||
}
|
||
|
||
SUB (rh, rl, ph, pl);
|
||
|
||
/* Top half of quotient is correct; save it */
|
||
*(--qq) = L2H (qa);
|
||
qa = (L2H (rh) | HIGH (rl)) / ch;
|
||
|
||
/* Approx low half of q */
|
||
/* Compute ph, pl, again */
|
||
pl = cl * qa;
|
||
ph = ch * qa;
|
||
ph += HIGH (pl);
|
||
pl = LOW (pl) | L2H (LOW (ph));
|
||
ph = HIGH (ph);
|
||
|
||
/* While ph:pl > rh:rl, decrement qa, adjust qh:ql */
|
||
while (ph > rh || ph == rh && pl > rl)
|
||
{
|
||
qa--;
|
||
SUB (ph, pl, 0, d);
|
||
}
|
||
|
||
/* Subtract ph:pl from rh:rl; we know rh will be 0 */
|
||
rl -= pl;
|
||
*qq |= qa;
|
||
}
|
||
|
||
/* Denormalize dividend */
|
||
if (k != 0) {
|
||
if((qq > nn) && (qq < &nn[orig_nl])) {
|
||
/* Overlap between qq and nn. Care of *qq! */
|
||
orig_nl = (qq - nn);
|
||
BnnShiftRight (nn, orig_nl, k);
|
||
nn[orig_nl - 1] = prev_qq;
|
||
} else if(qq == nn) {
|
||
BnnShiftRight(&nn[orig_nl - 1], 1, k);
|
||
} else {
|
||
BnnShiftRight (nn, orig_nl, k);
|
||
} }
|
||
return (rl >> k);
|
||
}
|
||
}
|
||
|
||
/***************************************/
|
||
|
||
|