select 5.0 / 2
, pg_typeof(5.0 / 2);
pg_typeof | |
---|---|
2.5000000000000000 | numeric |
Why the result is 2.5000000000000000
?
When we insert 2.5
into a numeric
column or select 2.5
from a numeric column we don't get extra zeroes, we just get 2.5
.
I expected 2.5
with scale of 1, without the extra 0
's all the way up to scale of 16.
The operator responsible for numeric/numeric
division defaults to scale of 16
. It's not explicitly stated in the doc, although there is a hint: that exact scale being shown in the example.
numeric_type / numeric_type → numeric_type
Division (for integral types, division truncates the result towards zero)
5.0 / 2 → 2.5000000000000000
In cases like this, you can always take a look at the source to clarify things. Before going into that, I'll mention that the table linked above lists a few functions that might interest you:
min_scale ( numeric ) → integer
Minimum scale (number of fractional decimal digits) needed to represent the supplied value precisely
min_scale(8.4100) → 2
scale ( numeric ) → integer
Scale of the argument (the number of decimal digits in the fractional part)
scale(8.4100) → 4
trim_scale ( numeric ) → numeric
Reduces the value's scale (number of fractional decimal digits) by removing trailing zeroes
trim_scale(8.4100) → 8.41
You can use them to inspect, estimate and apply the minimum scale automatically. You can also use a cast with precision and scale specified as typemod in parentheses ::numeric(2,1)
:
demo at db<>fiddle
select a
, b
, numeric_div_result
, scale(numeric_div_result)
, min_scale(numeric_div_result)
, trim_scale(numeric_div_result)
, "::numeric(2,1)"
from(values(5.,2)
,(5.,4)
,(0.,1)
,(1.,3)
,(31,29.)
,(31,29+0e-21))as val(a,b)
cross join lateral(select a/b as numeric_div_result)
cross join lateral(select numeric_div_result::numeric(2,1) as "::numeric(2,1)");
a | b | numeric_div_result | scale | min_scale | trim_scale | ::numeric(2,1) |
---|---|---|---|---|---|---|
5 | 2 | 2.5000000000000000 | 16 | 1 | 2.5 | 2.5 |
5 | 4 | 1.2500000000000000 | 16 | 2 | 1.25 | 1.3 |
0 | 1 | 0.00000000000000000000 | 20 | 0 | 0 | 0.0 |
1 | 3 | 0.33333333333333333333 | 20 | 20 | 0.33333333333333333333 | 0.3 |
31 | 29 | 1.0689655172413793 | 16 | 16 | 1.0689655172413793 | 1.1 |
The second example shows why trim_scale()
might be better than assuming a target scale in a fixed cast. The last example shows the trick with the addition of a high-precision zero to force a higher precision result:
a | b | numeric_div_result | scale | min_scale | trim_scale | ::numeric(2,1) |
---|---|---|---|---|---|---|
31 | 29.000000000000000000000 | 1.068965517241379310345 | 21 | 21 | 1.068965517241379310345 | 1.1 |
A fun addition is 1/998001: the digits of its result are a repeating sequence of all three-digit numbers except 998. Unfortunately, it runs out of the 1000 NUMERIC_MAX_PRECISION
limiting division results, before getting very far:
select 1/(998001+0e-1337);
0.0000010020030040050060070080090100110120130140150160170180190200210220230240250260270280290300310320330340350360370380390400410420430440450460470480490500510520530540550560570580590600610620630640650660670680690700710720730740750760770780790800810820830840850860870880890900910920930940950960970980991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323 |
If you're wondering why numeric/int
division ends up executing a numeric/numeric
, refer to Chapter 10. Type Conversion: 10.2. Operators. There's no built-in numeric/int
operator, so the right operand has to be converted.
The reason a literal 5.0
is a numeric
and not real
, float
, smallint
, int
or bigint
, while 2
is an int
and none of the other two integer types, can be found in 4.1.2.6. Numeric Constants:
A numeric constant that contains neither a decimal point nor an exponent is initially presumed to be type
integer
if its value fits in typeinteger
(32 bits); otherwise it is presumed to be typebigint
if its value fits in typebigint
(64 bits); otherwise it is taken to be typenumeric
.
This is a similar thread to this one:
The difference is that it's the opposite question: that one's about maximising the scale, this one's about reducing it. In both cases the starting point is about the same: postgres/src/include/utils /numeric.h:45
:
/*
* For inherently inexact calculations such as division and square root,
* we try to get at least this many significant digits; the idea is to
* deliver a result no worse than float8 would.
*/
#define NUMERIC_MIN_SIG_DIGITS 16
It's used by select_div_scale
in postgres/src/backend/utils/adt /numeric.c:10128
/*
* Default scale selection for division
*
* Returns the appropriate result scale for the division result.
*/
static int
select_div_scale(const NumericVar *var1, const NumericVar *var2)
Which is called by numeric_div
found in postgres/src/backend/utils/adt/numeric.c:3133
:
/*
* numeric_div() -
*
* Divide one numeric into another
*/
Datum
numeric_div(PG_FUNCTION_ARGS)
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
res = numeric_div_opt_error(num1, num2, NULL);
PG_RETURN_NUMERIC(res);
}
And that's the real function behind numeric/numeric
operator you see in pg_operator.oprcode
:
select oid::regoperator
,oprcode
from pg_operator
where oprname='/'
and oprleft='numeric'::regtype
and oprright='numeric'::regtype;
oid | oprcode |
---|---|
/(numeric,numeric) | numeric_div |
The 1.0/3
in the example from the other thread does a bit more, but in your case NUMERIC_MIN_SIG_DIGITS
is where the scale estimation ends. Note that this default scale isn't the same one as the default scale of numeric
type, as described in the doc:
Specifying:
NUMERIC
without any precision or scale creates an “unconstrained numeric” column in which numeric values of any length can be stored, up to the implementation limits. A column of this kind will not coerce input values to any particular scale, whereas numeric columns with a declared scale will coerce input values to that scale.
What NUMERIC_MIN_SIG_DIGITS
dictates here is only the scale of the result of division using /
.