@@ -1524,18 +1524,23 @@ dacos(PG_FUNCTION_ARGS)
15241524 float8 arg1 = PG_GETARG_FLOAT8 (0 );
15251525 float8 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 )
15341537 ereport (ERROR ,
15351538 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
15361539 errmsg ("input is out of range" )));
15371540
1538- CHECKFLOATVAL (result , isinf (arg1 ), true);
1541+ result = acos (arg1 );
1542+
1543+ CHECKFLOATVAL (result , false, true);
15391544 PG_RETURN_FLOAT8 (result );
15401545}
15411546
@@ -1549,14 +1554,23 @@ dasin(PG_FUNCTION_ARGS)
15491554 float8 arg1 = PG_GETARG_FLOAT8 (0 );
15501555 float8 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 )
15551567 ereport (ERROR ,
15561568 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
15571569 errmsg ("input is out of range" )));
15581570
1559- CHECKFLOATVAL (result , isinf (arg1 ), true);
1571+ result = asin (arg1 );
1572+
1573+ CHECKFLOATVAL (result , false, true);
15601574 PG_RETURN_FLOAT8 (result );
15611575}
15621576
@@ -1570,14 +1584,18 @@ datan(PG_FUNCTION_ARGS)
15701584 float8 arg1 = PG_GETARG_FLOAT8 (0 );
15711585 float8 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+ */
15741596 result = 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);
15811599 PG_RETURN_FLOAT8 (result );
15821600}
15831601
@@ -1592,14 +1610,17 @@ datan2(PG_FUNCTION_ARGS)
15921610 float8 arg2 = PG_GETARG_FLOAT8 (1 );
15931611 float8 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+ */
15961621 result = 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);
16031624 PG_RETURN_FLOAT8 (result );
16041625}
16051626
@@ -1613,14 +1634,33 @@ dcos(PG_FUNCTION_ARGS)
16131634 float8 arg1 = PG_GETARG_FLOAT8 (0 );
16141635 float8 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+ */
16161656 errno = 0 ;
16171657 result = cos (arg1 );
1618- if (errno != 0 )
1658+ if (errno != 0 || isinf ( arg1 ) )
16191659 ereport (ERROR ,
16201660 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16211661 errmsg ("input is out of range" )));
16221662
1623- CHECKFLOATVAL (result , isinf ( arg1 ) , true);
1663+ CHECKFLOATVAL (result , false , true);
16241664 PG_RETURN_FLOAT8 (result );
16251665}
16261666
@@ -1634,15 +1674,20 @@ dcot(PG_FUNCTION_ARGS)
16341674 float8 arg1 = PG_GETARG_FLOAT8 (0 );
16351675 float8 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() */
16371682 errno = 0 ;
16381683 result = tan (arg1 );
1639- if (errno != 0 )
1684+ if (errno != 0 || isinf ( arg1 ) )
16401685 ereport (ERROR ,
16411686 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16421687 errmsg ("input is out of range" )));
16431688
16441689 result = 1.0 / result ;
1645- CHECKFLOATVAL (result , true /* cotan(pi/2 ) == inf */ , true);
1690+ CHECKFLOATVAL (result , true /* cot(0 ) == Inf */ , true);
16461691 PG_RETURN_FLOAT8 (result );
16471692}
16481693
@@ -1656,14 +1701,19 @@ dsin(PG_FUNCTION_ARGS)
16561701 float8 arg1 = PG_GETARG_FLOAT8 (0 );
16571702 float8 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() */
16591709 errno = 0 ;
16601710 result = sin (arg1 );
1661- if (errno != 0 )
1711+ if (errno != 0 || isinf ( arg1 ) )
16621712 ereport (ERROR ,
16631713 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16641714 errmsg ("input is out of range" )));
16651715
1666- CHECKFLOATVAL (result , isinf ( arg1 ) , true);
1716+ CHECKFLOATVAL (result , false , true);
16671717 PG_RETURN_FLOAT8 (result );
16681718}
16691719
@@ -1677,9 +1727,14 @@ dtan(PG_FUNCTION_ARGS)
16771727 float8 arg1 = PG_GETARG_FLOAT8 (0 );
16781728 float8 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() */
16801735 errno = 0 ;
16811736 result = tan (arg1 );
1682- if (errno != 0 )
1737+ if (errno != 0 || isinf ( arg1 ) )
16831738 ereport (ERROR ,
16841739 (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
16851740 errmsg ("input is out of range" )));
0 commit comments