[Patch] Log10 and hyperbolic functions for SQL:2016 compliance
Hello hackers,
In his blog post (What's new in SQL 2016)[
https://modern-sql.com/blog/2017-06/whats-new-in-sql-2016], Markus Winand
explained some of the changes added to SQL:2016. I spotted that Postgres
was behind other RDBMS on hyperbolic functions and log10 function.
The log10 function existed but under the name log(<value>).
The new functions can be called in a simple select statement :
select log10(100);
select sinh(0);
select cosh(0);
select tanh(0);
Even if Markus Winand had added hyperbolic functions in the paragraph
"Trigonometric and Logarithmic Functions", I didn't add hyperbolic function
with the trigonometric functions in the documentation, because hyperbolic
functions are not trigonometric functions.
I added regression tests for the new functions, but I didn't for log10
function, assuming that if log function worked, log10 will work too.
You'll find enclosed the first version of the patch that can build
successfully on my laptop against master. I'm open to any improvement.
Cheers,
Lætitia
--
*Think! Do you really need to print this email ? *
*There is no Planet B.*
Attachments:
adding_log10_and_hyperbolic_functions_v1.patchtext/x-patch; charset=US-ASCII; name=adding_log10_and_hyperbolic_functions_v1.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4930ec17f6..94e3fcd4b9 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -896,6 +896,19 @@
<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>
@@ -1147,7 +1160,7 @@
</para>
<para>
- Finally, <xref linkend="functions-math-trig-table"/> shows the
+ <xref linkend="functions-math-trig-table"/> shows the
available trigonometric functions. All trigonometric functions
take arguments and return values of type <type>double
precision</type>. Each of the trigonometric functions comes in
@@ -1311,8 +1324,65 @@
</para>
</note>
- </sect1>
+ <para>
+ Finally, <xref linkend="functions-math-hyp-table"/> shows the
+ available hyperbolic functions.
+ </para>
+ <table id="functions-math-hyp-table">
+ <title>Hyperbolic Functions</title>
+
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Return Type</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>sinh</primary>
+ </indexterm>
+ <literal><function>sinh(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></entry>
+ <entry>hyperbolic tangent</entry>
+ <entry><literal>tanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
<sect1 id="functions-string">
<title>String Functions and Operators</title>
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 117ded8d1d..c83eed99c6 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2375,6 +2375,54 @@ radians(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
}
+/* ========== HYPERBOLIC FUNCTIONS ========== */
+
+/*
+ * dsinh - returns the hyperbolic sine of arg1
+ */
+Datum
+dsinh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ result = sinhf(arg1);
+
+ check_float8_val(result, isinf(arg1), 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;
+
+ result = coshf(arg1);
+
+ check_float8_val(result, isinf(arg1), 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;
+
+ errno = 0;
+ result = tanhf(arg1);
+
+ check_float8_val(result, false, true);
+ PG_RETURN_FLOAT8(result);
+}
/*
* drandom - returns a random number
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3ecc2e12c3..ca6b09a13d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2617,6 +2617,9 @@
{ oid => '1340', descr => 'base 10 logarithm',
proname => 'log', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog10' },
+{ oid => '1364', 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' },
@@ -3283,6 +3286,17 @@
{ 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 => '1618',
proname => 'interval_mul', prorettype => 'interval',
proargtypes => 'interval float8', prosrc => 'interval_mul' },
@@ -4195,6 +4209,9 @@
{ oid => '1741', descr => 'base 10 logarithm',
proname => 'log', prolang => 'sql', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
+{ oid => '2023', descr => 'base 10 logarithm',
+ proname => 'log10', prolang => '14', 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' },
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 75c0bf389b..4a9e0fb203 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -632,4 +632,77 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
10 | 0 | 0 | t
(5 rows)
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+ sinh
+------
+ 0
+(1 row)
+
+SELECT sinh(float8 'Infinity');
+ sinh
+----------
+ Infinity
+(1 row)
+
+SELECT sinh(float8 '-Infinity');
+ sinh
+-----------
+ -Infinity
+(1 row)
+
+SELECT sinh(float8 'NaN');
+ sinh
+------
+ NaN
+(1 row)
+
+SELECT cosh(float8 '0');
+ cosh
+------
+ 1
+(1 row)
+
+SELECT cosh(float8 'Infinity');
+ cosh
+----------
+ Infinity
+(1 row)
+
+SELECT cosh(float8 '-Infinity');
+ cosh
+----------
+ Infinity
+(1 row)
+
+SELECT cosh(float8 'NaN');
+ cosh
+------
+ NaN
+(1 row)
+
+SELECT tanh(float8 '0');
+ tanh
+------
+ 0
+(1 row)
+
+SELECT tanh(float8 'Infinity');
+ tanh
+------
+ 1
+(1 row)
+
+SELECT tanh(float8 '-Infinity');
+ tanh
+------
+ -1
+(1 row)
+
+SELECT tanh(float8 'NaN');
+ tanh
+------
+ NaN
+(1 row)
+
RESET extra_float_digits;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 6595fd2b95..56053d530d 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -232,4 +232,18 @@ SELECT x, y,
FROM (SELECT 10*cosd(a), 10*sind(a)
FROM generate_series(0, 360, 90) AS t(a)) AS t(x,y);
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+SELECT sinh(float8 'Infinity');
+SELECT sinh(float8 '-Infinity');
+SELECT sinh(float8 'NaN');
+SELECT cosh(float8 '0');
+SELECT cosh(float8 'Infinity');
+SELECT cosh(float8 '-Infinity');
+SELECT cosh(float8 'NaN');
+SELECT tanh(float8 '0');
+SELECT tanh(float8 'Infinity');
+SELECT tanh(float8 '-Infinity');
+SELECT tanh(float8 'NaN');
+
RESET extra_float_digits;
=?UTF-8?Q?L=C3=A6titia_Avrot?= <laetitia.avrot@gmail.com> writes:
[ adding_log10_and_hyperbolic_functions_v1.patch ]
No objection to the feature, but
- Why are you using the float4-width library functions (coshf etc)
rather than the float8-width ones (cosh etc)?
- I wonder whether these library functions exist everywhere.
If they don't, what will we do about it ... throw an error?
I see that SUSv2 requires cosh() and so on, so it's quite possible
that these do exist everywhere we care about. I'd be okay with
throwing a patch onto the buildfarm to see, and adding an autoconf
test only if the buildfarm is unhappy. But we should be clear on
what we're going to do about it if that happens.
I added regression tests for the new functions, but I didn't for log10
function, assuming that if log function worked, log10 will work too.
Not quite sure I believe that.
Actually, what I'd counsel is that you *not* include tests of what
these do with Inf and NaN. There is no upside to doing so, and lots
of downside if older platforms are squirrely in their behavior, which
is hardly unlikely (cf opossum ...)
regards, tom lane
Hi,
Thanks for your time and advice, Tom!
[ adding_log10_and_hyperbolic_functions_v1.patch ]
No objection to the feature, but
- Why are you using the float4-width library functions (coshf etc)
rather than the float8-width ones (cosh etc)?Well, I guess the only reason is that I wasn't paying attention enough...
I changed for the float8-width library functions.
- I wonder whether these library functions exist everywhere.
If they don't, what will we do about it ... throw an error?I see that SUSv2 requires cosh() and so on, so it's quite possible
that these do exist everywhere we care about. I'd be okay with
throwing a patch onto the buildfarm to see, and adding an autoconf
test only if the buildfarm is unhappy. But we should be clear on
what we're going to do about it if that happens.I think I was too confident because of the "it works on my laptop"
syndrome... I don't know how to answer to this point.
I added regression tests for the new functions, but I didn't for log10
function, assuming that if log function worked, log10 will work too.Not quite sure I believe that.
Do you mean I should also add a regression test for the new log10 function
too ?
Actually, what I'd counsel is that you *not* include tests of what
these do with Inf and NaN. There is no upside to doing so, and lots
of downside if older platforms are squirrely in their behavior, which
is hardly unlikely (cf opossum ...)
I changed the regression tests for hyperbolic functions, so it doesn't test
for Inf and NaN.
You'll find enclosed the new version of the patch.
Cheers,
Lætitia
Attachments:
adding_log10_and_hyperbolic_functions_v2.patchtext/x-patch; charset=US-ASCII; name=adding_log10_and_hyperbolic_functions_v2.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4930ec17f6..94e3fcd4b9 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -896,6 +896,19 @@
<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>
@@ -1147,7 +1160,7 @@
</para>
<para>
- Finally, <xref linkend="functions-math-trig-table"/> shows the
+ <xref linkend="functions-math-trig-table"/> shows the
available trigonometric functions. All trigonometric functions
take arguments and return values of type <type>double
precision</type>. Each of the trigonometric functions comes in
@@ -1311,8 +1324,65 @@
</para>
</note>
- </sect1>
+ <para>
+ Finally, <xref linkend="functions-math-hyp-table"/> shows the
+ available hyperbolic functions.
+ </para>
+ <table id="functions-math-hyp-table">
+ <title>Hyperbolic Functions</title>
+
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Return Type</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>sinh</primary>
+ </indexterm>
+ <literal><function>sinh(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></entry>
+ <entry>hyperbolic tangent</entry>
+ <entry><literal>tanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
<sect1 id="functions-string">
<title>String Functions and Operators</title>
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 117ded8d1d..7712c3d5bd 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2375,6 +2375,54 @@ radians(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
}
+/* ========== HYPERBOLIC FUNCTIONS ========== */
+
+/*
+ * dsinh - returns the hyperbolic sine of arg1
+ */
+Datum
+dsinh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ result = sinh(arg1);
+
+ check_float8_val(result, isinf(arg1), 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;
+
+ result = cosh(arg1);
+
+ check_float8_val(result, isinf(arg1), 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;
+
+ errno = 0;
+ result = tanh(arg1);
+
+ check_float8_val(result, false, true);
+ PG_RETURN_FLOAT8(result);
+}
/*
* drandom - returns a random number
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3ecc2e12c3..ca6b09a13d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2617,6 +2617,9 @@
{ oid => '1340', descr => 'base 10 logarithm',
proname => 'log', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog10' },
+{ oid => '1364', 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' },
@@ -3283,6 +3286,17 @@
{ 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 => '1618',
proname => 'interval_mul', prorettype => 'interval',
proargtypes => 'interval float8', prosrc => 'interval_mul' },
@@ -4195,6 +4209,9 @@
{ oid => '1741', descr => 'base 10 logarithm',
proname => 'log', prolang => 'sql', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
+{ oid => '2023', descr => 'base 10 logarithm',
+ proname => 'log10', prolang => '14', 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' },
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 75c0bf389b..3f76929591 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -632,4 +632,23 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
10 | 0 | 0 | t
(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)
+
RESET extra_float_digits;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 6595fd2b95..b099ae6321 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -232,4 +232,9 @@ SELECT x, y,
FROM (SELECT 10*cosd(a), 10*sind(a)
FROM generate_series(0, 360, 90) AS t(a)) AS t(x,y);
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+SELECT cosh(float8 '0');
+SELECT tanh(float8 '0');
+
RESET extra_float_digits;
Hi,
Thanks to Emil Iggland's kind review, I added precision on documentation
for hyperbolic functions.
I added the patch to the next commitfest.
Cheers,
Lætitia
Le dim. 27 janv. 2019 à 20:39, Lætitia Avrot <laetitia.avrot@gmail.com> a
écrit :
Hi,
Thanks for your time and advice, Tom!
[ adding_log10_and_hyperbolic_functions_v1.patch ]
No objection to the feature, but
- Why are you using the float4-width library functions (coshf etc)
rather than the float8-width ones (cosh etc)?Well, I guess the only reason is that I wasn't paying attention enough...
I changed for the float8-width library functions.
- I wonder whether these library functions exist everywhere.
If they don't, what will we do about it ... throw an error?I see that SUSv2 requires cosh() and so on, so it's quite possible
that these do exist everywhere we care about. I'd be okay with
throwing a patch onto the buildfarm to see, and adding an autoconf
test only if the buildfarm is unhappy. But we should be clear on
what we're going to do about it if that happens.I think I was too confident because of the "it works on my laptop"
syndrome... I don't know how to answer to this point.
I added regression tests for the new functions, but I didn't for log10
function, assuming that if log function worked, log10 will work too.Not quite sure I believe that.
Do you mean I should also add a regression test for the new log10
function too ?
Actually, what I'd counsel is that you *not* include tests of what
these do with Inf and NaN. There is no upside to doing so, and lots
of downside if older platforms are squirrely in their behavior, which
is hardly unlikely (cf opossum ...)I changed the regression tests for hyperbolic functions, so it doesn't
test for Inf and NaN.You'll find enclosed the new version of the patch.
Cheers,
Lætitia
--
*Think! Do you really need to print this email ? *
*There is no Planet B.*
Attachments:
adding_log10_and_hyperbolic_functions_v3.patchtext/x-patch; charset=US-ASCII; name=adding_log10_and_hyperbolic_functions_v3.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4930ec17f6..30ecf496ca 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -896,6 +896,19 @@
<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>
@@ -1147,7 +1160,7 @@
</para>
<para>
- Finally, <xref linkend="functions-math-trig-table"/> shows the
+ <xref linkend="functions-math-trig-table"/> shows the
available trigonometric functions. All trigonometric functions
take arguments and return values of type <type>double
precision</type>. Each of the trigonometric functions comes in
@@ -1311,8 +1324,66 @@
</para>
</note>
- </sect1>
+ <para>
+ Finally, <xref linkend="functions-math-hyp-table"/> shows the
+ available hyperbolic functions. All hyperbolic functions apply to
+ hyperbolic angles expressed in hyperbolic radians.
+ </para>
+ <table id="functions-math-hyp-table">
+ <title>Hyperbolic Functions</title>
+
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Return Type</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>sinh</primary>
+ </indexterm>
+ <literal><function>sinh(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></entry>
+ <entry>hyperbolic tangent</entry>
+ <entry><literal>tanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
<sect1 id="functions-string">
<title>String Functions and Operators</title>
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 117ded8d1d..7712c3d5bd 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2375,6 +2375,54 @@ radians(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
}
+/* ========== HYPERBOLIC FUNCTIONS ========== */
+
+/*
+ * dsinh - returns the hyperbolic sine of arg1
+ */
+Datum
+dsinh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ result = sinh(arg1);
+
+ check_float8_val(result, isinf(arg1), 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;
+
+ result = cosh(arg1);
+
+ check_float8_val(result, isinf(arg1), 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;
+
+ errno = 0;
+ result = tanh(arg1);
+
+ check_float8_val(result, false, true);
+ PG_RETURN_FLOAT8(result);
+}
/*
* drandom - returns a random number
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3ecc2e12c3..ca6b09a13d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2617,6 +2617,9 @@
{ oid => '1340', descr => 'base 10 logarithm',
proname => 'log', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog10' },
+{ oid => '1364', 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' },
@@ -3283,6 +3286,17 @@
{ 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 => '1618',
proname => 'interval_mul', prorettype => 'interval',
proargtypes => 'interval float8', prosrc => 'interval_mul' },
@@ -4195,6 +4209,9 @@
{ oid => '1741', descr => 'base 10 logarithm',
proname => 'log', prolang => 'sql', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
+{ oid => '2023', descr => 'base 10 logarithm',
+ proname => 'log10', prolang => '14', 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' },
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 75c0bf389b..3f76929591 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -632,4 +632,23 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
10 | 0 | 0 | t
(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)
+
RESET extra_float_digits;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 6595fd2b95..b099ae6321 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -232,4 +232,9 @@ SELECT x, y,
FROM (SELECT 10*cosd(a), 10*sind(a)
FROM generate_series(0, 360, 90) AS t(a)) AS t(x,y);
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+SELECT cosh(float8 '0');
+SELECT tanh(float8 '0');
+
RESET extra_float_digits;
On 2019-Jan-31, L�titia Avrot wrote:
Hi,
Thanks to Emil Iggland's kind review, I added precision on documentation
for hyperbolic functions.
Hello
I see that in dtanh() you set errno to 0 before calling tanh(), but 1)
you don't check for it afterwards (seems like you should be checking for
ERANGE, as well as checking the return value for isinf()), and 2) you
don't do that in dsinh() and dcosh() and I'm not quite sure I see why.
What's up with that?
Thanks,
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Hi Alvaro,
Thank you so much for taking the time to review the patch and for taking
the time again to sort things
out with me this evening.
I see that in dtanh() you set errno to 0 before calling tanh(), but 1)
you don't check for it afterwards (seems like you should be checking for
ERANGE, as well as checking the return value for isinf()), and 2) you
don't do that in dsinh() and dcosh() and I'm not quite sure I see why.
What's up with that?
At the time I wrote that patch, I tried to include errno testing.Then, I
think again and
came back with the wrong idea everything would be fine.
By re-reading math.h documentation, it is now clear that the three
functions can raise a
ERANGE error.
There are two cases :
- range error due to overflow occurs.
- range error occurs due to underflow. In that case, the correct result
(after rounding) is returned. So I assume we can ignore that case.
For sinh and cosh, we can have both cases and we added support for overflow.
For tanh, the only possible case is underflow and then, the result is
correct.
We included comments to explain errno handling in those functions.
Cheers,
Lætitia
Attachments:
adding_log10_and_hyperbolic_functions_v4.patchtext/x-patch; charset=US-ASCII; name=adding_log10_and_hyperbolic_functions_v4.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4930ec17f6..30ecf496ca 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -896,6 +896,19 @@
<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>
@@ -1147,7 +1160,7 @@
</para>
<para>
- Finally, <xref linkend="functions-math-trig-table"/> shows the
+ <xref linkend="functions-math-trig-table"/> shows the
available trigonometric functions. All trigonometric functions
take arguments and return values of type <type>double
precision</type>. Each of the trigonometric functions comes in
@@ -1311,8 +1324,66 @@
</para>
</note>
- </sect1>
+ <para>
+ Finally, <xref linkend="functions-math-hyp-table"/> shows the
+ available hyperbolic functions. All hyperbolic functions apply to
+ hyperbolic angles expressed in hyperbolic radians.
+ </para>
+ <table id="functions-math-hyp-table">
+ <title>Hyperbolic Functions</title>
+
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Return Type</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>sinh</primary>
+ </indexterm>
+ <literal><function>sinh(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></entry>
+ <entry>hyperbolic tangent</entry>
+ <entry><literal>tanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
<sect1 id="functions-string">
<title>String Functions and Operators</title>
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 117ded8d1d..29a6ba0859 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2375,6 +2375,77 @@ radians(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
}
+/* ========== 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, it
+ * can be either -infinite or infinite, 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, isinf(arg1), 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 infinite.
+ */
+ if (errno == ERANGE)
+ result = get_float8_infinity();
+
+ check_float8_val(result, isinf(arg1), 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 have errno check because it nevers overflows.
+ */
+ result = tanh(arg1);
+
+ check_float8_val(result, false, true);
+ PG_RETURN_FLOAT8(result);
+}
/*
* drandom - returns a random number
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b8de13f03b..ecd05949a2 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2617,6 +2617,9 @@
{ oid => '1340', descr => 'base 10 logarithm',
proname => 'log', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog10' },
+{ oid => '1364', 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' },
@@ -3283,6 +3286,17 @@
{ 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 => '1618',
proname => 'interval_mul', prorettype => 'interval',
proargtypes => 'interval float8', prosrc => 'interval_mul' },
@@ -4195,6 +4209,9 @@
{ oid => '1741', descr => 'base 10 logarithm',
proname => 'log', prolang => 'sql', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
+{ oid => '2023', descr => 'base 10 logarithm',
+ proname => 'log10', prolang => '14', 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' },
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 75c0bf389b..3f76929591 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -632,4 +632,23 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
10 | 0 | 0 | t
(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)
+
RESET extra_float_digits;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 6595fd2b95..b099ae6321 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -232,4 +232,9 @@ SELECT x, y,
FROM (SELECT 10*cosd(a), 10*sind(a)
FROM generate_series(0, 360, 90) AS t(a)) AS t(x,y);
+-- hyperbolic functions
+SELECT sinh(float8 '0');
+SELECT cosh(float8 '0');
+SELECT tanh(float8 '0');
+
RESET extra_float_digits;
"Lætitia" == Lætitia Avrot <laetitia.avrot@gmail.com> writes:
[snip patch]
The spec doesn't require the inverse functions (asinh, acosh, atanh),
but surely there is no principled reason to omit them?
--
Andrew (irc:RhodiumToad)
Andrew Gierth <andrew@tao11.riddles.org.uk> writes:
The spec doesn't require the inverse functions (asinh, acosh, atanh),
but surely there is no principled reason to omit them?
+1 --- AFAICS, the C library has offered all six since C89.
regards, tom lane
Hi Andrew and Tom,
I considered that option before writing my patch but I refrained for 2
reasons:
- There is no consensus about how to name these functions. The standard
8000-2 goes with arsinh, arcosh and artanh,
but you will find easily arcsinh, arccosh and arctanh or even argsinh,
argcosh and argtanh. In IT, the names asinh,
acosh and atanh are commonly used too. We might implement them with
asinh, acosh and atanh names and add
aliases if SQL standard decide to add it under other names though.
- If we go with inverse hyperbolic functions, I guess we could add other
hyperbolic functions as hyperbolic cosecant,
secant and cotangent too. Then it adds the inverse hyperbolic functions
of these three functions. These six functions
are not described in math.h library. I guess it's because these functions
are quite simple to deduce from the others.
So, as you're asking that too, maybe my reasons weren't good enough. You'll
find enclosed a new version of the patch
with asinh, acosh and atanh (v5).
Then I tried for several days to implement the 6 last hyperbolic functions,
but I wasn't satisfied with the result, so I just dropped it.
Cheers,
Lætitia
Le dim. 3 févr. 2019 à 16:12, Tom Lane <tgl@sss.pgh.pa.us> a écrit :
Andrew Gierth <andrew@tao11.riddles.org.uk> writes:
The spec doesn't require the inverse functions (asinh, acosh, atanh),
but surely there is no principled reason to omit them?+1 --- AFAICS, the C library has offered all six since C89.
regards, tom lane
--
*Think! Do you really need to print this email ? *
*There is no Planet B.*
Attachments:
adding_log10_and_hyperbolic_functions_v5.patchtext/x-patch; charset=US-ASCII; name=adding_log10_and_hyperbolic_functions_v5.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4930ec17f6..61980cfcf5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -896,6 +896,19 @@
<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>
@@ -1147,7 +1160,7 @@
</para>
<para>
- Finally, <xref linkend="functions-math-trig-table"/> shows the
+ <xref linkend="functions-math-trig-table"/> shows the
available trigonometric functions. All trigonometric functions
take arguments and return values of type <type>double
precision</type>. Each of the trigonometric functions comes in
@@ -1311,8 +1324,103 @@
</para>
</note>
- </sect1>
+ <para>
+ Finally, <xref linkend="functions-math-hyp-table"/> shows the
+ available hyperbolic functions. All hyperbolic functions apply to
+ hyperbolic angles expressed in hyperbolic radians. All inverse hyperbolic
+ functions applies to the area of a hyperbolic angle.
+ </para>
+
+ <table id="functions-math-hyp-table">
+ <title>Hyperbolic Functions</title>
+ <tgroup cols="5">
+ <thead>
+ <row>
+ <entry>Function</entry>
+ <entry>Return Type</entry>
+ <entry>Description</entry>
+ <entry>Example</entry>
+ <entry>Result</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <indexterm>
+ <primary>sinh</primary>
+ </indexterm>
+ <literal><function>sinh(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></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(dp)</function></literal>
+ </entry>
+ <entry><type>dp</type></entry>
+ <entry>inverse hyperbolic tangent</entry>
+ <entry><literal>atanh(0)</literal></entry>
+ <entry><literal>0</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
<sect1 id="functions-string">
<title>String Functions and Operators</title>
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 117ded8d1d..8a0690e11e 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -2375,6 +2375,169 @@ radians(PG_FUNCTION_ARGS)
PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
}
+/* ========== 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, it
+ * can be either -infinite or infinite, 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 infinite.
+ */
+ 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 have errno check because it nevers 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;
+
+ errno = 0;
+ result = asinh(arg1);
+
+ /*
+ * if an ERANGE error occurs, it means there is an overflow. For asinh, it
+ * can be either -infinite or infinite, 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);
+}
+
+/*
+ * dacosh - returns the inverse hyperbolic cosine of arg1
+ */
+Datum
+dacosh(PG_FUNCTION_ARGS)
+{
+ float8 arg1 = PG_GETARG_FLOAT8(0);
+ float8 result;
+
+ errno = 0;
+ result = acosh(arg1);
+
+ /*
+ * If arg1 is less than 1, a domain error occurs.
+ */
+ if (errno == EDOM)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("input can't be less than 1")));
+
+ /*
+ * if an ERANGE error occurs, it means there is an overflow. As acosh is
+ * always positive, it means the result is positive infinite.
+ */
+ if (errno == ERANGE)
+ result = get_float8_infinity();
+
+ 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;
+
+ errno = 0;
+ result = tanh(arg1);
+
+ /*
+ * if an ERANGE error occurs, it normaly means there is an overflow, but due
+ * to a bug in glibc 2.9 and earlier, an EDOM can occur instead of ERANGE.
+ * In that case, result is either HUGE_VAL or -HUGE_VAL.
+ */
+ if (errno == ERANGE && result != HUGE_VAL && result != -HUGE_VAL)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("input can't be less than -1 or more than 1")));
+ else if (errno == EDOM || errno == ERANGE)
+ {
+ if (arg1 < 0)
+ result = -get_float8_infinity();
+ else
+ result = get_float8_infinity();
+ }
+
+ check_float8_val(result, true, true);
+ PG_RETURN_FLOAT8(result);
+}
/*
* drandom - returns a random number
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index b8de13f03b..a2a2296ada 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -2617,6 +2617,9 @@
{ oid => '1340', descr => 'base 10 logarithm',
proname => 'log', prorettype => 'float8', proargtypes => 'float8',
prosrc => 'dlog10' },
+{ oid => '1364', 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' },
@@ -3283,6 +3286,25 @@
{ 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' },
@@ -4195,6 +4217,9 @@
{ oid => '1741', descr => 'base 10 logarithm',
proname => 'log', prolang => 'sql', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'select pg_catalog.log(10, $1)' },
+{ oid => '2023', descr => 'base 10 logarithm',
+ proname => 'log10', prolang => '14', 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' },
diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out
index 75c0bf389b..7e1d639d4d 100644
--- a/src/test/regress/expected/float8.out
+++ b/src/test/regress/expected/float8.out
@@ -632,4 +632,41 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
10 | 0 | 0 | t
(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;
diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql
index 6595fd2b95..152c4fa126 100644
--- a/src/test/regress/sql/float8.sql
+++ b/src/test/regress/sql/float8.sql
@@ -232,4 +232,12 @@ SELECT x, y,
FROM (SELECT 10*cosd(a), 10*sind(a)
FROM generate_series(0, 360, 90) AS t(a)) AS t(x,y);
+-- 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;
On 12/02/2019 06:44, Lætitia Avrot wrote:
Hi Andrew and Tom,
I considered that option before writing my patch but I refrained for 2
reasons:- There is no consensus about how to name these functions. The
standard 8000-2 goes with arsinh, arcosh and artanh,
but you will find easily arcsinh, arccosh and arctanh or even
argsinh, argcosh and argtanh. In IT, the names asinh,
acosh and atanh are commonly used too. We might implement them with
asinh, acosh and atanh names and add
aliases if SQL standard decide to add it under other names though.
[...]
Le dim. 3 févr. 2019 à 16:12, Tom Lane <tgl@sss.pgh.pa.us
<mailto:tgl@sss.pgh.pa.us>> a écrit :Andrew Gierth <andrew@tao11.riddles.org.uk
<mailto:andrew@tao11.riddles.org.uk>> writes:The spec doesn't require the inverse functions (asinh, acosh,
atanh),
but surely there is no principled reason to omit them?
+1 --- AFAICS, the C library has offered all six since C89.
regards, tom lane
[...]
I can only remember coming across the asinh, acosh, and atanh forms. In
45 years of programming.
Cheers,
Gavin
Gavin Flower <GavinFlower@archidevsys.co.nz> writes:
On 12/02/2019 06:44, Lætitia Avrot wrote:
I considered that option before writing my patch but I refrained for 2
reasons:- There is no consensus about how to name these functions. The
standard 8000-2 goes with arsinh, arcosh and artanh,
but you will find easily arcsinh, arccosh and arctanh or even
argsinh, argcosh and argtanh. In IT, the names asinh,
acosh and atanh are commonly used too. We might implement them with
asinh, acosh and atanh names and add
aliases if SQL standard decide to add it under other names though.
I can only remember coming across the asinh, acosh, and atanh forms. In
45 years of programming.
I don't think this is a problem. Postgres has never had any hesitation
about adopting C-standard function names if there's nothing in the SQL
standard. The C standard says asinh etc, so those are the names to use.
As Lætitia says, there'd be little problem with adding aliases if someday
the SQL committee decides to add these with other spellings.
regards, tom lane
On Sun, 3 Feb 2019 at 15:12, Tom Lane <tgl@sss.pgh.pa.us> wrote:
Andrew Gierth <andrew@tao11.riddles.org.uk> writes:
The spec doesn't require the inverse functions (asinh, acosh, atanh),
but surely there is no principled reason to omit them?+1 --- AFAICS, the C library has offered all six since C89.
+1 for including the inverse functions. However, it looks to me like
the inverse functions are C99-specific, so they might not be available
on all supported platforms. If they're not, we may need to provide our
own implementations.
I did a bit of research and had play. It looks like it might not be
too hard to provide our own implementations, but it does take a bit of
care to avoid rounding and overflow errors. Attached are some
standalone C programs where I tested various algorithms. A decent
approach seems to be to either use log1p() (which is itself
C99-specific, hence that's the first thing I played with) or to use a
single round of Newton-Raphson to correct rounding errors, in a
similar way to how we implement cbrt() on platforms that don't have
that.
Of course that may all be moot -- those functions may in fact be
available everywhere we care about, but it was interesting to play
around with them anyway.
Regards,
Dean
Dean Rasheed <dean.a.rasheed@gmail.com> writes:
+1 for including the inverse functions. However, it looks to me like
the inverse functions are C99-specific, so they might not be available
on all supported platforms. If they're not, we may need to provide our
own implementations.
FWIW, I'm pretty sure they're available everywhere. It's true C89
doesn't mention them, but POSIX has had them for a long time. The
SUSv2 version of POSIX has them, and so does my pet dinosaur HPUX 10.20,
which has this to say about their origin:
$ man asinh
...
STANDARDS CONFORMANCE
asinh(): SVID3, XPG4.2
Windows, as usual, is a wild card, but as far as I can tell by googling
they exist in Windows too (at least recent versions).
It's definitely possible that there are substandard implementations
out there, though. Hopefully the buildfarm will alert us to any
problems.
Of course that may all be moot -- those functions may in fact be
available everywhere we care about, but it was interesting to play
around with them anyway.
Yeah, math functions are fun to play around with ... and we could end
up needing the code. We'll see.
regards, tom lane
=?UTF-8?Q?L=C3=A6titia_Avrot?= <laetitia.avrot@gmail.com> writes:
So, as you're asking that too, maybe my reasons weren't good enough. You'll
find enclosed a new version of the patch
with asinh, acosh and atanh (v5).
Pushed with some minor adjustments (mainly cleanup of the error handling).
Then I tried for several days to implement the 6 last hyperbolic functions,
but I wasn't satisfied with the result, so I just dropped it.
Yeah, I agree that sech() and so on are not worth the trouble. If they
were commonly used, they'd be in POSIX ...
regards, tom lane
Thanks, Tom !
Thank you everyone for your help and patience.
Cheers,
Lætitia
Le mar. 12 mars 2019 à 20:57, Tom Lane <tgl@sss.pgh.pa.us> a écrit :
Show quoted text
=?UTF-8?Q?L=C3=A6titia_Avrot?= <laetitia.avrot@gmail.com> writes:
So, as you're asking that too, maybe my reasons weren't good enough.
You'll
find enclosed a new version of the patch
with asinh, acosh and atanh (v5).Pushed with some minor adjustments (mainly cleanup of the error handling).
Then I tried for several days to implement the 6 last hyperbolic
functions,
but I wasn't satisfied with the result, so I just dropped it.
Yeah, I agree that sech() and so on are not worth the trouble. If they
were commonly used, they'd be in POSIX ...regards, tom lane
I really appreciate the addition of tanh into core postgres.
If someone doubts it is useful: it is used as a part of math in
geographical calculations.
Say you have your cars in planar Mercator projection and want to move them
"1 second forward by this heading with this speed". sin/cos and the
distance on X/Y, but the distance must be scaled properly - and that
scaling coefficient is cosd(latitude), which you don't have directly - you
have it in projected meters. If you don't want to fire up full-featured
PostGIS on this hot path you inline all formulas together, result is nice
and small - but has tanh in it, which I was surprised to find only in
Oracle Compatibility extensions. Pure sql tanh was good enough, but gave me
disturbance :)
Here's the code:
https://github.com/gojuno/lostgis/blob/master/sql/functions/coslat.sql#L21
On Wed, Mar 13, 2019 at 5:34 PM Lætitia Avrot <laetitia.avrot@gmail.com>
wrote:
Thanks, Tom !
Thank you everyone for your help and patience.
Cheers,
Lætitia
Le mar. 12 mars 2019 à 20:57, Tom Lane <tgl@sss.pgh.pa.us> a écrit :
=?UTF-8?Q?L=C3=A6titia_Avrot?= <laetitia.avrot@gmail.com> writes:
So, as you're asking that too, maybe my reasons weren't good enough.
You'll
find enclosed a new version of the patch
with asinh, acosh and atanh (v5).Pushed with some minor adjustments (mainly cleanup of the error handling).
Then I tried for several days to implement the 6 last hyperbolic
functions,
but I wasn't satisfied with the result, so I just dropped it.
Yeah, I agree that sech() and so on are not worth the trouble. If they
were commonly used, they'd be in POSIX ...regards, tom lane
--
Darafei Praliaskouski
Support me: http://patreon.com/komzpa