mirror of
https://github.com/postgres/postgres.git
synced 2025-05-11 05:41:32 +03:00
Avoid wrong results for power() with NaN input on more platforms.
Buildfarm results show that the modern POSIX rule that 1 ^ NaN = 1 is not honored on *BSD until relatively recently, and really old platforms don't believe that NaN ^ 0 = 1 either. (This is unsurprising, perhaps, since SUSv2 doesn't require either behavior.) In hopes of getting to platform independent behavior, let's deal with all the NaN-input cases explicitly in dpow(). Note that numeric_power() doesn't know either of these special cases. But since that behavior is platform-independent, I think it should be addressed separately, and probably not back-patched. Discussion: https://postgr.es/m/75DB81BEEA95B445AE6D576A0A5C9E936A73E741@BPXM05GP.gisp.nec.co.jp
This commit is contained in:
parent
2acbeea48c
commit
d6ec3d2375
@ -1461,6 +1461,25 @@ dpow(PG_FUNCTION_ARGS)
|
|||||||
float8 arg2 = PG_GETARG_FLOAT8(1);
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
||||||
float8 result;
|
float8 result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other
|
||||||
|
* cases with NaN inputs yield NaN (with no error). Many older platforms
|
||||||
|
* get one or more of these cases wrong, so deal with them via explicit
|
||||||
|
* logic rather than trusting pow(3).
|
||||||
|
*/
|
||||||
|
if (isnan(arg1))
|
||||||
|
{
|
||||||
|
if (isnan(arg2) || arg2 != 0.0)
|
||||||
|
PG_RETURN_FLOAT8(get_float8_nan());
|
||||||
|
PG_RETURN_FLOAT8(1.0);
|
||||||
|
}
|
||||||
|
if (isnan(arg2))
|
||||||
|
{
|
||||||
|
if (arg1 != 1.0)
|
||||||
|
PG_RETURN_FLOAT8(get_float8_nan());
|
||||||
|
PG_RETURN_FLOAT8(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The SQL spec requires that we emit a particular SQLSTATE error code for
|
* The SQL spec requires that we emit a particular SQLSTATE error code for
|
||||||
* certain error conditions. Specifically, we don't return a
|
* certain error conditions. Specifically, we don't return a
|
||||||
@ -1482,12 +1501,11 @@ dpow(PG_FUNCTION_ARGS)
|
|||||||
* 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. Also, some versions
|
* (HUGE_VAL) but finite result to signal overflow.
|
||||||
* 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) && !isnan(arg1) && !isnan(arg2))
|
if (errno == EDOM && isnan(result))
|
||||||
{
|
{
|
||||||
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. */
|
||||||
|
@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN');
|
|||||||
NaN
|
NaN
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '-1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT power(float8 '1', float8 'NaN');
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
power
|
power
|
||||||
-------
|
-------
|
||||||
|
@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN');
|
|||||||
NaN
|
NaN
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '-1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT power(float8 '1', float8 'NaN');
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
power
|
power
|
||||||
-------
|
-------
|
||||||
|
@ -362,6 +362,12 @@ SELECT power(float8 'NaN', float8 'NaN');
|
|||||||
NaN
|
NaN
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '-1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT power(float8 '1', float8 'NaN');
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
power
|
power
|
||||||
-------
|
-------
|
||||||
|
@ -358,6 +358,12 @@ SELECT power(float8 'NaN', float8 'NaN');
|
|||||||
NaN
|
NaN
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SELECT power(float8 '-1', float8 'NaN');
|
||||||
|
power
|
||||||
|
-------
|
||||||
|
NaN
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT power(float8 '1', float8 'NaN');
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
power
|
power
|
||||||
-------
|
-------
|
||||||
|
@ -111,6 +111,7 @@ SELECT power(float8 '144', float8 '0.5');
|
|||||||
SELECT power(float8 'NaN', float8 '0.5');
|
SELECT power(float8 'NaN', float8 '0.5');
|
||||||
SELECT power(float8 '144', float8 'NaN');
|
SELECT power(float8 '144', float8 'NaN');
|
||||||
SELECT power(float8 'NaN', float8 'NaN');
|
SELECT power(float8 'NaN', float8 'NaN');
|
||||||
|
SELECT power(float8 '-1', float8 'NaN');
|
||||||
SELECT power(float8 '1', float8 'NaN');
|
SELECT power(float8 '1', float8 'NaN');
|
||||||
SELECT power(float8 'NaN', float8 '0');
|
SELECT power(float8 'NaN', float8 '0');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user