zmod.c

来自「Calc Software Package for Number Calc」· C语言 代码 · 共 2,164 行 · 第 1/4 页

C
2,164
字号
		carry.ivalue += (FULL) topdigit;		hd[-1] = carry.silow;		topdigit = carry.sihigh;	}	if (topdigit == 0) {		len = modlen;		while (*--hd == 0 && len > 1) {			len--;		}		res->len = len;		if  (zrel(*res, rp->mod) < 0) {			if (ztmp.len)				zfree(ztmp);			return;		}	}	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++ = (HALF)(BASE1 - carry.silow);		carry.silow = carry.sihigh;	}	len = modlen;	hd = &res->v[len - 1];	while ((*hd == 0) && (len > 1)) {		hd--;		len--;	}	res->len = len;	if (ztmp.len)		zfree(ztmp);}/* * 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. * * given: *	rp		REDC information *	z1		REDC number to be raised *	z2		normal number to raise number to *	res		result */voidzredcpower(REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res){	HALF *hp;		/* pointer to current word of the power */	ZVALUE *pp;		/* pointer to low power table */	ZVALUE ans, temp;	/* calculation values */	ZVALUE ztmp;	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 sign;	int i;	if (zisneg(z2)) {		math_error("Negative power in zredcpower");		/*NOTREACHED*/	}	if (zisunit(rp->mod)) {		*res = _zero_;		return;	}	sign = zisodd(z2) ? z1.sign : 0;	z1.sign = 0;	ztmp.len = 0;	if (zrel(z1, rp->mod) >= 0) {		zmod(z1, rp->mod, &ztmp, 0);		z1 = ztmp;	}	/*	 * Check for zero or the REDC format for one.	 */	if (ziszero(z1)) {		if (ziszero(z2))			*res = _one_;		else			*res = _zero_;		if (ztmp.len)			zfree(ztmp);		return;	}	if (zcmp(z1, rp->one) == 0) {		if (sign)			zsub(rp->mod, rp->one, res);		else			zcopy(rp->one, res);		if (ztmp.len)			zfree(ztmp);		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) ^ sign) {				*res = temp;				if (ztmp.len)					zfree(ztmp);				return;			}			zfree(temp);			zcopy(rp->one, res);			if (ztmp.len)				zfree(ztmp);			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];			if (pp->len > 0) {				zfree(*pp);			}			*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);	}	if (sign && !ziszero(ans)) {		zsub(rp->mod, ans, res);		zfree(ans);	} else {		*res = ans;	}	if (ztmp.len)		zfree(ztmp);}/* * zhnrmod - compute z mod h*2^n+r * * We compute v mod h*2^n+r, where h>0, n>0, abs(r) <= 1, as follows: * *	Let v = b*2^n + a, where 0 <= a < 2^n * *	Now v mod h*2^n+r == b*2^n + a mod h*2^n+r, *	and thus v mod h*2^n+r == b*2^n mod h*2^n+r + a mod h*2^n+r. * *	Because 0 <= a < 2^n < h*2^n+r, a mod h*2^n+r == a. *	Thus v mod h*2^n+r == b*2^n mod h*2^n+r + a. * *	It can be shown that b*2^n mod h*2^n == 2^n * (b mod h). * *	Thus for r == 0, v mod h*2^n+r == (2^n)*(b mod h) + a. * *	It can be shown that v mod 2^n-1 == a+b mod 2^n-1. * *	Thus for r == -1, v mod h*2^n+r == (2^n)*(b mod h) + a + int(b/h). * *	It can be shown that v mod 2^n+1 == a-b mod 2^n+1. * *	Thus for r == +1, v mod h*2^n+r == (2^n)*(b mod h) + a - int(b/h). * *	Therefore, v mod h*2^n+r == (2^n)*(b mod h) + a - r*int(b/h). * * The above proof leads to the following calc resource file which computes * the value z mod h*2^n+r: * *    define hnrmod(v,h,n,r) *    { *	local a,b,modulus,tquo,tmod,lbit,ret; * *	if (!isint(h) || h < 1) { *	    quit "h must be an integer be > 0"; *	} *	if (!isint(n) || n < 1) { *	    quit "n must be an integer be > 0"; *	} *	if (r != 1 && r != 0 && r != -1) { *	    quit "r must be -1, 0 or 1"; *	} * *	lbit = lowbit(h); *	if (lbit > 0) { *	    n += lbit; *	    h >>= lbit; *	} * *	modulus = h<<n+r; *	if (modulus <= 2^31-1) { *	    return v % modulus; *	} *	ret = v; * *	do { *	    if (highbit(ret) < n) { *		break; *	    } *	    b = ret>>n; *	    a = ret - (b<<n); * *	    switch (r) { *	    case -1: *		if (h == 1) { *		    ret = a + b; *		} else { *		    quomod(b, h, tquo, tmod); *		    ret = tmod<<n + a + tquo; *		} *		break; *	    case 0: *		if (h == 1) { *		    ret = a; *		} else { *		    ret = (b%h)<<n + a; *		} *		break; *	    case 1: *		if (h == 1) { *		    ret = ((a > b) ? a-b : modulus+a-b); *		} else { *		    quomod(b, h, tquo, tmod); *		    tmod = tmod<<n + a; *		    ret = ((tmod >= tquo) ? tmod-tquo : modulus+tmod-tquo); *		} *		break; *	    } *	} while (ret > modulus); *	ret = ((ret < 0) ? ret+modlus : ((ret == modulus) ? 0 : ret)); * *	return ret; *    } * * This function implements the above calc resource file. * * given: *	v		take mod of this value, v >= 0 *	zh		h from modulus h*2^n+r, h > 0 *	zn		n from modulus h*2^n+r, n > 0 *	zr		r from modulus h*2^n+r, abs(r) <= 1 *	res		v mod h*2^n+r */voidzhnrmod(ZVALUE v, ZVALUE zh, ZVALUE zn, ZVALUE zr, ZVALUE *res){	ZVALUE a;		/* lower n bits of v */	ZVALUE b;		/* bits above the lower n bits of v */	ZVALUE h;		/* working zh value */	ZVALUE modulus;		/* h^2^n + r */	ZVALUE tquo;		/* b // h */	ZVALUE tmod;		/* b % h or (b%h)<<n + a */	ZVALUE t;		/* temp ZVALUE */	ZVALUE t2;		/* temp ZVALUE */	ZVALUE ret;		/* return value, what *res is set to */	long n;			/* integer value of zn */	long r;			/* integer value of zr */	long hbit;		/* highbit(res) */	long lbit;		/* lowbit(h) */	int zrelval;		/* return value of zrel() */	int hisone;		/* 1 => h == 1, 0 => h != 1 */	/*	 * firewall	 */	if (zisneg(zh) || ziszero(zh)) {		math_error("h must be > 0");		/*NOTREACHED*/	}	if (zisneg(zn) || ziszero(zn)) {		math_error("n must be > 0");		/*NOTREACHED*/	}	if (zge31b(zn)) {		math_error("n must be < 2^31");		/*NOTREACHED*/	}	if (!zisabsleone(zr)) {		math_error("r must be -1, 0 or 1");		/*NOTREACHED*/	}	/*	 * setup for loop	 */	n = ztolong(zn);	r = ztolong(zr);	if (zisneg(zr)) {		r = -r;	}	/* lbit = lowbit(h); */	lbit = zlowbit(zh);	/* if (lbit > 0) { n += lbit; h >>= lbit; } */	if (lbit > 0) {		n += lbit;		zshift(zh, -lbit, &h);	} else {		h = zh;	}	/* modulus = h<<n+r; */	zshift(h, n, &t);	switch (r) {	case 1:		zadd(t, _one_, &modulus);		zfree(t);		break;	case 0:		modulus = t;		break;	case -1:		zsub(t, _one_, &modulus);		zfree(t);		break;	}	/* if (modulus <= MAXLONG) { return v % modulus; } */	if (!zgtmaxlong(modulus)) {		itoz(zmodi(v, ztolong(modulus)), res);		zfree(modulus);		if (lbit > 0) {			zfree(h);		}		return;	}	/* ret = v; */	zcopy(v, &ret);	/*	 * shift-add modulus loop	 */	hisone = zisone(h);	do {		/*		 * split ret into to chunks, the lower n bits		 * and everything above the lower n bits		 */		/* if (highbit(ret) < n) { break; } */		hbit = (long)zhighbit(ret);		if (hbit < n) {			zrelval = (zcmp(ret, modulus) ? -1 : 0);			break;		}		/* b = ret>>n; */		zshift(ret, -n, &b);		b.sign = ret.sign;		/* a = ret - (b<<n); */		a.sign = ret.sign;		a.len = (n+BASEB-1)/BASEB;		a.v = alloc(a.len);		memcpy(a.v, ret.v, a.len*sizeof(HALF));		if (n % BASEB) {			a.v[a.len - 1] &= lowhalf[n % BASEB];		}		ztrim(&a);		/*		 * switch depending on r == -1, 0 or 1		 */		switch (r) {		case -1:	/* v mod h*2^h-1 */			/* if (h == 1) ... */			if (hisone) {				/* ret = a + b; */				zfree(ret);				zadd(a, b, &ret);			/* ... else ... */			} else {				/* quomod(b, h, tquo, tmod); */				(void) zdiv(b, h, &tquo, &tmod, 0);				/* ret = tmod<<n + a + tquo; */				zshift(tmod, n, &t);				zfree(tmod);				zadd(a, tquo, &t2);				zfree(tquo);				zfree(ret);				zadd(t, t2, &ret);				zfree(t);				zfree(t2);			}			break;		case 0:		/* v mod h*2^h-1 */			/* if (h == 1) ... */			if (hisone) {				/* ret = a; */				zfree(ret);				zcopy(a, &ret);			/* ... else ... */			} else {				/* ret = (b%h)<<n + a; */				(void) zmod(b, h, &tmod, 0);				zshift(tmod, n, &t);				zfree(tmod);				zfree(ret);				zadd(t, a, &ret);				zfree(t);			}			break;		case 1:		/* v mod h*2^h-1 */			/* if (h == 1) ... */			if (hisone) {				/* ret = a-b; */				zfree(ret);				zsub(a, b, &ret);			/* ... else ... */			} else {				/* quomod(b, h, tquo, tmod); */				(void) zdiv(b, h, &tquo, &tmod, 0);				/* tmod = tmod<<n + a; */				zshift(tmod, n, &t);				zfree(tmod);				zadd(t, a, &tmod);				zfree(t);				/* ret = tmod-tquo; */				zfree(ret);				zsub(tmod, tquo, &ret);				zfree(tquo);				zfree(tmod);			}			break;		}		zfree(a);		zfree(b);	/* ... while (abs(ret) > modulus); */	} while ((zrelval = zabsrel(ret, modulus)) > 0);	/* ret = ((ret < 0) ? ret+modlus : ((ret == modulus) ? 0 : ret)); */	if (ret.sign) {		zadd(ret, modulus, &t);		zfree(ret);		ret = t;	} else if (zrelval == 0) {		zfree(ret);		ret = _zero_;	}	zfree(modulus);	if (lbit > 0) {		zfree(h);	}	/*	 * return ret	 */	*res = ret;	return;}

⌨️ 快捷键说明

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