mirror of
https://github.com/postgres/postgres.git
synced 2025-04-22 23:02:54 +03:00
Avoid wrong results for power() with NaN input on some platforms.
Per spec, the result of power() should be NaN if either input is NaN. It appears that on some versions of Windows, the libc function does return NaN, but it also sets errno = EDOM, confusing our code that attempts to work around shortcomings of other platforms. Hence, add guard tests to avoid substituting a wrong result for the right one. It's been like this for a long time (and the odd behavior only appears in older MSVC releases, too) so back-patch to all supported branches. Dang Minh Huong, reviewed by David Rowley Discussion: https://postgr.es/m/75DB81BEEA95B445AE6D576A0A5C9E936A73E741@BPXM05GP.gisp.nec.co.jp
This commit is contained in:
parent
85475afdb6
commit
61b200e2f5
@ -1566,14 +1566,15 @@ dpow(PG_FUNCTION_ARGS)
|
|||||||
* pow() sets errno only on some platforms, depending on whether it
|
* pow() sets errno only on some platforms, depending on whether it
|
||||||
* follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using
|
* follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using
|
||||||
* errno. However, some platform/CPU combinations return errno == EDOM
|
* errno. However, some platform/CPU combinations return errno == EDOM
|
||||||
* and result == Nan for negative arg1 and very large arg2 (they must be
|
* and result == NaN for negative arg1 and very large arg2 (they must be
|
||||||
* using something different from our floor() test to decide it's
|
* using something different from our floor() test to decide it's
|
||||||
* invalid). Other platforms (HPPA) return errno == ERANGE and a large
|
* invalid). Other platforms (HPPA) return errno == ERANGE and a large
|
||||||
* (HUGE_VAL) but finite result to signal overflow.
|
* (HUGE_VAL) but finite result to signal overflow. Also, some versions
|
||||||
|
* of MSVC return errno == EDOM and result == NaN for NaN inputs.
|
||||||
*/
|
*/
|
||||||
errno = 0;
|
errno = 0;
|
||||||
result = pow(arg1, arg2);
|
result = pow(arg1, arg2);
|
||||||
if (errno == EDOM && isnan(result))
|
if (errno == EDOM && isnan(result) && !isnan(arg1) && !isnan(arg2))
|
||||||
{
|
{
|
||||||
if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
|
if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
|
||||||
/* The sign of Inf is not significant in this case. */
|
/* The sign of Inf is not significant in this case. */
|
||||||
|
@ -340,6 +340,36 @@ SELECT power(float8 '144', float8 '0.5');
|
|||||||
12
|
12
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0.5');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '144', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- take exp of ln(f.f1)
|
-- take exp of ln(f.f1)
|
||||||
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
||||||
FROM FLOAT8_TBL f
|
FROM FLOAT8_TBL f
|
||||||
|
@ -344,6 +344,36 @@ SELECT power(float8 '144', float8 '0.5');
|
|||||||
12
|
12
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0.5');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '144', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- take exp of ln(f.f1)
|
-- take exp of ln(f.f1)
|
||||||
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
||||||
FROM FLOAT8_TBL f
|
FROM FLOAT8_TBL f
|
||||||
|
@ -344,6 +344,36 @@ SELECT power(float8 '144', float8 '0.5');
|
|||||||
12
|
12
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0.5');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '144', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- take exp of ln(f.f1)
|
-- take exp of ln(f.f1)
|
||||||
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
||||||
FROM FLOAT8_TBL f
|
FROM FLOAT8_TBL f
|
||||||
|
@ -340,6 +340,36 @@ SELECT power(float8 '144', float8 '0.5');
|
|||||||
12
|
12
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0.5');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '144', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 'NaN', float8 '0');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- take exp of ln(f.f1)
|
-- take exp of ln(f.f1)
|
||||||
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
||||||
FROM FLOAT8_TBL f
|
FROM FLOAT8_TBL f
|
||||||
|
@ -108,6 +108,11 @@ SELECT '' AS three, f.f1, |/f.f1 AS sqrt_f1
|
|||||||
|
|
||||||
-- power
|
-- power
|
||||||
SELECT power(float8 '144', float8 '0.5');
|
SELECT power(float8 '144', float8 '0.5');
|
||||||
|
SELECT power(float8 'NaN', float8 '0.5');
|
||||||
|
SELECT power(float8 '144', float8 'NaN');
|
||||||
|
SELECT power(float8 'NaN', float8 'NaN');
|
||||||
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
|
SELECT power(float8 'NaN', float8 '0');
|
||||||
|
|
||||||
-- take exp of ln(f.f1)
|
-- take exp of ln(f.f1)
|
||||||
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
SELECT '' AS three, f.f1, exp(ln(f.f1)) AS exp_ln_f1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user