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

📄 zmul.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 2 页
字号:
		*h1++ = sival.silow;		*h2++ = sival.silow;		carryACBD = sival.sihigh;	}	/*	 * Now add in the bottom half of B*D and the top half of A*C.	 * These additions are straightforward, except that A*C should	 * be done first because of possible carries from B*D, and the	 * top half of A*C might not exist.  Add in one of the carries	 * from the previous addition while we are at it.	 */	h1 = baseAC + shift;	hd = baseAC;	carry = carryACBD;	len = sizetotal - 3 * shift;	while (len--) {		sival.ivalue = ((FULL) *h1++) + ((FULL) *hd) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	while (carry) {		sival.ivalue = ((FULL) *hd) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	h1 = baseBD;	hd = baseBD + shift;	carry = 0;	len = shift;	while (len--) {		sival.ivalue = ((FULL) *h1++) + ((FULL) *hd) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	while (carry) {		sival.ivalue = ((FULL) *hd) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	/*	 * Now finally add in the other delayed carry from the	 * above addition.	 */	hd = baseAC + shift;	while (carryACBD) {		sival.ivalue = ((FULL) *hd) + carryACBD;		*hd++ = sival.silow;		carryACBD = sival.sihigh;	}	/*	 * Now finally add or subtract (A-B)*(D-C) into the final result at	 * the correct position (S), according to whether it is positive or	 * negative.  When subtracting, the answer cannot go negative.	 */	h1 = baseABDC;	hd = ans + shift;	carry = 0;	len = sizeABDC;	if (neg) {		while (len--) {			sival.ivalue = BASE1 - ((FULL) *hd) +				((FULL) *h1++) + carry;			*hd++ = (HALF)(BASE1 - sival.silow);			carry = sival.sihigh;		}		while (carry) {			sival.ivalue = BASE1 - ((FULL) *hd) + carry;			*hd++ = (HALF)(BASE1 - sival.silow);			carry = sival.sihigh;		}	} else {		while (len--) {			sival.ivalue = ((FULL) *h1++) + ((FULL) *hd) + carry;			*hd++ = sival.silow;			carry = sival.sihigh;		}		while (carry) {			sival.ivalue = ((FULL) *hd) + carry;			*hd++ = sival.silow;			carry = sival.sihigh;		}	}	/*	 * Finally determine the size of the final result and return that.	 */	len = sizetotal;	hd = &ans[len - 1];	while ((*hd == 0) && (len > 1)) {		hd--;		len--;	}	tempbuf = temp;	return len;}/* * Square a number by using the following formula recursively: *	(A*S+B)^2 = (S^2+S)*A^2 + (S+1)*B^2 - S*(A-B)^2 * where S is a power of 2^16, and so multiplies by it are shifts, * and A and B are the left and right halfs of the number to square. */voidzsquare(ZVALUE z, ZVALUE *res){	LEN len;	if (ziszero(z)) {		*res = _zero_;		return;	}	if (zisunit(z)) {		*res = _one_;		return;	}	/*	 * Allocate a temporary array if necessary for the recursion to use.	 * The array needs to be allocated large enough for all of the	 * temporary results to fit in.	 This size is about 3 times the	 * size of the original number, since each recursion level uses 3/2	 * of the size of its given number, and whose size is 1/2 the size	 * of the previous level.  The sum of the infinite series is 3.	 * Allocate some extra words for rounding up the sizes.	 */	len = 3 * z.len + 32;	tempbuf = zalloctemp(len);	res->sign = 0;	res->v = alloc((z.len+2) * 2);	/*	 * Without the memset below, Purify reports that dosquare()	 *	 will read uninitialized memory at the dosquare() line below	 *	 the comment:	 *	 *		uninitialized memory read (see zsquare)	 *	 * This problem occurs during regression test #622 and may	 * be duplicated by executing:	 *	 *	config("sq2", 2);	 *	0xffff0000ffffffff00000000ffff0000000000000000ffff^2;	 */	memset((char *)res->v, 0, ((z.len+2) * 2)*sizeof(HALF));	res->len = dosquare(z.v, z.len, res->v);}/* * Recursive routine to square a number by splitting it up into two numbers * of half the size, and using the results of squaring the subpieces. * The result is placed in the indicated array, which must be large * enough for the result (size * 2).  Returns the size of the result. * This uses a temporary array which must be 3 times as large as the * size of the number at the top level recursive call. * * given: *	vp		value to be squared *	size		length of value to square *	ans		location for result */static LENdosquare(HALF *vp, LEN size, HALF *ans){	LEN shift;		/* amount numbers are shifted by */	LEN sizeA;		/* size of left half of number to square */	LEN sizeB;		/* size of right half of number to square */	LEN sizeAA;		/* size of square of left half */	LEN sizeBB;		/* size of square of right half */	LEN sizeAABB;		/* size of sum of squares of A and B */	LEN sizeAB;		/* size of difference of A and B */	LEN sizeABAB;		/* size of square of difference of A and B */	LEN subsize;		/* size of difference of halfs */	LEN copysize;		/* size of number left to copy */	LEN sumsize;		/* size of sum */	LEN sizetotal;		/* total size of square */	LEN len;		/* temporary length */	LEN len1;		/* another temporary length */	FULL carry;		/* carry digit for small multiplications */	FULL digit;		/* single digit multiplying by */	HALF *temp;		/* base for temporary calculations */	HALF *baseA;		/* base of left half of number */	HALF *baseB;		/* base of right half of number */	HALF *baseAA;		/* base of square of left half of number */	HALF *baseBB;		/* base of square of right half of number */	HALF *baseAABB;		/* base of sum of squares of A and B */	HALF *baseAB;		/* base of difference of A and B */	HALF *baseABAB;		/* base of square of difference of A and B */	register HALF *hd, *h1, *h2, *h3;	/* for inner loops */	SIUNION sival;		/* for addition of digits */	/*	 * First trim the number of leading zeroes.	 */	hd = &vp[size - 1];	while ((*hd == 0) && (size > 1)) {		size--;		hd--;	}	sizetotal = size + size;	/*	 * If the number has only a small number of digits, then use the	 * (almost) normal multiplication method.  Multiply each halfword	 * only by those halfwards further on in the number.  Missed terms	 * will then be the same pairs of products repeated, and the squares	 * of each halfword.  The first case is handled by doubling the	 * result.  The second case is handled explicitly.  The number of	 * digits where the algorithm changes is settable from 2 to maxint.	 */	if (size < conf->sq2) {		hd = ans;		len = sizetotal;		while (len--)			*hd++ = 0;		h2 = vp;		hd = ans + 1;		for (len = size; len--; hd += 2) {			digit = (FULL) *h2++;			if (digit == 0)				continue;			h3 = h2;			h1 = hd;			carry = 0;			len1 = len;			while (len1 >= 4) {	/* expand the loop some */				len1 -= 4;				sival.ivalue = (digit * ((FULL) *h3++))					+ ((FULL) *h1) + carry;				*h1++ = sival.silow;				sival.ivalue = (digit * ((FULL) *h3++))					+ ((FULL) *h1) + ((FULL) sival.sihigh);				*h1++ = sival.silow;				sival.ivalue = (digit * ((FULL) *h3++))					+ ((FULL) *h1) + ((FULL) sival.sihigh);				*h1++ = sival.silow;				sival.ivalue = (digit * ((FULL) *h3++))					+ ((FULL) *h1) + ((FULL) sival.sihigh);				*h1++ = sival.silow;				carry = sival.sihigh;			}			while (len1--) {				sival.ivalue = (digit * ((FULL) *h3++))					+ ((FULL) *h1) + carry;				*h1++ = sival.silow;				carry = sival.sihigh;			}			while (carry) {				sival.ivalue = ((FULL) *h1) + carry;				*h1++ = sival.silow;				carry = sival.sihigh;			}		}		/*		 * Now double the result.		 * There is no final carry to worry about because we		 * handle all digits of the result which must fit.		 */		carry = 0;		hd = ans;		len = sizetotal;		while (len--) {			digit = ((FULL) *hd);			sival.ivalue = digit + digit + carry;			/* ignore Saber-C warning #112 - get ushort from uint */			/*	  ok to ignore on name dosquare`sival */			*hd++ = sival.silow;			carry = sival.sihigh;		}		/*		 * Now add in the squares of each halfword.		 */		carry = 0;		hd = ans;		h3 = vp;		len = size;		while (len--) {			digit = ((FULL) *h3++);			sival.ivalue = digit * digit + ((FULL) *hd) + carry;			*hd++ = sival.silow;			carry = sival.sihigh;			sival.ivalue = ((FULL) *hd) + carry;			*hd++ = sival.silow;			carry = sival.sihigh;		}		while (carry) {			sival.ivalue = ((FULL) *hd) + carry;			*hd++ = sival.silow;			carry = sival.sihigh;		}		/*		 * Finally return the size of the result.		 */		len = sizetotal;		hd = &ans[len - 1];		while ((*hd == 0) && (len > 1)) {			len--;			hd--;		}		return len;	}	/*	 * The number to be squared is large.	 * Allocate temporary space and determine the sizes and	 * positions of the values to be calculated.	 */	temp = tempbuf;	tempbuf += (3 * (size + 1) / 2);	sizeA = size / 2;	sizeB = size - sizeA;	shift = sizeB;	baseA = vp + sizeB;	baseB = vp;	baseAA = &ans[shift * 2];	baseBB = ans;	baseAABB = temp;	baseAB = temp;	baseABAB = &temp[shift];	/*	 * Trim the second number of leading zeroes.	 */	hd = &baseB[sizeB - 1];	while ((*hd == 0) && (sizeB > 1)) {		sizeB--;		hd--;	}	/*	 * Now to proceed to calculate the result using the formula.	 *	(A*S+B)^2 = (S^2+S)*A^2 + (S+1)*B^2 - S*(A-B)^2.	 * The steps are done in the following order:	 *	S^2*A^2 + B^2	 *	A^2 + B^2	 *	(S^2+S)*A^2 + (S+1)*B^2	 *	(A-B)^2	 *	(S^2+S)*A^2 + (S+1)*B^2 - S*(A-B)^2.	 *	 * Begin by forming the squares of two the halfs concatenated	 * together in the final result location.  Make sure that the	 * highest words of the results are zero.	 */	sizeBB = dosquare(baseB, sizeB, baseBB);	hd = &baseBB[sizeBB];	len = shift * 2 - sizeBB;	while (len--)		*hd++ = 0;	sizeAA = dosquare(baseA, sizeA, baseAA);	hd = &baseAA[sizeAA];	len = sizetotal - shift * 2 - sizeAA;	while (len--)		*hd++ = 0;	/*	 * Sum the two squares into a temporary location.	 */	if (sizeAA >= sizeBB) {		h1 = baseAA;		h2 = baseBB;		sizeAABB = sizeAA;		sumsize = sizeBB;	} else {		h1 = baseBB;		h2 = baseAA;		sizeAABB = sizeBB;		sumsize = sizeAA;	}	copysize = sizeAABB - sumsize;	hd = baseAABB;	carry = 0;	while (sumsize--) {		sival.ivalue = ((FULL) *h1++) + ((FULL) *h2++) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	while (copysize--) {		sival.ivalue = ((FULL) *h1++) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	if (carry) {		*hd = (HALF)carry;		sizeAABB++;	}	/*	 * Add the sum back into the previously calculated squares	 * shifted over to the proper location.	 */	h1 = baseAABB;	hd = ans + shift;	carry = 0;	len = sizeAABB;	while (len--) {		sival.ivalue = ((FULL) *hd) + ((FULL) *h1++) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	while (carry) {		/* uninitialized memory read (see zsquare) */		sival.ivalue = ((FULL) *hd) + carry;		*hd++ = sival.silow;		carry = sival.sihigh;	}	/*	 * Calculate the absolute value of the difference of the two halfs	 * into a temporary location.	 */	if (sizeA == sizeB) {		len = sizeA;		h1 = &baseA[len - 1];		h2 = &baseB[len - 1];		while ((len > 1) && (*h1 == *h2)) {			len--;			h1--;			h2--;		}	}	if ((sizeA > sizeB) || ((sizeA == sizeB) && (*h1 > *h2))) {		h1 = baseA;		h2 = baseB;		sizeAB = sizeA;		subsize = sizeB;	} else {		h1 = baseB;		h2 = baseA;		sizeAB = sizeB;		subsize = sizeA;	}	copysize = sizeAB - subsize;	hd = baseAB;	carry = 0;	while (subsize--) {		sival.ivalue = BASE1 - ((FULL) *h1++) + ((FULL) *h2++) + carry;		*hd++ = (HALF)(BASE1 - sival.silow);		carry = sival.sihigh;	}	while (copysize--) {		sival.ivalue = (BASE1 - ((FULL) *h1++)) + carry;		*hd++ = (HALF)(BASE1 - sival.silow);		carry = sival.sihigh;	}	hd = &baseAB[sizeAB - 1];	while ((*hd == 0) && (sizeAB > 1)) {		sizeAB--;		hd--;	}	/*	 * Now square the number into another temporary location,	 * and subtract that from the final result.	 */	sizeABAB = dosquare(baseAB, sizeAB, baseABAB);	h1 = baseABAB;	hd = ans + shift;	carry = 0;	while (sizeABAB--) {		sival.ivalue = BASE1 - ((FULL) *hd) + ((FULL) *h1++) + carry;		*hd++ = (HALF)(BASE1 - sival.silow);		carry = sival.sihigh;	}	while (carry) {		sival.ivalue = BASE1 - ((FULL) *hd) + carry;		*hd++ = (HALF)(BASE1 - sival.silow);		carry = sival.sihigh;	}	/*	 * Return the size of the result.	 */	len = sizetotal;	hd = &ans[len - 1];	while ((*hd == 0) && (len > 1)) {		len--;		hd--;	}	tempbuf = temp;	return len;}/* * Return a pointer to a buffer to be used for holding a temporary number. * The buffer will be at least as large as the specified number of HALFs, * and remains valid until the next call to this routine.  The buffer cannot * be freed by the caller.  There is only one temporary buffer, and so as to * avoid possible conflicts this is only used by the lowest level routines * such as divide, multiply, and square. * * given: *	len		required number of HALFs in buffer */HALF *zalloctemp(LEN len){	HALF *hp;	static LEN buflen;	/* current length of temp buffer */	static HALF *bufptr;	/* pointer to current temp buffer */	if (len <= buflen)		return bufptr;	/*	 * We need to grow the temporary buffer.	 * First free any existing buffer, and then allocate the new one.	 * While we are at it, make the new buffer bigger than necessary	 * in order to reduce the number of reallocations.	 */	len += 100;	if (buflen) {		buflen = 0;		free(bufptr);	}	/* don't call alloc() because _math_abort_ may not be set right */	hp = (HALF *) malloc((len+1) * sizeof(HALF));	if (hp == NULL) {		math_error("No memory for temp buffer");		/*NOTREACHED*/	}	bufptr = hp;	buflen = len;	return hp;}

⌨️ 快捷键说明

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