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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user