⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zmod.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (tmp1.v != z1.v)			zfree(tmp1);		if (tmp2.v != z2.v)			zfree(tmp2);		return TRUE;	}	/*	 * Either one of the numbers is negative or is large.	 * So do the standard thing and subtract the two numbers.	 * Then they are equal if the result is 0 (mod z3).	 */	zsub(tmp1, tmp2, &tmp3);	if (tmp1.v != z1.v)		zfree(tmp1);	if (tmp2.v != z2.v)		zfree(tmp2);	/*	 * Compare the result with the modulus to see if it is equal to	 * or less than the modulus.  If so, we know the mod result.	 */	tmp3.sign = 0;	cv = zrel(tmp3, z3);	if (cv == 0) {		zfree(tmp3);		return FALSE;	}	if (cv < 0) {		zfree(tmp3);		return TRUE;	}	/*	 * We are forced to actually do the division.	 * The numbers are congruent if the result is zero.	 */	zmod(tmp3, z3, &tmp1);	zfree(tmp3);	if (ziszero(tmp1)) {		zfree(tmp1);		return FALSE;	} else {		zfree(tmp1);		return TRUE;	}}/* * Compute the result of raising one number to a power modulo another number. * That is, this computes:  a^b (modulo c). * This calculates the result by examining the power POWBITS bits at a time, * using a small table of POWNUMS low powers to calculate powers for those bits, * and repeated squaring and multiplying by the partial powers to generate * the complete power.  If the power being raised to is high enough, then * this uses the REDC algorithm to avoid doing many divisions.  When using * REDC, multiple calls to this routine using the same modulus will be * slightly faster. */voidzpowermod(z1, z2, z3, res)	ZVALUE z1, z2, z3, *res;{	HALF *hp;		/* pointer to current word of the power */	REDC *rp;		/* REDC information to be used */	ZVALUE *pp;		/* pointer to low power table */	ZVALUE ans, temp;	/* calculation values */	ZVALUE modpow;		/* current small power */	ZVALUE lowpowers[POWNUMS];	/* low powers */	int sign;		/* original sign of number */	int curshift;		/* shift value for word of power */	HALF curhalf;		/* current word of power */	unsigned int curpow;	/* current low power */	unsigned int curbit;	/* current bit of low power */	int i;	if (zisneg(z3) || ziszero(z3))		math_error("Non-positive modulus in zpowermod");	if (zisneg(z2))		math_error("Negative power in zpowermod");	sign = z1.sign;	z1.sign = 0;	/*	 * Check easy cases first.	 */	if ((ziszero(z1) && !ziszero(z2)) || zisunit(z3)) {		/* 0^(non_zero) or x^y mod 1 always produces zero */		*res = _zero_;		return;	}	if (ziszero(z2)) {			/* x^0 == 1 */		*res = _one_;		return;	}	if (zistwo(z3)) {			/* mod 2 */		if (zisodd(z1))			*res = _one_;		else			*res = _zero_;		return;	}	if (zisunit(z1) && (!sign || ziseven(z2))) {		/* 1^x or (-1)^(2x) */		*res = _one_;		return;	}	/*	 * Normalize the number being raised to be non-negative and to lie	 * within the modulo range.  Then check for zero or one specially.	 */	zmod(z1, z3, &temp);	if (ziszero(temp)) {		zfree(temp);		*res = _zero_;		return;	}	z1 = temp;	if (sign) {		zsub(z3, z1, &temp);		zfree(z1);		z1 = temp;	}	if (zisunit(z1)) {		zfree(z1);		*res = _one_;		return;	}	/*	 * If the modulus is odd, large enough, is not one less than an	 * exact power of two, and if the power is large enough, then use	 * the REDC algorithm.  The size where this is done is configurable.	 */	if ((z2.len > 1) && (z3.len >= _pow2_) && zisodd(z3)		&& !zisallbits(z3))	{		if (powermodredc && zcmp(powermodredc->mod, z3)) {			zredcfree(powermodredc);			powermodredc = NULL;		}		if (powermodredc == NULL)			powermodredc = zredcalloc(z3);		rp = powermodredc;		zredcencode(rp, z1, &temp);		zredcpower(rp, temp, z2, &z1);		zfree(temp);		zredcdecode(rp, z1, res);		zfree(z1);		return;	}	/*	 * Modulus or power is small enough to perform the power raising	 * directly.  Initialize the table of powers.	 */	for (pp = &lowpowers[2]; pp < &lowpowers[POWNUMS]; pp++)		pp->len = 0;	lowpowers[0] = _one_;	lowpowers[1] = z1;	ans = _one_;	hp = &z2.v[z2.len - 1];	curhalf = *hp;	curshift = BASEB - POWBITS;	while (curshift && ((curhalf >> curshift) == 0))		curshift -= POWBITS;	/*	 * Calculate the result by examining the power POWBITS bits at a time,	 * and use the table of low powers at each iteration.	 */	for (;;) {		curpow = (curhalf >> curshift) & (POWNUMS - 1);		pp = &lowpowers[curpow];		/*		 * If the small power is not yet saved in the table, then		 * calculate it and remember it in the table for future use.		 */		if (pp->len == 0) {			if (curpow & 0x1)				zcopy(z1, &modpow);			else				modpow = _one_;			for (curbit = 0x2; curbit <= curpow; curbit *= 2) {				pp = &lowpowers[curbit];				if (pp->len == 0) {					zsquare(lowpowers[curbit/2], &temp);					zmod(temp, z3, pp);					zfree(temp);				}				if (curbit & curpow) {					zmul(*pp, modpow, &temp);					zfree(modpow);					zmod(temp, z3, &modpow);					zfree(temp);				}			}			pp = &lowpowers[curpow];			*pp = modpow;		}		/*		 * If the power is nonzero, then accumulate the small power		 * into the result.		 */		if (curpow) {			zmul(ans, *pp, &temp);			zfree(ans);			zmod(temp, z3, &ans);			zfree(temp);		}		/*		 * Select the next POWBITS bits of the power, if there is		 * any more to generate.		 */		curshift -= POWBITS;		if (curshift < 0) {			if (hp-- == z2.v)				break;			curhalf = *hp;			curshift = BASEB - POWBITS;		}		/*		 * Square the result POWBITS times to make room for the next		 * chunk of bits.		 */		for (i = 0; i < POWBITS; i++) {			zsquare(ans, &temp);			zfree(ans);			zmod(temp, z3, &ans);			zfree(temp);		}	}	for (pp = &lowpowers[2]; pp < &lowpowers[POWNUMS]; pp++) {		if (pp->len)			freeh(pp->v);	}	*res = ans;}/* * Initialize the REDC algorithm for a particular modulus, * returning a pointer to a structure that is used for other * REDC calls.  An error is generated if the structure cannot * be allocated.  The modulus must be odd and positive. */REDC *zredcalloc(z1)	ZVALUE z1;		/* modulus to initialize for */{	REDC *rp;		/* REDC information */	ZVALUE tmp;	long bit;	if (ziseven(z1) || zisneg(z1))		math_error("REDC requires positive odd modulus");	rp = (REDC *) malloc(sizeof(REDC));	if (rp == NULL)		math_error("Cannot allocate REDC structure");	/*	 * Round up the binary modulus to the next power of two	 * which is at a word boundary.  Then the shift and modulo	 * operations mod the binary modulus can be done very cheaply.	 * Calculate the REDC format for the number 1 for future use.	 */	bit = zhighbit(z1) + 1;	if (bit % BASEB)		bit += (BASEB - (bit % BASEB));	zcopy(z1, &rp->mod);	zbitvalue(bit, &tmp);	z1.sign = 1;	(void) zmodinv(z1, tmp, &rp->inv);	zmod(tmp, rp->mod, &rp->one);	zfree(tmp);	rp->len = bit / BASEB;	return rp;}/* * Free any numbers associated with the specified REDC structure, * and then the REDC structure itself. */voidzredcfree(rp)	REDC *rp;		/* REDC information to be cleared */{	zfree(rp->mod);	zfree(rp->inv);	zfree(rp->one);	free(rp);}/* * Convert a normal number into the specified REDC format. * The number to be converted can be negative or out of modulo range. * The resulting number can be used for multiplying, adding, subtracting, * or comparing with any other such converted numbers, as if the numbers * were being calculated modulo the number which initialized the REDC * information.  When the final value is unconverted, the result is the * same as if the usual operations were done with the original numbers. */voidzredcencode(rp, z1, res)	REDC *rp;		/* REDC information */	ZVALUE z1;		/* number to be converted */	ZVALUE *res;		/* returned converted number */{	ZVALUE tmp1, tmp2;	/*	 * Handle the cases 0, 1, -1, and 2 specially since these are	 * easy to calculate.  Zero transforms to zero, and the others	 * can be obtained from the precomputed REDC format for 1 since	 * addition and subtraction act normally for REDC format numbers.	 */	if (ziszero(z1)) {		*res = _zero_;		return;	}	if (zisone(z1)) {		zcopy(rp->one, res);		return;	}	if (zisunit(z1)) {		zsub(rp->mod, rp->one, res);		return;	}	if (zistwo(z1)) {		zadd(rp->one, rp->one, &tmp1);		if (zrel(tmp1, rp->mod) < 0) {			*res = tmp1;			return;		}		zsub(tmp1, rp->mod, res);		zfree(tmp1);		return;	}	/*	 * Not a trivial number to convert, so do the full transformation.	 * Convert negative numbers to positive numbers before converting.	 */	tmp1.len = 0;	if (zisneg(z1)) {		zmod(z1, rp->mod, &tmp1);		z1 = tmp1;	}	zshift(z1, rp->len * BASEB, &tmp2);	if (tmp1.len)		zfree(tmp1);	zmod(tmp2, rp->mod, res);	zfree(tmp2);}/* * The REDC algorithm used to convert numbers out of REDC format and also * used after multiplication of two REDC numbers.  Using this routine * avoids any divides, replacing the divide by two multiplications. * If the numbers are very large, then these two multiplies will be * quicker than the divide, since dividing is harder than multiplying. */voidzredcdecode(rp, z1, res)	REDC *rp;		/* REDC information */	ZVALUE z1;		/* number to be transformed */	ZVALUE *res;		/* returned transformed number */{	ZVALUE tmp1, tmp2;	/* temporaries */	HALF *hp;		/* saved pointer to tmp2 value */	if (zisneg(z1))		math_error("Negative number for zredc");	/*	 * Check first for the special values for 0 and 1 that are easy.	 */	if (ziszero(z1)) {		*res = _zero_;		return;	}	if ((z1.len == rp->one.len) && (z1.v[0] == rp->one.v[0]) &&		(zcmp(z1, rp->one) == 0)) {			*res = _one_;			return;	}	/*	 * First calculate the following:	 * 	tmp2 = ((z1 % 2^bitnum) * inv) % 2^bitnum.	 * The mod operations can be done with no work since the bit	 * number was selected as a multiple of the word size.  Just	 * reduce the sizes of the numbers as required.	 */	tmp1 = z1;	if (tmp1.len > rp->len)		tmp1.len = rp->len;	zmul(tmp1, rp->inv, &tmp2);	if (tmp2.len > rp->len)		tmp2.len = rp->len;	/*	 * Next calculate the following:	 *	res = (z1 + tmp2 * modulus) / 2^bitnum	 * The division by a power of 2 is always exact, and requires no	 * work.  Just adjust the address and length of the number to do	 * the divide, but save the original pointer for freeing later.	 */	zmul(tmp2, rp->mod, &tmp1);	zfree(tmp2);	zadd(z1, tmp1, &tmp2);	zfree(tmp1);	hp = tmp2.v;	if (tmp2.len <= rp->len) {		freeh(hp);		*res = _zero_;		return;	}	tmp2.v += rp->len;	tmp2.len -= rp->len;	/*	 * Finally do a final modulo by a simple subtraction if necessary.	 * This is all that is needed because the previous calculation is	 * guaranteed to always be less than twice the modulus.	 */	if (zrel(tmp2, rp->mod) < 0)		zcopy(tmp2, res);	else		zsub(tmp2, rp->mod, res);	freeh(hp);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -