📄 numeric.c
字号:
{ Numeric res; NumericVar arg; NumericVar result; int res_dscale; /* ---------- * Handle NULL * ---------- */ if (num == NULL) return NULL; /* ---------- * Handle NaN * ---------- */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* ---------- * Same procedure like for sqrt(). * ---------- */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE); global_rscale = MAX(global_rscale, res_dscale + 4); global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE); exp_var(&arg, &result); result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg); return res;}/* ---------- * numeric_ln() - * * Compute the natural logarithm of x * ---------- */Numericnumeric_ln(Numeric num){ Numeric res; NumericVar arg; NumericVar result; int res_dscale; /* ---------- * Handle NULL * ---------- */ if (num == NULL) return NULL; /* ---------- * Handle NaN * ---------- */ if (NUMERIC_IS_NAN(num)) return make_result(&const_nan); /* ---------- * Same procedure like for sqrt() * ---------- */ init_var(&arg); init_var(&result); set_var_from_num(num, &arg); res_dscale = MAX(arg.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); global_rscale = MAX(arg.rscale, NUMERIC_MIN_RESULT_SCALE); global_rscale = MAX(global_rscale, res_dscale + 4); global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE); ln_var(&arg, &result); result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg); return res;}/* ---------- * numeric_ln() - * * Compute the logarithm of x in a given base * ---------- */Numericnumeric_log(Numeric num1, Numeric num2){ Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; int res_dscale; /* ---------- * Handle NULL * ---------- */ if (num1 == NULL || num2 == NULL) return NULL; /* ---------- * Handle NaN * ---------- */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* ---------- * Initialize things and calculate scales * ---------- */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE); global_rscale = MAX(global_rscale, res_dscale + 4); global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE); /* ---------- * Call log_var() to compute and return the result * ---------- */ log_var(&arg1, &arg2, &result); result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); return res;}/* ---------- * numeric_power() - * * Raise m to the power of x * ---------- */Numericnumeric_power(Numeric num1, Numeric num2){ Numeric res; NumericVar arg1; NumericVar arg2; NumericVar result; int res_dscale; /* ---------- * Handle NULL * ---------- */ if (num1 == NULL || num2 == NULL) return NULL; /* ---------- * Handle NaN * ---------- */ if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2)) return make_result(&const_nan); /* ---------- * Initialize things and calculate scales * ---------- */ init_var(&arg1); init_var(&arg2); init_var(&result); set_var_from_num(num1, &arg1); set_var_from_num(num2, &arg2); res_dscale = MAX(arg1.dscale + arg2.dscale, NUMERIC_MIN_DISPLAY_SCALE); res_dscale = MIN(res_dscale, NUMERIC_MAX_DISPLAY_SCALE); global_rscale = MAX(arg1.rscale + arg2.rscale, NUMERIC_MIN_RESULT_SCALE); global_rscale = MAX(global_rscale, res_dscale + 4); global_rscale = MIN(global_rscale, NUMERIC_MAX_RESULT_SCALE); /* ---------- * Call log_var() to compute and return the result * ---------- */ power_var(&arg1, &arg2, &result); result.dscale = res_dscale; res = make_result(&result); free_var(&result); free_var(&arg2); free_var(&arg1); return res;}/* ---------------------------------------------------------------------- * * Type conversion functions * * ---------------------------------------------------------------------- */Numericint4_numeric(int32 val){ Numeric res; NumericVar result; char *tmp; init_var(&result); tmp = int4out(val); set_var_from_str(tmp, &result); res = make_result(&result); free_var(&result); pfree(tmp); return res;}int32numeric_int4(Numeric num){ char *tmp; int32 result; if (num == NULL) return 0; if (NUMERIC_IS_NAN(num)) return 0; tmp = numeric_out(num); result = int4in(tmp); pfree(tmp); return result;}Numericfloat8_numeric(float64 val){ Numeric res; NumericVar result; char buf[512]; if (val == NULL) return NULL; if (isnan(*val)) return make_result(&const_nan); init_var(&result); sprintf(buf, "%f", *val); set_var_from_str(buf, &result); res = make_result(&result); free_var(&result); return res;}float64numeric_float8(Numeric num){ char *tmp; float64 result; if (num == NULL) return NULL; if (NUMERIC_IS_NAN(num)) { result = (float64) palloc(sizeof(float64data)); *result = NAN; return result; } tmp = numeric_out(num); result = float8in(tmp); pfree(tmp); return result;}Numericfloat4_numeric(float32 val){ Numeric res; NumericVar result; char *tmp; if (val == NULL) return NULL; if (isnan(*val)) return make_result(&const_nan); init_var(&result); tmp = float4out(val); set_var_from_str(tmp, &result); res = make_result(&result); free_var(&result); pfree(tmp); return res;}float32numeric_float4(Numeric num){ char *tmp; float32 result; if (num == NULL) return NULL; if (NUMERIC_IS_NAN(num)) { result = (float32) palloc(sizeof(float32data)); *result = NAN; return result; } tmp = numeric_out(num); result = float4in(tmp); pfree(tmp); return result;}/* ---------------------------------------------------------------------- * * Local functions follow * * ---------------------------------------------------------------------- */#ifdef NUMERIC_DEBUG/* ---------- * dump_numeric() - Dump a value in the db storage format for debugging * ---------- */static voiddump_numeric(char *str, Numeric num){ int i; printf("%s: NUMERIC w=%d r=%d d=%d ", str, num->n_weight, num->n_rscale, NUMERIC_DSCALE(num)); switch (NUMERIC_SIGN(num)) { case NUMERIC_POS: printf("POS"); break; case NUMERIC_NEG: printf("NEG"); break; case NUMERIC_NAN: printf("NaN"); break; default: printf("SIGN=0x%x", NUMERIC_SIGN(num)); break; } for (i = 0; i < num->varlen - NUMERIC_HDRSZ; i++) printf(" %d %d", (num->n_data[i] >> 4) & 0x0f, num->n_data[i] & 0x0f); printf("\n");}/* ---------- * dump_var() - Dump a value in the variable format for debugging * ---------- */static voiddump_var(char *str, NumericVar *var){ int i; printf("%s: VAR w=%d r=%d d=%d ", str, var->weight, var->rscale, var->dscale); switch (var->sign) { case NUMERIC_POS: printf("POS"); break; case NUMERIC_NEG: printf("NEG"); break; case NUMERIC_NAN: printf("NaN"); break; default: printf("SIGN=0x%x", var->sign); break; } for (i = 0; i < var->ndigits; i++) printf(" %d", var->digits[i]); printf("\n");}#endif /* NUMERIC_DEBUG *//* ---------- * digitbuf_alloc() - * * All variables used in the arithmetic functions hold some base * information (sign, scales etc.) and a digit buffer for the * value itself. All the variable level functions are written in * a style that makes it possible to give one and the same variable * as argument and result destination. * * The two functions below manage unused buffers in a free list * as a try to reduce the number of malloc()/free() calls. * ---------- */static NumericDigitBuf *digitbuf_alloc(int size){ NumericDigitBuf *buf; int asize; /* ---------- * Lookup the free list if there is a digit buffer of * the required size available * ---------- */ for (buf = digitbuf_freelist; buf != NULL; buf = buf->next) { if (buf->size < size) continue; /* ---------- * We found a free buffer that is big enough - remove it from * the free list * ---------- */ if (buf->prev == NULL) { digitbuf_freelist = buf->next; if (buf->next != NULL) buf->next->prev = NULL; } else { buf->prev->next = buf->next; if (buf->next != NULL) buf->next->prev = buf->prev; } digitbuf_nfree--; /* ---------- * Put it onto the used list * ---------- */ buf->prev = NULL; buf->next = digitbuf_usedlist; if (digitbuf_usedlist != NULL) digitbuf_usedlist->prev = buf; digitbuf_usedlist = buf; /* ---------- * Return this buffer * ---------- */ return buf; } /* ---------- * There is no free buffer big enough - allocate a new one * ---------- */ for (asize = NUMERIC_MIN_BUFSIZE; asize < size; asize *= 2); buf = (NumericDigitBuf *) malloc(sizeof(NumericDigitBuf) + asize); buf->size = asize; /* ---------- * Put it onto the used list * ---------- */ buf->prev = NULL; buf->next = digitbuf_usedlist; if (digitbuf_usedlist != NULL) digitbuf_usedlist->prev = buf; digitbuf_usedlist = buf; /* ---------- * Return the new buffer * ---------- */ return buf;}/* ---------- * digitbuf_free() - * ---------- */static voiddigitbuf_free(NumericDigitBuf *buf){ NumericDigitBuf *smallest; if (buf == NULL) return; /* ---------- * Remove the buffer from the used list * ---------- */ if (buf->prev == NULL) { digitbuf_usedlist = buf->next; if (buf->next != NULL) buf->next->prev = NULL; } else { buf->prev->next = buf->next; if (buf->next != NULL) buf->next->prev = buf->prev; } /* ---------- * Put it onto the free list * ---------- */ if (digitbuf_freelist != NULL) digitbuf_freelist->prev = buf; buf->prev = NULL; buf->next = digitbuf_freelist; digitbuf_freelist = buf; digitbuf_nfree++; /* ---------- * Check for maximum free buffers * ---------- */ if (digitbuf_nfree <= NUMERIC_MAX_FREEBUFS) return; /* ---------- * Have too many free buffers - destroy the smallest one * ---------- */ smallest = buf; for (buf = digitbuf_freelist->next; buf != NULL; buf = buf->next) { if (buf->size < smallest->size) smallest = buf; } /* ---------- * Remove it from the free list * ---------- */ if (smallest->prev == NULL) { digitbuf_freelist = smallest->next; if (smallest->next != NULL) smallest->next->prev = NULL; } else { smallest->prev->next = smallest->next; if (smallest->next != NULL) smallest->next->prev = smallest->prev; } digitbuf_nfree--; /* ---------- * And destroy it * ---------- */ free(smallest);}/* ---------- * free_var() - * * Return the digit buffer of a variable to the pool * ---------- */static voidfree_var(NumericVar *var){ if (var->buf != NULL) { digitbuf_free(var->buf); var->buf = NULL; var->digits = NULL; } var->sign = NUMERIC_NAN;}/* ---------- * free_allvars() - * * Put all the currently used buffers back into the pool. * * Warning: the variables currently holding the buffers aren't * cleaned! This function should only be used directly before * a call to elog(ERROR,...) or if it is totally impossible that * any other call to free_var() will occur. None of the variable * level functions should call it if it might return later without * an error. * ---------- */static voidfree_allvars(void){ NumericDigitBuf *buf; NumericDigitBuf *next; buf = digitbuf_usedlist; while (buf != NULL) { next = buf->next; digitbuf_free(buf); buf = next; }}/* ---------- * set_var_from_str() * * Parse a string and put the number into a variable * ---------- */static voidset_var_from_str(char *str, NumericVar *dest){ char *cp = str; bool have_dp = FALSE; int i = 1; while (*cp) { if (!isspace(*cp)) break; cp++; } digitbuf_free(dest->buf); dest->buf = digitbuf_alloc(strlen(cp) + 2); dest->digits = (NumericDigit *) (dest->buf) + sizeof(NumericDigitBuf); dest->digits[0] = 0; dest->weight = 0; dest->dscale = 0; switch (*cp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -