1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Fix two edge cases in numeric log(base, val).

For log(base, +Infinity) where 0 < base < 1, the correct output
is -Infinity, not +Infinity as we had been giving.

log(1, x) is erroneous regardless of x.  Formerly we returned
+Infinity when x is +Infinity, and threw a rather confusing
"division by zero" error for finite-positive x.  Change both
cases to report "cannot take logarithm using base one".

While the cases with infinite inputs are clearly wrong, it's
not clear that people would appreciate such a behavior change
in stable branches, so fix master only.

Author: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/08270B8B-634F-4381-9D6F-9BDB18DA82A0@gmail.com
This commit is contained in:
Tom Lane
2026-10-15 11:25:10 -04:00
parent 30d4a6daac
commit 94e1385ed2
3 changed files with 33 additions and 3 deletions

View File

@@ -3885,8 +3885,18 @@ numeric_log(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(make_result(&const_zero));
}
Assert(NUMERIC_IS_PINF(num2));
/* log(finite-positive, Inf) is Inf */
PG_RETURN_NUMERIC(make_result(&const_pinf));
/*
* For a finite-positive base, log(base, Inf) = Inf / ln(base), so the
* sign depends on whether base is more or less than 1. If base = 1,
* fall through and let log_var report the error.
*/
init_var_from_num(num1, &arg1);
sign1 = cmp_var(&arg1, &const_one);
if (sign1 < 0)
PG_RETURN_NUMERIC(make_result(&const_ninf));
if (sign1 > 0)
PG_RETURN_NUMERIC(make_result(&const_pinf));
}
/*
@@ -10812,6 +10822,16 @@ log_var(const NumericVar *base, const NumericVar *num, NumericVar *result)
int ln_base_rscale;
int ln_num_rscale;
/*
* ln_var will throw a suitable error for most invalid-input cases, but we
* need a special case for base == 1, else we'd report "division by zero"
* which is a bit confusing.
*/
if (cmp_var(base, &const_one) == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
errmsg("cannot take logarithm using base one")));
init_var(&ln_base);
init_var(&ln_num);

View File

@@ -933,6 +933,14 @@ FROM v AS v1(x1), v AS v2(x2);
NaN | NaN | NaN
(16 rows)
SELECT log('0.5'::numeric, 'inf');
log
-----------
-Infinity
(1 row)
SELECT log('1'::numeric, 'inf');
ERROR: cannot take logarithm using base one
SELECT log('0'::numeric, '10');
ERROR: cannot take logarithm of zero
SELECT log('10'::numeric, '0');
@@ -3492,7 +3500,7 @@ ERROR: cannot take logarithm of zero
select log(12.34, 0.0);
ERROR: cannot take logarithm of zero
select log(1.0, 12.34);
ERROR: division by zero
ERROR: cannot take logarithm using base one
-- some random tests
select log(1.23e-89, 6.4689e45);
log

View File

@@ -713,6 +713,8 @@ SELECT x1, x2,
log(x1, x2)
FROM v AS v1(x1), v AS v2(x2);
SELECT log('0.5'::numeric, 'inf');
SELECT log('1'::numeric, 'inf');
SELECT log('0'::numeric, '10');
SELECT log('10'::numeric, '0');
SELECT log('-inf'::numeric, '10');