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

📄 zmath.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
		zsub(z2, ztmp1, rem);		zfree(ztmp1);	} else		*rem = ztmp1;}/* * Calculate the mod of an integer by a small number. * This is only defined for positive moduli. */longzmodi(z, n)	ZVALUE z;	long n;{	register HALF *h1;	FULL val;	HALF divval[2];	ZVALUE div;	ZVALUE temp;	long len;	if (n == 0)		math_error("Division by zero");	if (n < 0)		math_error("Non-positive modulus");	if (ziszero(z) || (n == 1))		return 0;	if (zisone(z))		return 1;	/*	 * If the modulus is by a large number, then call the normal	 * modulo routine.	 */	if (n & ~BASE1) {		div.sign = 0;		div.len = 2;		div.v = divval;		divval[0] = (HALF) n;		divval[1] = ((FULL) n) >> BASEB;		zmod(z, div, &temp);		n = (zistiny(temp) ? z1tol(temp) : z2tol(temp));		zfree(temp);		return n;	}	/*	 * The modulus is by a small number, so we can do this quickly.	 */	len = z.len;	h1 = z.v + len - 1;	val = 0;	while (len--)		val = ((val << BASEB) + ((FULL) *h1--)) % n;	if (z.sign)		val = n - val;	return val;}/* * Return whether or not one number exactly divides another one. * Returns TRUE if division occurs with no remainder. * z1 is the number to be divided by z2. */BOOLzdivides(z1, z2)	ZVALUE z1, z2;		/* numbers to test division into and by */{	ZVALUE temp;	long cv;	z1.sign = 0;	z2.sign = 0;	/*	 * Take care of obvious cases first	 */	if (zisleone(z2)) {	/* division by zero or one */		if (*z2.v == 0)			math_error("Division by zero");		return TRUE;	}	if (ziszero(z1))	/* everything divides zero */		return TRUE;	if (z1.len < z2.len)	/* quick size comparison */		return FALSE;	if ((z1.len == z2.len) && (z1.v[z1.len-1] < z2.v[z2.len-1]))	/* more */		return FALSE;	if (zisodd(z1) && ziseven(z2))	/* can't divide odd by even */		return FALSE;	if (zlowbit(z1) < zlowbit(z2))	/* can't have smaller power of two */		return FALSE;	cv = zrel(z1, z2);	/* can't divide smaller number */	if (cv <= 0)		return (cv == 0);	/*	 * Now do the real work.  Divisor divides dividend if the gcd of the	 * two numbers equals the divisor.	 */	zgcd(z1, z2, &temp);	cv = zcmp(z2, temp);	zfree(temp);	return (cv == 0);}/* * Compute the logical OR of two numbers */voidzor(z1, z2, res)	ZVALUE z1, z2, *res;{	register HALF *sp, *dp;	long len;	ZVALUE bz, lz, dest;	if (z1.len >= z2.len) {		bz = z1;		lz = z2;	} else {		bz = z2;		lz = z1;	}	dest.len = bz.len;	dest.v = alloc(dest.len);	dest.sign = 0;	zcopyval(bz, dest);	len = lz.len;	sp = lz.v;	dp = dest.v;	while (len--)		*dp++ |= *sp++;	*res = dest;}/* * Compute the logical AND of two numbers. */voidzand(z1, z2, res)	ZVALUE z1, z2, *res;{	register HALF *h1, *h2, *hd;	register long len;	ZVALUE dest;	len = ((z1.len <= z2.len) ? z1.len : z2.len);	h1 = &z1.v[len-1];	h2 = &z2.v[len-1];	while ((len > 1) && ((*h1 & *h2) == 0)) {		h1--;		h2--;		len--;	}	dest.len = len;	dest.v = alloc(len);	dest.sign = 0;	h1 = z1.v;	h2 = z2.v;	hd = dest.v;	while (len--)		*hd++ = (*h1++ & *h2++);	*res = dest;}/* * Compute the logical XOR of two numbers. */voidzxor(z1, z2, res)	ZVALUE z1, z2, *res;{	register HALF *sp, *dp;	long len;	ZVALUE bz, lz, dest;	if (z1.len == z2.len) {		for (len = z1.len; ((len > 1) && (z1.v[len-1] == z2.v[len-1])); len--) ;		z1.len = len;		z2.len = len;	}	if (z1.len >= z2.len) {		bz = z1;		lz = z2;	} else {		bz = z2;		lz = z1;	}	dest.len = bz.len;	dest.v = alloc(dest.len);	dest.sign = 0;	zcopyval(bz, dest);	len = lz.len;	sp = lz.v;	dp = dest.v;	while (len--)		*dp++ ^= *sp++;	*res = dest;}/* * Shift a number left (or right) by the specified number of bits. * Positive shift means to the left.  When shifting right, rightmost * bits are lost.  The sign of the number is preserved. */voidzshift(z, n, res)	ZVALUE z, *res;	long n;{	ZVALUE ans;	long hc;		/* number of halfwords shift is by */	if (ziszero(z)) {		*res = _zero_;		return;	}	if (n == 0) {		zcopy(z, res);		return;	}	/*	 * If shift value is negative, then shift right.	 * Check for large shifts, and handle word-sized shifts quickly.	 */	if (n < 0) {		n = -n;		if ((n < 0) || (n >= (z.len * BASEB))) {			*res = _zero_;			return;		}		hc = n / BASEB;		n %= BASEB;		z.v += hc;		z.len -= hc;		ans.len = z.len;		ans.v = alloc(ans.len);		ans.sign = z.sign;		zcopyval(z, ans);		if (n > 0) {			zshiftr(ans, n);			ztrim(&ans);		}		if (ziszero(ans)) {			zfree(ans);			ans = _zero_;		}		*res = ans;		return;	}	/*	 * Shift value is positive, so shift leftwards.	 * Check specially for a shift of the value 1, since this is common.	 * Also handle word-sized shifts quickly.	 */	if (zisunit(z)) {		zbitvalue(n, res);		res->sign = z.sign;		return;	}	hc = n / BASEB;	n %= BASEB;	ans.len = z.len + hc + 1;	ans.v = alloc(ans.len);	ans.sign = z.sign;	if (hc > 0)		memset((char *) ans.v, 0, hc * sizeof(HALF));	memcpy((char *) (ans.v + hc), 	    (char *) z.v, z.len * sizeof(HALF));	ans.v[ans.len - 1] = 0;	if (n > 0) {		ans.v += hc;		ans.len -= hc;		zshiftl(ans, n);		ans.v -= hc;		ans.len += hc;	}	ztrim(&ans);	*res = ans;}/* * Return the position of the lowest bit which is set in the binary * representation of a number (counting from zero).  This is the highest * power of two which evenly divides the number. */longzlowbit(z)	ZVALUE z;{	register HALF *zp;	long n;	HALF dataval;	HALF *bitval;	n = 0;	for (zp = z.v; *zp == 0; zp++)		if (++n >= z.len)			return 0;	dataval = *zp;	bitval = bitmask;	while ((*(bitval++) & dataval) == 0) {	}	return (n*BASEB)+(bitval-bitmask-1);}/* * Return the position of the highest bit which is set in the binary * representation of a number (counting from zero).  This is the highest power * of two which is less than or equal to the number (which is assumed nonzero). */longzhighbit(z)	ZVALUE z;{	HALF dataval;	HALF *bitval;	dataval = z.v[z.len-1];	bitval = bitmask+BASEB;	if (dataval) {		while ((*(--bitval) & dataval) == 0) {		}	}	return (z.len*BASEB)+(bitval-bitmask-BASEB);}#if 0/* * Reverse the bits of a particular range of bits of a number. * * This function returns an integer with bits a thru b swapped. * That is, bit a is swapped with bit b, bit a+1 is swapped with b-1, * and so on. * * As a special case, if the ending bit position is < 0, is it taken to  * mean the highest bit set.  Thus zbitrev(0, -1, z, &res) will  * perform a complete bit reverse of the number 'z'. * * As a special case, if the starting bit position is < 0, is it taken to  * mean the lowest bit set.  Thus zbitrev(-1, -1, z, &res) is the * same as zbitrev(lowbit(z), highbit(z), z, &res). * * Note that the low order bit number is taken to be 0.  Also, bitrev * ignores the sign of the number. * * Bits beyond the highest bit are taken to be zero.  Thus the calling * bitrev(0, 100, _one_, &res) will result in a value of 2^100. */voidzbitrev(low, high, z, res)	long low;	/* lowest bit to reverse, <0 => lowbit(z) */	long high;	/* highest bit to reverse, <0 => highbit(z) */	ZVALUE z;	/* value to bit reverse */	ZVALUE *res;	/* resulting bit reverse number */{}#endif/* * Return whether or not the specifed bit number is set in a number. * Rightmost bit of a number is bit 0. */BOOLzisset(z, n)	ZVALUE z;	long n;{	if ((n < 0) || ((n / BASEB) >= z.len))		return FALSE;	return ((z.v[n / BASEB] & (((HALF) 1) << (n % BASEB))) != 0);}/* * Check whether or not a number has exactly one bit set, and * thus is an exact power of two.  Returns TRUE if so. */BOOLzisonebit(z)	ZVALUE z;{	register HALF *hp;	register LEN len;	if (ziszero(z) || zisneg(z))		return FALSE;	hp = z.v;	len = z.len;	while (len > 4) {		len -= 4;		if (*hp++ || *hp++ || *hp++ || *hp++)			return FALSE;	}	while (--len > 0) {		if (*hp++)			return FALSE;	}	return ((*hp & -*hp) == *hp);		/* NEEDS 2'S COMPLEMENT */}/* * Check whether or not a number has all of its bits set below some * bit position, and thus is one less than an exact power of two. * Returns TRUE if so. */BOOLzisallbits(z)	ZVALUE z;{	register HALF *hp;	register LEN len;	HALF digit;	if (ziszero(z) || zisneg(z))		return FALSE;	hp = z.v;	len = z.len;	while (len > 4) {		len -= 4;		if ((*hp++ != BASE1) || (*hp++ != BASE1) ||			(*hp++ != BASE1) || (*hp++ != BASE1))				return FALSE;	}	while (--len > 0) {		if (*hp++ != BASE1)			return FALSE;	}	digit = (HALF)(*hp + 1);	return ((digit & -digit) == digit);	/* NEEDS 2'S COMPLEMENT */}/* * Return the number whose binary representation contains only one bit which * is in the specified position (counting from zero).  This is equivilant * to raising two to the given power. */voidzbitvalue(n, res)	long n;	ZVALUE *res;{	ZVALUE z;	if (n < 0) n = 0;	z.sign = 0;	z.len = (n / BASEB) + 1;	z.v = alloc(z.len);	zclearval(z);	z.v[z.len-1] = (((HALF) 1) << (n % BASEB));	*res = z;}/* * Compare a number against zero. * Returns the sgn function of the number (-1, 0, or 1). */FLAGztest(z)	ZVALUE z;{	register int sign;	register HALF *h;	register long len;	sign = 1;	if (z.sign)		sign = -sign;	h = z.v;	len = z.len;	while (len--)		if (*h++)			return sign;	return 0;}/* * Compare two numbers to see which is larger. * Returns -1 if first number is smaller, 0 if they are equal, and 1 if * first number is larger.  This is the same result as ztest(z2-z1). */FLAGzrel(z1, z2)	ZVALUE z1, z2;{	register HALF *h1, *h2;	register long len1, len2;	int sign;	sign = 1;	if (z1.sign < z2.sign)		return 1;	if (z2.sign < z1.sign)		return -1;	if (z2.sign)		sign = -1;	len1 = z1.len;	len2 = z2.len;	h1 = z1.v + z1.len - 1;	h2 = z2.v + z2.len - 1;	while (len1 > len2) {		if (*h1--)			return sign;		len1--;	}	while (len2 > len1) {		if (*h2--)			return -sign;		len2--;	}	while (len1--) {		if (*h1-- != *h2--)			break;	}	if ((len1 = *++h1) > (len2 = *++h2))		return sign;	if (len1 < len2)		return -sign;	return 0;}/* * Compare two numbers to see if they are equal or not. * Returns TRUE if they differ. */BOOLzcmp(z1, z2)	ZVALUE z1, z2;{	register HALF *h1, *h2;	register long len;	if ((z1.sign != z2.sign) || (z1.len != z2.len) || (*z1.v != *z2.v))		return TRUE;	len = z1.len;	h1 = z1.v;	h2 = z2.v;	while (len-- > 0) {		if (*h1++ != *h2++)			return TRUE;	}	return FALSE;}/* * Internal utility subroutines */static voiddadd(z1, z2, y, n)	ZVALUE z1, z2;	long y, n;{	HALF *s1, *s2;	short carry;	long sum;	s1 = z1.v + y - n;	s2 = z2.v;	carry = 0;	while (n--) {		sum = (long)*s1 + (long)*s2 + carry;		carry = 0;		if (sum >= BASE) {			sum -= BASE;			carry = 1;		}		*s1 = (HALF)sum;		++s1;		++s2;	}	sum = (long)*s1 + carry;	*s1 = (HALF)sum;}/* * Do subtract for divide, returning TRUE if subtraction went negative. */static BOOLdsub(z1, z2, y, n)	ZVALUE z1, z2;	long y, n;{	HALF *s1, *s2, *s3;	FULL i1;	BOOL neg;	neg = FALSE;	s1 = z1.v + y - n;	s2 = z2.v;	if (++n > z2.len)		n = z2.len;	while (n--) {		i1 = (FULL) *s1;		if (i1 < (FULL) *s2) {			s3 = s1 + 1;			while (s3 < z1.v + z1.len && !(*s3)) {				*s3 = BASE1;				++s3;			}			if (s3 >= z1.v + z1.len)				neg = TRUE;			else				--(*s3);			i1 += BASE;		}		*s1 = i1 - (FULL) *s2;		++s1;		++s2;	}	return neg;}/* * Multiply a number by a single 'digit'. * This is meant to be used only by the divide routine, and so the * destination area must already be allocated and be large enough. */static voiddmul(z, mul, dest)	ZVALUE z;	FULL mul;	ZVALUE *dest;{	register HALF *zp, *dp;	SIUNION sival;	FULL carry;	long len;	dp = dest->v;	dest->sign = 0;	if (mul == 0) {		dest->len = 1;		*dp = 0;		return;	}	len = z.len;	zp = z.v + len - 1;	while ((*zp == 0) && (len > 1)) {		len--;		zp--;	}	dest->len = len;	zp = z.v;	carry = 0;	while (len >= 4) {		len -= 4;		sival.ivalue = (mul * ((FULL) *zp++)) + carry;		*dp++ = sival.silow;		sival.ivalue = (mul * ((FULL) *zp++)) + ((FULL) sival.sihigh);		*dp++ = sival.silow;		sival.ivalue = (mul * ((FULL) *zp++)) + ((FULL) sival.sihigh);		*dp++ = sival.silow;		sival.ivalue = (mul * ((FULL) *zp++)) + ((FULL) sival.sihigh);		*dp++ = sival.silow;		carry = sival.sihigh;	}	while (--len >= 0) {		sival.ivalue = (mul * ((FULL) *zp++)) + carry;		*dp++ = sival.silow;		carry = sival.sihigh;	}	if (carry) {		*dp = (HALF)carry;		dest->len++;	}}/* * Utility to calculate the gcd of two small integers. */longiigcd(i1, i2)	long i1, i2;{	FULL f1, f2, temp;	f1 = (FULL) ((i1 >= 0) ? i1 : -i1);	f2 = (FULL) ((i2 >= 0) ? i2 : -i2);	while (f1) {		temp = f2 % f1;		f2 = f1;		f1 = temp;	}	return (long) f2;}voidztrim(z)	ZVALUE *z;{	register HALF *h;	register long len;	h = z->v + z->len - 1;	len = z->len;	while (*h == 0 && len > 1) {		--h;		--len;	}	z->len = len;}/* * Utility routine to shift right. */voidzshiftr(z, n)	ZVALUE z;	long n;{	register HALF *h, *lim;	FULL mask, maskt;	long len;	if (n >= BASEB) {		len = n / BASEB;		h = z.v;		lim = z.v + z.len - len;		while (h < lim) {			h[0] = h[len];			++h;		}		n -= BASEB * len;		lim = z.v + z.len;		while (h < lim)			*h++ = 0;	}	if (n) {		len = z.len;		h = z.v + len - 1;		mask = 0;		while (len--) {			maskt = (((FULL) *h) << (BASEB - n)) & BASE1;			*h = (*h >> n) | mask;			mask = maskt;			--h;		}	}}/* * Utility routine to shift left. */voidzshiftl(z, n)	ZVALUE z;	long n;{	register HALF *h;	FULL mask, i;	long len;	if (n >= BASEB) {		len = n / BASEB;		h = z.v + z.len - 1;		while (!*h)			--h;		while (h >= z.v) {			h[len] = h[0];			--h;		}		n -= BASEB * len;		while (len)			h[len--] = 0;	}	if (n > 0) {		len = z.len;		h = z.v;		mask = 0;		while (len--) {			i = (((FULL) *h) << n) | mask;			if (i > BASE1) {				mask = i >> BASEB;				i &= BASE1;			} else				mask = 0;			*h = (HALF) i;			++h;		}	}}/* * initmasks - init the bitmask rotation arrays * * bitmask[i] 	 (1 << (i-1)),  for  -BASEB*4<=i<=BASEB*4 * * The bmask array contains 8 cycles of rotations of a bit mask. */voidinitmasks(){	int i;	/*	 * setup the bmask array	 */	bmask = alloc((long)((8*BASEB)+1));	for (i=0; i < (8*BASEB)+1; ++i) {		bmask[i] = 1 << (i%BASEB);	}	/*	 * setup the rmask pointers	 */	rmask = (HALF **)malloc(sizeof(HALF *)*((BASEB*4)+2));	for (i = 0; i <= (4*BASEB)+1; ++i) {		rmask[i] = &bmask[(2*BASEB)+i];	}	/*	 * setup the bitmask array to allow -4*BASEB thru 4*BASEB indexing	 */	bitmask = &bmask[4*BASEB];	return;}/* END CODE */

⌨️ 快捷键说明

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