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

📄 zmod.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Multiply two numbers in REDC format together producing a result also * in REDC format.  If the result is converted back to a normal number, * then the result is the same as the modulo'd multiplication of the * original numbers before they were converted to REDC format.  This * calculation is done in one of two ways, depending on the size of the * modulus.  For large numbers, the REDC definition is used directly * which involves three multiplies overall.  For small numbers, a * complicated routine is used which does the indicated multiplication * and the REDC algorithm at the same time to produce the result. */voidzredcmul(rp, z1, z2, res)	REDC *rp;		/* REDC information */	ZVALUE z1;		/* first REDC number to be multiplied */	ZVALUE z2;		/* second REDC number to be multiplied */	ZVALUE *res;		/* resulting REDC number */{	FULL mulb;	FULL muln;	HALF *h1;	HALF *h2;	HALF *h3;	HALF *hd;	HALF Ninv;	HALF topdigit = 0;	LEN modlen;	LEN len;	LEN len2;	SIUNION sival1;	SIUNION sival2;	SIUNION sival3;	SIUNION carry;	ZVALUE tmp;	if (zisneg(z1) || (z1.len > rp->mod.len) ||		zisneg(z2) || (z2.len > rp->mod.len))			math_error("Negative or too large number in zredcmul");	/*	 * Check for special values which we easily know the answer.	 */	if (ziszero(z1) || ziszero(z2)) {		*res = _zero_;		return;	}	if ((z1.len == rp->one.len) && (z1.v[0] == rp->one.v[0]) &&		(zcmp(z1, rp->one) == 0)) {			zcopy(z2, res);			return;	}	if ((z2.len == rp->one.len) && (z2.v[0] == rp->one.v[0]) &&		(zcmp(z2, rp->one) == 0)) {			zcopy(z1, res);			return;	}	/*	 * If the size of the modulus is large, then just do the multiply,	 * followed by the two multiplies contained in the REDC routine.	 * This will be quicker than directly doing the REDC calculation	 * because of the O(N^1.585) speed of the multiplies.  The size	 * of the number which this is done is configurable.	 */	if (rp->mod.len >= _redc2_) {		zmul(z1, z2, &tmp);		zredcdecode(rp, tmp, res);		zfree(tmp);		return;	}	/*	 * The number is small enough to calculate by doing the O(N^2) REDC	 * algorithm directly.  This algorithm performs the multiplication and	 * the reduction at the same time.  Notice the obscure facts that	 * only the lowest word of the inverse value is used, and that	 * there is no shifting of the partial products as there is in a	 * normal multiply.	 */	modlen = rp->mod.len;	Ninv = rp->inv.v[0];	/*	 * Allocate the result and clear it.	 * The size of the result will be equal to or smaller than	 * the modulus size.	 */	res->sign = 0;	res->len = modlen;	res->v = alloc(modlen);	hd = res->v;	len = modlen;	zclearval(*res);	/*	 * Do this outermost loop over all the digits of z1.	 */	h1 = z1.v;	len = z1.len;	while (len--) {		/*		 * Start off with the next digit of z1, the first		 * digit of z2, and the first digit of the modulus.		 */		mulb = (FULL) *h1++;		h2 = z2.v;		h3 = rp->mod.v;		hd = res->v;		sival1.ivalue = mulb * ((FULL) *h2++) + ((FULL) *hd++);		muln = ((HALF) (sival1.silow * Ninv));		sival2.ivalue = muln * ((FULL) *h3++);		sival3.ivalue = ((FULL) sival1.silow) + ((FULL) sival2.silow);		carry.ivalue = ((FULL) sival1.sihigh) + ((FULL) sival2.sihigh)			+ ((FULL) sival3.sihigh);		/*		 * Do this innermost loop for each digit of z2, except		 * for the first digit which was just done above.		 */		len2 = z2.len;		while (--len2 > 0) {			sival1.ivalue = mulb * ((FULL) *h2++);			sival2.ivalue = muln * ((FULL) *h3++);			sival3.ivalue = ((FULL) sival1.silow)				+ ((FULL) sival2.silow)				+ ((FULL) *hd)				+ ((FULL) carry.silow);			carry.ivalue = ((FULL) sival1.sihigh)				+ ((FULL) sival2.sihigh)				+ ((FULL) sival3.sihigh)				+ ((FULL) carry.sihigh);			hd[-1] = sival3.silow;			hd++;		}		/*		 * Now continue the loop as necessary so the total number		 * of interations is equal to the size of the modulus.		 * This acts as if the innermost loop was repeated for		 * high digits of z2 that are zero.		 */		len2 = modlen - z2.len;		while (len2--) {			sival2.ivalue = muln * ((FULL) *h3++);			sival3.ivalue = ((FULL) sival2.silow)				+ ((FULL) *hd)				+ ((FULL) carry.silow);			carry.ivalue = ((FULL) sival2.sihigh)				+ ((FULL) sival3.sihigh)				+ ((FULL) carry.sihigh);			hd[-1] = sival3.silow;			hd++;		}		res->v[modlen - 1] = carry.silow;		topdigit = carry.sihigh;	}	/*	 * Now continue the loop as necessary so the total number	 * of interations is equal to the size of the modulus.	 * This acts as if the outermost loop was repeated for high	 * digits of z1 that are zero.	 */	len = modlen - z1.len;	while (len--) {		/*		 * Start off with the first digit of the modulus.		 */		h3 = rp->mod.v;		hd = res->v;		muln = ((HALF) (*hd * Ninv));		sival2.ivalue = muln * ((FULL) *h3++);		sival3.ivalue = ((FULL) *hd++) + ((FULL) sival2.silow);		carry.ivalue = ((FULL) sival2.sihigh) + ((FULL) sival3.sihigh);		/*		 * Do this innermost loop for each digit of the modulus,		 * except for the first digit which was just done above.		 */		len2 = modlen;		while (--len2 > 0) {			sival2.ivalue = muln * ((FULL) *h3++);			sival3.ivalue = ((FULL) sival2.silow)				+ ((FULL) *hd)				+ ((FULL) carry.silow);			carry.ivalue = ((FULL) sival2.sihigh)				+ ((FULL) sival3.sihigh)				+ ((FULL) carry.sihigh);			hd[-1] = sival3.silow;			hd++;		}		res->v[modlen - 1] = carry.silow;		topdigit = carry.sihigh;	}	/*	 * Determine the true size of the result, taking the top digit of	 * the current result into account.  The top digit is not stored in	 * the number because it is temporary and would become zero anyway	 * after the final subtraction is done.	 */	if (topdigit == 0) {		len = modlen;		hd = &res->v[len - 1];		while ((*hd == 0) && (len > 1)) {			hd--;			len--;		}		res->len = len;	}	/*	 * Compare the result with the modulus.	 * If it is less than the modulus, then the calculation is complete.	 */	if ((topdigit == 0) && ((len < modlen)		|| (res->v[len - 1] < rp->mod.v[len - 1])		|| (zrel(*res, rp->mod) < 0)))			return;	/*	 * Do a subtraction to reduce the result to a value less than	 * the modulus.  The REDC algorithm guarantees that a single subtract	 * is all that is needed.  Ignore any borrowing from the possible	 * highest word of the current result because that would affect	 * only the top digit value that was not stored and would become	 * zero anyway.	 */	carry.ivalue = 0;	h1 = rp->mod.v;	hd = res->v;	len = modlen;	while (len--) {		carry.ivalue = BASE1 - ((FULL) *hd) + ((FULL) *h1++)			+ ((FULL) carry.silow);		*hd++ = BASE1 - carry.silow;		carry.silow = carry.sihigh;	}	/*	 * Now finally recompute the size of the result.	 */	len = modlen;	hd = &res->v[len - 1];	while ((*hd == 0) && (len > 1)) {		hd--;		len--;	}	res->len = len;}/* * Square a number in REDC format producing a result also in REDC format. */voidzredcsquare(rp, z1, res)	REDC *rp;		/* REDC information */	ZVALUE z1;		/* REDC number to be squared */	ZVALUE *res;		/* resulting REDC number */{	ZVALUE tmp;	if (zisneg(z1))		math_error("Negative number in zredcsquare");	if (ziszero(z1)) {		*res = _zero_;		return;	}	if ((z1.len == rp->one.len) && (z1.v[0] == rp->one.v[0]) &&		(zcmp(z1, rp->one) == 0)) {			zcopy(z1, res);			return;	}	/*	 * If the modulus is small enough, then call the multiply	 * routine to produce the result.  Otherwise call the O(N^1.585)	 * routines to get the answer.	 */	if (rp->mod.len < _redc2_) {		zredcmul(rp, z1, z1, res);		return;	}	zsquare(z1, &tmp);	zredcdecode(rp, tmp, res);	zfree(tmp);}/* * Compute the result of raising a REDC format number to a power. * The result is within the range 0 to the modulus - 1. * 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. */voidzredcpower(rp, z1, z2, res)	REDC *rp;		/* REDC information */	ZVALUE z1;		/* REDC number to be raised */	ZVALUE z2;		/* normal number to raise number to */	ZVALUE *res;		/* result */{	HALF *hp;		/* pointer to current word of the power */	ZVALUE *pp;		/* pointer to low power table */	ZVALUE ans, temp;	/* calculation values */	ZVALUE modpow;		/* current small power */	ZVALUE lowpowers[POWNUMS];	/* low powers */	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(z1))		math_error("Negative number in zredcpower");	if (zisneg(z2))		math_error("Negative power in zredcpower");	/*	 * Check for zero or the REDC format for one.	 */	if (ziszero(z1) || zisunit(rp->mod)) {		*res = _zero_;		return;	}	if (zcmp(z1, rp->one) == 0) {		zcopy(rp->one, res);		return;	}	/*	 * See if the number being raised is the REDC format for -1.	 * If so, then the answer is the REDC format for one or minus one.	 * To do this check, calculate the REDC format for -1.	 */	if (((HALF)(z1.v[0] + rp->one.v[0])) == rp->mod.v[0]) {		zsub(rp->mod, rp->one, &temp);		if (zcmp(z1, temp) == 0) {			if (zisodd(z2)) {				*res = temp;				return;			}			zfree(temp);			zcopy(rp->one, res);			return;		}		zfree(temp);	}	for (pp = &lowpowers[2]; pp < &lowpowers[POWNUMS]; pp++)		pp->len = 0;	zcopy(rp->one, &lowpowers[0]);	zcopy(z1, &lowpowers[1]);	zcopy(rp->one, &ans);	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				zcopy(rp->one, &modpow);			for (curbit = 0x2; curbit <= curpow; curbit *= 2) {				pp = &lowpowers[curbit];				if (pp->len == 0)					zredcsquare(rp, lowpowers[curbit/2],						pp);				if (curbit & curpow) {					zredcmul(rp, *pp, modpow, &temp);					zfree(modpow);					modpow = temp;				}			}			pp = &lowpowers[curpow];			*pp = modpow;		}		/*		 * If the power is nonzero, then accumulate the small power		 * into the result.		 */		if (curpow) {			zredcmul(rp, ans, *pp, &temp);			zfree(ans);			ans = 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++) {			zredcsquare(rp, ans, &temp);			zfree(ans);			ans = temp;		}	}	for (pp = lowpowers; pp < &lowpowers[POWNUMS]; pp++) {		if (pp->len)			freeh(pp->v);	}	*res = ans;}/* END CODE */

⌨️ 快捷键说明

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