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

📄 numeric.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* Select display scale */	res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;	res_dscale = Max(res_dscale, var1->dscale);	res_dscale = Max(res_dscale, var2->dscale);	res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);	res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);	/* Select result scale */	*rscale = res_rscale = res_dscale + 4;	return res_dscale;}intPGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result){	NumericDigit *res_digits;	int			res_ndigits;	int			res_sign;	int			res_weight;	numeric		dividend;	numeric		divisor[10];	int			ndigits_tmp;	int			weight_tmp;	int			rscale_tmp;	int			ri;	int			i;	long		guess;	long		first_have;	long		first_div;	int			first_nextdigit;	int			stat = 0;	int			rscale;	int			res_dscale = select_div_scale(var1, var2, &rscale);	int			err = -1;	NumericDigit *tmp_buf;	/*	 * First of all division by zero check	 */	ndigits_tmp = var2->ndigits + 1;	if (ndigits_tmp == 1)	{		errno = PGTYPES_NUM_DIVIDE_ZERO;		return -1;	}	/*	 * Determine the result sign, weight and number of digits to calculate	 */	if (var1->sign == var2->sign)		res_sign = NUMERIC_POS;	else		res_sign = NUMERIC_NEG;	res_weight = var1->weight - var2->weight + 1;	res_ndigits = rscale + res_weight;	if (res_ndigits <= 0)		res_ndigits = 1;	/*	 * Now result zero check	 */	if (var1->ndigits == 0)	{		zero_var(result);		result->rscale = rscale;		return 0;	}	/*	 * Initialize local variables	 */	init_var(&dividend);	for (i = 1; i < 10; i++)		init_var(&divisor[i]);	/*	 * Make a copy of the divisor which has one leading zero digit	 */	divisor[1].ndigits = ndigits_tmp;	divisor[1].rscale = var2->ndigits;	divisor[1].sign = NUMERIC_POS;	divisor[1].buf = digitbuf_alloc(ndigits_tmp);	if (divisor[1].buf == NULL)		goto done;	divisor[1].digits = divisor[1].buf;	divisor[1].digits[0] = 0;	memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);	/*	 * Make a copy of the dividend	 */	dividend.ndigits = var1->ndigits;	dividend.weight = 0;	dividend.rscale = var1->ndigits;	dividend.sign = NUMERIC_POS;	dividend.buf = digitbuf_alloc(var1->ndigits);	if (dividend.buf == NULL)		goto done;	dividend.digits = dividend.buf;	memcpy(dividend.digits, var1->digits, var1->ndigits);	/*	 * Setup the result. Do the allocation in a temporary buffer first, so we	 * don't free result->buf unless we have successfully allocated a buffer	 * to replace it with.	 */	tmp_buf = digitbuf_alloc(res_ndigits + 2);	if (tmp_buf == NULL)		goto done;	digitbuf_free(result->buf);	result->buf = tmp_buf;	res_digits = result->buf;	result->digits = res_digits;	result->ndigits = res_ndigits;	result->weight = res_weight;	result->rscale = rscale;	result->sign = res_sign;	res_digits[0] = 0;	first_div = divisor[1].digits[1] * 10;	if (ndigits_tmp > 2)		first_div += divisor[1].digits[2];	first_have = 0;	first_nextdigit = 0;	weight_tmp = 1;	rscale_tmp = divisor[1].rscale;	for (ri = 0; ri <= res_ndigits; ri++)	{		first_have = first_have * 10;		if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)			first_have += dividend.digits[first_nextdigit];		first_nextdigit++;		guess = (first_have * 10) / first_div + 1;		if (guess > 9)			guess = 9;		while (guess > 0)		{			if (divisor[guess].buf == NULL)			{				int			i;				long		sum = 0;				memcpy(&divisor[guess], &divisor[1], sizeof(numeric));				divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);				if (divisor[guess].buf == NULL)					goto done;				divisor[guess].digits = divisor[guess].buf;				for (i = divisor[1].ndigits - 1; i >= 0; i--)				{					sum += divisor[1].digits[i] * guess;					divisor[guess].digits[i] = sum % 10;					sum /= 10;				}			}			divisor[guess].weight = weight_tmp;			divisor[guess].rscale = rscale_tmp;			stat = cmp_abs(&dividend, &divisor[guess]);			if (stat >= 0)				break;			guess--;		}		res_digits[ri + 1] = guess;		if (stat == 0)		{			ri++;			break;		}		weight_tmp--;		rscale_tmp++;		if (guess == 0)			continue;		if (sub_abs(&dividend, &divisor[guess], &dividend) != 0)			goto done;		first_nextdigit = dividend.weight - weight_tmp;		first_have = 0;		if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)			first_have = dividend.digits[first_nextdigit];		first_nextdigit++;	}	result->ndigits = ri + 1;	if (ri == res_ndigits + 1)	{		int			carry = (res_digits[ri] > 4) ? 1 : 0;		result->ndigits = ri;		res_digits[ri] = 0;		while (carry && ri > 0)		{			carry += res_digits[--ri];			res_digits[ri] = carry % 10;			carry /= 10;		}	}	while (result->ndigits > 0 && *(result->digits) == 0)	{		(result->digits)++;		(result->weight)--;		(result->ndigits)--;	}	while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)		(result->ndigits)--;	if (result->ndigits == 0)		result->sign = NUMERIC_POS;	result->dscale = res_dscale;	err = 0;					/* if we've made it this far, return success */done:	/*	 * Tidy up	 */	if (dividend.buf != NULL)		digitbuf_free(dividend.buf);	for (i = 1; i < 10; i++)	{		if (divisor[i].buf != NULL)			digitbuf_free(divisor[i].buf);	}	return err;}intPGTYPESnumeric_cmp(numeric *var1, numeric *var2){	/* use cmp_abs function to calculate the result */	/* both are positive: normal comparation with cmp_abs */	if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)		return cmp_abs(var1, var2);	/* both are negative: return the inverse of the normal comparation */	if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)	{		/*		 * instead of inverting the result, we invert the paramter ordering		 */		return cmp_abs(var2, var1);	}	/* one is positive, one is negative: trivial */	if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)		return 1;	if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)		return -1;	errno = PGTYPES_NUM_BAD_NUMERIC;	return INT_MAX;}intPGTYPESnumeric_from_int(signed int int_val, numeric *var){	/* implicit conversion */	signed long int long_int = int_val;	return PGTYPESnumeric_from_long(long_int, var);}intPGTYPESnumeric_from_long(signed long int long_val, numeric *var){	/* calculate the size of the long int number */	/* a number n needs log_10 n digits */	/*	 * however we multiply by 10 each time and compare instead of calculating	 * the logarithm	 */	int			size = 0;	int			i;	signed long int abs_long_val = long_val;	signed long int extract;	signed long int reach_limit;	if (abs_long_val < 0)	{		abs_long_val *= -1;		var->sign = NUMERIC_NEG;	}	else		var->sign = NUMERIC_POS;	reach_limit = 1;	do	{		size++;		reach_limit *= 10;	} while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);	if (reach_limit > LONG_MAX / 10)	{		/* add the first digit and a .0 */		size += 2;	}	else	{		/* always add a .0 */		size++;		reach_limit /= 10;	}	if (alloc_var(var, size) < 0)		return -1;	var->rscale = 1;	var->dscale = 1;	var->weight = size - 2;	i = 0;	do	{		extract = abs_long_val - (abs_long_val % reach_limit);		var->digits[i] = extract / reach_limit;		abs_long_val -= extract;		i++;		reach_limit /= 10;		/*		 * we can abandon if abs_long_val reaches 0, because the memory is		 * initialized properly and filled with '0', so converting 10000 in		 * only one step is no problem		 */	} while (abs_long_val > 0);	return 0;}intPGTYPESnumeric_copy(numeric *src, numeric *dst){	int			i;	if (dst == NULL)		return -1;	zero_var(dst);	dst->weight = src->weight;	dst->rscale = src->rscale;	dst->dscale = src->dscale;	dst->sign = src->sign;	if (alloc_var(dst, src->ndigits) != 0)		return -1;	for (i = 0; i < src->ndigits; i++)		dst->digits[i] = src->digits[i];	return 0;}intPGTYPESnumeric_from_double(double d, numeric *dst){	char		buffer[100];	numeric    *tmp;	int			i;	if (sprintf(buffer, "%f", d) == 0)		return -1;	if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)		return -1;	i = PGTYPESnumeric_copy(tmp, dst);	PGTYPESnumeric_free(tmp);	if (i != 0)		return -1;	errno = 0;	return 0;}static intnumericvar_to_double(numeric *var, double *dp){	char	   *tmp;	double		val;	char	   *endptr;	numeric    *varcopy = PGTYPESnumeric_new();	if (PGTYPESnumeric_copy(var, varcopy) < 0)	{		PGTYPESnumeric_free(varcopy);		return -1;	}	tmp = get_str_from_var(varcopy, varcopy->dscale);	PGTYPESnumeric_free(varcopy);	if (tmp == NULL)		return -1;	/*	 * strtod does not reset errno to 0 in case of success.	 */	errno = 0;	val = strtod(tmp, &endptr);	if (errno == ERANGE)	{		free(tmp);		if (val == 0)			errno = PGTYPES_NUM_UNDERFLOW;		else			errno = PGTYPES_NUM_OVERFLOW;		return -1;	}	/* can't free tmp yet, endptr points still into it */	if (*endptr != '\0')	{		/* shouldn't happen ... */		free(tmp);		errno = PGTYPES_NUM_BAD_NUMERIC;		return -1;	}	free(tmp);	*dp = val;	return 0;}intPGTYPESnumeric_to_double(numeric *nv, double *dp){	double		tmp;	int			i;	if ((i = numericvar_to_double(nv, &tmp)) != 0)		return -1;	*dp = tmp;	return 0;}intPGTYPESnumeric_to_int(numeric *nv, int *ip){	long		l;	int			i;	if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)		return i;	if (l < -INT_MAX || l > INT_MAX)	{		errno = PGTYPES_NUM_OVERFLOW;		return -1;	}	*ip = (int) l;	return 0;}intPGTYPESnumeric_to_long(numeric *nv, long *lp){	char	   *s = PGTYPESnumeric_to_asc(nv, 0);	char	   *endptr;	if (s == NULL)		return -1;	errno = 0;	*lp = strtol(s, &endptr, 10);	if (endptr == s)		/* this should not happen actually */		return -1;	if (errno == ERANGE)	{		if (*lp == LONG_MIN)			errno = PGTYPES_NUM_UNDERFLOW;		else			errno = PGTYPES_NUM_OVERFLOW;		return -1;	}	free(s);	return 0;}intPGTYPESnumeric_to_decimal(numeric *src, decimal *dst){	int			i;	if (src->ndigits > DECSIZE)	{		errno = PGTYPES_NUM_OVERFLOW;		return -1;	}	dst->weight = src->weight;	dst->rscale = src->rscale;	dst->dscale = src->dscale;	dst->sign = src->sign;	dst->ndigits = src->ndigits;	for (i = 0; i < src->ndigits; i++)		dst->digits[i] = src->digits[i];	return 0;}intPGTYPESnumeric_from_decimal(decimal *src, numeric *dst){	int			i;	zero_var(dst);	dst->weight = src->weight;	dst->rscale = src->rscale;	dst->dscale = src->dscale;	dst->sign = src->sign;	if (alloc_var(dst, src->ndigits) != 0)		return -1;	for (i = 0; i < src->ndigits; i++)		dst->digits[i] = src->digits[i];	return 0;}

⌨️ 快捷键说明

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