@@ -1524,18 +1524,23 @@ dacos(PG_FUNCTION_ARGS)
15241524float8 arg1 = PG_GETARG_FLOAT8 (0 );
15251525float8 result ;
15261526
1527+ /* Per the POSIX spec, return NaN if the input is NaN */
1528+ if (isnan (arg1 ))
1529+ PG_RETURN_FLOAT8 (get_float8_nan ());
1530+
15271531/*
1528- * We use errno here because the trigonometric functions are cyclic and
1529- * hard to check for underflow.
1532+ * The principal branch of the inverse cosine function maps values in the
1533+ * range [-1, 1] to values in the range [0, Pi], so we should reject any
1534+ * inputs outside that range and the result will always be finite.
15301535 */
1531- errno = 0 ;
1532- result = acos (arg1 );
1533- if (errno != 0 )
1536+ if (arg1 < -1.0 || arg1 > 1.0 )
15341537ereport (ERROR ,
15351538(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
15361539errmsg ("input is out of range" )));
15371540
1538- CHECKFLOATVAL (result ,isinf (arg1 ), true);
1541+ result = acos (arg1 );
1542+
1543+ CHECKFLOATVAL (result , false, true);
15391544PG_RETURN_FLOAT8 (result );
15401545}
15411546
@@ -1549,14 +1554,23 @@ dasin(PG_FUNCTION_ARGS)
15491554float8 arg1 = PG_GETARG_FLOAT8 (0 );
15501555float8 result ;
15511556
1552- errno = 0 ;
1553- result = asin (arg1 );
1554- if (errno != 0 )
1557+ /* Per the POSIX spec, return NaN if the input is NaN */
1558+ if (isnan (arg1 ))
1559+ PG_RETURN_FLOAT8 (get_float8_nan ());
1560+
1561+ /*
1562+ * The principal branch of the inverse sine function maps values in the
1563+ * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
1564+ * any inputs outside that range and the result will always be finite.
1565+ */
1566+ if (arg1 < -1.0 || arg1 > 1.0 )
15551567ereport (ERROR ,
15561568(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
15571569errmsg ("input is out of range" )));
15581570
1559- CHECKFLOATVAL (result ,isinf (arg1 ), true);
1571+ result = asin (arg1 );
1572+
1573+ CHECKFLOATVAL (result , false, true);
15601574PG_RETURN_FLOAT8 (result );
15611575}
15621576
@@ -1570,14 +1584,18 @@ datan(PG_FUNCTION_ARGS)
15701584float8 arg1 = PG_GETARG_FLOAT8 (0 );
15711585float8 result ;
15721586
1573- errno = 0 ;
1587+ /* Per the POSIX spec, return NaN if the input is NaN */
1588+ if (isnan (arg1 ))
1589+ PG_RETURN_FLOAT8 (get_float8_nan ());
1590+
1591+ /*
1592+ * The principal branch of the inverse tangent function maps all inputs to
1593+ * values in the range [-Pi/2, Pi/2], so the result should always be
1594+ * finite, even if the input is infinite.
1595+ */
15741596result = atan (arg1 );
1575- if (errno != 0 )
1576- ereport (ERROR ,
1577- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1578- errmsg ("input is out of range" )));
15791597
1580- CHECKFLOATVAL (result ,isinf ( arg1 ) , true);
1598+ CHECKFLOATVAL (result ,false , true);
15811599PG_RETURN_FLOAT8 (result );
15821600}
15831601
@@ -1592,14 +1610,17 @@ datan2(PG_FUNCTION_ARGS)
15921610float8 arg2 = PG_GETARG_FLOAT8 (1 );
15931611float8 result ;
15941612
1595- errno = 0 ;
1613+ /* Per the POSIX spec, return NaN if either input is NaN */
1614+ if (isnan (arg1 )|| isnan (arg2 ))
1615+ PG_RETURN_FLOAT8 (get_float8_nan ());
1616+
1617+ /*
1618+ * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
1619+ * should always be finite, even if the inputs are infinite.
1620+ */
15961621result = atan2 (arg1 ,arg2 );
1597- if (errno != 0 )
1598- ereport (ERROR ,
1599- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1600- errmsg ("input is out of range" )));
16011622
1602- CHECKFLOATVAL (result ,isinf ( arg1 ) || isinf ( arg2 ) , true);
1623+ CHECKFLOATVAL (result ,false , true);
16031624PG_RETURN_FLOAT8 (result );
16041625}
16051626
@@ -1613,14 +1634,33 @@ dcos(PG_FUNCTION_ARGS)
16131634float8 arg1 = PG_GETARG_FLOAT8 (0 );
16141635float8 result ;
16151636
1637+ /* Per the POSIX spec, return NaN if the input is NaN */
1638+ if (isnan (arg1 ))
1639+ PG_RETURN_FLOAT8 (get_float8_nan ());
1640+
1641+ /*
1642+ * cos() is periodic and so theoretically can work for all finite inputs,
1643+ * but some implementations may choose to throw error if the input is so
1644+ * large that there are no significant digits in the result. So we should
1645+ * check for errors. POSIX allows an error to be reported either via
1646+ * errno or via fetestexcept(), but currently we only support checking
1647+ * errno. (fetestexcept() is rumored to report underflow unreasonably
1648+ * early on some platforms, so it's not clear that believing it would be a
1649+ * net improvement anyway.)
1650+ *
1651+ * For infinite inputs, POSIX specifies that the trigonometric functions
1652+ * should return a domain error; but we won't notice that unless the
1653+ * platform reports via errno, so also explicitly test for infinite
1654+ * inputs.
1655+ */
16161656errno = 0 ;
16171657result = cos (arg1 );
1618- if (errno != 0 )
1658+ if (errno != 0 || isinf ( arg1 ) )
16191659ereport (ERROR ,
16201660(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16211661errmsg ("input is out of range" )));
16221662
1623- CHECKFLOATVAL (result ,isinf ( arg1 ) , true);
1663+ CHECKFLOATVAL (result ,false , true);
16241664PG_RETURN_FLOAT8 (result );
16251665}
16261666
@@ -1634,15 +1674,20 @@ dcot(PG_FUNCTION_ARGS)
16341674float8 arg1 = PG_GETARG_FLOAT8 (0 );
16351675float8 result ;
16361676
1677+ /* Per the POSIX spec, return NaN if the input is NaN */
1678+ if (isnan (arg1 ))
1679+ PG_RETURN_FLOAT8 (get_float8_nan ());
1680+
1681+ /* Be sure to throw an error if the input is infinite --- see dcos() */
16371682errno = 0 ;
16381683result = tan (arg1 );
1639- if (errno != 0 )
1684+ if (errno != 0 || isinf ( arg1 ) )
16401685ereport (ERROR ,
16411686(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16421687errmsg ("input is out of range" )));
16431688
16441689result = 1.0 /result ;
1645- CHECKFLOATVAL (result , true/*cotan(pi/2 ) ==inf */ , true);
1690+ CHECKFLOATVAL (result , true/*cot(0 ) ==Inf */ , true);
16461691PG_RETURN_FLOAT8 (result );
16471692}
16481693
@@ -1656,14 +1701,19 @@ dsin(PG_FUNCTION_ARGS)
16561701float8 arg1 = PG_GETARG_FLOAT8 (0 );
16571702float8 result ;
16581703
1704+ /* Per the POSIX spec, return NaN if the input is NaN */
1705+ if (isnan (arg1 ))
1706+ PG_RETURN_FLOAT8 (get_float8_nan ());
1707+
1708+ /* Be sure to throw an error if the input is infinite --- see dcos() */
16591709errno = 0 ;
16601710result = sin (arg1 );
1661- if (errno != 0 )
1711+ if (errno != 0 || isinf ( arg1 ) )
16621712ereport (ERROR ,
16631713(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16641714errmsg ("input is out of range" )));
16651715
1666- CHECKFLOATVAL (result ,isinf ( arg1 ) , true);
1716+ CHECKFLOATVAL (result ,false , true);
16671717PG_RETURN_FLOAT8 (result );
16681718}
16691719
@@ -1677,9 +1727,14 @@ dtan(PG_FUNCTION_ARGS)
16771727float8 arg1 = PG_GETARG_FLOAT8 (0 );
16781728float8 result ;
16791729
1730+ /* Per the POSIX spec, return NaN if the input is NaN */
1731+ if (isnan (arg1 ))
1732+ PG_RETURN_FLOAT8 (get_float8_nan ());
1733+
1734+ /* Be sure to throw an error if the input is infinite --- see dcos() */
16801735errno = 0 ;
16811736result = tan (arg1 );
1682- if (errno != 0 )
1737+ if (errno != 0 || isinf ( arg1 ) )
16831738ereport (ERROR ,
16841739(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16851740errmsg ("input is out of range" )));