diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/utils/adt/float.c | 160 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.dat | 25 | ||||
-rw-r--r-- | src/test/regress/expected/float8.out | 37 | ||||
-rw-r--r-- | src/test/regress/sql/float8.sql | 8 |
5 files changed, 228 insertions, 4 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 37c202d21ca..8e16d755b04 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -230,9 +230,9 @@ float4in(PG_FUNCTION_ARGS) * 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)) @@ -2426,6 +2426,160 @@ radians(PG_FUNCTION_ARGS) } +/* ========== 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 */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 47ad6a9a8e1..8132e28c307 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201903101 +#define CATALOG_VERSION_NO 201903121 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index b47ac0b9926..c4b012cf4c1 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -2616,6 +2616,9 @@ { 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' }, @@ -3282,6 +3285,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' }, @@ -4201,6 +4223,9 @@ { 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' }, diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out index c3a6f5331fe..36b2acda739 100644 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -454,6 +454,43 @@ SELECT '' AS five, * FROM FLOAT8_TBL; | -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'); diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql index a33321811d3..4660cd265eb 100644 --- a/src/test/regress/sql/float8.sql +++ b/src/test/regress/sql/float8.sql @@ -154,6 +154,14 @@ SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f; 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 |