📄 bigdigits.c
字号:
{ /* Sets a = 0 */
/* Prevent optimiser ignoring this */
volatile DIGIT_T optdummy;
DIGIT_T *p = a;
while (ndigits--)
a[ndigits] = 0;
optdummy = *p;
}
void mpSetDigit(DIGIT_T a[], DIGIT_T d, size_t ndigits)
{ /* Sets a = d where d is a single digit */
size_t i;
for (i = 1; i < ndigits; i++)
{
a[i] = 0;
}
a[0] = d;
}
DIGIT_T mpShiftLeft(DIGIT_T a[], const DIGIT_T *b,
size_t shift, size_t ndigits)
{ /* Computes a = b << shift */
/* [v2.1] Modified to cope with shift > BITS_PERDIGIT */
size_t i, y, nw, bits;
DIGIT_T mask, carry, nextcarry;
/* Do we shift whole digits? */
if (shift >= BITS_PER_DIGIT)
{
nw = shift / BITS_PER_DIGIT;
i = ndigits;
while (i--)
{
if (i >= nw)
a[i] = b[i-nw];
else
a[i] = 0;
}
/* Call again to shift bits inside digits */
bits = shift % BITS_PER_DIGIT;
carry = b[ndigits-nw] << bits;
if (bits)
carry |= mpShiftLeft(a, a, bits, ndigits);
return carry;
}
else
{
bits = shift;
}
/* Construct mask = high bits set */
mask = ~(~(DIGIT_T)0 >> bits);
y = BITS_PER_DIGIT - bits;
carry = 0;
for (i = 0; i < ndigits; i++)
{
nextcarry = (b[i] & mask) >> y;
a[i] = b[i] << bits | carry;
carry = nextcarry;
}
return carry;
}
DIGIT_T mpShiftRight(DIGIT_T a[], const DIGIT_T b[], size_t shift, size_t ndigits)
{ /* Computes a = b >> shift */
/* [v2.1] Modified to cope with shift > BITS_PERDIGIT */
size_t i, y, nw, bits;
DIGIT_T mask, carry, nextcarry;
/* Do we shift whole digits? */
if (shift >= BITS_PER_DIGIT)
{
nw = shift / BITS_PER_DIGIT;
for (i = 0; i < ndigits; i++)
{
if ((i+nw) < ndigits)
a[i] = b[i+nw];
else
a[i] = 0;
}
/* Call again to shift bits inside digits */
bits = shift % BITS_PER_DIGIT;
carry = b[nw-1] >> bits;
if (bits)
carry |= mpShiftRight(a, a, bits, ndigits);
return carry;
}
else
{
bits = shift;
}
/* Construct mask to set low bits */
/* (thanks to Jesse Chisholm for suggesting this improved technique) */
mask = ~(~(DIGIT_T)0 << bits);
y = BITS_PER_DIGIT - bits;
carry = 0;
i = ndigits;
while (i--)
{
nextcarry = (b[i] & mask) << y;
a[i] = b[i] >> bits | carry;
carry = nextcarry;
}
return carry;
}
void mpModPowerOf2(DIGIT_T a[], size_t ndigits, size_t L)
/* Computes a = a mod 2^L */
/* i.e. clears all bits >= L */
{
size_t i, nw, bits;
DIGIT_T mask;
/* High digits to clear */
nw = L / BITS_PER_DIGIT;
for (i = nw+1; i < ndigits; i++)
a[i] = 0;
/* Low bits to keep */
bits = L % BITS_PER_DIGIT;
mask = ~(~0 << bits);
if (ndigits > nw)
a[nw] &= mask;
}
void mpXorBits(DIGIT_T a[], const DIGIT_T b[], const DIGIT_T c[], size_t ndigits)
/* Computes bitwise a = b XOR c */
{
size_t i;
for (i = 0; i < ndigits; i++)
a[i] = b[i] ^ c[i];
}
void mpOrBits(DIGIT_T a[], const DIGIT_T b[], const DIGIT_T c[], size_t ndigits)
/* Computes bitwise a = b OR c */
{
size_t i;
for (i = 0; i < ndigits; i++)
a[i] = b[i] | c[i];
}
void mpAndBits(DIGIT_T a[], const DIGIT_T b[], const DIGIT_T c[], size_t ndigits)
/* Computes bitwise a = b AND c */
{
size_t i;
for (i = 0; i < ndigits; i++)
a[i] = b[i] & c[i];
}
DIGIT_T mpShortAdd(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v,
size_t ndigits)
{
/* Calculates w = u + v
where w, u are multiprecision integers of ndigits each
and v is a single precision digit.
Returns carry if overflow.
Ref: Derived from Knuth Algorithm A.
*/
DIGIT_T k;
size_t j;
k = 0;
/* Add v to first digit of u */
w[0] = u[0] + v;
if (w[0] < v)
k = 1;
else
k = 0;
/* Add carry to subsequent digits */
for (j = 1; j < ndigits; j++)
{
w[j] = u[j] + k;
if (w[j] < k)
k = 1;
else
k = 0;
}
return k;
}
DIGIT_T mpShortSub(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v,
size_t ndigits)
{
/* Calculates w = u - v
where w, u are multiprecision integers of ndigits each
and v is a single precision digit.
Returns borrow: 0 if u >= v, or 1 if v > u.
Ref: Derived from Knuth Algorithm S.
*/
DIGIT_T k;
size_t j;
k = 0;
/* Subtract v from first digit of u */
w[0] = u[0] - v;
if (w[0] > MAX_DIGIT - v)
k = 1;
else
k = 0;
/* Subtract borrow from subsequent digits */
for (j = 1; j < ndigits; j++)
{
w[j] = u[j] - k;
if (w[j] > MAX_DIGIT - k)
k = 1;
else
k = 0;
}
return k;
}
DIGIT_T mpShortMult(DIGIT_T w[], const DIGIT_T u[], DIGIT_T v,
size_t ndigits)
{
/* Computes product w = u * v
Returns overflow k
where w, u are multiprecision integers of ndigits each
and v, k are single precision digits
Ref: Knuth Algorithm M.
*/
DIGIT_T k, t[2];
size_t j;
if (v == 0)
{ /* [2005-08-29] Set w = 0 */
for (j = 0; j < ndigits; j++)
w[j] = 0;
return 0;
}
k = 0;
for (j = 0; j < ndigits; j++)
{
/* t = x_i * v */
spMultiply(t, u[j], v);
/* w_i = LOHALF(t) + carry */
w[j] = t[0] + k;
/* Overflow? */
if (w[j] < k)
t[1]++;
/* Carry forward HIHALF(t) */
k = t[1];
}
return k;
}
DIGIT_T mpShortDiv(DIGIT_T q[], const DIGIT_T u[], DIGIT_T v,
size_t ndigits)
{
/* Calculates quotient q = u div v
Returns remainder r = u mod v
where q, u are multiprecision integers of ndigits each
and r, v are single precision digits.
Makes no assumptions about normalisation.
Ref: Knuth Vol 2 Ch 4.3.1 Exercise 16 p625
*/
size_t j;
DIGIT_T t[2], r;
size_t shift;
DIGIT_T bitmask, overflow, *uu;
if (ndigits == 0) return 0;
if (v == 0) return 0; /* Divide by zero error */
/* Normalise first */
/* Requires high bit of V
to be set, so find most signif. bit then shift left,
i.e. d = 2^shift, u' = u * d, v' = v * d.
*/
bitmask = HIBITMASK;
for (shift = 0; shift < BITS_PER_DIGIT; shift++)
{
if (v & bitmask)
break;
bitmask >>= 1;
}
v <<= shift;
overflow = mpShiftLeft(q, u, shift, ndigits);
uu = q;
/* Step S1 - modified for extra digit. */
r = overflow; /* New digit Un */
j = ndigits;
while (j--)
{
/* Step S2. */
t[1] = r;
t[0] = uu[j];
overflow = spDivide(&q[j], &r, t, v);
}
/* Unnormalise */
r >>= shift;
return r;
}
DIGIT_T mpShortMod(const DIGIT_T a[], DIGIT_T d, size_t ndigits)
{
/* Calculates r = a mod d
where a is a multiprecision integer of ndigits
and r, d are single precision digits
using bit-by-bit method from left to right.
Use remainder from divide function.
Updated Version 2 to use malloc.
*/
DIGIT_T *q;
DIGIT_T r = 0;
q = mpAlloc(ndigits * 2);
r = mpShortDiv(q, a, d, ndigits);
mpSetZero(q, ndigits);
mpFree(&q);
return r;
}
int mpShortCmp(const DIGIT_T a[], DIGIT_T b, size_t ndigits)
{
/* Returns sign of (a - b) where b is a single digit */
size_t i;
/* Changed in Ver 2.0 to cope with zero-length a */
if (ndigits == 0) return (b ? -1 : 0);
for (i = 1; i < ndigits; i++)
{
if (a[i] != 0)
return 1; /* GT */
}
if (a[0] < b)
return -1; /* LT */
else if (a[0] > b)
return 1; /* GT */
return 0; /* EQ */
}
/* [v2.1] changed to use C99 format types */
void mpPrint(const DIGIT_T *p, size_t len)
{
while (len--)
{
printf("%08" PRIxBIGD " ", p[len]);
}
}
void mpPrintNL(const DIGIT_T *p, size_t len)
{
size_t i = 0;
while (len--)
{
if ((i % 8) == 0 && i)
printf("\n");
printf("%08" PRIxBIGD " ", p[len]);
i++;
}
printf("\n");
}
void mpPrintTrim(const DIGIT_T *p, size_t len)
{
/* Trim leading zeroes */
while (len--)
{
if (p[len] != 0)
break;
}
len++;
/* Catch empty len to show 0 */
if (0 == len) len = 1;
mpPrint(p, len);
}
void mpPrintTrimNL(const DIGIT_T *p, size_t len)
{
/* Trim leading zeroes */
while (len--)
{
if (p[len] != 0)
break;
}
len++;
/* Catch empty len to show 0 */
if (0 == len) len = 1;
mpPrintNL(p, len);
}
size_t mpConvFromOctets(DIGIT_T a[], size_t ndigits, const unsigned char *c, size_t nbytes)
/* Converts nbytes octets into big digit a of max size ndigits
Returns actual number of digits set (may be larger than mpSizeof)
*/
{
size_t i;
int j, k;
DIGIT_T t;
mpSetZero(a, ndigits);
/* Read in octets, least significant first */
/* i counts into big_d, j along c, and k is # bits to shift */
for (i = 0, j = nbytes - 1; i < ndigits && j >= 0; i++)
{
t = 0;
for (k = 0; j >= 0 && k < BITS_PER_DIGIT; j--, k += 8)
t |= ((DIGIT_T)c[j]) << k;
a[i] = t;
}
return i;
}
size_t mpConvToOctets(const DIGIT_T a[], size_t ndigits, unsigned char *c, size_t nbytes)
/* Convert big digit a into string of octets, in big-endian order,
padding on the left to nbytes or truncating if necessary.
Return number of octets required excluding leading zero bytes.
*/
{
int j, k, len;
DIGIT_T t;
size_t i, noctets, nbits;
nbits = mpBitLength(a, ndigits);
noctets = (nbits + 7) / 8;
len = (int)nbytes;
for (i = 0, j = len - 1; i < ndigits && j >= 0; i++)
{
t = a[i];
for (k = 0; j >= 0 && k < BITS_PER_DIGIT; j--, k += 8)
c[j] = (unsigned char)(t >> k);
}
for ( ; j >= 0; j--)
c[j] = 0;
return (size_t)noctets;
}
static size_t uiceil(double x)
/* Returns ceil(x) as a non-negative integer or 0 if x < 0 */
{
size_t c;
if (x < 0) return 0;
c = (size_t)x;
if ((x - c) > 0.0)
c++;
return c;
}
static size_t conv_to_base(const DIGIT_T a[], size_t ndigits, char *s, size_t smax, int base)
/* Convert big digit a into a string in given base format,
where s has max size smax.
Return number of chars set excluding leading zeroes.
smax can be 0 to find out the required length.
*/
{
const char DEC_DIGITS[] = "0123456789";
const char HEX_DIGITS[] = "0123456789abcdef";
size_t newlen, nbytes, nchars;
unsigned char *bytes, *newdigits;
size_t n;
unsigned long t;
size_t i, j, isig;
const char *digits;
double factor;
switch (base)
{
case 10:
digits = DEC_DIGITS;
factor = 2.40824; /* log(256)/log(10)=2.40824 */
break;
case 16:
digits = HEX_DIGITS;
factor = 2.0; /* log(256)/log(16)=2.0 */
break;
default:
assert (10 == base || 16 == base);
return 0;
}
/* Set up output string with null chars */
if (smax > 0 && s)
{
memset(s, '0', smax-1);
s[smax-1] = '\0';
}
/* Catch zero input value (return 1 not zero) */
if (mpIsZero(a, ndigits))
{
if (smax > 0 && s)
s[1] = '\0';
return 1;
}
/* First, we convert to 8-bit octets (bytes), which are easier to handle */
nbytes = ndigits * BITS_PER_DIGIT / 8;
bytes = calloc(nbytes, 1);
if (!bytes) mpFail("conv_to_base: Not enough memory: " __FILE__);
n = mpConvToOctets(a, ndigits, bytes, nbytes);
/* Create some temp storage for int values */
newlen = uiceil(n * factor);
newdigits = calloc(newlen, 1);
if (!newdigits) mpFail("conv_to_base: Not enough memory: " __FILE__);
for (i = 0; i < nbytes; i++)
{
t = bytes[i];
for (j = newlen; j > 0; j--)
{
t += (unsigned long)newdigits[j-1] * 256;
newdigits[j-1] = (unsigned char)(t % base);
t /= base;
}
}
/* Find index of leading significant digit */
for (isig = 0; isig < newlen; isig++)
if (newdigits[isig])
break;
nchars = newlen - isig;
/* Convert to a null-terminated string of decimal chars */
/* up to limit, unless user has specified null or size == 0 */
if (smax > 0 && s)
{
for (i = 0; i < nchars && i < smax-1; i++)
{
s[i] = digits[newdigits[isig+i]];
}
s[i] = '\0';
}
free(bytes);
free(newdigits);
return nchars;
}
size_t mpConvToDecimal(const DIGIT_T a[], size_t ndigits, char *s, size_t smax)
/* Convert big digit a into a string in decimal format,
where s has max size smax.
Return number of chars set excluding leading zeroes.
*/
{
return conv_to_base(a, ndigits, s, smax, 10);
}
size_t mpConvToHex(const DIGIT_T a[], size_t ndigits, char *s, size_t smax)
/* Convert big digit a into a string in hexadecimal format,
where s has max size smax.
Return number of chars set excluding leading zeroes.
*/
{
return conv_to_base(a, ndigits, s, smax, 16);
}
size_t mpConvFromDecimal(DIGIT_T a[], size_t ndigits, const char *s)
/* Convert a string in decimal format to a big digit.
Return actual number of digits set (may be larger than mpSizeof).
Just ignores invalid characters in s.
*/
{
size_t newlen;
unsigned char *newdigits;
size_t n;
unsigned long t;
size_t i, j;
const int base = 10;
mpSetZero(a, ndigits);
/* Create some temp storage for int values */
n = strlen(s);
if (0 == n) return 0;
newlen = uiceil(n * 0.41524); /* log(10)/log(256)=0.41524 */
newdigits = calloc(newlen, 1);
if (!newdigits) mpFail("mpConvFromDecimal: Not enough memory: " __FILE__);
/* Work through zero-terminated string */
for (i = 0; s[i]; i++)
{
t = s[i] - '0';
if (t > 9 || t < 0) continue;
for (j = newlen; j > 0; j--)
{
t += (unsigned long)newdigits[j-1] * base;
newdigits[j-1] = (unsigned char)(t & 0xFF);
t >>= 8;
}
}
/* Convert bytes to big digits */
n = mpConvFromOctets(a, ndigits, newdigits, newlen);
/* Clean up */
free(newdigits);
return n;
}
size_t mpConvFromHex(DIGIT_T a[], size_t ndigits, const char *s)
/* Convert a string in hexadecimal format to a big digit.
Return actual number of digits set (may be larger than mpSizeof).
Just ignores invalid characters in s.
*/
{
size_t newlen;
unsigned char *newdigits;
size_t n;
unsigned long t;
size_t i, j;
mpSetZero(a, ndigits);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -