📄 numeric.c
字号:
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_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); PG_RETURN_NUMERIC(res);}/* * numeric_ln() - * * Compute the natural logarithm of x */Datumnumeric_ln(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); Numeric res; NumericVar arg; NumericVar result; int dec_digits; int rscale; /* * Handle NaN */ if (NUMERIC_IS_NAN(num)) PG_RETURN_NUMERIC(make_result(&const_nan)); init_var(&arg); init_var(&result); set_var_from_num(num, &arg); /* Approx decimal digits before decimal point */ dec_digits = (arg.weight + 1) * DEC_DIGITS; if (dec_digits > 1) rscale = NUMERIC_MIN_SIG_DIGITS - (int) log10(dec_digits - 1); else if (dec_digits < 1) rscale = NUMERIC_MIN_SIG_DIGITS - (int) log10(1 - dec_digits); else rscale = NUMERIC_MIN_SIG_DIGITS; rscale = Max(rscale, arg.dscale); rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE); rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE); ln_var(&arg, &result, rscale); res = make_result(&result); free_var(&result); free_var(&arg); PG_RETURN_NUMERIC(res);}/* * numeric_log() - * * Compute the logarithm of x in a given base */Datumnumeric_log(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Initialize things */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); /* * Call log_var() to compute and return the result; note it handles * scale selection itself. */ log_var(&arg1, &arg2, &result); res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); PG_RETURN_NUMERIC(res);}/* * numeric_power() - * * Raise b to the power of x */Datumnumeric_power(PG_FUNCTION_ARGS){ Numeric num1 = PG_GETARG_NUMERIC(0); Numeric num2 = PG_GETARG_NUMERIC(1); Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; /* * Handle NaN */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) PG_RETURN_NUMERIC(make_result(&const_nan)); /* * Initialize things */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); /* * Call power_var() to compute and return the result; note it handles * scale selection itself. */ power_var(&arg1, &arg2, &result); res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); PG_RETURN_NUMERIC(res);}/* ---------------------------------------------------------------------- * * Type conversion functions * * ---------------------------------------------------------------------- */Datumint4_numeric(PG_FUNCTION_ARGS){ int32 val = PG_GETARG_INT32(0); Numeric res; NumericVar result; init_var(&result); int8_to_numericvar((int64) val, &result); res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}Datumnumeric_int4(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); NumericVar x; int64 val; int32 result; /* XXX would it be better to return NULL? */ if (NUMERIC_IS_NAN(num)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert NaN to integer"))); /* Convert to variable format and thence to int8 */ init_var(&x); set_var_from_num(num, &x); if (!numericvar_to_int8(&x, &val)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); free_var(&x); /* Down-convert to int4 */ result = (int32) val; /* Test for overflow by reverse-conversion. */ if ((int64) result != val) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT32(result);}Datumint8_numeric(PG_FUNCTION_ARGS){ int64 val = PG_GETARG_INT64(0); Numeric res; NumericVar result; init_var(&result); int8_to_numericvar(val, &result); res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}Datumnumeric_int8(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); NumericVar x; int64 result; /* XXX would it be better to return NULL? */ if (NUMERIC_IS_NAN(num)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert NaN to integer"))); /* Convert to variable format and thence to int8 */ init_var(&x); set_var_from_num(num, &x); if (!numericvar_to_int8(&x, &result)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); free_var(&x); PG_RETURN_INT64(result);}Datumint2_numeric(PG_FUNCTION_ARGS){ int16 val = PG_GETARG_INT16(0); Numeric res; NumericVar result; init_var(&result); int8_to_numericvar((int64) val, &result); res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}Datumnumeric_int2(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); NumericVar x; int64 val; int16 result; /* XXX would it be better to return NULL? */ if (NUMERIC_IS_NAN(num)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot convert NaN to integer"))); /* Convert to variable format and thence to int8 */ init_var(&x); set_var_from_num(num, &x); if (!numericvar_to_int8(&x, &val)) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); free_var(&x); /* Down-convert to int2 */ result = (int16) val; /* Test for overflow by reverse-conversion. */ if ((int64) result != val) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("integer out of range"))); PG_RETURN_INT16(result);}Datumfloat8_numeric(PG_FUNCTION_ARGS){ float8 val = PG_GETARG_FLOAT8(0); Numeric res; NumericVar result; char buf[DBL_DIG + 100]; if (isnan(val)) PG_RETURN_NUMERIC(make_result(&const_nan)); sprintf(buf, "%.*g", DBL_DIG, val); init_var(&result); set_var_from_str(buf, &result); res = make_result(&result); free_var(&result); PG_RETURN_NUMERIC(res);}Datumnumeric_float8(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); char *tmp; Datum result; if (NUMERIC_IS_NAN(num)) PG_RETURN_FLOAT8(NAN); tmp = DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(num))); result = DirectFunctionCall1(float8in, CStringGetDatum(tmp)); pfree(tmp); PG_RETURN_DATUM(result);}/* Convert numeric to float8; if out of range, return +/- HUGE_VAL */Datumnumeric_float8_no_overflow(PG_FUNCTION_ARGS){ Numeric num = PG_GETARG_NUMERIC(0); double val; if (NUMERIC_IS_NAN(num)) PG_RETURN_FLOAT8(NAN); val = numeric_to_double_no_overflow(num); PG_RETURN_FLOAT8(val);}Datumfloat4_numeric(PG_FUNCTION_ARGS){ float4 val = PG_GETARG_FLOAT4(0); Numeric res; NumericVar result; char buf[FLT_DIG + 100]; if (isnan(val)) PG_RETURN_NUMERIC(make_result(&const_nan)); sprintf(buf, "%.*g", FLT_DIG, val);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -