mirror of
https://github.com/postgres/postgres.git
synced 2025-06-27 23:21:58 +03:00
Support EEEE (scientific notation) in to_char().
Pavel Stehule, Brendan Jurd
This commit is contained in:
@ -14,7 +14,7 @@
|
||||
* Copyright (c) 1998-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.118 2009/06/11 14:49:03 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.119 2009/08/10 18:29:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -247,6 +247,7 @@ static const char *set_var_from_str(const char *str, const char *cp,
|
||||
static void set_var_from_num(Numeric value, NumericVar *dest);
|
||||
static void set_var_from_var(NumericVar *value, NumericVar *dest);
|
||||
static char *get_str_from_var(NumericVar *var, int dscale);
|
||||
static char *get_str_from_var_sci(NumericVar *var, int rscale);
|
||||
|
||||
static Numeric make_result(NumericVar *var);
|
||||
|
||||
@ -426,6 +427,32 @@ numeric_out(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_CSTRING(str);
|
||||
}
|
||||
|
||||
/*
|
||||
* numeric_out_sci() -
|
||||
*
|
||||
* Output function for numeric data type in scientific notation.
|
||||
*/
|
||||
char *
|
||||
numeric_out_sci(Numeric num, int scale)
|
||||
{
|
||||
NumericVar x;
|
||||
char *str;
|
||||
|
||||
/*
|
||||
* Handle NaN
|
||||
*/
|
||||
if (NUMERIC_IS_NAN(num))
|
||||
return pstrdup("NaN");
|
||||
|
||||
init_var(&x);
|
||||
set_var_from_num(num, &x);
|
||||
|
||||
str = get_str_from_var_sci(&x, scale);
|
||||
|
||||
free_var(&x);
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* numeric_recv - converts external binary format to numeric
|
||||
*
|
||||
@ -3364,6 +3391,110 @@ get_str_from_var(NumericVar *var, int dscale)
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_str_from_var_sci() -
|
||||
*
|
||||
* Convert a var to a normalised scientific notation text representation.
|
||||
* This function does the heavy lifting for numeric_out_sci().
|
||||
*
|
||||
* This notation has the general form a * 10^b, where a is known as the
|
||||
* "significand" and b is known as the "exponent".
|
||||
*
|
||||
* Because we can't do superscript in ASCII (and because we want to copy
|
||||
* printf's behaviour) we display the exponent using E notation, with a
|
||||
* minimum of two exponent digits.
|
||||
*
|
||||
* For example, the value 1234 could be output as 1.2e+03.
|
||||
*
|
||||
* We assume that the exponent can fit into an int32.
|
||||
*
|
||||
* rscale is the number of decimal digits desired after the decimal point in
|
||||
* the output, negative values will be treated as meaning zero.
|
||||
*
|
||||
* CAUTION: var's contents may be modified by rounding!
|
||||
*
|
||||
* Returns a palloc'd string.
|
||||
*/
|
||||
static char *
|
||||
get_str_from_var_sci(NumericVar *var, int rscale)
|
||||
{
|
||||
int32 exponent;
|
||||
NumericVar denominator;
|
||||
NumericVar significand;
|
||||
int denom_scale;
|
||||
size_t len;
|
||||
char *str;
|
||||
char *sig_out;
|
||||
|
||||
if (rscale < 0)
|
||||
rscale = 0;
|
||||
|
||||
/*
|
||||
* Determine the exponent of this number in normalised form.
|
||||
*
|
||||
* This is the exponent required to represent the number with only one
|
||||
* significant digit before the decimal place.
|
||||
*/
|
||||
if (var->ndigits > 0)
|
||||
{
|
||||
exponent = (var->weight + 1) * DEC_DIGITS;
|
||||
|
||||
/*
|
||||
* Compensate for leading decimal zeroes in the first numeric digit by
|
||||
* decrementing the exponent.
|
||||
*/
|
||||
exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If var has no digits, then it must be zero.
|
||||
*
|
||||
* Zero doesn't technically have a meaningful exponent in normalised
|
||||
* notation, but we just display the exponent as zero for consistency
|
||||
* of output.
|
||||
*/
|
||||
exponent = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The denominator is set to 10 raised to the power of the exponent.
|
||||
*
|
||||
* We then divide var by the denominator to get the significand, rounding
|
||||
* to rscale decimal digits in the process.
|
||||
*/
|
||||
if (exponent < 0)
|
||||
denom_scale = -exponent;
|
||||
else
|
||||
denom_scale = 0;
|
||||
|
||||
init_var(&denominator);
|
||||
init_var(&significand);
|
||||
|
||||
int8_to_numericvar((int64) 10, &denominator);
|
||||
power_var_int(&denominator, exponent, &denominator, denom_scale);
|
||||
div_var(var, &denominator, &significand, rscale, true);
|
||||
sig_out = get_str_from_var(&significand, rscale);
|
||||
|
||||
free_var(&denominator);
|
||||
free_var(&significand);
|
||||
|
||||
/*
|
||||
* Allocate space for the result.
|
||||
*
|
||||
* In addition to the significand, we need room for the exponent decoration
|
||||
* ("e"), the sign of the exponent, up to 10 digits for the exponent
|
||||
* itself, and of course the null terminator.
|
||||
*/
|
||||
len = strlen(sig_out) + 13;
|
||||
str = palloc(len);
|
||||
snprintf(str, len, "%se%+03d", sig_out, exponent);
|
||||
|
||||
pfree(sig_out);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* make_result() -
|
||||
|
Reference in New Issue
Block a user