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

📄 numeric.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
	i1 = res_rscale + var1->weight + 1;	i2 = res_rscale + var2->weight + 1;	for (i = res_ndigits - 1; i >= 0; i--)	{		i1--;		i2--;		if (i1 >= 0 && i1 < var1ndigits)			carry += var1digits[i1];		if (i2 >= 0 && i2 < var2ndigits)			carry += var2digits[i2];		if (carry >= 10)		{			res_digits[i] = carry - 10;			carry = 1;		}		else		{			res_digits[i] = carry;			carry = 0;		}	}	while (res_ndigits > 0 && *res_digits == 0)	{		res_digits++;		res_weight--;		res_ndigits--;	}	while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)		res_ndigits--;	if (res_ndigits == 0)		res_weight = 0;	digitbuf_free(result->buf);	result->ndigits = res_ndigits;	result->buf = res_buf;	result->digits = res_digits;	result->weight = res_weight;	result->rscale = res_rscale;	result->dscale = res_dscale;	return 0;}/* ---------- * sub_abs() - * *	Subtract the absolute value of var2 from the absolute value of var1 *	and store in result. result might point to one of the operands *	without danger. * *	ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!! * ---------- */static intsub_abs(numeric *var1, numeric *var2, numeric *result){	NumericDigit *res_buf;	NumericDigit *res_digits;	int			res_ndigits;	int			res_weight;	int			res_rscale;	int			res_dscale;	int			i,				i1,				i2;	int			borrow = 0;	/* copy these values into local vars for speed in inner loop */	int			var1ndigits = var1->ndigits;	int			var2ndigits = var2->ndigits;	NumericDigit *var1digits = var1->digits;	NumericDigit *var2digits = var2->digits;	res_weight = var1->weight;	res_rscale = Max(var1->rscale, var2->rscale);	res_dscale = Max(var1->dscale, var2->dscale);	res_ndigits = res_rscale + res_weight + 1;	if (res_ndigits <= 0)		res_ndigits = 1;	if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)		return -1;	res_digits = res_buf;	i1 = res_rscale + var1->weight + 1;	i2 = res_rscale + var2->weight + 1;	for (i = res_ndigits - 1; i >= 0; i--)	{		i1--;		i2--;		if (i1 >= 0 && i1 < var1ndigits)			borrow += var1digits[i1];		if (i2 >= 0 && i2 < var2ndigits)			borrow -= var2digits[i2];		if (borrow < 0)		{			res_digits[i] = borrow + 10;			borrow = -1;		}		else		{			res_digits[i] = borrow;			borrow = 0;		}	}	while (res_ndigits > 0 && *res_digits == 0)	{		res_digits++;		res_weight--;		res_ndigits--;	}	while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)		res_ndigits--;	if (res_ndigits == 0)		res_weight = 0;	digitbuf_free(result->buf);	result->ndigits = res_ndigits;	result->buf = res_buf;	result->digits = res_digits;	result->weight = res_weight;	result->rscale = res_rscale;	result->dscale = res_dscale;	return 0;}/* ---------- * add_var() - * *	Full version of add functionality on variable level (handling signs). *	result might point to one of the operands too without danger. * ---------- */intPGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result){	/*	 * Decide on the signs of the two variables what to do	 */	if (var1->sign == NUMERIC_POS)	{		if (var2->sign == NUMERIC_POS)		{			/*			 * Both are positive result = +(ABS(var1) + ABS(var2))			 */			if (add_abs(var1, var2, result) != 0)				return -1;			result->sign = NUMERIC_POS;		}		else		{			/*			 * var1 is positive, var2 is negative Must compare absolute values			 */			switch (cmp_abs(var1, var2))			{				case 0:					/* ----------					 * ABS(var1) == ABS(var2)					 * result = ZERO					 * ----------					 */					zero_var(result);					result->rscale = Max(var1->rscale, var2->rscale);					result->dscale = Max(var1->dscale, var2->dscale);					break;				case 1:					/* ----------					 * ABS(var1) > ABS(var2)					 * result = +(ABS(var1) - ABS(var2))					 * ----------					 */					if (sub_abs(var1, var2, result) != 0)						return -1;					result->sign = NUMERIC_POS;					break;				case -1:					/* ----------					 * ABS(var1) < ABS(var2)					 * result = -(ABS(var2) - ABS(var1))					 * ----------					 */					if (sub_abs(var2, var1, result) != 0)						return -1;					result->sign = NUMERIC_NEG;					break;			}		}	}	else	{		if (var2->sign == NUMERIC_POS)		{			/* ----------			 * var1 is negative, var2 is positive			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0:					/* ----------					 * ABS(var1) == ABS(var2)					 * result = ZERO					 * ----------					 */					zero_var(result);					result->rscale = Max(var1->rscale, var2->rscale);					result->dscale = Max(var1->dscale, var2->dscale);					break;				case 1:					/* ----------					 * ABS(var1) > ABS(var2)					 * result = -(ABS(var1) - ABS(var2))					 * ----------					 */					if (sub_abs(var1, var2, result) != 0)						return -1;					result->sign = NUMERIC_NEG;					break;				case -1:					/* ----------					 * ABS(var1) < ABS(var2)					 * result = +(ABS(var2) - ABS(var1))					 * ----------					 */					if (sub_abs(var2, var1, result) != 0)						return -1;					result->sign = NUMERIC_POS;					break;			}		}		else		{			/* ----------			 * Both are negative			 * result = -(ABS(var1) + ABS(var2))			 * ----------			 */			if (add_abs(var1, var2, result) != 0)				return -1;			result->sign = NUMERIC_NEG;		}	}	return 0;}/* ---------- * sub_var() - * *	Full version of sub functionality on variable level (handling signs). *	result might point to one of the operands too without danger. * ---------- */intPGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result){	/*	 * Decide on the signs of the two variables what to do	 */	if (var1->sign == NUMERIC_POS)	{		if (var2->sign == NUMERIC_NEG)		{			/* ----------			 * var1 is positive, var2 is negative			 * result = +(ABS(var1) + ABS(var2))			 * ----------			 */			if (add_abs(var1, var2, result) != 0)				return -1;			result->sign = NUMERIC_POS;		}		else		{			/* ----------			 * Both are positive			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0:					/* ----------					 * ABS(var1) == ABS(var2)					 * result = ZERO					 * ----------					 */					zero_var(result);					result->rscale = Max(var1->rscale, var2->rscale);					result->dscale = Max(var1->dscale, var2->dscale);					break;				case 1:					/* ----------					 * ABS(var1) > ABS(var2)					 * result = +(ABS(var1) - ABS(var2))					 * ----------					 */					if (sub_abs(var1, var2, result) != 0)						return -1;					result->sign = NUMERIC_POS;					break;				case -1:					/* ----------					 * ABS(var1) < ABS(var2)					 * result = -(ABS(var2) - ABS(var1))					 * ----------					 */					if (sub_abs(var2, var1, result) != 0)						return -1;					result->sign = NUMERIC_NEG;					break;			}		}	}	else	{		if (var2->sign == NUMERIC_NEG)		{			/* ----------			 * Both are negative			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0:					/* ----------					 * ABS(var1) == ABS(var2)					 * result = ZERO					 * ----------					 */					zero_var(result);					result->rscale = Max(var1->rscale, var2->rscale);					result->dscale = Max(var1->dscale, var2->dscale);					break;				case 1:					/* ----------					 * ABS(var1) > ABS(var2)					 * result = -(ABS(var1) - ABS(var2))					 * ----------					 */					if (sub_abs(var1, var2, result) != 0)						return -1;					result->sign = NUMERIC_NEG;					break;				case -1:					/* ----------					 * ABS(var1) < ABS(var2)					 * result = +(ABS(var2) - ABS(var1))					 * ----------					 */					if (sub_abs(var2, var1, result) != 0)						return -1;					result->sign = NUMERIC_POS;					break;			}		}		else		{			/* ----------			 * var1 is negative, var2 is positive			 * result = -(ABS(var1) + ABS(var2))			 * ----------			 */			if (add_abs(var1, var2, result) != 0)				return -1;			result->sign = NUMERIC_NEG;		}	}	return 0;}/* ---------- * mul_var() - * *	Multiplication on variable level. Product of var1 * var2 is stored *	in result.	Accuracy of result is determined by global_rscale. * ---------- */intPGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result){	NumericDigit *res_buf;	NumericDigit *res_digits;	int			res_ndigits;	int			res_weight;	int			res_sign;	int			i,				ri,				i1,				i2;	long		sum = 0;	int			global_rscale = var1->rscale + var2->rscale;	res_weight = var1->weight + var2->weight + 2;	res_ndigits = var1->ndigits + var2->ndigits + 1;	if (var1->sign == var2->sign)		res_sign = NUMERIC_POS;	else		res_sign = NUMERIC_NEG;	if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)		return -1;	res_digits = res_buf;	memset(res_digits, 0, res_ndigits);	ri = res_ndigits;	for (i1 = var1->ndigits - 1; i1 >= 0; i1--)	{		sum = 0;		i = --ri;		for (i2 = var2->ndigits - 1; i2 >= 0; i2--)		{			sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];			res_digits[i--] = sum % 10;			sum /= 10;		}		res_digits[i] = sum;	}	i = res_weight + global_rscale + 2;	if (i >= 0 && i < res_ndigits)	{		sum = (res_digits[i] > 4) ? 1 : 0;		res_ndigits = i;		i--;		while (sum)		{			sum += res_digits[i];			res_digits[i--] = sum % 10;			sum /= 10;		}	}	while (res_ndigits > 0 && *res_digits == 0)	{		res_digits++;		res_weight--;		res_ndigits--;	}	while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)		res_ndigits--;	if (res_ndigits == 0)	{		res_sign = NUMERIC_POS;		res_weight = 0;	}	digitbuf_free(result->buf);	result->buf = res_buf;	result->digits = res_digits;	result->ndigits = res_ndigits;	result->weight = res_weight;	result->rscale = global_rscale;	result->sign = res_sign;	result->dscale = var1->dscale + var2->dscale;	return 0;}/* * Default scale selection for division * * Returns the appropriate display scale for the division result, * and sets global_rscale to the result scale to use during div_var. * * Note that this must be called before div_var. */static intselect_div_scale(numeric *var1, numeric *var2, int *rscale){	int			weight1,				weight2,				qweight,				i;	NumericDigit firstdigit1,				firstdigit2;	int			res_dscale;	int			res_rscale;	/*	 * The result scale of a division isn't specified in any SQL standard. For	 * PostgreSQL we select a display scale that will give at least	 * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a	 * result no less accurate than float8; but use a scale not less than	 * either input's display scale.	 */	/* Get the actual (normalized) weight and first digit of each input */	weight1 = 0;				/* values to use if var1 is zero */	firstdigit1 = 0;	for (i = 0; i < var1->ndigits; i++)	{		firstdigit1 = var1->digits[i];		if (firstdigit1 != 0)		{			weight1 = var1->weight - i;			break;		}	}	weight2 = 0;				/* values to use if var2 is zero */	firstdigit2 = 0;	for (i = 0; i < var2->ndigits; i++)	{		firstdigit2 = var2->digits[i];		if (firstdigit2 != 0)		{			weight2 = var2->weight - i;			break;		}	}	/*	 * Estimate weight of quotient.  If the two first digits are equal, we	 * can't be sure, but assume that var1 is less than var2.	 */	qweight = weight1 - weight2;	if (firstdigit1 <= firstdigit2)		qweight--;

⌨️ 快捷键说明

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