<entry><literal>2</literal></entry>
</row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>log10</primary>
+ </indexterm>
+ <literal><function>log10(<type>dp</type> or <type>numeric</type>)</function></literal>
+ </entry>
+ <entry>(same as input)</entry>
+ <entry>base 10 logarithm</entry>
+ <entry><literal>log10(100.0)</literal></entry>
+ <entry><literal>2</literal></entry>
+ </row>
+
<row>
<entry><literal><function>log(<parameter>b</parameter> <type>numeric</type>,
<parameter>x</parameter> <type>numeric</type>)</function></literal></entry>
</para>
<para>
- Finally, <xref linkend="functions-math-trig-table"/> shows the
- available trigonometric functions. All trigonometric functions
+ <xref linkend="functions-math-trig-table"/> shows the
+ available trigonometric functions. All these functions
take arguments and return values of type <type>double
precision</type>. Each of the trigonometric functions comes in
two variants, one that measures angles in radians and one that
</para>
</note>
+ <para>
+ <xref linkend="functions-math-hyp-table"/> shows the
+ available hyperbolic functions. All these functions
+ take arguments and return values of type <type>double
+ precision</type>.
+ </para>
+
+ <table id="functions-math-hyp-table">
+ <title>Hyperbolic Functions</title>
+
+ <tgroup cols="4">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>sinh</primary>
+ </indexterm>
+ <literal><function>sinh(<replaceable>x</replaceable>)</function></literal>
+ </entry>
+ <entry>hyperbolic sine</entry>
+ <entry><literal>sinh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>cosh</primary>
+ </indexterm>
+ <literal><function>cosh(<replaceable>x</replaceable>)</function></literal>
+ </entry>
+ <entry>hyperbolic cosine</entry>
+ <entry><literal>cosh(0)</literal></entry>
+ <entry><literal>1</literal></entry>
+ </row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>tanh</primary>
+ </indexterm>
+ <literal><function>tanh(<replaceable>x</replaceable>)</function></literal>
+ </entry>
+ <entry>hyperbolic tangent</entry>
+ <entry><literal>tanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>asinh</primary>
+ </indexterm>
+ <literal><function>asinh(<replaceable>x</replaceable>)</function></literal>
+ </entry>
+ <entry>inverse hyperbolic sine</entry>
+ <entry><literal>asinh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>acosh</primary>
+ </indexterm>
+ <literal><function>acosh(<replaceable>x</replaceable>)</function></literal>
+ </entry>
+ <entry>inverse hyperbolic cosine</entry>
+ <entry><literal>acosh(1)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>atanh</primary>
+ </indexterm>
+ <literal><function>atanh(<replaceable>x</replaceable>)</function></literal>
+ </entry>
+ <entry>inverse hyperbolic tangent</entry>
+ <entry><literal>atanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
</sect1>
* detect whether it's a "real" out-of-range condition by checking
* to see if the result is zero or huge.
*
- * Use isinf() rather than HUGE_VALF on VS2013 because it generates
- * a spurious overflow warning for -HUGE_VALF. Also use isinf() if
- * HUGE_VALF is missing.
+ * Use isinf() rather than HUGE_VALF on VS2013 because it
+ * generates a spurious overflow warning for -HUGE_VALF. Also use
+ * isinf() if HUGE_VALF is missing.
*/
if (val == 0.0 ||
#if !defined(HUGE_VALF) || (defined(_MSC_VER) && (_MSC_VER < 1900))
}
+/* ========== HYPERBOLIC FUNCTIONS ========== */
+
+
+/*
+ * dsinh - returns the hyperbolic sine of arg1
+ */
+Datum
+dsinh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ errno = 0;
+ result = sinh(arg1);
+
+ /*
+ * if an ERANGE error occurs, it means there is an overflow. For sinh,
+ * the result should be either -infinity or infinity, depending on the
+ * sign of arg1.
+ */
+ if (errno == ERANGE)
+ {
+ if (arg1 < 0)
+ result = -get_float8_infinity();
+ else
+ result = get_float8_infinity();
+ }
+
+ check_float8_val(result, true, true);
+ PG_RETURN_FLOAT8(result);
+}
+
+
+/*
+ * dcosh - returns the hyperbolic cosine of arg1
+ */
+Datum
+dcosh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ errno = 0;
+ result = cosh(arg1);
+
+ /*
+ * if an ERANGE error occurs, it means there is an overflow. As cosh is
+ * always positive, it always means the result is positive infinity.
+ */
+ if (errno == ERANGE)
+ result = get_float8_infinity();
+
+ check_float8_val(result, true, false);
+ PG_RETURN_FLOAT8(result);
+}
+
+/*
+ * dtanh - returns the hyperbolic tangent of arg1
+ */
+Datum
+dtanh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ /*
+ * For tanh, we don't need an errno check because it never overflows.
+ */
+ result = tanh(arg1);
+
+ check_float8_val(result, false, true);
+ PG_RETURN_FLOAT8(result);
+}
+
+/*
+ * dasinh - returns the inverse hyperbolic sine of arg1
+ */
+Datum
+dasinh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ /*
+ * For asinh, we don't need an errno check because it never overflows.
+ */
+ result = asinh(arg1);
+
+ check_float8_val(result, true, true);
+ PG_RETURN_FLOAT8(result);
+}
+
+/*
+ * dacosh - returns the inverse hyperbolic cosine of arg1
+ */
+Datum
+dacosh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ /*
+ * acosh is only defined for inputs >= 1.0. By checking this ourselves,
+ * we need not worry about checking for an EDOM error, which is a good
+ * thing because some implementations will report that for NaN. Otherwise,
+ * no error is possible.
+ */
+ if (arg1 < 1.0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("input is out of range")));
+
+ result = acosh(arg1);
+
+ check_float8_val(result, true, true);
+ PG_RETURN_FLOAT8(result);
+}
+
+/*
+ * datanh - returns the inverse hyperbolic tangent of arg1
+ */
+Datum
+datanh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ /*
+ * atanh is only defined for inputs between -1 and 1. By checking this
+ * ourselves, we need not worry about checking for an EDOM error, which is
+ * a good thing because some implementations will report that for NaN.
+ */
+ if (arg1 < -1.0 || arg1 > 1.0)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("input is out of range")));
+
+ /*
+ * Also handle the infinity cases ourselves; this is helpful because old
+ * glibc versions may produce the wrong errno for this. All other inputs
+ * cannot produce an error.
+ */
+ if (arg1 == -1.0)
+ result = -get_float8_infinity();
+ else if (arg1 == 1.0)
+ result = get_float8_infinity();
+ else
+ result = atanh(arg1);
+
+ check_float8_val(result, true, true);
+ PG_RETURN_FLOAT8(result);
+}
+
+
/*
* drandom - returns a random number
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201903101
+#define CATALOG_VERSION_NO 201903121
#endif
{ oid => '1340', descr => 'base 10 logarithm',
proname => 'log', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog10' },
+{ oid => '1194', descr => 'base 10 logarithm',
+ proname => 'log10', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'dlog10' },
{ oid => '1341', descr => 'natural logarithm',
proname => 'ln', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog1' },
{ oid => '1610', descr => 'PI',
proname => 'pi', prorettype => 'float8', proargtypes => '', prosrc => 'dpi' },
+{ oid => '2462', descr => 'hyperbolic sine',
+ proname => 'sinh', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'dsinh' },
+{ oid => '2463', descr => 'hyperbolic cosine',
+ proname => 'cosh', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'dcosh' },
+{ oid => '2464', descr => 'hyperbolic tangent',
+ proname => 'tanh', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'dtanh' },
+{ oid => '2465', descr => 'inverse hyperbolic sine',
+ proname => 'asinh', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'dasinh' },
+{ oid => '2466', descr => 'inverse hyperbolic cosine',
+ proname => 'acosh', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'dacosh' },
+{ oid => '2467', descr => 'inverse hyperbolic tangent',
+ proname => 'atanh', prorettype => 'float8', proargtypes => 'float8',
+ prosrc => 'datanh' },
+
{ oid => '1618',
proname => 'interval_mul', prorettype => 'interval',
proargtypes => 'interval float8', prosrc => 'interval_mul' },
{ oid => '1741', descr => 'base 10 logarithm',
proname => 'log', prolang => 'sql', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
+{ oid => '1481', descr => 'base 10 logarithm',
+ proname => 'log10', prolang => 'sql', prorettype => 'numeric',
+ proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
{ oid => '1742', descr => 'convert float4 to numeric',
proname => 'numeric', prorettype => 'numeric', proargtypes => 'float4',
prosrc => 'float4_numeric' },
| -1.2345678901234e-200
(5 rows)
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+ sinh
+------
+ 0
+(1 row)
+
+SELECT cosh(float8 '0');
+ cosh
+------
+ 1
+(1 row)
+
+SELECT tanh(float8 '0');
+ tanh
+------
+ 0
+(1 row)
+
+SELECT asinh(float8 '0');
+ asinh
+-------
+ 0
+(1 row)
+
+SELECT acosh(float8 '1');
+ acosh
+-------
+ 0
+(1 row)
+
+SELECT atanh(float8 '0');
+ atanh
+-------
+ 0
+(1 row)
+
RESET extra_float_digits;
-- test for over- and underflow
INSERT INTO FLOAT8_TBL(f1) VALUES ('10e400');
SELECT '' AS five, * FROM FLOAT8_TBL;
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+SELECT cosh(float8 '0');
+SELECT tanh(float8 '0');
+SELECT asinh(float8 '0');
+SELECT acosh(float8 '1');
+SELECT atanh(float8 '0');
+
RESET extra_float_digits;
-- test for over- and underflow