Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite532b1d

Browse files
committed
Fix power() for infinity inputs some more.
Buildfarm results for commitdecbe2b show that AIX and illumoshave non-POSIX-compliant pow() functions, as do ancient NetBSDand HPUX releases. While it's dubious how much we should careabout the latter two platforms, the former two are probably enoughreason to put in manual handling of infinite-input cases. Hence,do so, and clean up the post-pow() error handling to reflect itsnow-more-limited scope. (Notably, while we no longer expect toever see EDOM from pow(), report it as a domain error if we do.The former coding had the net effect of expensively converting theerror to ERANGE, which seems highly questionable: if pow() wantedto report ERANGE, it would have done so.)Patch by me; thanks to Michael Paquier for review.Discussion:https://postgr.es/m/E1jkU7H-00024V-NZ@gemulon.postgresql.org
1 parent7a3543c commite532b1d

File tree

3 files changed

+94
-23
lines changed

3 files changed

+94
-23
lines changed

‎src/backend/utils/adt/float.c‎

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,33 +1540,101 @@ dpow(PG_FUNCTION_ARGS)
15401540
errmsg("a negative number raised to a non-integer power yields a complex result")));
15411541

15421542
/*
1543-
* pow() sets errno only on some platforms, depending on whether it
1544-
* follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using
1545-
* errno. However, some platform/CPU combinations return errno == EDOM
1546-
* and result == NaN for negative arg1 and very large arg2 (they must be
1547-
* using something different from our floor() test to decide it's
1548-
* invalid). Other platforms (HPPA) return errno == ERANGE and a large
1549-
* (HUGE_VAL) but finite result to signal overflow.
1543+
* We don't trust the platform's pow() to handle infinity cases per POSIX
1544+
* spec either, so deal with those explicitly too. It's easier to handle
1545+
* infinite y first, so that it doesn't matter if x is also infinite.
15501546
*/
1551-
errno=0;
1552-
result=pow(arg1,arg2);
1553-
if (errno==EDOM&&isnan(result))
1547+
if (isinf(arg2))
15541548
{
1555-
if ((fabs(arg1)>1&&arg2 >=0)|| (fabs(arg1)<1&&arg2<0))
1556-
/* The sign of Inf is not significant in this case. */
1557-
result=get_float8_infinity();
1558-
elseif (fabs(arg1)!=1)
1559-
result=0;
1560-
else
1561-
result=1;
1549+
doubleabsx=fabs(arg1);
1550+
1551+
if (absx==1.0)
1552+
result=1.0;
1553+
elseif (arg2>0.0)/* y = +Inf */
1554+
{
1555+
if (absx>1.0)
1556+
result=arg2;
1557+
else
1558+
result=0.0;
1559+
}
1560+
else/* y = -Inf */
1561+
{
1562+
if (absx>1.0)
1563+
result=0.0;
1564+
else
1565+
result=-arg2;
1566+
}
15621567
}
1563-
elseif (errno==ERANGE&&result!=0&& !isinf(result))
1564-
result=get_float8_infinity();
1568+
elseif (isinf(arg1))
1569+
{
1570+
if (arg2==0.0)
1571+
result=1.0;
1572+
elseif (arg1>0.0)/* x = +Inf */
1573+
{
1574+
if (arg2>0.0)
1575+
result=arg1;
1576+
else
1577+
result=0.0;
1578+
}
1579+
else/* x = -Inf */
1580+
{
1581+
boolyisoddinteger= false;
15651582

1566-
if (unlikely(isinf(result))&& !isinf(arg1)&& !isinf(arg2))
1567-
float_overflow_error();
1568-
if (unlikely(result==0.0)&&arg1!=0.0&& !isinf(arg1)&& !isinf(arg2))
1569-
float_underflow_error();
1583+
if (arg2==floor(arg2))
1584+
{
1585+
/* y is integral; it's odd if y/2 is not integral */
1586+
doublehalfy=arg2*0.5;/* should be computed exactly */
1587+
1588+
if (halfy!=floor(halfy))
1589+
yisoddinteger= true;
1590+
}
1591+
if (arg2>0.0)
1592+
result=yisoddinteger ?arg1 :-arg1;
1593+
else
1594+
result=yisoddinteger ?-0.0 :0.0;
1595+
}
1596+
}
1597+
else
1598+
{
1599+
/*
1600+
* pow() sets errno on only some platforms, depending on whether it
1601+
* follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we must check both
1602+
* errno and invalid output values. (We can't rely on just the
1603+
* latter, either; some old platforms return a large-but-finite
1604+
* HUGE_VAL when reporting overflow.)
1605+
*/
1606+
errno=0;
1607+
result=pow(arg1,arg2);
1608+
if (errno==EDOM||isnan(result))
1609+
{
1610+
/*
1611+
* We eliminated all the possible domain errors above, or should
1612+
* have; but if pow() has a more restrictive test for "is y an
1613+
* integer?" than we do, we could get here anyway. Historical
1614+
* evidence suggests that some platforms once implemented the test
1615+
* as "y == (long) y", which of course misbehaves beyond LONG_MAX.
1616+
* There's not a lot of choice except to accept the platform's
1617+
* conclusion that we have a domain error.
1618+
*/
1619+
ereport(ERROR,
1620+
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
1621+
errmsg("a negative number raised to a non-integer power yields a complex result")));
1622+
}
1623+
elseif (errno==ERANGE)
1624+
{
1625+
if (result!=0.0)
1626+
float_overflow_error();
1627+
else
1628+
float_underflow_error();
1629+
}
1630+
else
1631+
{
1632+
if (unlikely(isinf(result)))
1633+
float_overflow_error();
1634+
if (unlikely(result==0.0)&&arg1!=0.0)
1635+
float_underflow_error();
1636+
}
1637+
}
15701638

15711639
PG_RETURN_FLOAT8(result);
15721640
}

‎src/test/regress/expected/float8.out‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,8 @@ SELECT power(float8 '-inf', float8 '3');
525525
-Infinity
526526
(1 row)
527527

528+
SELECT power(float8 '-inf', float8 '3.5');
529+
ERROR: a negative number raised to a non-integer power yields a complex result
528530
SELECT power(float8 '-inf', float8 'inf');
529531
power
530532
----------

‎src/test/regress/sql/float8.sql‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ SELECT power(float8 '-inf', float8 '-2');
144144
SELECT power(float8'-inf', float8'-3');
145145
SELECT power(float8'-inf', float8'2');
146146
SELECT power(float8'-inf', float8'3');
147+
SELECT power(float8'-inf', float8'3.5');
147148
SELECT power(float8'-inf', float8'inf');
148149
SELECT power(float8'-inf', float8'-inf');
149150

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp