numeric.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,840 行 · 第 1/5 页

C
2,840
字号
			result = 1;			/* NAN > non-NAN */	}	else if (NUMERIC_IS_NAN(num2))	{		result = -1;			/* non-NAN < NAN */	}	else	{		result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),								num1->n_weight, NUMERIC_SIGN(num1),								NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),								num2->n_weight, NUMERIC_SIGN(num2));	}	return result;}Datumhash_numeric(PG_FUNCTION_ARGS){	Numeric		key = PG_GETARG_NUMERIC(0);	Datum		digit_hash;	Datum		result;	int			weight;	int			start_offset;	int			end_offset;	int			i;	int			hash_len;	/* If it's NaN, don't try to hash the rest of the fields */	if (NUMERIC_IS_NAN(key))		PG_RETURN_UINT32(0);	weight = key->n_weight;	start_offset = 0;	end_offset = 0;	/*	 * Omit any leading or trailing zeros from the input to the hash. The	 * numeric implementation *should* guarantee that leading and trailing	 * zeros are suppressed, but we're paranoid. Note that we measure the	 * starting and ending offsets in units of NumericDigits, not bytes.	 */	for (i = 0; i < NUMERIC_NDIGITS(key); i++)	{		if (NUMERIC_DIGITS(key)[i] != (NumericDigit) 0)			break;		start_offset++;		/*		 * The weight is effectively the # of digits before the decimal point,		 * so decrement it for each leading zero we skip.		 */		weight--;	}	/*	 * If there are no non-zero digits, then the value of the number is zero,	 * regardless of any other fields.	 */	if (NUMERIC_NDIGITS(key) == start_offset)		PG_RETURN_UINT32(-1);	for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)	{		if (NUMERIC_DIGITS(key)[i] != (NumericDigit) 0)			break;		end_offset++;	}	/* If we get here, there should be at least one non-zero digit */	Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));	/*	 * Note that we don't hash on the Numeric's scale, since two numerics can	 * compare equal but have different scales. We also don't hash on the	 * sign, although we could: since a sign difference implies inequality,	 * this shouldn't affect correctness.	 */	hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;	digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset),						  hash_len * sizeof(NumericDigit));	/* Mix in the weight, via XOR */	result = digit_hash ^ weight;	PG_RETURN_DATUM(result);}/* ---------------------------------------------------------------------- * * Basic arithmetic functions * * ---------------------------------------------------------------------- *//* * numeric_add() - * *	Add two numerics */Datumnumeric_add(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the values, let add_var() compute the result and return it.	 */	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);	set_var_from_num(num2, &arg2);	add_var(&arg1, &arg2, &result);	res = make_result(&result);	free_var(&arg1);	free_var(&arg2);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_sub() - * *	Subtract one numeric from another */Datumnumeric_sub(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the values, let sub_var() compute the result and return it.	 */	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);	set_var_from_num(num2, &arg2);	sub_var(&arg1, &arg2, &result);	res = make_result(&result);	free_var(&arg1);	free_var(&arg2);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_mul() - * *	Calculate the product of two numerics */Datumnumeric_mul(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the values, let mul_var() compute the result and return it.	 * Unlike add_var() and sub_var(), mul_var() will round its result. In the	 * case of numeric_mul(), which is invoked for the * operator on numerics,	 * we request exact representation for the product (rscale = sum(dscale of	 * arg1, dscale of arg2)).	 */	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);	set_var_from_num(num2, &arg2);	mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);	res = make_result(&result);	free_var(&arg1);	free_var(&arg2);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_div() - * *	Divide one numeric into another */Datumnumeric_div(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	Numeric		res;	int			rscale;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the arguments	 */	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);	set_var_from_num(num2, &arg2);	/*	 * Select scale for division result	 */	rscale = select_div_scale(&arg1, &arg2);	/*	 * Do the divide and return the result	 */	div_var(&arg1, &arg2, &result, rscale, true);	res = make_result(&result);	free_var(&arg1);	free_var(&arg2);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_mod() - * *	Calculate the modulo of two numerics */Datumnumeric_mod(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	Numeric		res;	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);	set_var_from_num(num2, &arg2);	mod_var(&arg1, &arg2, &result);	res = make_result(&result);	free_var(&result);	free_var(&arg2);	free_var(&arg1);	PG_RETURN_NUMERIC(res);}/* * numeric_inc() - * *	Increment a number by one */Datumnumeric_inc(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	NumericVar	arg;	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Compute the result and return it	 */	init_var(&arg);	set_var_from_num(num, &arg);	add_var(&arg, &const_one, &arg);	res = make_result(&arg);	free_var(&arg);	PG_RETURN_NUMERIC(res);}/* * numeric_smaller() - * *	Return the smaller of two numbers */Datumnumeric_smaller(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	/*	 * Use cmp_numerics so that this will agree with the comparison operators,	 * particularly as regards comparisons involving NaN.	 */	if (cmp_numerics(num1, num2) < 0)		PG_RETURN_NUMERIC(num1);	else		PG_RETURN_NUMERIC(num2);}/* * numeric_larger() - * *	Return the larger of two numbers */Datumnumeric_larger(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	/*	 * Use cmp_numerics so that this will agree with the comparison operators,	 * particularly as regards comparisons involving NaN.	 */	if (cmp_numerics(num1, num2) > 0)		PG_RETURN_NUMERIC(num1);	else		PG_RETURN_NUMERIC(num2);}/* ---------------------------------------------------------------------- * * Advanced math functions * * ---------------------------------------------------------------------- *//* * numeric_fac() * * Compute factorial */Datumnumeric_fac(PG_FUNCTION_ARGS){	int64		num = PG_GETARG_INT64(0);	Numeric		res;	NumericVar	fact;	NumericVar	result;	if (num <= 1)	{		res = make_result(&const_one);		PG_RETURN_NUMERIC(res);	}	/* Fail immediately if the result would overflow */	if (num > 32177)		ereport(ERROR,				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),				 errmsg("value overflows numeric format")));	init_var(&fact);	init_var(&result);	int8_to_numericvar(num, &result);	for (num = num - 1; num > 1; num--)	{		/* this loop can take awhile, so allow it to be interrupted */		CHECK_FOR_INTERRUPTS();		int8_to_numericvar(num, &fact);		mul_var(&result, &fact, &result, 0);	}	res = make_result(&result);	free_var(&fact);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_sqrt() - * *	Compute the square root of a numeric. */Datumnumeric_sqrt(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	NumericVar	arg;	NumericVar	result;	int			sweight;	int			rscale;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the argument and determine the result scale.	We choose a scale	 * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any	 * case not less than the input's dscale.	 */	init_var(&arg);	init_var(&result);	set_var_from_num(num, &arg);	/* Assume the input was normalized, so arg.weight is accurate */	sweight = (arg.weight + 1) * DEC_DIGITS / 2 - 1;	rscale = NUMERIC_MIN_SIG_DIGITS - sweight;	rscale = Max(rscale, arg.dscale);	rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);	rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);	/*	 * Let sqrt_var() do the calculation and return the result.	 */	sqrt_var(&arg, &result, rscale);	res = make_result(&result);	free_var(&result);	free_var(&arg);	PG_RETURN_NUMERIC(res);}/* * numeric_exp() - * *	Raise e to the power of x */Datumnumeric_exp(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	NumericVar	arg;	NumericVar	result;	int			rscale;	double		val;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the argument and determine the result scale.	We choose a scale	 * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any	 * case not less than the input's dscale.	 */	init_var(&arg);	init_var(&result);	set_var_from_num(num, &arg);	/* convert input to float8, ignoring overflow */	val = numericvar_to_double_no_overflow(&arg);	/*	 * log10(result) = num * log10(e), so this is approximately the decimal	 * weight of the result:	 */	val *= 0.434294481903252;	/* limit to something that won't cause integer overflow */	val = Max(val, -NUMERIC_MAX_RESULT_SCALE);	val = Min(val, NUMERIC_MAX_RESULT_SCALE);	rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;	rscale = Max(rscale, arg.dscale);	rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);	rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);	/*	 * Let exp_var() do the calculation and return the result.	 */	exp_var(&arg, &result, rscale);	res = make_result(&result);	free_var(&result);	free_var(&arg);

⌨️ 快捷键说明

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