📄 bignum.h
字号:
/*
Compare a multiple-precision number to a scalar.
*/
{
return compare_diff(a, lng, &ivalue, 1);
}
/****************************************************************************/
static inline int compare_same(digit_tc a[],
digit_tc b[],
DWORDC lng)
/*
Compare two multiple precision numbers a and b each of length lng.
Function value is the sign of a - b, namely
+1 if a > b
0 if a = b
-1 if a < b
*/
#if USEASM_IX86
#pragma warning(disable : 4035) /* No return value */
{
/*
We could use REPE CMPSD,
but REPE is slow (4 cycles)
on the Pentium. Plus we
would need std and cld
to adjust the direction flag.
We anticipate that most loops
will have either 1 or 2 iterations,
and use RISC instructions.
*/
_asm {
mov eax,lng
mov esi,a
mov edi,b
label1:
test eax,eax
jz label2 ; If nothing left, exit with eax = 0
mov ecx,[esi+4*eax-4] ;
mov edx,[edi+4*eax-4]
dec eax ; Decrement remaining loop count
cmp ecx,edx ; Test a[i] - b[i]
je label1
sbb eax,eax ; eax = 0 if a > b, -1 if a < b
or eax,1 ; eax = 1 if a > b, -1 if a < b
label2:
}
}
#pragma warning(default : 4035)
#else
{
DWORD i;
for (i = lng-1; i != -1; i--) {
if (a[i] != b[i]) return (a[i] > b[i] ? +1 : -1);
}
return 0;
} /* compare_same */
#endif
/****************************************************************************/
#if USEASM_ALPHA
extern void mp_clear(MP_OUTPUT, DWORDC);
#elif 0
static inline void mp_clear(digit_t a[],
DWORDC lnga)
/*
Zero a multiple-precision number.
*/
{
DWORD i;
for (i = 0; i != lnga; i++) a[i] = 0;
}
#else
#define mp_clear(dest, lng) (void)memset((void *)(dest), 0, (lng)*sizeof(digit_t))
#endif
/****************************************************************************/
#if USEASM_ALPHA
extern void mp_extend(MP_INPUT, DWORDC, MP_OUTPUT, DWORDC);
// See alpha.s
#else
static inline void mp_extend(digit_tc a[],
DWORDC lnga,
digit_t b[],
DWORDC lngb)
/*
Copy a to b, while changing its length from
lnga to lngb (zero fill). Require lngb >= lnga.
*/
{
mp_copy(a, b, lnga);
mp_clear(b + lnga, lngb - lnga);
}
#endif
/****************************************************************************/
static inline digit_t mp_getbit(digit_tc a[],
DWORDC ibit)
/* Extract bit of multiple precision number */
{
return digit_getbit(a[ibit/RADIX_BITS], ibit % RADIX_BITS);
}
/******************************************************************************/
static inline int mp_jacobi_wrt_immediate(digit_tc numer[],
DWORD lnumer,
digit_tc denom)
// Return jacobi(numer, denom), where denom is single precision
{
digit_tc rem = divide_immediate(numer, denom,
reciprocal_1_NULL,
digit_NULL, lnumer);
return digit_jacobi(rem, denom);
} /* mp_jacobi_wrt_immediate */
/***************************************************************************/
static inline DWORD mp_remove2(digit_t a[],
DWORDC lng)
/*
mp_remove2 divides -a- by a power of 2 as large as possible
(i.e., keep dividing by 2 until a is odd).
*/
{
int nzero;
digit_tc a0 = a[0];
if (a0 == 0) {
nzero = mp_trailing_zero_count(a, lng);
mp_longshift(a, -nzero, a, lng);
} else {
nzero = trailing_zero_count(a0);
if (nzero != 0) {
DWORD i;
digit_t carried_bits = DIGIT_ZERO;
for (i = lng-1; i != -1; i--) {
digit_tc anew = (a[i] >> nzero) | carried_bits;
carried_bits = a[i] << (RADIX_BITS - nzero);
a[i] = anew;
}
}
}
return (DWORD)nzero;
} /* mp_remove2 */
/****************************************************************************/
static inline void mp_setbit(digit_t a[],
DWORDC ibit,
digit_tc new_value)
/*
Set a bit to 0 or 1,
when the number is viewed as a bit array.
*/
{
DWORDC j = ibit / RADIX_BITS;
DWORDC ishift = ibit % RADIX_BITS;
digit_tc mask1 = (DIGIT_ONE & new_value) << ishift;
digit_tc mask2 = (DIGIT_ONE & ~new_value) << ishift;
a[j] = (a[j] & ~mask2) | mask1;
}
/****************************************************************************/
#if MEMORY_BANK_ALLOWANCE == 0
#define Preferred_Memory_Bank(new_array, old_array) new_array
#else
static inline digit_t* Preferred_Memory_Bank(digit_t *new_array,
digit_tc *old_array)
/*
To avoid memory bank conflicts, it is desirable
that (input) arguments to vmulxx assembly routines start
on distinct memory banks, when not doing a squaring.
If MEMORY_BANK_ALLOWANCE > 0,
then new_array should have MEMORY_BANK_ALLOWANCE
extra entries at the end. We return either
new_array or new_array + 1, whichever ensures the
addresses are distinct.
CAUTION -- This routine does non-portable pointer manipulations.
*/
{
return new_array + (1 & ~(old_array - new_array));
}
#endif
/****************************************************************************/
static inline void set_immediate(digit_t a[],
digit_tc ivalue,
DWORDC lnga)
{
a[0] = ivalue;
mp_clear(a + 1, lnga - 1);
}
/****************************************************************************/
static inline DWORD set_immediate_signed(digit_t a[],
signed long ivalue)
{
a[0] = labs(ivalue);
return (ivalue > 0) - (ivalue < 0); /* Sign of result -- -1, 0, +1 */
}
/****************************************************************************/
static inline DWORD significant_digit_count(digit_tc a[],
DWORDC lng)
/*
Return the number of significant digits in a.
Function value is zero precisely when a == 0.
*/
#if USEASM_IX86
#pragma warning(disable : 4035) /* No return value */
{
/*
We could use REPE SCASD,
but the REPE overhead is
four cycles/compare on the Pentium.
We would also need sld and cld.
It is shorter to use RISC instructions.
We anticipate that the leading term a[lng-1]
will usually be nonzero.
*/
_asm {
mov eax,lng
mov edx,a
label1:
test eax,eax
jz label2 ; If nothing left in number, return 0
mov ecx,[edx+4*eax-4]
dec eax
test ecx,ecx ; Test leading digit
jz label1
inc eax ; Nonzero element found; return old eax
label2:
}
}
#pragma warning(default : 4035)
#else
{
DWORD i = lng;
while (i != 0 && a[i-1] == 0) i--;
return i;
} /* significant_digit_count */
#endif
#define all_zero(a, lng) (significant_digit_count(a, lng) == 0)
/****************************************************************************/
static inline digit_t sub_immediate(digit_tc a[],
digit_tc isub,
digit_t b[],
DWORDC lng)
/*
Compute b = a - isub, where isub has length 1.
Both a and b have length lng.
Function value is borrow out of leftmost digit in b.
*/
{
return (lng == 0 ? isub : sub_diff(a, lng, &isub, 1, b));
}
/****************************************************************************/
static inline int trailing_zero_count(digit_tc d)
/*
Given a nonzero integer d, this routine computes
the largest integer n such that 2^n divides d.
If d = 2^n * (2k + 1), then
d = k *2^(n+1) + 2^n
-d = (-1-k)*2^(n+1) + 2^n
The integers k and -1 - k are one's complements of
each other, so d & (-d) = 2^n. Once we determine
2^n from d, we can get n via significant_bit_count.
*/
#if USEASM_IX86
#pragma warning(disable : 4035) /* No return value */
{
_asm {
mov eax,d
bsf eax,eax ; eax = index of rightmost nonzero bit
; BSF is slow on Pentium,
; but fast on Pentium Pro.
}
}
#pragma warning(default : 4035)
#else
{
return significant_bit_count(d & (-d)) - 1;
} /* trailing_zero_count */
#endif
/****************************************************************************/
static inline void digits_to_dwords(digit_tc pdigit[],
DWORD pdword[],
DWORDC lng_dwords)
{
#if DWORDS_PER_DIGIT == 1
mp_copy(pdigit, (digit_t*)pdword, lng_dwords);
#elif DWORDS_PER_DIGIT == 2
DWORDC lng_half = lng_dwords >> 1;
DWORD i;
if (IS_ODD(lng_dwords)) {
pdword[lng_dwords-1] = (DWORD)pdigit[lng_half];
}
for (i = 0; i != lng_half; i++) {
digit_tc dig = pdigit[i];
pdword[2*i ] = (DWORD)dig;
pdword[2*i + 1] = (DWORD)(dig >> DWORD_BITS);
}
#else
#error "Unexpected DWORDS_PER_DIGIT"
#endif
} /* digits_to_dwords */
/****************************************************************************/
static inline void dwords_to_digits(DWORDC pdword[],
digit_t pdigit[],
DWORDC lng_dwords)
{
#if DWORDS_PER_DIGIT == 1
mp_copy((digit_t*)pdword, pdigit, lng_dwords);
#elif DWORDS_PER_DIGIT == 2
DWORDC lng_half = lng_dwords >> 1;
DWORD i;
if (IS_ODD(lng_dwords)) {
pdigit[lng_half] = (digit_t)pdword[lng_dwords - 1]; // Zero fill
}
for (i = 0; i != lng_half; i++) {
pdigit[i] = ((digit_t)pdword[2*i+1] << DWORD_BITS)
| (digit_t)pdword[2*i];
}
#else
#error "Unexpected DWORDS_PER_DIGIT"
#endif
} /* dwords_to_digits */
#endif // RADIX_BITS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -