1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* float.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Functions for the built-in floating-point types.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2021-01-02 19:06:25 +01:00
|
|
|
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/float.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
2001-05-03 21:00:37 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <ctype.h>
|
2007-01-02 21:50:35 +01:00
|
|
|
#include <float.h>
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <math.h>
|
1997-09-07 07:04:48 +02:00
|
|
|
#include <limits.h>
|
2000-06-14 20:18:01 +02:00
|
|
|
|
2002-08-26 19:54:02 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2017-12-13 01:32:31 +01:00
|
|
|
#include "common/int.h"
|
Change floating-point output format for improved performance.
Previously, floating-point output was done by rounding to a specific
decimal precision; by default, to 6 or 15 decimal digits (losing
information) or as requested using extra_float_digits. Drivers that
wanted exact float values, and applications like pg_dump that must
preserve values exactly, set extra_float_digits=3 (or sometimes 2 for
historical reasons, though this isn't enough for float4).
Unfortunately, decimal rounded output is slow enough to become a
noticable bottleneck when dealing with large result sets or COPY of
large tables when many floating-point values are involved.
Floating-point output can be done much faster when the output is not
rounded to a specific decimal length, but rather is chosen as the
shortest decimal representation that is closer to the original float
value than to any other value representable in the same precision. The
recently published Ryu algorithm by Ulf Adams is both relatively
simple and remarkably fast.
Accordingly, change float4out/float8out to output shortest decimal
representations if extra_float_digits is greater than 0, and make that
the new default. Applications that need rounded output can set
extra_float_digits back to 0 or below, and take the resulting
performance hit.
We make one concession to portability for systems with buggy
floating-point input: we do not output decimal values that fall
exactly halfway between adjacent representable binary values (which
would rely on the reader doing round-to-nearest-even correctly). This
is known to be a problem at least for VS2013 on Windows.
Our version of the Ryu code originates from
https://github.com/ulfjack/ryu/ at commit c9c3fb1979, but with the
following (significant) modifications:
- Output format is changed to use fixed-point notation for small
exponents, as printf would, and also to use lowercase 'e', a
minimum of 2 exponent digits, and a mandatory sign on the exponent,
to keep the formatting as close as possible to previous output.
- The output of exact midpoint values is disabled as noted above.
- The integer fast-path code is changed somewhat (since we have
fixed-point output and the upstream did not).
- Our project style has been largely applied to the code with the
exception of C99 declaration-after-statement, which has been
retained as an exception to our present policy.
- Most of upstream's debugging and conditionals are removed, and we
use our own configure tests to determine things like uint128
availability.
Changing the float output format obviously affects a number of
regression tests. This patch uses an explicit setting of
extra_float_digits=0 for test output that is not expected to be
exactly reproducible (e.g. due to numerical instability or differing
algorithms for transcendental functions).
Conversions from floats to numeric are unchanged by this patch. These
may appear in index expressions and it is not yet clear whether any
change should be made, so that can be left for another day.
This patch assumes that the only supported floating point format is
now IEEE format, and the documentation is updated to reflect that.
Code by me, adapting the work of Ulf Adams and other contributors.
References:
https://dl.acm.org/citation.cfm?id=3192369
Reviewed-by: Tom Lane, Andres Freund, Donald Dong
Discussion: https://postgr.es/m/87r2el1bx6.fsf@news-spur.riddles.org.uk
2019-02-13 16:20:33 +01:00
|
|
|
#include "common/shortest_dec.h"
|
2003-05-09 23:19:50 +02:00
|
|
|
#include "libpq/pqformat.h"
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
#include "miscadmin.h"
|
2000-07-17 05:05:41 +02:00
|
|
|
#include "utils/array.h"
|
2018-07-29 03:30:48 +02:00
|
|
|
#include "utils/float.h"
|
|
|
|
#include "utils/fmgrprotos.h"
|
2011-12-07 06:18:38 +01:00
|
|
|
#include "utils/sortsupport.h"
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
#include "utils/timestamp.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
Change floating-point output format for improved performance.
Previously, floating-point output was done by rounding to a specific
decimal precision; by default, to 6 or 15 decimal digits (losing
information) or as requested using extra_float_digits. Drivers that
wanted exact float values, and applications like pg_dump that must
preserve values exactly, set extra_float_digits=3 (or sometimes 2 for
historical reasons, though this isn't enough for float4).
Unfortunately, decimal rounded output is slow enough to become a
noticable bottleneck when dealing with large result sets or COPY of
large tables when many floating-point values are involved.
Floating-point output can be done much faster when the output is not
rounded to a specific decimal length, but rather is chosen as the
shortest decimal representation that is closer to the original float
value than to any other value representable in the same precision. The
recently published Ryu algorithm by Ulf Adams is both relatively
simple and remarkably fast.
Accordingly, change float4out/float8out to output shortest decimal
representations if extra_float_digits is greater than 0, and make that
the new default. Applications that need rounded output can set
extra_float_digits back to 0 or below, and take the resulting
performance hit.
We make one concession to portability for systems with buggy
floating-point input: we do not output decimal values that fall
exactly halfway between adjacent representable binary values (which
would rely on the reader doing round-to-nearest-even correctly). This
is known to be a problem at least for VS2013 on Windows.
Our version of the Ryu code originates from
https://github.com/ulfjack/ryu/ at commit c9c3fb1979, but with the
following (significant) modifications:
- Output format is changed to use fixed-point notation for small
exponents, as printf would, and also to use lowercase 'e', a
minimum of 2 exponent digits, and a mandatory sign on the exponent,
to keep the formatting as close as possible to previous output.
- The output of exact midpoint values is disabled as noted above.
- The integer fast-path code is changed somewhat (since we have
fixed-point output and the upstream did not).
- Our project style has been largely applied to the code with the
exception of C99 declaration-after-statement, which has been
retained as an exception to our present policy.
- Most of upstream's debugging and conditionals are removed, and we
use our own configure tests to determine things like uint128
availability.
Changing the float output format obviously affects a number of
regression tests. This patch uses an explicit setting of
extra_float_digits=0 for test output that is not expected to be
exactly reproducible (e.g. due to numerical instability or differing
algorithms for transcendental functions).
Conversions from floats to numeric are unchanged by this patch. These
may appear in index expressions and it is not yet clear whether any
change should be made, so that can be left for another day.
This patch assumes that the only supported floating point format is
now IEEE format, and the documentation is updated to reflect that.
Code by me, adapting the work of Ulf Adams and other contributors.
References:
https://dl.acm.org/citation.cfm?id=3192369
Reviewed-by: Tom Lane, Andres Freund, Donald Dong
Discussion: https://postgr.es/m/87r2el1bx6.fsf@news-spur.riddles.org.uk
2019-02-13 16:20:33 +01:00
|
|
|
/*
|
|
|
|
* Configurable GUC parameter
|
|
|
|
*
|
|
|
|
* If >0, use shortest-decimal format for output; this is both the default and
|
|
|
|
* allows for compatibility with clients that explicitly set a value here to
|
|
|
|
* get round-trip-accurate results. If 0 or less, then use the old, slow,
|
|
|
|
* decimal rounding method.
|
|
|
|
*/
|
|
|
|
int extra_float_digits = 1;
|
2002-11-08 18:37:52 +01:00
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
/* Cached constants for degree-based trig functions */
|
|
|
|
static bool degree_consts_set = false;
|
|
|
|
static float8 sin_30 = 0;
|
|
|
|
static float8 one_minus_cos_60 = 0;
|
|
|
|
static float8 asin_0_5 = 0;
|
|
|
|
static float8 acos_0_5 = 0;
|
|
|
|
static float8 atan_1_0 = 0;
|
|
|
|
static float8 tan_45 = 0;
|
|
|
|
static float8 cot_45 = 0;
|
|
|
|
|
2016-04-25 21:21:04 +02:00
|
|
|
/*
|
|
|
|
* These are intentionally not static; don't "fix" them. They will never
|
|
|
|
* be referenced by other files, much less changed; but we don't want the
|
|
|
|
* compiler to know that, else it might try to precompute expressions
|
|
|
|
* involving them. See comments for init_degree_constants().
|
|
|
|
*/
|
|
|
|
float8 degree_c_thirty = 30.0;
|
|
|
|
float8 degree_c_forty_five = 45.0;
|
|
|
|
float8 degree_c_sixty = 60.0;
|
|
|
|
float8 degree_c_one_half = 0.5;
|
|
|
|
float8 degree_c_one = 1.0;
|
|
|
|
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
/* State for drandom() and setseed() */
|
|
|
|
static bool drandom_seed_set = false;
|
|
|
|
static unsigned short drandom_seed[3] = {0, 0, 0};
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
/* Local function prototypes */
|
|
|
|
static double sind_q1(double x);
|
|
|
|
static double cosd_q1(double x);
|
2016-04-25 21:21:04 +02:00
|
|
|
static void init_degree_constants(void);
|
2016-01-24 00:12:54 +01:00
|
|
|
|
2004-03-15 04:29:22 +01:00
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
/*
|
|
|
|
* We use these out-of-line ereport() calls to report float overflow,
|
|
|
|
* underflow, and zero-divide, because following our usual practice of
|
|
|
|
* repeating them at each call site would lead to a lot of code bloat.
|
|
|
|
*
|
|
|
|
* This does mean that you don't get a useful error location indicator.
|
|
|
|
*/
|
|
|
|
pg_noinline void
|
|
|
|
float_overflow_error(void)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("value out of range: overflow")));
|
|
|
|
}
|
|
|
|
|
|
|
|
pg_noinline void
|
|
|
|
float_underflow_error(void)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("value out of range: underflow")));
|
|
|
|
}
|
|
|
|
|
|
|
|
pg_noinline void
|
|
|
|
float_zero_divide_error(void)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
errmsg("division by zero")));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-03-14 06:22:52 +01:00
|
|
|
/*
|
|
|
|
* Returns -1 if 'val' represents negative infinity, 1 if 'val'
|
|
|
|
* represents (positive) infinity, and 0 otherwise. On some platforms,
|
|
|
|
* this is equivalent to the isinf() macro, but not everywhere: C99
|
|
|
|
* does not specify that isinf() needs to distinguish between positive
|
|
|
|
* and negative infinity.
|
|
|
|
*/
|
2004-03-15 04:29:22 +01:00
|
|
|
int
|
2004-03-14 06:22:52 +01:00
|
|
|
is_infinite(double val)
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
int inf = isinf(val);
|
2004-03-14 06:22:52 +01:00
|
|
|
|
|
|
|
if (inf == 0)
|
|
|
|
return 0;
|
2007-01-02 22:25:50 +01:00
|
|
|
else if (val > 0)
|
2004-03-14 06:22:52 +01:00
|
|
|
return 1;
|
2007-01-02 22:25:50 +01:00
|
|
|
else
|
|
|
|
return -1;
|
2004-03-14 06:22:52 +01:00
|
|
|
}
|
2002-11-08 18:37:52 +01:00
|
|
|
|
2004-03-15 04:29:22 +01:00
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
/* ========== USER I/O ROUTINES ========== */
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
* float4in - converts "num" to float4
|
2019-02-13 16:19:44 +01:00
|
|
|
*
|
|
|
|
* Note that this code now uses strtof(), where it used to use strtod().
|
|
|
|
*
|
|
|
|
* The motivation for using strtof() is to avoid a double-rounding problem:
|
|
|
|
* for certain decimal inputs, if you round the input correctly to a double,
|
|
|
|
* and then round the double to a float, the result is incorrect in that it
|
|
|
|
* does not match the result of rounding the decimal value to float directly.
|
|
|
|
*
|
|
|
|
* One of the best examples is 7.038531e-26:
|
|
|
|
*
|
|
|
|
* 0xAE43FDp-107 = 7.03853069185120912085...e-26
|
|
|
|
* midpoint 7.03853100000000022281...e-26
|
|
|
|
* 0xAE43FEp-107 = 7.03853130814879132477...e-26
|
|
|
|
*
|
|
|
|
* making 0xAE43FDp-107 the correct float result, but if you do the conversion
|
|
|
|
* via a double, you get
|
|
|
|
*
|
|
|
|
* 0xAE43FD.7FFFFFF8p-107 = 7.03853099999999907487...e-26
|
|
|
|
* midpoint 7.03853099999999964884...e-26
|
|
|
|
* 0xAE43FD.80000000p-107 = 7.03853100000000022281...e-26
|
|
|
|
* 0xAE43FD.80000008p-107 = 7.03853100000000137076...e-26
|
|
|
|
*
|
|
|
|
* so the value rounds to the double exactly on the midpoint between the two
|
|
|
|
* nearest floats, and then rounding again to a float gives the incorrect
|
|
|
|
* result of 0xAE43FEp-107.
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4in(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
char *num = PG_GETARG_CSTRING(0);
|
2004-03-14 06:22:52 +01:00
|
|
|
char *orig_num;
|
2019-02-13 16:19:44 +01:00
|
|
|
float val;
|
1997-09-08 04:41:22 +02:00
|
|
|
char *endptr;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-03-14 06:22:52 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* endptr points to the first character _after_ the sequence we recognized
|
|
|
|
* as a valid floating point number. orig_num points to the original input
|
|
|
|
* string.
|
2004-03-14 06:22:52 +01:00
|
|
|
*/
|
|
|
|
orig_num = num;
|
|
|
|
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
/* skip leading whitespace */
|
|
|
|
while (*num != '\0' && isspace((unsigned char) *num))
|
|
|
|
num++;
|
|
|
|
|
2004-03-14 06:22:52 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Check for an empty-string input to begin with, to avoid the vagaries of
|
|
|
|
* strtod() on different platforms.
|
2004-03-14 06:22:52 +01:00
|
|
|
*/
|
|
|
|
if (*num == '\0')
|
2005-02-11 05:09:05 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2017-01-18 20:08:20 +01:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
|
|
|
"real", orig_num)));
|
2004-03-14 06:22:52 +01:00
|
|
|
|
2005-12-02 03:49:11 +01:00
|
|
|
errno = 0;
|
2019-02-13 16:19:44 +01:00
|
|
|
val = strtof(num, &endptr);
|
2004-03-11 03:11:14 +01:00
|
|
|
|
2004-03-14 06:22:52 +01:00
|
|
|
/* did we not see anything that looks like a double? */
|
2004-04-02 01:52:18 +02:00
|
|
|
if (endptr == num || errno != 0)
|
1999-01-24 01:12:59 +01:00
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
int save_errno = errno;
|
2012-02-01 19:11:16 +01:00
|
|
|
|
2001-06-02 22:18:30 +02:00
|
|
|
/*
|
2019-02-13 16:19:44 +01:00
|
|
|
* C99 requires that strtof() accept NaN, [+-]Infinity, and [+-]Inf,
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
* but not all platforms support all of these (and some accept them
|
|
|
|
* but set ERANGE anyway...) Therefore, we check for these inputs
|
2019-02-13 16:19:44 +01:00
|
|
|
* ourselves if strtof() fails.
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
*
|
|
|
|
* Note: C99 also requires hexadecimal input as well as some extended
|
|
|
|
* forms of NaN, but we consider these forms unportable and don't try
|
2019-02-13 16:19:44 +01:00
|
|
|
* to support them. You can use 'em if your strtof() takes 'em.
|
2001-06-02 22:18:30 +02:00
|
|
|
*/
|
2004-05-07 02:24:59 +02:00
|
|
|
if (pg_strncasecmp(num, "NaN", 3) == 0)
|
2004-03-11 03:11:14 +01:00
|
|
|
{
|
2004-03-15 04:29:22 +01:00
|
|
|
val = get_float4_nan();
|
2004-03-14 06:22:52 +01:00
|
|
|
endptr = num + 3;
|
|
|
|
}
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strncasecmp(num, "Infinity", 8) == 0)
|
2004-03-14 06:22:52 +01:00
|
|
|
{
|
2004-03-15 04:29:22 +01:00
|
|
|
val = get_float4_infinity();
|
2004-03-14 06:22:52 +01:00
|
|
|
endptr = num + 8;
|
|
|
|
}
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
|
|
|
|
{
|
|
|
|
val = get_float4_infinity();
|
|
|
|
endptr = num + 9;
|
|
|
|
}
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
|
2004-03-14 06:22:52 +01:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
val = -get_float4_infinity();
|
2004-03-14 06:22:52 +01:00
|
|
|
endptr = num + 9;
|
|
|
|
}
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
else if (pg_strncasecmp(num, "inf", 3) == 0)
|
|
|
|
{
|
|
|
|
val = get_float4_infinity();
|
|
|
|
endptr = num + 3;
|
|
|
|
}
|
|
|
|
else if (pg_strncasecmp(num, "+inf", 4) == 0)
|
|
|
|
{
|
|
|
|
val = get_float4_infinity();
|
|
|
|
endptr = num + 4;
|
|
|
|
}
|
|
|
|
else if (pg_strncasecmp(num, "-inf", 4) == 0)
|
|
|
|
{
|
|
|
|
val = -get_float4_infinity();
|
|
|
|
endptr = num + 4;
|
|
|
|
}
|
2012-02-01 19:11:16 +01:00
|
|
|
else if (save_errno == ERANGE)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Some platforms return ERANGE for denormalized numbers (those
|
|
|
|
* that are not zero, but are too close to zero to have full
|
2014-05-06 18:12:18 +02:00
|
|
|
* precision). We'd prefer not to throw error for that, so try to
|
2012-06-10 21:20:04 +02:00
|
|
|
* detect whether it's a "real" out-of-range condition by checking
|
|
|
|
* to see if the result is zero or huge.
|
2019-02-13 16:19:44 +01:00
|
|
|
*
|
Add support for hyperbolic functions, as well as log10().
The SQL:2016 standard adds support for the hyperbolic functions
sinh(), cosh(), and tanh(). POSIX has long required libm to
provide those functions as well as their inverses asinh(),
acosh(), atanh(). Hence, let's just expose the libm functions
to the SQL level. As with the trig functions, we only implement
versions for float8, not numeric.
For the moment, we'll assume that all platforms actually do have
these functions; if experience teaches otherwise, some autoconf
effort may be needed.
SQL:2016 also adds support for base-10 logarithm, but with the
function name log10(), whereas the name we've long used is log().
Add aliases named log10() for the float8 and numeric versions.
Lætitia Avrot
Discussion: https://postgr.es/m/CAB_COdguG22LO=rnxDQ2DW1uzv8aQoUzyDQNJjrR4k00XSgm5w@mail.gmail.com
2019-03-12 20:55:09 +01:00
|
|
|
* 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.
|
2012-02-01 19:11:16 +01:00
|
|
|
*/
|
2019-02-13 16:19:44 +01:00
|
|
|
if (val == 0.0 ||
|
|
|
|
#if !defined(HUGE_VALF) || (defined(_MSC_VER) && (_MSC_VER < 1900))
|
|
|
|
isinf(val)
|
|
|
|
#else
|
|
|
|
(val >= HUGE_VALF || val <= -HUGE_VALF)
|
|
|
|
#endif
|
|
|
|
)
|
2012-02-01 19:11:16 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("\"%s\" is out of range for type real",
|
|
|
|
orig_num)));
|
|
|
|
}
|
2001-06-02 22:18:30 +02:00
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2017-01-18 20:08:20 +01:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
|
|
|
"real", orig_num)));
|
1999-01-24 01:12:59 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-03-11 03:11:14 +01:00
|
|
|
/* skip trailing whitespace */
|
2004-04-02 00:51:31 +02:00
|
|
|
while (*endptr != '\0' && isspace((unsigned char) *endptr))
|
2004-03-11 03:11:14 +01:00
|
|
|
endptr++;
|
|
|
|
|
|
|
|
/* if there is any junk left at the end of the string, bail out */
|
|
|
|
if (*endptr != '\0')
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
2017-01-18 20:08:20 +01:00
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
|
|
|
"real", orig_num)));
|
2004-03-04 22:47:18 +01:00
|
|
|
|
2019-02-13 16:19:44 +01:00
|
|
|
PG_RETURN_FLOAT4(val);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* float4out - converts a float4 number to a string
|
|
|
|
* using a standard output format
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4out(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 num = PG_GETARG_FLOAT4(0);
|
Improve snprintf.c's handling of NaN, Infinity, and minus zero.
Up to now, float4out/float8out handled NaN and Infinity cases explicitly,
and invoked psprintf only for ordinary float values. This was done because
platform implementations of snprintf produce varying representations of
these special cases. But now that we use snprintf.c always, it's better
to give it the responsibility to produce a uniform representation of
these cases, so that we have uniformity across the board not only in
float4out/float8out. Hence, move that work into fmtfloat().
Also, teach fmtfloat() to recognize IEEE minus zero and handle it
correctly. The previous coding worked only accidentally, and would
fail for e.g. "%+f" format (it'd print "+-0.00000"). Now that we're
using snprintf.c everywhere, it's not acceptable for it to do weird
things in corner cases. (This incidentally avoids a portability
problem we've seen on some really ancient platforms, that native
sprintf does the wrong thing with minus zero.)
Also, introduce a new entry point in snprintf.c to allow float[48]out
to bypass the work of interpreting a well-known format spec, as well
as bypassing the overhead of the psprintf layer. I modeled this API
loosely on strfromd(). In my testing, this brings float[48]out back
to approximately the same speed they had when using native snprintf,
fixing one of the main performance issues caused by using snprintf.c.
(There is some talk of more aggressive work to improve the speed of
floating-point output conversion, but these changes seem to provide
a better starting point for such work anyway.)
Getting rid of the previous ad-hoc hack for Infinity/NaN in fmtfloat()
allows removing <ctype.h> from snprintf.c's #includes. I also removed
a few other #includes that I think are historical, though the buildfarm
may expose that as wrong.
Discussion: https://postgr.es/m/13178.1538794717@sss.pgh.pa.us
2018-10-08 18:19:20 +02:00
|
|
|
char *ascii = (char *) palloc(32);
|
|
|
|
int ndig = FLT_DIG + extra_float_digits;
|
2002-11-08 18:37:52 +01:00
|
|
|
|
Change floating-point output format for improved performance.
Previously, floating-point output was done by rounding to a specific
decimal precision; by default, to 6 or 15 decimal digits (losing
information) or as requested using extra_float_digits. Drivers that
wanted exact float values, and applications like pg_dump that must
preserve values exactly, set extra_float_digits=3 (or sometimes 2 for
historical reasons, though this isn't enough for float4).
Unfortunately, decimal rounded output is slow enough to become a
noticable bottleneck when dealing with large result sets or COPY of
large tables when many floating-point values are involved.
Floating-point output can be done much faster when the output is not
rounded to a specific decimal length, but rather is chosen as the
shortest decimal representation that is closer to the original float
value than to any other value representable in the same precision. The
recently published Ryu algorithm by Ulf Adams is both relatively
simple and remarkably fast.
Accordingly, change float4out/float8out to output shortest decimal
representations if extra_float_digits is greater than 0, and make that
the new default. Applications that need rounded output can set
extra_float_digits back to 0 or below, and take the resulting
performance hit.
We make one concession to portability for systems with buggy
floating-point input: we do not output decimal values that fall
exactly halfway between adjacent representable binary values (which
would rely on the reader doing round-to-nearest-even correctly). This
is known to be a problem at least for VS2013 on Windows.
Our version of the Ryu code originates from
https://github.com/ulfjack/ryu/ at commit c9c3fb1979, but with the
following (significant) modifications:
- Output format is changed to use fixed-point notation for small
exponents, as printf would, and also to use lowercase 'e', a
minimum of 2 exponent digits, and a mandatory sign on the exponent,
to keep the formatting as close as possible to previous output.
- The output of exact midpoint values is disabled as noted above.
- The integer fast-path code is changed somewhat (since we have
fixed-point output and the upstream did not).
- Our project style has been largely applied to the code with the
exception of C99 declaration-after-statement, which has been
retained as an exception to our present policy.
- Most of upstream's debugging and conditionals are removed, and we
use our own configure tests to determine things like uint128
availability.
Changing the float output format obviously affects a number of
regression tests. This patch uses an explicit setting of
extra_float_digits=0 for test output that is not expected to be
exactly reproducible (e.g. due to numerical instability or differing
algorithms for transcendental functions).
Conversions from floats to numeric are unchanged by this patch. These
may appear in index expressions and it is not yet clear whether any
change should be made, so that can be left for another day.
This patch assumes that the only supported floating point format is
now IEEE format, and the documentation is updated to reflect that.
Code by me, adapting the work of Ulf Adams and other contributors.
References:
https://dl.acm.org/citation.cfm?id=3192369
Reviewed-by: Tom Lane, Andres Freund, Donald Dong
Discussion: https://postgr.es/m/87r2el1bx6.fsf@news-spur.riddles.org.uk
2019-02-13 16:20:33 +01:00
|
|
|
if (extra_float_digits > 0)
|
|
|
|
{
|
|
|
|
float_to_shortest_decimal_buf(num, ascii);
|
|
|
|
PG_RETURN_CSTRING(ascii);
|
|
|
|
}
|
|
|
|
|
Improve snprintf.c's handling of NaN, Infinity, and minus zero.
Up to now, float4out/float8out handled NaN and Infinity cases explicitly,
and invoked psprintf only for ordinary float values. This was done because
platform implementations of snprintf produce varying representations of
these special cases. But now that we use snprintf.c always, it's better
to give it the responsibility to produce a uniform representation of
these cases, so that we have uniformity across the board not only in
float4out/float8out. Hence, move that work into fmtfloat().
Also, teach fmtfloat() to recognize IEEE minus zero and handle it
correctly. The previous coding worked only accidentally, and would
fail for e.g. "%+f" format (it'd print "+-0.00000"). Now that we're
using snprintf.c everywhere, it's not acceptable for it to do weird
things in corner cases. (This incidentally avoids a portability
problem we've seen on some really ancient platforms, that native
sprintf does the wrong thing with minus zero.)
Also, introduce a new entry point in snprintf.c to allow float[48]out
to bypass the work of interpreting a well-known format spec, as well
as bypassing the overhead of the psprintf layer. I modeled this API
loosely on strfromd(). In my testing, this brings float[48]out back
to approximately the same speed they had when using native snprintf,
fixing one of the main performance issues caused by using snprintf.c.
(There is some talk of more aggressive work to improve the speed of
floating-point output conversion, but these changes seem to provide
a better starting point for such work anyway.)
Getting rid of the previous ad-hoc hack for Infinity/NaN in fmtfloat()
allows removing <ctype.h> from snprintf.c's #includes. I also removed
a few other #includes that I think are historical, though the buildfarm
may expose that as wrong.
Discussion: https://postgr.es/m/13178.1538794717@sss.pgh.pa.us
2018-10-08 18:19:20 +02:00
|
|
|
(void) pg_strfromd(ascii, 32, ndig, num);
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_CSTRING(ascii);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2003-05-09 23:19:50 +02:00
|
|
|
/*
|
|
|
|
* float4recv - converts external binary format to float4
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float4recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* float4send - converts float4 to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float4send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float4 num = PG_GETARG_FLOAT4(0);
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendfloat4(&buf, num);
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* float8in - converts "num" to float8
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8in(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
char *num = PG_GETARG_CSTRING(0);
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num));
|
|
|
|
}
|
|
|
|
|
2019-03-16 10:21:19 +01:00
|
|
|
/* Convenience macro: set *have_error flag (if provided) or throw error */
|
2019-08-05 08:35:16 +02:00
|
|
|
#define RETURN_ERROR(throw_error, have_error) \
|
2019-03-16 10:21:19 +01:00
|
|
|
do { \
|
|
|
|
if (have_error) { \
|
|
|
|
*have_error = true; \
|
|
|
|
return 0.0; \
|
|
|
|
} else { \
|
|
|
|
throw_error; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
/*
|
2019-03-16 10:21:19 +01:00
|
|
|
* float8in_internal_opt_error - guts of float8in()
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
*
|
|
|
|
* This is exposed for use by functions that want a reasonably
|
|
|
|
* platform-independent way of inputting doubles. The behavior is
|
|
|
|
* essentially like strtod + ereport on error, but note the following
|
|
|
|
* differences:
|
|
|
|
* 1. Both leading and trailing whitespace are skipped.
|
|
|
|
* 2. If endptr_p is NULL, we throw error if there's trailing junk.
|
|
|
|
* Otherwise, it's up to the caller to complain about trailing junk.
|
|
|
|
* 3. In event of a syntax error, the report mentions the given type_name
|
|
|
|
* and prints orig_string as the input; this is meant to support use of
|
|
|
|
* this function with types such as "box" and "point", where what we are
|
|
|
|
* parsing here is just a substring of orig_string.
|
|
|
|
*
|
|
|
|
* "num" could validly be declared "const char *", but that results in an
|
|
|
|
* unreasonable amount of extra casting both here and in callers, so we don't.
|
2019-03-16 10:21:19 +01:00
|
|
|
*
|
|
|
|
* When "*have_error" flag is provided, it's set instead of throwing an
|
|
|
|
* error. This is helpful when caller need to handle errors by itself.
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
*/
|
|
|
|
double
|
2019-03-16 10:21:19 +01:00
|
|
|
float8in_internal_opt_error(char *num, char **endptr_p,
|
|
|
|
const char *type_name, const char *orig_string,
|
|
|
|
bool *have_error)
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
double val;
|
|
|
|
char *endptr;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2019-08-05 08:35:16 +02:00
|
|
|
if (have_error)
|
|
|
|
*have_error = false;
|
|
|
|
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
/* skip leading whitespace */
|
|
|
|
while (*num != '\0' && isspace((unsigned char) *num))
|
|
|
|
num++;
|
|
|
|
|
2004-03-14 06:22:52 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Check for an empty-string input to begin with, to avoid the vagaries of
|
|
|
|
* strtod() on different platforms.
|
2004-03-14 06:22:52 +01:00
|
|
|
*/
|
|
|
|
if (*num == '\0')
|
2019-03-16 10:21:19 +01:00
|
|
|
RETURN_ERROR(ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input syntax for type %s: \"%s\"",
|
2019-08-05 08:35:16 +02:00
|
|
|
type_name, orig_string))),
|
|
|
|
have_error);
|
2004-03-14 06:22:52 +01:00
|
|
|
|
2005-12-02 03:49:11 +01:00
|
|
|
errno = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
val = strtod(num, &endptr);
|
2004-03-11 03:11:14 +01:00
|
|
|
|
2004-03-14 06:22:52 +01:00
|
|
|
/* did we not see anything that looks like a double? */
|
2004-04-02 01:52:18 +02:00
|
|
|
if (endptr == num || errno != 0)
|
1999-01-10 18:13:06 +01:00
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
int save_errno = errno;
|
2012-02-01 19:11:16 +01:00
|
|
|
|
2004-03-11 03:11:14 +01:00
|
|
|
/*
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
* C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
|
|
|
|
* but not all platforms support all of these (and some accept them
|
|
|
|
* but set ERANGE anyway...) Therefore, we check for these inputs
|
|
|
|
* ourselves if strtod() fails.
|
|
|
|
*
|
|
|
|
* Note: C99 also requires hexadecimal input as well as some extended
|
|
|
|
* forms of NaN, but we consider these forms unportable and don't try
|
|
|
|
* to support them. You can use 'em if your strtod() takes 'em.
|
2004-03-11 03:11:14 +01:00
|
|
|
*/
|
2004-05-07 02:24:59 +02:00
|
|
|
if (pg_strncasecmp(num, "NaN", 3) == 0)
|
2004-03-11 03:11:14 +01:00
|
|
|
{
|
2004-03-15 04:29:22 +01:00
|
|
|
val = get_float8_nan();
|
2004-03-14 06:22:52 +01:00
|
|
|
endptr = num + 3;
|
|
|
|
}
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strncasecmp(num, "Infinity", 8) == 0)
|
2004-03-14 06:22:52 +01:00
|
|
|
{
|
2004-03-15 04:29:22 +01:00
|
|
|
val = get_float8_infinity();
|
2004-03-14 06:22:52 +01:00
|
|
|
endptr = num + 8;
|
|
|
|
}
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
|
|
|
|
{
|
|
|
|
val = get_float8_infinity();
|
|
|
|
endptr = num + 9;
|
|
|
|
}
|
2004-05-07 02:24:59 +02:00
|
|
|
else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
|
2004-03-14 06:22:52 +01:00
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
val = -get_float8_infinity();
|
2004-03-14 06:22:52 +01:00
|
|
|
endptr = num + 9;
|
|
|
|
}
|
Make sure float4in/float8in accept all standard spellings of "infinity".
The C99 and POSIX standards require strtod() to accept all these spellings
(case-insensitively): "inf", "+inf", "-inf", "infinity", "+infinity",
"-infinity". However, pre-C99 systems might accept only some or none of
these, and apparently Windows still doesn't accept "inf". To avoid
surprising cross-platform behavioral differences, manually check for each
of these spellings if strtod() fails. We were previously handling just
"infinity" and "-infinity" that way, but since C99 is most of the world
now, it seems likely that applications are expecting all these spellings
to work.
Per bug #8355 from Basil Peace. It turns out this fix won't actually
resolve his problem, because Python isn't being this careful; but that
doesn't mean we shouldn't be.
2013-08-03 18:39:47 +02:00
|
|
|
else if (pg_strncasecmp(num, "inf", 3) == 0)
|
|
|
|
{
|
|
|
|
val = get_float8_infinity();
|
|
|
|
endptr = num + 3;
|
|
|
|
}
|
|
|
|
else if (pg_strncasecmp(num, "+inf", 4) == 0)
|
|
|
|
{
|
|
|
|
val = get_float8_infinity();
|
|
|
|
endptr = num + 4;
|
|
|
|
}
|
|
|
|
else if (pg_strncasecmp(num, "-inf", 4) == 0)
|
|
|
|
{
|
|
|
|
val = -get_float8_infinity();
|
|
|
|
endptr = num + 4;
|
|
|
|
}
|
2012-02-01 19:11:16 +01:00
|
|
|
else if (save_errno == ERANGE)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Some platforms return ERANGE for denormalized numbers (those
|
|
|
|
* that are not zero, but are too close to zero to have full
|
2014-05-06 18:12:18 +02:00
|
|
|
* precision). We'd prefer not to throw error for that, so try to
|
2012-06-10 21:20:04 +02:00
|
|
|
* detect whether it's a "real" out-of-range condition by checking
|
|
|
|
* to see if the result is zero or huge.
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
*
|
|
|
|
* On error, we intentionally complain about double precision not
|
|
|
|
* the given type name, and we print only the part of the string
|
|
|
|
* that is the current number.
|
2012-02-01 19:11:16 +01:00
|
|
|
*/
|
|
|
|
if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
{
|
|
|
|
char *errnumber = pstrdup(num);
|
|
|
|
|
|
|
|
errnumber[endptr - num] = '\0';
|
2019-03-16 10:21:19 +01:00
|
|
|
RETURN_ERROR(ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
2019-08-05 08:35:16 +02:00
|
|
|
errmsg("\"%s\" is out of range for type double precision",
|
|
|
|
errnumber))),
|
|
|
|
have_error);
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
}
|
2012-02-01 19:11:16 +01:00
|
|
|
}
|
1999-01-10 18:13:06 +01:00
|
|
|
else
|
2019-03-16 10:21:19 +01:00
|
|
|
RETURN_ERROR(ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input syntax for type "
|
|
|
|
"%s: \"%s\"",
|
2019-08-05 08:35:16 +02:00
|
|
|
type_name, orig_string))),
|
|
|
|
have_error);
|
1999-01-10 18:13:06 +01:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-03-11 03:11:14 +01:00
|
|
|
/* skip trailing whitespace */
|
2004-04-02 00:51:31 +02:00
|
|
|
while (*endptr != '\0' && isspace((unsigned char) *endptr))
|
2004-03-11 03:11:14 +01:00
|
|
|
endptr++;
|
|
|
|
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
/* report stopping point if wanted, else complain if not end of string */
|
|
|
|
if (endptr_p)
|
|
|
|
*endptr_p = endptr;
|
|
|
|
else if (*endptr != '\0')
|
2019-03-16 10:21:19 +01:00
|
|
|
RETURN_ERROR(ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("invalid input syntax for type "
|
|
|
|
"%s: \"%s\"",
|
2019-08-05 08:35:16 +02:00
|
|
|
type_name, orig_string))),
|
|
|
|
have_error);
|
2004-03-04 22:47:18 +01:00
|
|
|
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
return val;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2019-03-16 10:21:19 +01:00
|
|
|
/*
|
2019-05-26 14:58:18 +02:00
|
|
|
* Interface to float8in_internal_opt_error() without "have_error" argument.
|
2019-03-16 10:21:19 +01:00
|
|
|
*/
|
|
|
|
double
|
|
|
|
float8in_internal(char *num, char **endptr_p,
|
|
|
|
const char *type_name, const char *orig_string)
|
|
|
|
{
|
|
|
|
return float8in_internal_opt_error(num, endptr_p, type_name,
|
|
|
|
orig_string, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* float8out - converts float8 number to a string
|
|
|
|
* using a standard output format
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8out(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 num = PG_GETARG_FLOAT8(0);
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
|
|
|
|
PG_RETURN_CSTRING(float8out_internal(num));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* float8out_internal - guts of float8out()
|
|
|
|
*
|
|
|
|
* This is exposed for use by functions that want a reasonably
|
|
|
|
* platform-independent way of outputting doubles.
|
|
|
|
* The result is always palloc'd.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
float8out_internal(double num)
|
|
|
|
{
|
Improve snprintf.c's handling of NaN, Infinity, and minus zero.
Up to now, float4out/float8out handled NaN and Infinity cases explicitly,
and invoked psprintf only for ordinary float values. This was done because
platform implementations of snprintf produce varying representations of
these special cases. But now that we use snprintf.c always, it's better
to give it the responsibility to produce a uniform representation of
these cases, so that we have uniformity across the board not only in
float4out/float8out. Hence, move that work into fmtfloat().
Also, teach fmtfloat() to recognize IEEE minus zero and handle it
correctly. The previous coding worked only accidentally, and would
fail for e.g. "%+f" format (it'd print "+-0.00000"). Now that we're
using snprintf.c everywhere, it's not acceptable for it to do weird
things in corner cases. (This incidentally avoids a portability
problem we've seen on some really ancient platforms, that native
sprintf does the wrong thing with minus zero.)
Also, introduce a new entry point in snprintf.c to allow float[48]out
to bypass the work of interpreting a well-known format spec, as well
as bypassing the overhead of the psprintf layer. I modeled this API
loosely on strfromd(). In my testing, this brings float[48]out back
to approximately the same speed they had when using native snprintf,
fixing one of the main performance issues caused by using snprintf.c.
(There is some talk of more aggressive work to improve the speed of
floating-point output conversion, but these changes seem to provide
a better starting point for such work anyway.)
Getting rid of the previous ad-hoc hack for Infinity/NaN in fmtfloat()
allows removing <ctype.h> from snprintf.c's #includes. I also removed
a few other #includes that I think are historical, though the buildfarm
may expose that as wrong.
Discussion: https://postgr.es/m/13178.1538794717@sss.pgh.pa.us
2018-10-08 18:19:20 +02:00
|
|
|
char *ascii = (char *) palloc(32);
|
|
|
|
int ndig = DBL_DIG + extra_float_digits;
|
2002-11-08 18:37:52 +01:00
|
|
|
|
Change floating-point output format for improved performance.
Previously, floating-point output was done by rounding to a specific
decimal precision; by default, to 6 or 15 decimal digits (losing
information) or as requested using extra_float_digits. Drivers that
wanted exact float values, and applications like pg_dump that must
preserve values exactly, set extra_float_digits=3 (or sometimes 2 for
historical reasons, though this isn't enough for float4).
Unfortunately, decimal rounded output is slow enough to become a
noticable bottleneck when dealing with large result sets or COPY of
large tables when many floating-point values are involved.
Floating-point output can be done much faster when the output is not
rounded to a specific decimal length, but rather is chosen as the
shortest decimal representation that is closer to the original float
value than to any other value representable in the same precision. The
recently published Ryu algorithm by Ulf Adams is both relatively
simple and remarkably fast.
Accordingly, change float4out/float8out to output shortest decimal
representations if extra_float_digits is greater than 0, and make that
the new default. Applications that need rounded output can set
extra_float_digits back to 0 or below, and take the resulting
performance hit.
We make one concession to portability for systems with buggy
floating-point input: we do not output decimal values that fall
exactly halfway between adjacent representable binary values (which
would rely on the reader doing round-to-nearest-even correctly). This
is known to be a problem at least for VS2013 on Windows.
Our version of the Ryu code originates from
https://github.com/ulfjack/ryu/ at commit c9c3fb1979, but with the
following (significant) modifications:
- Output format is changed to use fixed-point notation for small
exponents, as printf would, and also to use lowercase 'e', a
minimum of 2 exponent digits, and a mandatory sign on the exponent,
to keep the formatting as close as possible to previous output.
- The output of exact midpoint values is disabled as noted above.
- The integer fast-path code is changed somewhat (since we have
fixed-point output and the upstream did not).
- Our project style has been largely applied to the code with the
exception of C99 declaration-after-statement, which has been
retained as an exception to our present policy.
- Most of upstream's debugging and conditionals are removed, and we
use our own configure tests to determine things like uint128
availability.
Changing the float output format obviously affects a number of
regression tests. This patch uses an explicit setting of
extra_float_digits=0 for test output that is not expected to be
exactly reproducible (e.g. due to numerical instability or differing
algorithms for transcendental functions).
Conversions from floats to numeric are unchanged by this patch. These
may appear in index expressions and it is not yet clear whether any
change should be made, so that can be left for another day.
This patch assumes that the only supported floating point format is
now IEEE format, and the documentation is updated to reflect that.
Code by me, adapting the work of Ulf Adams and other contributors.
References:
https://dl.acm.org/citation.cfm?id=3192369
Reviewed-by: Tom Lane, Andres Freund, Donald Dong
Discussion: https://postgr.es/m/87r2el1bx6.fsf@news-spur.riddles.org.uk
2019-02-13 16:20:33 +01:00
|
|
|
if (extra_float_digits > 0)
|
|
|
|
{
|
|
|
|
double_to_shortest_decimal_buf(num, ascii);
|
|
|
|
return ascii;
|
|
|
|
}
|
|
|
|
|
Improve snprintf.c's handling of NaN, Infinity, and minus zero.
Up to now, float4out/float8out handled NaN and Infinity cases explicitly,
and invoked psprintf only for ordinary float values. This was done because
platform implementations of snprintf produce varying representations of
these special cases. But now that we use snprintf.c always, it's better
to give it the responsibility to produce a uniform representation of
these cases, so that we have uniformity across the board not only in
float4out/float8out. Hence, move that work into fmtfloat().
Also, teach fmtfloat() to recognize IEEE minus zero and handle it
correctly. The previous coding worked only accidentally, and would
fail for e.g. "%+f" format (it'd print "+-0.00000"). Now that we're
using snprintf.c everywhere, it's not acceptable for it to do weird
things in corner cases. (This incidentally avoids a portability
problem we've seen on some really ancient platforms, that native
sprintf does the wrong thing with minus zero.)
Also, introduce a new entry point in snprintf.c to allow float[48]out
to bypass the work of interpreting a well-known format spec, as well
as bypassing the overhead of the psprintf layer. I modeled this API
loosely on strfromd(). In my testing, this brings float[48]out back
to approximately the same speed they had when using native snprintf,
fixing one of the main performance issues caused by using snprintf.c.
(There is some talk of more aggressive work to improve the speed of
floating-point output conversion, but these changes seem to provide
a better starting point for such work anyway.)
Getting rid of the previous ad-hoc hack for Infinity/NaN in fmtfloat()
allows removing <ctype.h> from snprintf.c's #includes. I also removed
a few other #includes that I think are historical, though the buildfarm
may expose that as wrong.
Discussion: https://postgr.es/m/13178.1538794717@sss.pgh.pa.us
2018-10-08 18:19:20 +02:00
|
|
|
(void) pg_strfromd(ascii, 32, ndig, num);
|
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types. However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs. This was exposed by commit acdf2a8b372aec1d, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members. We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.
To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.
While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.
In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.
Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
2016-03-30 23:25:03 +02:00
|
|
|
return ascii;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2003-05-09 23:19:50 +02:00
|
|
|
/*
|
|
|
|
* float8recv - converts external binary format to float8
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float8recv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* float8send - converts float8 to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float8send(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 num = PG_GETARG_FLOAT8(0);
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
pq_sendfloat8(&buf, num);
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ========== PUBLIC ROUTINES ========== */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ======================
|
|
|
|
* FLOAT4 BASE OPERATIONS
|
|
|
|
* ======================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float4abs - returns |arg1| (absolute value)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4abs(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT4((float4) fabs(arg1));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float4um - returns -arg1 (unary minus)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4um(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
2007-01-02 21:00:50 +01:00
|
|
|
float4 result;
|
|
|
|
|
2009-02-18 20:23:26 +01:00
|
|
|
result = -arg1;
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT4(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2001-06-07 02:09:32 +02:00
|
|
|
Datum
|
|
|
|
float4up(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float4 arg = PG_GETARG_FLOAT4(0);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-06-07 02:09:32 +02:00
|
|
|
PG_RETURN_FLOAT4(arg);
|
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4larger(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
|
|
|
float4 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
if (float4_gt(arg1, arg2))
|
2003-07-30 21:48:41 +02:00
|
|
|
result = arg1;
|
|
|
|
else
|
|
|
|
result = arg2;
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT4(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4smaller(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
|
|
|
float4 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
if (float4_lt(arg1, arg2))
|
2003-07-30 21:48:41 +02:00
|
|
|
result = arg1;
|
|
|
|
else
|
|
|
|
result = arg2;
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT4(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ======================
|
|
|
|
* FLOAT8 BASE OPERATIONS
|
|
|
|
* ======================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float8abs - returns |arg1| (absolute value)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8abs(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT8(fabs(arg1));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float8um - returns -arg1 (unary minus)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8um(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2009-02-18 20:23:26 +01:00
|
|
|
result = -arg1;
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2001-06-07 02:09:32 +02:00
|
|
|
Datum
|
|
|
|
float8up(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg = PG_GETARG_FLOAT8(0);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-06-07 02:09:32 +02:00
|
|
|
PG_RETURN_FLOAT8(arg);
|
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8larger(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
if (float8_gt(arg1, arg2))
|
2003-07-30 21:48:41 +02:00
|
|
|
result = arg1;
|
|
|
|
else
|
|
|
|
result = arg2;
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8smaller(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
if (float8_lt(arg1, arg2))
|
2003-07-30 21:48:41 +02:00
|
|
|
result = arg1;
|
|
|
|
else
|
|
|
|
result = arg2;
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ====================
|
|
|
|
* ARITHMETIC OPERATORS
|
|
|
|
* ====================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float4pl - returns arg1 + arg2
|
|
|
|
* float4mi - returns arg1 - arg2
|
|
|
|
* float4mul - returns arg1 * arg2
|
|
|
|
* float4div - returns arg1 / arg2
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4pl(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2009-02-18 20:23:26 +01:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4mi(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4mul(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4div(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT4(float4_div(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float8pl - returns arg1 + arg2
|
|
|
|
* float8mi - returns arg1 - arg2
|
|
|
|
* float8mul - returns arg1 * arg2
|
|
|
|
* float8div - returns arg1 / arg2
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8pl(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8mi(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8mul(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8div(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_div(arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ====================
|
|
|
|
* COMPARISON OPERATORS
|
|
|
|
* ====================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
int
|
2001-05-03 21:00:37 +02:00
|
|
|
float4_cmp_internal(float4 a, float4 b)
|
|
|
|
{
|
2018-07-29 03:30:48 +02:00
|
|
|
if (float4_gt(a, b))
|
|
|
|
return 1;
|
|
|
|
if (float4_lt(a, b))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2001-05-03 21:00:37 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4eq(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-05-11 17:11:47 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float4_eq(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4ne(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float4_ne(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4lt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float4_lt(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4le(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float4_le(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4gt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float4_gt(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float4ge(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float4_ge(arg1, arg2));
|
2001-05-03 21:00:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
btfloat4cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2011-12-07 06:18:38 +01:00
|
|
|
static int
|
|
|
|
btfloat4fastcmp(Datum x, Datum y, SortSupport ssup)
|
|
|
|
{
|
|
|
|
float4 arg1 = DatumGetFloat4(x);
|
|
|
|
float4 arg2 = DatumGetFloat4(y);
|
|
|
|
|
|
|
|
return float4_cmp_internal(arg1, arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
btfloat4sortsupport(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
2011-12-07 06:18:38 +01:00
|
|
|
|
|
|
|
ssup->comparator = btfloat4fastcmp;
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2016-07-15 00:45:59 +02:00
|
|
|
int
|
2001-05-03 21:00:37 +02:00
|
|
|
float8_cmp_internal(float8 a, float8 b)
|
|
|
|
{
|
2018-07-29 03:30:48 +02:00
|
|
|
if (float8_gt(a, b))
|
|
|
|
return 1;
|
|
|
|
if (float8_lt(a, b))
|
|
|
|
return -1;
|
|
|
|
return 0;
|
2001-05-03 21:00:37 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8eq(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_eq(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8ne(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_ne(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8lt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_lt(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8le(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_le(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8gt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_gt(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float8ge(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_ge(arg1, arg2));
|
2001-05-03 21:00:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
btfloat8cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
|
|
|
|
PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2011-12-07 06:18:38 +01:00
|
|
|
static int
|
|
|
|
btfloat8fastcmp(Datum x, Datum y, SortSupport ssup)
|
|
|
|
{
|
|
|
|
float8 arg1 = DatumGetFloat8(x);
|
|
|
|
float8 arg2 = DatumGetFloat8(y);
|
|
|
|
|
|
|
|
return float8_cmp_internal(arg1, arg2);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
btfloat8sortsupport(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
2011-12-07 06:18:38 +01:00
|
|
|
|
|
|
|
ssup->comparator = btfloat8fastcmp;
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
Datum
|
|
|
|
btfloat48cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
|
|
|
|
/* widen float4 to float8 and then compare */
|
|
|
|
PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
btfloat84cmp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
|
|
|
|
|
|
|
/* widen float4 to float8 and then compare */
|
|
|
|
PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
|
|
|
|
}
|
|
|
|
|
2018-02-24 19:23:38 +01:00
|
|
|
/*
|
|
|
|
* in_range support function for float8.
|
|
|
|
*
|
|
|
|
* Note: we needn't supply a float8_float4 variant, as implicit coercion
|
|
|
|
* of the offset value takes care of that scenario just as well.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
in_range_float8_float8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 val = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 base = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 offset = PG_GETARG_FLOAT8(2);
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
float8 sum;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reject negative or NaN offset. Negative is per spec, and NaN is
|
|
|
|
* because appropriate semantics for that seem non-obvious.
|
|
|
|
*/
|
|
|
|
if (isnan(offset) || offset < 0)
|
|
|
|
ereport(ERROR,
|
2018-06-11 17:15:28 +02:00
|
|
|
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
|
2018-02-24 19:23:38 +01:00
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deal with cases where val and/or base is NaN, following the rule that
|
|
|
|
* NaN sorts after non-NaN (cf float8_cmp_internal). The offset cannot
|
|
|
|
* affect the conclusion.
|
|
|
|
*/
|
|
|
|
if (isnan(val))
|
|
|
|
{
|
|
|
|
if (isnan(base))
|
|
|
|
PG_RETURN_BOOL(true); /* NAN = NAN */
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(!less); /* NAN > non-NAN */
|
|
|
|
}
|
|
|
|
else if (isnan(base))
|
|
|
|
{
|
|
|
|
PG_RETURN_BOOL(less); /* non-NAN < NAN */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-07-21 04:03:18 +02:00
|
|
|
* Deal with cases where both base and offset are infinite, and computing
|
|
|
|
* base +/- offset would produce NaN. This corresponds to a window frame
|
|
|
|
* whose boundary infinitely precedes +inf or infinitely follows -inf,
|
|
|
|
* which is not well-defined. For consistency with other cases involving
|
|
|
|
* infinities, such as the fact that +inf infinitely follows +inf, we
|
|
|
|
* choose to assume that +inf infinitely precedes +inf and -inf infinitely
|
|
|
|
* follows -inf, and therefore that all finite and infinite values are in
|
|
|
|
* such a window frame.
|
|
|
|
*
|
|
|
|
* offset is known positive, so we need only check the sign of base in
|
|
|
|
* this test.
|
2018-02-24 19:23:38 +01:00
|
|
|
*/
|
2020-07-21 04:03:18 +02:00
|
|
|
if (isinf(offset) && isinf(base) &&
|
|
|
|
(sub ? base > 0 : base < 0))
|
|
|
|
PG_RETURN_BOOL(true);
|
2018-02-24 19:23:38 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise it should be safe to compute base +/- offset. We trust the
|
2020-07-21 04:03:18 +02:00
|
|
|
* FPU to cope if an input is +/-inf or the true sum would overflow, and
|
2018-02-24 19:23:38 +01:00
|
|
|
* produce a suitably signed infinity, which will compare properly against
|
|
|
|
* val whether or not that's infinity.
|
|
|
|
*/
|
|
|
|
if (sub)
|
|
|
|
sum = base - offset;
|
|
|
|
else
|
|
|
|
sum = base + offset;
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
PG_RETURN_BOOL(val <= sum);
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(val >= sum);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* in_range support function for float4.
|
|
|
|
*
|
|
|
|
* We would need a float4_float8 variant in any case, so we supply that and
|
|
|
|
* let implicit coercion take care of the float4_float4 case.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
in_range_float4_float8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2018-05-05 19:21:50 +02:00
|
|
|
float4 val = PG_GETARG_FLOAT4(0);
|
|
|
|
float4 base = PG_GETARG_FLOAT4(1);
|
|
|
|
float8 offset = PG_GETARG_FLOAT8(2);
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
float8 sum;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reject negative or NaN offset. Negative is per spec, and NaN is
|
|
|
|
* because appropriate semantics for that seem non-obvious.
|
|
|
|
*/
|
|
|
|
if (isnan(offset) || offset < 0)
|
|
|
|
ereport(ERROR,
|
2018-06-11 17:15:28 +02:00
|
|
|
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
|
2018-05-05 19:21:50 +02:00
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deal with cases where val and/or base is NaN, following the rule that
|
|
|
|
* NaN sorts after non-NaN (cf float8_cmp_internal). The offset cannot
|
|
|
|
* affect the conclusion.
|
|
|
|
*/
|
|
|
|
if (isnan(val))
|
|
|
|
{
|
|
|
|
if (isnan(base))
|
|
|
|
PG_RETURN_BOOL(true); /* NAN = NAN */
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(!less); /* NAN > non-NAN */
|
|
|
|
}
|
|
|
|
else if (isnan(base))
|
|
|
|
{
|
|
|
|
PG_RETURN_BOOL(less); /* non-NAN < NAN */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2020-07-21 04:03:18 +02:00
|
|
|
* Deal with cases where both base and offset are infinite, and computing
|
|
|
|
* base +/- offset would produce NaN. This corresponds to a window frame
|
|
|
|
* whose boundary infinitely precedes +inf or infinitely follows -inf,
|
|
|
|
* which is not well-defined. For consistency with other cases involving
|
|
|
|
* infinities, such as the fact that +inf infinitely follows +inf, we
|
|
|
|
* choose to assume that +inf infinitely precedes +inf and -inf infinitely
|
|
|
|
* follows -inf, and therefore that all finite and infinite values are in
|
|
|
|
* such a window frame.
|
|
|
|
*
|
|
|
|
* offset is known positive, so we need only check the sign of base in
|
|
|
|
* this test.
|
2018-05-05 19:21:50 +02:00
|
|
|
*/
|
2020-07-21 04:03:18 +02:00
|
|
|
if (isinf(offset) && isinf(base) &&
|
|
|
|
(sub ? base > 0 : base < 0))
|
|
|
|
PG_RETURN_BOOL(true);
|
2018-05-05 19:21:50 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise it should be safe to compute base +/- offset. We trust the
|
2020-07-21 04:03:18 +02:00
|
|
|
* FPU to cope if an input is +/-inf or the true sum would overflow, and
|
2018-05-05 19:21:50 +02:00
|
|
|
* produce a suitably signed infinity, which will compare properly against
|
|
|
|
* val whether or not that's infinity.
|
|
|
|
*/
|
|
|
|
if (sub)
|
|
|
|
sum = base - offset;
|
|
|
|
else
|
|
|
|
sum = base + offset;
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
PG_RETURN_BOOL(val <= sum);
|
|
|
|
else
|
|
|
|
PG_RETURN_BOOL(val >= sum);
|
2018-02-24 19:23:38 +01:00
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ===================
|
|
|
|
* CONVERSION ROUTINES
|
|
|
|
* ===================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ftod - converts a float4 number to a float8 number
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
ftod(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 num = PG_GETARG_FLOAT4(0);
|
1997-05-11 17:11:47 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8((float8) num);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* dtof - converts a float8 number to a float4 number
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dtof(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 num = PG_GETARG_FLOAT8(0);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
float4 result;
|
1997-05-11 17:11:47 +02:00
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
result = (float4) num;
|
|
|
|
if (unlikely(isinf(result)) && !isinf(num))
|
|
|
|
float_overflow_error();
|
|
|
|
if (unlikely(result == 0.0f) && num != 0.0)
|
|
|
|
float_underflow_error();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
PG_RETURN_FLOAT4(result);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* dtoi4 - converts a float8 number to an int4 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dtoi4(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 num = PG_GETARG_FLOAT8(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
/*
|
|
|
|
* Get rid of any fractional part in the input. This is so we don't fail
|
|
|
|
* on just-out-of-range values that would round into range. Note
|
|
|
|
* assumption that rint() will pass through a NaN or Inf unchanged.
|
|
|
|
*/
|
|
|
|
num = rint(num);
|
|
|
|
|
2019-11-07 17:22:52 +01:00
|
|
|
/* Range check */
|
|
|
|
if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT32(num)))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("integer out of range")));
|
1997-05-11 17:11:47 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
PG_RETURN_INT32((int32) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* dtoi2 - converts a float8 number to an int2 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
dtoi2(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
float8 num = PG_GETARG_FLOAT8(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
/*
|
|
|
|
* Get rid of any fractional part in the input. This is so we don't fail
|
|
|
|
* on just-out-of-range values that would round into range. Note
|
|
|
|
* assumption that rint() will pass through a NaN or Inf unchanged.
|
|
|
|
*/
|
|
|
|
num = rint(num);
|
|
|
|
|
2019-11-07 17:22:52 +01:00
|
|
|
/* Range check */
|
|
|
|
if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT16(num)))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
2004-10-04 16:42:48 +02:00
|
|
|
errmsg("smallint out of range")));
|
1997-05-11 17:11:47 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
PG_RETURN_INT16((int16) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* i4tod - converts an int4 number to a float8 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
i4tod(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-06-13 09:35:40 +02:00
|
|
|
int32 num = PG_GETARG_INT32(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT8((float8) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* i2tod - converts an int2 number to a float8 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
i2tod(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
int16 num = PG_GETARG_INT16(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT8((float8) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* ftoi4 - converts a float4 number to an int4 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
ftoi4(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 num = PG_GETARG_FLOAT4(0);
|
1997-05-11 17:11:47 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
/*
|
|
|
|
* Get rid of any fractional part in the input. This is so we don't fail
|
|
|
|
* on just-out-of-range values that would round into range. Note
|
|
|
|
* assumption that rint() will pass through a NaN or Inf unchanged.
|
|
|
|
*/
|
|
|
|
num = rint(num);
|
|
|
|
|
2019-11-07 17:22:52 +01:00
|
|
|
/* Range check */
|
|
|
|
if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT32(num)))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("integer out of range")));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
PG_RETURN_INT32((int32) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-06-05 09:29:25 +02:00
|
|
|
* ftoi2 - converts a float4 number to an int2 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
ftoi2(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
float4 num = PG_GETARG_FLOAT4(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
/*
|
|
|
|
* Get rid of any fractional part in the input. This is so we don't fail
|
|
|
|
* on just-out-of-range values that would round into range. Note
|
|
|
|
* assumption that rint() will pass through a NaN or Inf unchanged.
|
|
|
|
*/
|
|
|
|
num = rint(num);
|
|
|
|
|
2019-11-07 17:22:52 +01:00
|
|
|
/* Range check */
|
|
|
|
if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT16(num)))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
2004-10-04 16:42:48 +02:00
|
|
|
errmsg("smallint out of range")));
|
1997-05-11 17:11:47 +02:00
|
|
|
|
2018-11-24 02:57:11 +01:00
|
|
|
PG_RETURN_INT16((int16) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2007-01-02 21:00:50 +01:00
|
|
|
* i4tof - converts an int4 number to a float4 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-06-13 09:35:40 +02:00
|
|
|
Datum
|
|
|
|
i4tof(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-06-13 09:35:40 +02:00
|
|
|
int32 num = PG_GETARG_INT32(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT4((float4) num);
|
1997-05-11 17:11:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-06-05 09:29:25 +02:00
|
|
|
* i2tof - converts an int2 number to a float4 number
|
1997-05-11 17:11:47 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
i2tof(PG_FUNCTION_ARGS)
|
1997-05-11 17:11:47 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
int16 num = PG_GETARG_INT16(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT4((float4) num);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* =======================
|
|
|
|
* RANDOM FLOAT8 OPERATORS
|
|
|
|
* =======================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dround - returns ROUND(arg1)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dround(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
PG_RETURN_FLOAT8(rint(arg1));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-10-19 04:08:19 +02:00
|
|
|
/*
|
|
|
|
* dceil - returns the smallest integer greater than or
|
|
|
|
* equal to the specified float
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dceil(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(ceil(arg1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dfloor - returns the largest integer lesser than or
|
|
|
|
* equal to the specified float
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dfloor(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(floor(arg1));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dsign - returns -1 if the argument is less than 0, 0
|
|
|
|
* if the argument is equal to 0, and 1 if the
|
|
|
|
* argument is greater than zero.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dsign(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
if (arg1 > 0)
|
|
|
|
result = 1.0;
|
|
|
|
else if (arg1 < 0)
|
|
|
|
result = -1.0;
|
|
|
|
else
|
|
|
|
result = 0.0;
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dtrunc - returns truncation-towards-zero of arg1,
|
|
|
|
* arg1 >= 0 ... the greatest integer less
|
1997-09-07 07:04:48 +02:00
|
|
|
* than or equal to arg1
|
2000-08-01 20:29:35 +02:00
|
|
|
* arg1 < 0 ... the least integer greater
|
1997-09-07 07:04:48 +02:00
|
|
|
* than or equal to arg1
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dtrunc(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
if (arg1 >= 0)
|
|
|
|
result = floor(arg1);
|
1997-09-07 07:04:48 +02:00
|
|
|
else
|
2000-08-01 20:29:35 +02:00
|
|
|
result = -floor(-arg1);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dsqrt - returns square root of arg1
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dsqrt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
if (arg1 < 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-05-17 01:18:55 +02:00
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
|
2003-07-27 06:53:12 +02:00
|
|
|
errmsg("cannot take square root of a negative number")));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = sqrt(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)) && !isinf(arg1))
|
|
|
|
float_overflow_error();
|
|
|
|
if (unlikely(result == 0.0) && arg1 != 0.0)
|
|
|
|
float_underflow_error();
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dcbrt - returns cube root of arg1
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dcbrt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = cbrt(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)) && !isinf(arg1))
|
|
|
|
float_overflow_error();
|
|
|
|
if (unlikely(result == 0.0) && arg1 != 0.0)
|
|
|
|
float_underflow_error();
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dpow - returns pow(arg1,arg2)
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dpow(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 result;
|
1999-12-20 03:15:35 +01:00
|
|
|
|
2018-04-30 00:15:16 +02:00
|
|
|
/*
|
|
|
|
* The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other
|
|
|
|
* cases with NaN inputs yield NaN (with no error). Many older platforms
|
|
|
|
* get one or more of these cases wrong, so deal with them via explicit
|
|
|
|
* logic rather than trusting pow(3).
|
|
|
|
*/
|
|
|
|
if (isnan(arg1))
|
|
|
|
{
|
|
|
|
if (isnan(arg2) || arg2 != 0.0)
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
PG_RETURN_FLOAT8(1.0);
|
|
|
|
}
|
|
|
|
if (isnan(arg2))
|
|
|
|
{
|
|
|
|
if (arg1 != 1.0)
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
PG_RETURN_FLOAT8(1.0);
|
|
|
|
}
|
|
|
|
|
2004-05-17 01:18:55 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The SQL spec requires that we emit a particular SQLSTATE error code for
|
2009-06-11 16:49:15 +02:00
|
|
|
* certain error conditions. Specifically, we don't return a
|
|
|
|
* divide-by-zero error code for 0 ^ -1.
|
2004-05-17 01:18:55 +02:00
|
|
|
*/
|
2008-05-09 23:31:23 +02:00
|
|
|
if (arg1 == 0 && arg2 < 0)
|
2004-05-17 01:18:55 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
|
2008-05-09 23:31:23 +02:00
|
|
|
errmsg("zero raised to a negative power is undefined")));
|
|
|
|
if (arg1 < 0 && floor(arg2) != arg2)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
|
|
|
|
errmsg("a negative number raised to a non-integer power yields a complex result")));
|
2004-05-17 01:18:55 +02:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/*
|
2020-06-15 18:15:56 +02:00
|
|
|
* We don't trust the platform's pow() to handle infinity cases per POSIX
|
|
|
|
* spec either, so deal with those explicitly too. It's easier to handle
|
|
|
|
* infinite y first, so that it doesn't matter if x is also infinite.
|
1999-12-20 03:15:35 +01:00
|
|
|
*/
|
2020-06-15 18:15:56 +02:00
|
|
|
if (isinf(arg2))
|
2007-01-03 15:35:24 +01:00
|
|
|
{
|
2020-06-16 17:09:42 +02:00
|
|
|
float8 absx = fabs(arg1);
|
2020-06-15 18:15:56 +02:00
|
|
|
|
|
|
|
if (absx == 1.0)
|
|
|
|
result = 1.0;
|
|
|
|
else if (arg2 > 0.0) /* y = +Inf */
|
|
|
|
{
|
|
|
|
if (absx > 1.0)
|
|
|
|
result = arg2;
|
|
|
|
else
|
|
|
|
result = 0.0;
|
|
|
|
}
|
|
|
|
else /* y = -Inf */
|
|
|
|
{
|
|
|
|
if (absx > 1.0)
|
|
|
|
result = 0.0;
|
|
|
|
else
|
|
|
|
result = -arg2;
|
|
|
|
}
|
2007-01-03 15:35:24 +01:00
|
|
|
}
|
2020-06-15 18:15:56 +02:00
|
|
|
else if (isinf(arg1))
|
|
|
|
{
|
|
|
|
if (arg2 == 0.0)
|
|
|
|
result = 1.0;
|
|
|
|
else if (arg1 > 0.0) /* x = +Inf */
|
|
|
|
{
|
|
|
|
if (arg2 > 0.0)
|
|
|
|
result = arg1;
|
|
|
|
else
|
|
|
|
result = 0.0;
|
|
|
|
}
|
|
|
|
else /* x = -Inf */
|
|
|
|
{
|
2020-06-16 17:09:42 +02:00
|
|
|
/*
|
|
|
|
* Per POSIX, the sign of the result depends on whether y is an
|
|
|
|
* odd integer. Since x < 0, we already know from the previous
|
|
|
|
* domain check that y is an integer. It is odd if y/2 is not
|
|
|
|
* also an integer.
|
|
|
|
*/
|
|
|
|
float8 halfy = arg2 / 2; /* should be computed exactly */
|
|
|
|
bool yisoddinteger = (floor(halfy) != halfy);
|
2020-06-15 18:15:56 +02:00
|
|
|
|
|
|
|
if (arg2 > 0.0)
|
|
|
|
result = yisoddinteger ? arg1 : -arg1;
|
|
|
|
else
|
|
|
|
result = yisoddinteger ? -0.0 : 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* pow() sets errno on only some platforms, depending on whether it
|
|
|
|
* follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we must check both
|
|
|
|
* errno and invalid output values. (We can't rely on just the
|
|
|
|
* latter, either; some old platforms return a large-but-finite
|
|
|
|
* HUGE_VAL when reporting overflow.)
|
|
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
result = pow(arg1, arg2);
|
|
|
|
if (errno == EDOM || isnan(result))
|
|
|
|
{
|
|
|
|
/*
|
2020-06-16 01:10:30 +02:00
|
|
|
* We handled all possible domain errors above, so this should be
|
|
|
|
* impossible. However, old glibc versions on x86 have a bug that
|
|
|
|
* causes them to fail this way for abs(y) greater than 2^63:
|
|
|
|
*
|
|
|
|
* https://sourceware.org/bugzilla/show_bug.cgi?id=3866
|
|
|
|
*
|
|
|
|
* Hence, if we get here, assume y is finite but large (large
|
|
|
|
* enough to be certainly even). The result should be 0 if x == 0,
|
|
|
|
* 1.0 if abs(x) == 1.0, otherwise an overflow or underflow error.
|
2020-06-15 18:15:56 +02:00
|
|
|
*/
|
2020-06-16 01:10:30 +02:00
|
|
|
if (arg1 == 0.0)
|
|
|
|
result = 0.0; /* we already verified y is positive */
|
|
|
|
else
|
|
|
|
{
|
2020-06-16 17:09:42 +02:00
|
|
|
float8 absx = fabs(arg1);
|
2020-06-16 01:10:30 +02:00
|
|
|
|
|
|
|
if (absx == 1.0)
|
|
|
|
result = 1.0;
|
|
|
|
else if (arg2 >= 0.0 ? (absx > 1.0) : (absx < 1.0))
|
|
|
|
float_overflow_error();
|
|
|
|
else
|
|
|
|
float_underflow_error();
|
|
|
|
}
|
2020-06-15 18:15:56 +02:00
|
|
|
}
|
|
|
|
else if (errno == ERANGE)
|
|
|
|
{
|
|
|
|
if (result != 0.0)
|
|
|
|
float_overflow_error();
|
|
|
|
else
|
|
|
|
float_underflow_error();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
if (unlikely(result == 0.0) && arg1 != 0.0)
|
|
|
|
float_underflow_error();
|
|
|
|
}
|
|
|
|
}
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dexp - returns the exponential function of arg1
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dexp(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
1999-12-20 03:15:35 +01:00
|
|
|
|
2020-06-14 17:00:07 +02:00
|
|
|
/*
|
|
|
|
* Handle NaN and Inf cases explicitly. This avoids needing to assume
|
|
|
|
* that the platform's exp() conforms to POSIX for these cases, and it
|
|
|
|
* removes some edge cases for the overflow checks below.
|
|
|
|
*/
|
|
|
|
if (isnan(arg1))
|
|
|
|
result = arg1;
|
|
|
|
else if (isinf(arg1))
|
|
|
|
{
|
|
|
|
/* Per POSIX, exp(-Inf) is 0 */
|
|
|
|
result = (arg1 > 0.0) ? arg1 : 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* On some platforms, exp() will not set errno but just return Inf or
|
|
|
|
* zero to report overflow/underflow; therefore, test both cases.
|
|
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
result = exp(arg1);
|
|
|
|
if (unlikely(errno == ERANGE))
|
|
|
|
{
|
|
|
|
if (result != 0.0)
|
|
|
|
float_overflow_error();
|
|
|
|
else
|
|
|
|
float_underflow_error();
|
|
|
|
}
|
|
|
|
else if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
else if (unlikely(result == 0.0))
|
|
|
|
float_underflow_error();
|
|
|
|
}
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dlog1 - returns the natural logarithm of arg1
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dlog1(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-05-17 01:18:55 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Emit particular SQLSTATE error codes for ln(). This is required by the
|
|
|
|
* SQL standard.
|
2004-05-17 01:18:55 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
if (arg1 == 0.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-05-17 01:18:55 +02:00
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("cannot take logarithm of zero")));
|
2000-08-01 20:29:35 +02:00
|
|
|
if (arg1 < 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-05-17 01:18:55 +02:00
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("cannot take logarithm of a negative number")));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = log(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)) && !isinf(arg1))
|
|
|
|
float_overflow_error();
|
|
|
|
if (unlikely(result == 0.0) && arg1 != 1.0)
|
|
|
|
float_underflow_error();
|
2000-08-01 20:29:35 +02:00
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-03-15 00:06:59 +01:00
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dlog10 - returns the base 10 logarithm of arg1
|
2000-03-15 00:06:59 +01:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dlog10(PG_FUNCTION_ARGS)
|
2000-03-15 00:06:59 +01:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-03-15 00:06:59 +01:00
|
|
|
|
2004-05-17 01:18:55 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Emit particular SQLSTATE error codes for log(). The SQL spec doesn't
|
|
|
|
* define log(), but it does define ln(), so it makes sense to emit the
|
|
|
|
* same error code for an analogous error condition.
|
2004-05-17 01:18:55 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
if (arg1 == 0.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-05-17 01:18:55 +02:00
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("cannot take logarithm of zero")));
|
2000-08-01 20:29:35 +02:00
|
|
|
if (arg1 < 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
2004-05-17 01:18:55 +02:00
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("cannot take logarithm of a negative number")));
|
2000-03-15 00:06:59 +01:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = log10(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)) && !isinf(arg1))
|
|
|
|
float_overflow_error();
|
|
|
|
if (unlikely(result == 0.0) && arg1 != 1.0)
|
|
|
|
float_underflow_error();
|
2000-08-01 20:29:35 +02:00
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-03-15 00:06:59 +01:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-04-07 15:40:45 +02:00
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dacos - returns the arccos of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dacos(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
2007-01-03 05:21:47 +01:00
|
|
|
/*
|
2016-01-22 20:50:51 +01:00
|
|
|
* The principal branch of the inverse cosine function maps values in the
|
|
|
|
* range [-1, 1] to values in the range [0, Pi], so we should reject any
|
|
|
|
* inputs outside that range and the result will always be finite.
|
2007-01-03 05:21:47 +01:00
|
|
|
*/
|
2016-01-22 20:50:51 +01:00
|
|
|
if (arg1 < -1.0 || arg1 > 1.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
result = acos(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
2016-01-22 20:50:51 +01:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dasin - returns the arcsin of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dasin(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The principal branch of the inverse sine function maps values in the
|
|
|
|
* range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
|
|
|
|
* any inputs outside that range and the result will always be finite.
|
|
|
|
*/
|
|
|
|
if (arg1 < -1.0 || arg1 > 1.0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
result = asin(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
2016-01-22 20:50:51 +01:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* datan - returns the arctan of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
datan(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The principal branch of the inverse tangent function maps all inputs to
|
|
|
|
* values in the range [-Pi/2, Pi/2], so the result should always be
|
|
|
|
* finite, even if the input is infinite.
|
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
result = atan(arg1);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2016-01-22 21:46:22 +01:00
|
|
|
* atan2 - returns the arctan of arg1/arg2 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
datan2(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if either input is NaN */
|
|
|
|
if (isnan(arg1) || isnan(arg2))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* atan2 maps all inputs to values in the range [-Pi, Pi], so the result
|
|
|
|
* should always be finite, even if the inputs are infinite.
|
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
result = atan2(arg1, arg2);
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dcos - returns the cosine of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dcos(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cos() is periodic and so theoretically can work for all finite inputs,
|
|
|
|
* but some implementations may choose to throw error if the input is so
|
|
|
|
* large that there are no significant digits in the result. So we should
|
|
|
|
* check for errors. POSIX allows an error to be reported either via
|
|
|
|
* errno or via fetestexcept(), but currently we only support checking
|
|
|
|
* errno. (fetestexcept() is rumored to report underflow unreasonably
|
|
|
|
* early on some platforms, so it's not clear that believing it would be a
|
|
|
|
* net improvement anyway.)
|
|
|
|
*
|
|
|
|
* For infinite inputs, POSIX specifies that the trigonometric functions
|
|
|
|
* should return a domain error; but we won't notice that unless the
|
|
|
|
* platform reports via errno, so also explicitly test for infinite
|
|
|
|
* inputs.
|
|
|
|
*/
|
2005-12-02 03:49:11 +01:00
|
|
|
errno = 0;
|
2000-08-01 20:29:35 +02:00
|
|
|
result = cos(arg1);
|
2016-01-22 20:50:51 +01:00
|
|
|
if (errno != 0 || isinf(arg1))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dcot - returns the cotangent of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dcot(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/* Be sure to throw an error if the input is infinite --- see dcos() */
|
2005-12-02 03:49:11 +01:00
|
|
|
errno = 0;
|
2000-08-01 20:29:35 +02:00
|
|
|
result = tan(arg1);
|
2016-01-22 20:50:51 +01:00
|
|
|
if (errno != 0 || isinf(arg1))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
result = 1.0 / result;
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
/* Not checking for overflow because cot(0) == Inf */
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dsin - returns the sine of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dsin(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/* Be sure to throw an error if the input is infinite --- see dcos() */
|
2005-12-02 03:49:11 +01:00
|
|
|
errno = 0;
|
2000-08-01 20:29:35 +02:00
|
|
|
result = sin(arg1);
|
2016-01-22 20:50:51 +01:00
|
|
|
if (errno != 0 || isinf(arg1))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dtan - returns the tangent of arg1 (radians)
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dtan(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2016-01-22 20:50:51 +01:00
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
/* Be sure to throw an error if the input is infinite --- see dcos() */
|
2005-12-02 03:49:11 +01:00
|
|
|
errno = 0;
|
2000-08-01 20:29:35 +02:00
|
|
|
result = tan(arg1);
|
2016-01-22 20:50:51 +01:00
|
|
|
if (errno != 0 || isinf(arg1))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
/* Not checking for overflow because tan(pi/2) == Inf */
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
/* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the cached constants declared at the head of this file
|
|
|
|
* (sin_30 etc). The fact that we need those at all, let alone need this
|
|
|
|
* Rube-Goldberg-worthy method of initializing them, is because there are
|
|
|
|
* compilers out there that will precompute expressions such as sin(constant)
|
|
|
|
* using a sin() function different from what will be used at runtime. If we
|
|
|
|
* want exact results, we must ensure that none of the scaling constants used
|
2016-04-25 21:21:04 +02:00
|
|
|
* in the degree-based trig functions are computed that way. To do so, we
|
|
|
|
* compute them from the variables degree_c_thirty etc, which are also really
|
|
|
|
* constants, but the compiler cannot assume that.
|
2016-01-24 00:12:54 +01:00
|
|
|
*
|
2016-01-23 22:17:31 +01:00
|
|
|
* Other hazards we are trying to forestall with this kluge include the
|
|
|
|
* possibility that compilers will rearrange the expressions, or compute
|
|
|
|
* some intermediate results in registers wider than a standard double.
|
2016-04-26 17:24:15 +02:00
|
|
|
*
|
|
|
|
* In the places where we use these constants, the typical pattern is like
|
|
|
|
* volatile float8 sin_x = sin(x * RADIANS_PER_DEGREE);
|
|
|
|
* return (sin_x / sin_30);
|
|
|
|
* where we hope to get a value of exactly 1.0 from the division when x = 30.
|
|
|
|
* The volatile temporary variable is needed on machines with wide float
|
|
|
|
* registers, to ensure that the result of sin(x) is rounded to double width
|
|
|
|
* the same as the value of sin_30 has been. Experimentation with gcc shows
|
|
|
|
* that marking the temp variable volatile is necessary to make the store and
|
|
|
|
* reload actually happen; hopefully the same trick works for other compilers.
|
|
|
|
* (gcc's documentation suggests using the -ffloat-store compiler switch to
|
|
|
|
* ensure this, but that is compiler-specific and it also pessimizes code in
|
|
|
|
* many places where we don't care about this.)
|
2016-01-23 22:17:31 +01:00
|
|
|
*/
|
2016-04-25 21:21:04 +02:00
|
|
|
static void
|
|
|
|
init_degree_constants(void)
|
|
|
|
{
|
|
|
|
sin_30 = sin(degree_c_thirty * RADIANS_PER_DEGREE);
|
|
|
|
one_minus_cos_60 = 1.0 - cos(degree_c_sixty * RADIANS_PER_DEGREE);
|
|
|
|
asin_0_5 = asin(degree_c_one_half);
|
|
|
|
acos_0_5 = acos(degree_c_one_half);
|
|
|
|
atan_1_0 = atan(degree_c_one);
|
|
|
|
tan_45 = sind_q1(degree_c_forty_five) / cosd_q1(degree_c_forty_five);
|
|
|
|
cot_45 = cosd_q1(degree_c_forty_five) / sind_q1(degree_c_forty_five);
|
2016-01-23 22:17:31 +01:00
|
|
|
degree_consts_set = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INIT_DEGREE_CONSTANTS() \
|
|
|
|
do { \
|
|
|
|
if (!degree_consts_set) \
|
2016-04-25 21:21:04 +02:00
|
|
|
init_degree_constants(); \
|
2016-01-23 22:17:31 +01:00
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/*
|
|
|
|
* asind_q1 - returns the inverse sine of x in degrees, for x in
|
|
|
|
* the range [0, 1]. The result is an angle in the
|
|
|
|
* first quadrant --- [0, 90] degrees.
|
|
|
|
*
|
|
|
|
* For the 3 special case inputs (0, 0.5 and 1), this
|
|
|
|
* function will return exact values (0, 30 and 90
|
|
|
|
* degrees respectively).
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
asind_q1(double x)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Stitch together inverse sine and cosine functions for the ranges [0,
|
|
|
|
* 0.5] and (0.5, 1]. Each expression below is guaranteed to return
|
|
|
|
* exactly 30 for x=0.5, so the result is a continuous monotonic function
|
|
|
|
* over the full range.
|
|
|
|
*/
|
|
|
|
if (x <= 0.5)
|
2016-04-26 17:24:15 +02:00
|
|
|
{
|
|
|
|
volatile float8 asin_x = asin(x);
|
|
|
|
|
|
|
|
return (asin_x / asin_0_5) * 30.0;
|
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
else
|
2016-04-26 17:24:15 +02:00
|
|
|
{
|
|
|
|
volatile float8 acos_x = acos(x);
|
|
|
|
|
|
|
|
return 90.0 - (acos_x / acos_0_5) * 60.0;
|
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* acosd_q1 - returns the inverse cosine of x in degrees, for x in
|
|
|
|
* the range [0, 1]. The result is an angle in the
|
|
|
|
* first quadrant --- [0, 90] degrees.
|
|
|
|
*
|
|
|
|
* For the 3 special case inputs (0, 0.5 and 1), this
|
|
|
|
* function will return exact values (0, 60 and 90
|
|
|
|
* degrees respectively).
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
acosd_q1(double x)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Stitch together inverse sine and cosine functions for the ranges [0,
|
|
|
|
* 0.5] and (0.5, 1]. Each expression below is guaranteed to return
|
|
|
|
* exactly 60 for x=0.5, so the result is a continuous monotonic function
|
|
|
|
* over the full range.
|
|
|
|
*/
|
|
|
|
if (x <= 0.5)
|
2016-04-26 17:24:15 +02:00
|
|
|
{
|
|
|
|
volatile float8 asin_x = asin(x);
|
|
|
|
|
|
|
|
return 90.0 - (asin_x / asin_0_5) * 30.0;
|
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
else
|
2016-04-26 17:24:15 +02:00
|
|
|
{
|
|
|
|
volatile float8 acos_x = acos(x);
|
|
|
|
|
|
|
|
return (acos_x / acos_0_5) * 60.0;
|
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dacosd - returns the arccos of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dacosd(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/*
|
|
|
|
* The principal branch of the inverse cosine function maps values in the
|
|
|
|
* range [-1, 1] to values in the range [0, 180], so we should reject any
|
|
|
|
* inputs outside that range and the result will always be finite.
|
|
|
|
*/
|
|
|
|
if (arg1 < -1.0 || arg1 > 1.0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
|
|
|
|
|
|
|
if (arg1 >= 0.0)
|
|
|
|
result = acosd_q1(arg1);
|
|
|
|
else
|
|
|
|
result = 90.0 + asind_q1(-arg1);
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dasind - returns the arcsin of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dasind(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/*
|
|
|
|
* The principal branch of the inverse sine function maps values in the
|
|
|
|
* range [-1, 1] to values in the range [-90, 90], so we should reject any
|
|
|
|
* inputs outside that range and the result will always be finite.
|
|
|
|
*/
|
|
|
|
if (arg1 < -1.0 || arg1 > 1.0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
|
|
|
|
|
|
|
if (arg1 >= 0.0)
|
|
|
|
result = asind_q1(arg1);
|
|
|
|
else
|
|
|
|
result = -asind_q1(-arg1);
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* datand - returns the arctan of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
datand(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2016-04-26 17:24:15 +02:00
|
|
|
volatile float8 atan_arg1;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
/* Per the POSIX spec, return NaN if the input is NaN */
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/*
|
|
|
|
* The principal branch of the inverse tangent function maps all inputs to
|
|
|
|
* values in the range [-90, 90], so the result should always be finite,
|
|
|
|
* even if the input is infinite. Additionally, we take care to ensure
|
|
|
|
* than when arg1 is 1, the result is exactly 45.
|
|
|
|
*/
|
2016-04-26 17:24:15 +02:00
|
|
|
atan_arg1 = atan(arg1);
|
|
|
|
result = (atan_arg1 / atan_1_0) * 45.0;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* atan2d - returns the arctan of arg1/arg2 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
datan2d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 result;
|
2016-04-26 17:24:15 +02:00
|
|
|
volatile float8 atan2_arg1_arg2;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
/* Per the POSIX spec, return NaN if either input is NaN */
|
|
|
|
if (isnan(arg1) || isnan(arg2))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/*
|
|
|
|
* atan2d maps all inputs to values in the range [-180, 180], so the
|
|
|
|
* result should always be finite, even if the inputs are infinite.
|
2016-04-26 17:24:15 +02:00
|
|
|
*
|
|
|
|
* Note: this coding assumes that atan(1.0) is a suitable scaling constant
|
|
|
|
* to get an exact result from atan2(). This might well fail on us at
|
|
|
|
* some point, requiring us to decide exactly what inputs we think we're
|
|
|
|
* going to guarantee an exact result for.
|
2016-01-22 21:46:22 +01:00
|
|
|
*/
|
2016-04-26 17:24:15 +02:00
|
|
|
atan2_arg1_arg2 = atan2(arg1, arg2);
|
|
|
|
result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sind_0_to_30 - returns the sine of an angle that lies between 0 and
|
|
|
|
* 30 degrees. This will return exactly 0 when x is 0,
|
|
|
|
* and exactly 0.5 when x is 30 degrees.
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
sind_0_to_30(double x)
|
|
|
|
{
|
2016-04-26 17:24:15 +02:00
|
|
|
volatile float8 sin_x = sin(x * RADIANS_PER_DEGREE);
|
|
|
|
|
|
|
|
return (sin_x / sin_30) / 2.0;
|
2016-01-22 21:46:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cosd_0_to_60 - returns the cosine of an angle that lies between 0
|
|
|
|
* and 60 degrees. This will return exactly 1 when x
|
|
|
|
* is 0, and exactly 0.5 when x is 60 degrees.
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
cosd_0_to_60(double x)
|
|
|
|
{
|
2016-04-26 17:24:15 +02:00
|
|
|
volatile float8 one_minus_cos_x = 1.0 - cos(x * RADIANS_PER_DEGREE);
|
2016-01-24 18:53:03 +01:00
|
|
|
|
|
|
|
return 1.0 - (one_minus_cos_x / one_minus_cos_60) / 2.0;
|
2016-01-22 21:46:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sind_q1 - returns the sine of an angle in the first quadrant
|
|
|
|
* (0 to 90 degrees).
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
sind_q1(double x)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Stitch together the sine and cosine functions for the ranges [0, 30]
|
|
|
|
* and (30, 90]. These guarantee to return exact answers at their
|
|
|
|
* endpoints, so the overall result is a continuous monotonic function
|
|
|
|
* that gives exact results when x = 0, 30 and 90 degrees.
|
|
|
|
*/
|
|
|
|
if (x <= 30.0)
|
|
|
|
return sind_0_to_30(x);
|
|
|
|
else
|
|
|
|
return cosd_0_to_60(90.0 - x);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* cosd_q1 - returns the cosine of an angle in the first quadrant
|
|
|
|
* (0 to 90 degrees).
|
|
|
|
*/
|
|
|
|
static double
|
|
|
|
cosd_q1(double x)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Stitch together the sine and cosine functions for the ranges [0, 60]
|
|
|
|
* and (60, 90]. These guarantee to return exact answers at their
|
|
|
|
* endpoints, so the overall result is a continuous monotonic function
|
|
|
|
* that gives exact results when x = 0, 60 and 90 degrees.
|
|
|
|
*/
|
|
|
|
if (x <= 60.0)
|
|
|
|
return cosd_0_to_60(x);
|
|
|
|
else
|
|
|
|
return sind_0_to_30(90.0 - x);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dcosd - returns the cosine of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dcosd(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2016-01-23 22:17:31 +01:00
|
|
|
int sign = 1;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Per the POSIX spec, return NaN if the input is NaN and throw an error
|
|
|
|
* if the input is infinite.
|
|
|
|
*/
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
if (isinf(arg1))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/* Reduce the range of the input to [0,90] degrees */
|
|
|
|
arg1 = fmod(arg1, 360.0);
|
|
|
|
|
|
|
|
if (arg1 < 0.0)
|
2016-01-23 22:17:31 +01:00
|
|
|
{
|
2016-01-22 21:46:22 +01:00
|
|
|
/* cosd(-x) = cosd(x) */
|
|
|
|
arg1 = -arg1;
|
2016-01-23 22:17:31 +01:00
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
if (arg1 > 180.0)
|
2016-01-23 22:17:31 +01:00
|
|
|
{
|
2016-01-22 21:46:22 +01:00
|
|
|
/* cosd(360-x) = cosd(x) */
|
|
|
|
arg1 = 360.0 - arg1;
|
2016-01-23 22:17:31 +01:00
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
if (arg1 > 90.0)
|
|
|
|
{
|
|
|
|
/* cosd(180-x) = -cosd(x) */
|
|
|
|
arg1 = 180.0 - arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = sign * cosd_q1(arg1);
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dcotd - returns the cotangent of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dcotd(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2016-04-26 17:24:15 +02:00
|
|
|
volatile float8 cot_arg1;
|
2016-01-23 17:26:07 +01:00
|
|
|
int sign = 1;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Per the POSIX spec, return NaN if the input is NaN and throw an error
|
|
|
|
* if the input is infinite.
|
|
|
|
*/
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
if (isinf(arg1))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/* Reduce the range of the input to [0,90] degrees */
|
|
|
|
arg1 = fmod(arg1, 360.0);
|
|
|
|
|
|
|
|
if (arg1 < 0.0)
|
|
|
|
{
|
|
|
|
/* cotd(-x) = -cotd(x) */
|
|
|
|
arg1 = -arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 > 180.0)
|
|
|
|
{
|
|
|
|
/* cotd(360-x) = -cotd(x) */
|
|
|
|
arg1 = 360.0 - arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 > 90.0)
|
|
|
|
{
|
|
|
|
/* cotd(180-x) = -cotd(x) */
|
|
|
|
arg1 = 180.0 - arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
2016-04-26 17:24:15 +02:00
|
|
|
cot_arg1 = cosd_q1(arg1) / sind_q1(arg1);
|
|
|
|
result = sign * (cot_arg1 / cot_45);
|
2016-01-23 17:26:07 +01:00
|
|
|
|
|
|
|
/*
|
2016-01-23 22:17:31 +01:00
|
|
|
* On some machines we get cotd(270) = minus zero, but this isn't always
|
2016-01-23 17:26:07 +01:00
|
|
|
* true. For portability, and because the user constituency for this
|
|
|
|
* function probably doesn't want minus zero, force it to plain zero.
|
|
|
|
*/
|
|
|
|
if (result == 0.0)
|
|
|
|
result = 0.0;
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
/* Not checking for overflow because cotd(0) == Inf */
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dsind - returns the sine of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dsind(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2016-01-23 22:17:31 +01:00
|
|
|
int sign = 1;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Per the POSIX spec, return NaN if the input is NaN and throw an error
|
|
|
|
* if the input is infinite.
|
|
|
|
*/
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
if (isinf(arg1))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/* Reduce the range of the input to [0,90] degrees */
|
|
|
|
arg1 = fmod(arg1, 360.0);
|
|
|
|
|
|
|
|
if (arg1 < 0.0)
|
|
|
|
{
|
|
|
|
/* sind(-x) = -sind(x) */
|
|
|
|
arg1 = -arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 > 180.0)
|
|
|
|
{
|
|
|
|
/* sind(360-x) = -sind(x) */
|
|
|
|
arg1 = 360.0 - arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 > 90.0)
|
2016-01-23 22:17:31 +01:00
|
|
|
{
|
2016-01-22 21:46:22 +01:00
|
|
|
/* sind(180-x) = sind(x) */
|
|
|
|
arg1 = 180.0 - arg1;
|
2016-01-23 22:17:31 +01:00
|
|
|
}
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
result = sign * sind_q1(arg1);
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dtand - returns the tangent of arg1 (degrees)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
dtand(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 result;
|
2016-04-26 17:24:15 +02:00
|
|
|
volatile float8 tan_arg1;
|
2016-01-23 17:26:07 +01:00
|
|
|
int sign = 1;
|
2016-01-22 21:46:22 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Per the POSIX spec, return NaN if the input is NaN and throw an error
|
|
|
|
* if the input is infinite.
|
|
|
|
*/
|
|
|
|
if (isnan(arg1))
|
|
|
|
PG_RETURN_FLOAT8(get_float8_nan());
|
|
|
|
|
|
|
|
if (isinf(arg1))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("input is out of range")));
|
|
|
|
|
2016-01-23 22:17:31 +01:00
|
|
|
INIT_DEGREE_CONSTANTS();
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
/* Reduce the range of the input to [0,90] degrees */
|
|
|
|
arg1 = fmod(arg1, 360.0);
|
|
|
|
|
|
|
|
if (arg1 < 0.0)
|
|
|
|
{
|
|
|
|
/* tand(-x) = -tand(x) */
|
|
|
|
arg1 = -arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 > 180.0)
|
|
|
|
{
|
|
|
|
/* tand(360-x) = -tand(x) */
|
|
|
|
arg1 = 360.0 - arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg1 > 90.0)
|
|
|
|
{
|
|
|
|
/* tand(180-x) = -tand(x) */
|
|
|
|
arg1 = 180.0 - arg1;
|
|
|
|
sign = -sign;
|
|
|
|
}
|
|
|
|
|
2016-04-26 17:24:15 +02:00
|
|
|
tan_arg1 = sind_q1(arg1) / cosd_q1(arg1);
|
|
|
|
result = sign * (tan_arg1 / tan_45);
|
2016-01-23 17:26:07 +01:00
|
|
|
|
|
|
|
/*
|
2016-01-23 22:17:31 +01:00
|
|
|
* On some machines we get tand(180) = minus zero, but this isn't always
|
2016-01-23 17:26:07 +01:00
|
|
|
* true. For portability, and because the user constituency for this
|
|
|
|
* function probably doesn't want minus zero, force it to plain zero.
|
|
|
|
*/
|
|
|
|
if (result == 0.0)
|
|
|
|
result = 0.0;
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
/* Not checking for overflow because tand(90) == Inf */
|
|
|
|
|
2016-01-22 21:46:22 +01:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-07 15:40:45 +02:00
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* degrees - returns degrees converted from radians
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
degrees(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
|
2000-08-01 20:29:35 +02:00
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* dpi - returns the constant PI
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
dpi(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(M_PI);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* radians - returns radians converted from degrees
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
radians(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
|
2000-08-01 20:29:35 +02:00
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
Add support for hyperbolic functions, as well as log10().
The SQL:2016 standard adds support for the hyperbolic functions
sinh(), cosh(), and tanh(). POSIX has long required libm to
provide those functions as well as their inverses asinh(),
acosh(), atanh(). Hence, let's just expose the libm functions
to the SQL level. As with the trig functions, we only implement
versions for float8, not numeric.
For the moment, we'll assume that all platforms actually do have
these functions; if experience teaches otherwise, some autoconf
effort may be needed.
SQL:2016 also adds support for base-10 logarithm, but with the
function name log10(), whereas the name we've long used is log().
Add aliases named log10() for the float8 and numeric versions.
Lætitia Avrot
Discussion: https://postgr.es/m/CAB_COdguG22LO=rnxDQ2DW1uzv8aQoUzyDQNJjrR4k00XSgm5w@mail.gmail.com
2019-03-12 20:55:09 +01:00
|
|
|
/* ========== 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();
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(result == 0.0))
|
|
|
|
float_underflow_error();
|
|
|
|
|
Add support for hyperbolic functions, as well as log10().
The SQL:2016 standard adds support for the hyperbolic functions
sinh(), cosh(), and tanh(). POSIX has long required libm to
provide those functions as well as their inverses asinh(),
acosh(), atanh(). Hence, let's just expose the libm functions
to the SQL level. As with the trig functions, we only implement
versions for float8, not numeric.
For the moment, we'll assume that all platforms actually do have
these functions; if experience teaches otherwise, some autoconf
effort may be needed.
SQL:2016 also adds support for base-10 logarithm, but with the
function name log10(), whereas the name we've long used is log().
Add aliases named log10() for the float8 and numeric versions.
Lætitia Avrot
Discussion: https://postgr.es/m/CAB_COdguG22LO=rnxDQ2DW1uzv8aQoUzyDQNJjrR4k00XSgm5w@mail.gmail.com
2019-03-12 20:55:09 +01:00
|
|
|
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);
|
|
|
|
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(result)))
|
|
|
|
float_overflow_error();
|
|
|
|
|
Add support for hyperbolic functions, as well as log10().
The SQL:2016 standard adds support for the hyperbolic functions
sinh(), cosh(), and tanh(). POSIX has long required libm to
provide those functions as well as their inverses asinh(),
acosh(), atanh(). Hence, let's just expose the libm functions
to the SQL level. As with the trig functions, we only implement
versions for float8, not numeric.
For the moment, we'll assume that all platforms actually do have
these functions; if experience teaches otherwise, some autoconf
effort may be needed.
SQL:2016 also adds support for base-10 logarithm, but with the
function name log10(), whereas the name we've long used is log().
Add aliases named log10() for the float8 and numeric versions.
Lætitia Avrot
Discussion: https://postgr.es/m/CAB_COdguG22LO=rnxDQ2DW1uzv8aQoUzyDQNJjrR4k00XSgm5w@mail.gmail.com
2019-03-12 20:55:09 +01:00
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-04-07 15:40:45 +02:00
|
|
|
/*
|
2000-04-12 19:17:23 +02:00
|
|
|
* drandom - returns a random number
|
2000-04-07 15:40:45 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
drandom(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 result;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
/* Initialize random seed, if not done yet in this process */
|
|
|
|
if (unlikely(!drandom_seed_set))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If possible, initialize the seed using high-quality random bits.
|
|
|
|
* Should that fail for some reason, we fall back on a lower-quality
|
|
|
|
* seed based on current time and PID.
|
|
|
|
*/
|
2019-01-01 12:05:51 +01:00
|
|
|
if (!pg_strong_random(drandom_seed, sizeof(drandom_seed)))
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
{
|
|
|
|
TimestampTz now = GetCurrentTimestamp();
|
|
|
|
uint64 iseed;
|
|
|
|
|
|
|
|
/* Mix the PID with the most predictable bits of the timestamp */
|
|
|
|
iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
|
|
|
|
drandom_seed[0] = (unsigned short) iseed;
|
|
|
|
drandom_seed[1] = (unsigned short) (iseed >> 16);
|
|
|
|
drandom_seed[2] = (unsigned short) (iseed >> 32);
|
|
|
|
}
|
|
|
|
drandom_seed_set = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pg_erand48 produces desired result range [0.0 - 1.0) */
|
|
|
|
result = pg_erand48(drandom_seed);
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* setseed - set seed for the random number generator
|
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
setseed(PG_FUNCTION_ARGS)
|
2000-04-07 15:40:45 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 seed = PG_GETARG_FLOAT8(0);
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
uint64 iseed;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
Use a separate random seed for SQL random()/setseed() functions.
Previously, the SQL random() function depended on libc's random(3),
and setseed() invoked srandom(3). This results in interference between
these functions and backend-internal uses of random(3). We'd never paid
too much mind to that, but in the wake of commit 88bdbd3f7 which added
log_statement_sample_rate, the interference arguably has a security
consequence: if log_statement_sample_rate is active then an unprivileged
user could probably control which if any of his SQL commands get logged,
by issuing setseed() at the right times. That seems bad.
To fix this reliably, we need random() and setseed() to use their own
private random state variable. Standard random(3) isn't amenable to such
usage, so let's switch to pg_erand48(). It's hard to say whether that's
more or less "random" than any particular platform's version of random(3),
but it does have a wider seed value and a longer period than are required
by POSIX, so we can hope that this isn't a big downgrade. Also, we should
now have uniform behavior of random() across platforms, which is worth
something.
While at it, upgrade the per-process seed initialization method to use
pg_strong_random() if available, greatly reducing the predictability
of the initial seed value. (I'll separately do something similar for
the internal uses of random().)
In addition to forestalling the possible security problem, this has a
benefit in the other direction, which is that we can now document
setseed() as guaranteeing a reproducible sequence of random() values.
Previously, because of the possibility of internal calls of random(3),
we could not promise any such thing.
Discussion: https://postgr.es/m/3859.1545849900@sss.pgh.pa.us
2018-12-29 23:33:27 +01:00
|
|
|
if (seed < -1 || seed > 1 || isnan(seed))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("setseed parameter %g is out of allowed range [-1,1]",
|
|
|
|
seed)));
|
|
|
|
|
|
|
|
/* Use sign bit + 47 fractional bits to fill drandom_seed[] */
|
|
|
|
iseed = (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF));
|
|
|
|
drandom_seed[0] = (unsigned short) iseed;
|
|
|
|
drandom_seed[1] = (unsigned short) (iseed >> 16);
|
|
|
|
drandom_seed[2] = (unsigned short) (iseed >> 32);
|
|
|
|
drandom_seed_set = true;
|
2000-04-07 15:40:45 +02:00
|
|
|
|
2007-01-20 22:47:10 +01:00
|
|
|
PG_RETURN_VOID();
|
2000-08-01 20:29:35 +02:00
|
|
|
}
|
2000-04-07 15:40:45 +02:00
|
|
|
|
|
|
|
|
2000-07-17 05:05:41 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2000-07-17 05:05:41 +02:00
|
|
|
* =========================
|
|
|
|
* FLOAT AGGREGATE OPERATORS
|
|
|
|
* =========================
|
|
|
|
*
|
2006-03-10 21:15:28 +01:00
|
|
|
* float8_accum - accumulate for AVG(), variance aggregates, etc.
|
|
|
|
* float4_accum - same, but input data is float4
|
|
|
|
* float8_avg - produce final result for float AVG()
|
|
|
|
* float8_var_samp - produce final result for float VAR_SAMP()
|
|
|
|
* float8_var_pop - produce final result for float VAR_POP()
|
|
|
|
* float8_stddev_samp - produce final result for float STDDEV_SAMP()
|
|
|
|
* float8_stddev_pop - produce final result for float STDDEV_POP()
|
2000-07-17 05:05:41 +02:00
|
|
|
*
|
2018-10-06 12:20:09 +02:00
|
|
|
* The naive schoolbook implementation of these aggregates works by
|
|
|
|
* accumulating sum(X) and sum(X^2). However, this approach suffers from
|
|
|
|
* large rounding errors in the final computation of quantities like the
|
|
|
|
* population variance (N*sum(X^2) - sum(X)^2) / N^2, since each of the
|
|
|
|
* intermediate terms is potentially very large, while the difference is often
|
|
|
|
* quite small.
|
|
|
|
*
|
|
|
|
* Instead we use the Youngs-Cramer algorithm [1] which works by accumulating
|
|
|
|
* Sx=sum(X) and Sxx=sum((X-Sx/N)^2), using a numerically stable algorithm to
|
|
|
|
* incrementally update those quantities. The final computations of each of
|
|
|
|
* the aggregate values is then trivial and gives more accurate results (for
|
|
|
|
* example, the population variance is just Sxx/N). This algorithm is also
|
|
|
|
* fairly easy to generalize to allow parallel execution without loss of
|
|
|
|
* precision (see, for example, [2]). For more details, and a comparison of
|
|
|
|
* this with other algorithms, see [3].
|
|
|
|
*
|
2000-07-17 05:05:41 +02:00
|
|
|
* The transition datatype for all these aggregates is a 3-element array
|
2018-10-06 12:20:09 +02:00
|
|
|
* of float8, holding the values N, Sx, Sxx in that order.
|
2000-07-17 05:05:41 +02:00
|
|
|
*
|
|
|
|
* Note that we represent N as a float to avoid having to build a special
|
|
|
|
* datatype. Given a reasonable floating-point implementation, there should
|
|
|
|
* be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
|
|
|
|
* user will have doubtless lost interest anyway...)
|
2018-10-06 12:20:09 +02:00
|
|
|
*
|
|
|
|
* [1] Some Results Relevant to Choice of Sum and Sum-of-Product Algorithms,
|
|
|
|
* E. A. Youngs and E. M. Cramer, Technometrics Vol 13, No 3, August 1971.
|
|
|
|
*
|
|
|
|
* [2] Updating Formulae and a Pairwise Algorithm for Computing Sample
|
|
|
|
* Variances, T. F. Chan, G. H. Golub & R. J. LeVeque, COMPSTAT 1982.
|
|
|
|
*
|
|
|
|
* [3] Numerically Stable Parallel Computation of (Co-)Variance, Erich
|
|
|
|
* Schubert and Michael Gertz, Proceedings of the 30th International
|
|
|
|
* Conference on Scientific and Statistical Database Management, 2018.
|
2000-07-17 05:05:41 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
static float8 *
|
2006-07-28 20:33:04 +02:00
|
|
|
check_float8_array(ArrayType *transarray, const char *caller, int n)
|
2000-07-17 05:05:41 +02:00
|
|
|
{
|
|
|
|
/*
|
2006-07-28 20:33:04 +02:00
|
|
|
* We expect the input to be an N-element float array; verify that. We
|
2001-03-22 05:01:46 +01:00
|
|
|
* don't need to use deconstruct_array() since the array data is just
|
2006-07-28 20:33:04 +02:00
|
|
|
* going to look like a C array of N float8 values.
|
2000-07-17 05:05:41 +02:00
|
|
|
*/
|
2002-08-26 19:54:02 +02:00
|
|
|
if (ARR_NDIM(transarray) != 1 ||
|
2006-07-28 20:33:04 +02:00
|
|
|
ARR_DIMS(transarray)[0] != n ||
|
2005-11-17 23:14:56 +01:00
|
|
|
ARR_HASNULL(transarray) ||
|
2002-08-26 19:54:02 +02:00
|
|
|
ARR_ELEMTYPE(transarray) != FLOAT8OID)
|
2006-07-28 20:33:04 +02:00
|
|
|
elog(ERROR, "%s: expected %d-element float8 array", caller, n);
|
2000-07-17 05:05:41 +02:00
|
|
|
return (float8 *) ARR_DATA_PTR(transarray);
|
|
|
|
}
|
|
|
|
|
2016-04-08 19:44:50 +02:00
|
|
|
/*
|
|
|
|
* float8_combine
|
|
|
|
*
|
|
|
|
* An aggregate combine function used to combine two 3 fields
|
|
|
|
* aggregate transition data into a single transition data.
|
|
|
|
* This function is used only in two stage aggregation and
|
|
|
|
* shouldn't be called outside aggregate context.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float8_combine(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
float8 *transvalues1;
|
|
|
|
float8 *transvalues2;
|
2018-10-06 12:20:09 +02:00
|
|
|
float8 N1,
|
|
|
|
Sx1,
|
|
|
|
Sxx1,
|
|
|
|
N2,
|
|
|
|
Sx2,
|
|
|
|
Sxx2,
|
|
|
|
tmp,
|
|
|
|
N,
|
|
|
|
Sx,
|
|
|
|
Sxx;
|
2016-04-08 19:44:50 +02:00
|
|
|
|
|
|
|
transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
|
|
|
|
transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
N1 = transvalues1[0];
|
|
|
|
Sx1 = transvalues1[1];
|
|
|
|
Sxx1 = transvalues1[2];
|
|
|
|
|
|
|
|
N2 = transvalues2[0];
|
|
|
|
Sx2 = transvalues2[1];
|
|
|
|
Sxx2 = transvalues2[2];
|
|
|
|
|
|
|
|
/*--------------------
|
|
|
|
* The transition values combine using a generalization of the
|
|
|
|
* Youngs-Cramer algorithm as follows:
|
|
|
|
*
|
|
|
|
* N = N1 + N2
|
|
|
|
* Sx = Sx1 + Sx2
|
|
|
|
* Sxx = Sxx1 + Sxx2 + N1 * N2 * (Sx1/N1 - Sx2/N2)^2 / N;
|
|
|
|
*
|
|
|
|
* It's worth handling the special cases N1 = 0 and N2 = 0 separately
|
|
|
|
* since those cases are trivial, and we then don't need to worry about
|
|
|
|
* division-by-zero errors in the general case.
|
|
|
|
*--------------------
|
|
|
|
*/
|
|
|
|
if (N1 == 0.0)
|
|
|
|
{
|
|
|
|
N = N2;
|
|
|
|
Sx = Sx2;
|
|
|
|
Sxx = Sxx2;
|
|
|
|
}
|
|
|
|
else if (N2 == 0.0)
|
|
|
|
{
|
|
|
|
N = N1;
|
|
|
|
Sx = Sx1;
|
|
|
|
Sxx = Sxx1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
N = N1 + N2;
|
|
|
|
Sx = float8_pl(Sx1, Sx2);
|
|
|
|
tmp = Sx1 / N1 - Sx2 / N2;
|
|
|
|
Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N;
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
|
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're invoked as an aggregate, we can cheat and modify our first
|
|
|
|
* parameter in-place to reduce palloc overhead. Otherwise we construct a
|
|
|
|
* new array with the updated transition data and return it.
|
|
|
|
*/
|
|
|
|
if (AggCheckCallContext(fcinfo, NULL))
|
|
|
|
{
|
|
|
|
transvalues1[0] = N;
|
|
|
|
transvalues1[1] = Sx;
|
|
|
|
transvalues1[2] = Sxx;
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(transarray1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Datum transdatums[3];
|
|
|
|
ArrayType *result;
|
|
|
|
|
|
|
|
transdatums[0] = Float8GetDatumFast(N);
|
|
|
|
transdatums[1] = Float8GetDatumFast(Sx);
|
|
|
|
transdatums[2] = Float8GetDatumFast(Sxx);
|
|
|
|
|
|
|
|
result = construct_array(transdatums, 3,
|
|
|
|
FLOAT8OID,
|
2020-03-04 16:34:25 +01:00
|
|
|
sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE);
|
2016-04-08 19:44:50 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
2016-04-08 19:44:50 +02:00
|
|
|
}
|
|
|
|
|
2000-07-17 05:05:41 +02:00
|
|
|
Datum
|
|
|
|
float8_accum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 newval = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 *transvalues;
|
2018-10-06 12:20:09 +02:00
|
|
|
float8 N,
|
|
|
|
Sx,
|
|
|
|
Sxx,
|
|
|
|
tmp;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float8_accum", 3);
|
2018-10-06 12:20:09 +02:00
|
|
|
N = transvalues[0];
|
|
|
|
Sx = transvalues[1];
|
|
|
|
Sxx = transvalues[2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the Youngs-Cramer algorithm to incorporate the new value into the
|
|
|
|
* transition values.
|
|
|
|
*/
|
|
|
|
N += 1.0;
|
|
|
|
Sx += newval;
|
|
|
|
if (transvalues[0] > 0.0)
|
|
|
|
{
|
|
|
|
tmp = newval * N - Sx;
|
|
|
|
Sxx += tmp * tmp / (N * transvalues[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Overflow check. We only report an overflow error when finite
|
|
|
|
* inputs lead to infinite results. Note also that Sxx should be NaN
|
|
|
|
* if any of the inputs are infinite, so we intentionally prevent Sxx
|
|
|
|
* from becoming infinite.
|
|
|
|
*/
|
|
|
|
if (isinf(Sx) || isinf(Sxx))
|
|
|
|
{
|
|
|
|
if (!isinf(transvalues[1]) && !isinf(newval))
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
|
|
|
|
Sxx = get_float8_nan();
|
|
|
|
}
|
|
|
|
}
|
Fix behavior of float aggregates for single Inf or NaN inputs.
When there is just one non-null input value, and it is infinity or NaN,
aggregates such as stddev_pop and covar_pop should produce a NaN
result, because the calculation is not well-defined. They used to do
so, but since we adopted Youngs-Cramer aggregation in commit e954a727f,
they produced zero instead. That's an oversight, so fix it. Add tests
exercising these edge cases.
Affected aggregates are
var_pop(double precision)
stddev_pop(double precision)
var_pop(real)
stddev_pop(real)
regr_sxx(double precision,double precision)
regr_syy(double precision,double precision)
regr_sxy(double precision,double precision)
regr_r2(double precision,double precision)
regr_slope(double precision,double precision)
regr_intercept(double precision,double precision)
covar_pop(double precision,double precision)
corr(double precision,double precision)
Back-patch to v12 where the behavior change was accidentally introduced.
Report and patch by me; thanks to Dean Rasheed for review.
Discussion: https://postgr.es/m/353062.1591898766@sss.pgh.pa.us
2020-06-13 19:43:24 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* At the first input, we normally can leave Sxx as 0. However, if
|
|
|
|
* the first input is Inf or NaN, we'd better force Sxx to NaN;
|
|
|
|
* otherwise we will falsely report variance zero when there are no
|
|
|
|
* more inputs.
|
|
|
|
*/
|
|
|
|
if (isnan(newval) || isinf(newval))
|
|
|
|
Sxx = get_float8_nan();
|
|
|
|
}
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2005-04-07 01:56:07 +02:00
|
|
|
/*
|
2010-02-08 21:39:52 +01:00
|
|
|
* If we're invoked as an aggregate, we can cheat and modify our first
|
2005-10-15 04:49:52 +02:00
|
|
|
* parameter in-place to reduce palloc overhead. Otherwise we construct a
|
|
|
|
* new array with the updated transition data and return it.
|
2005-04-07 01:56:07 +02:00
|
|
|
*/
|
2010-02-08 21:39:52 +01:00
|
|
|
if (AggCheckCallContext(fcinfo, NULL))
|
2005-04-07 01:56:07 +02:00
|
|
|
{
|
2018-10-06 12:20:09 +02:00
|
|
|
transvalues[0] = N;
|
|
|
|
transvalues[1] = Sx;
|
|
|
|
transvalues[2] = Sxx;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2005-04-07 01:56:07 +02:00
|
|
|
PG_RETURN_ARRAYTYPE_P(transarray);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Datum transdatums[3];
|
|
|
|
ArrayType *result;
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
transdatums[0] = Float8GetDatumFast(N);
|
|
|
|
transdatums[1] = Float8GetDatumFast(Sx);
|
|
|
|
transdatums[2] = Float8GetDatumFast(Sxx);
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2005-04-07 01:56:07 +02:00
|
|
|
result = construct_array(transdatums, 3,
|
|
|
|
FLOAT8OID,
|
2020-03-04 16:34:25 +01:00
|
|
|
sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE);
|
2005-04-07 01:56:07 +02:00
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
2000-07-17 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float4_accum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2007-01-02 21:00:50 +01:00
|
|
|
/* do computations as float8 */
|
|
|
|
float8 newval = PG_GETARG_FLOAT4(1);
|
2000-07-17 05:05:41 +02:00
|
|
|
float8 *transvalues;
|
2018-10-06 12:20:09 +02:00
|
|
|
float8 N,
|
|
|
|
Sx,
|
|
|
|
Sxx,
|
|
|
|
tmp;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float4_accum", 3);
|
2018-10-06 12:20:09 +02:00
|
|
|
N = transvalues[0];
|
|
|
|
Sx = transvalues[1];
|
|
|
|
Sxx = transvalues[2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use the Youngs-Cramer algorithm to incorporate the new value into the
|
|
|
|
* transition values.
|
|
|
|
*/
|
|
|
|
N += 1.0;
|
|
|
|
Sx += newval;
|
|
|
|
if (transvalues[0] > 0.0)
|
|
|
|
{
|
|
|
|
tmp = newval * N - Sx;
|
|
|
|
Sxx += tmp * tmp / (N * transvalues[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Overflow check. We only report an overflow error when finite
|
|
|
|
* inputs lead to infinite results. Note also that Sxx should be NaN
|
|
|
|
* if any of the inputs are infinite, so we intentionally prevent Sxx
|
|
|
|
* from becoming infinite.
|
|
|
|
*/
|
|
|
|
if (isinf(Sx) || isinf(Sxx))
|
|
|
|
{
|
|
|
|
if (!isinf(transvalues[1]) && !isinf(newval))
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
|
|
|
|
Sxx = get_float8_nan();
|
|
|
|
}
|
|
|
|
}
|
Fix behavior of float aggregates for single Inf or NaN inputs.
When there is just one non-null input value, and it is infinity or NaN,
aggregates such as stddev_pop and covar_pop should produce a NaN
result, because the calculation is not well-defined. They used to do
so, but since we adopted Youngs-Cramer aggregation in commit e954a727f,
they produced zero instead. That's an oversight, so fix it. Add tests
exercising these edge cases.
Affected aggregates are
var_pop(double precision)
stddev_pop(double precision)
var_pop(real)
stddev_pop(real)
regr_sxx(double precision,double precision)
regr_syy(double precision,double precision)
regr_sxy(double precision,double precision)
regr_r2(double precision,double precision)
regr_slope(double precision,double precision)
regr_intercept(double precision,double precision)
covar_pop(double precision,double precision)
corr(double precision,double precision)
Back-patch to v12 where the behavior change was accidentally introduced.
Report and patch by me; thanks to Dean Rasheed for review.
Discussion: https://postgr.es/m/353062.1591898766@sss.pgh.pa.us
2020-06-13 19:43:24 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* At the first input, we normally can leave Sxx as 0. However, if
|
|
|
|
* the first input is Inf or NaN, we'd better force Sxx to NaN;
|
|
|
|
* otherwise we will falsely report variance zero when there are no
|
|
|
|
* more inputs.
|
|
|
|
*/
|
|
|
|
if (isnan(newval) || isinf(newval))
|
|
|
|
Sxx = get_float8_nan();
|
|
|
|
}
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2005-04-07 01:56:07 +02:00
|
|
|
/*
|
2010-02-08 21:39:52 +01:00
|
|
|
* If we're invoked as an aggregate, we can cheat and modify our first
|
2005-10-15 04:49:52 +02:00
|
|
|
* parameter in-place to reduce palloc overhead. Otherwise we construct a
|
|
|
|
* new array with the updated transition data and return it.
|
2005-04-07 01:56:07 +02:00
|
|
|
*/
|
2010-02-08 21:39:52 +01:00
|
|
|
if (AggCheckCallContext(fcinfo, NULL))
|
2005-04-07 01:56:07 +02:00
|
|
|
{
|
2018-10-06 12:20:09 +02:00
|
|
|
transvalues[0] = N;
|
|
|
|
transvalues[1] = Sx;
|
|
|
|
transvalues[2] = Sxx;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2005-04-07 01:56:07 +02:00
|
|
|
PG_RETURN_ARRAYTYPE_P(transarray);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Datum transdatums[3];
|
|
|
|
ArrayType *result;
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
transdatums[0] = Float8GetDatumFast(N);
|
|
|
|
transdatums[1] = Float8GetDatumFast(Sx);
|
|
|
|
transdatums[2] = Float8GetDatumFast(Sxx);
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2005-04-07 01:56:07 +02:00
|
|
|
result = construct_array(transdatums, 3,
|
|
|
|
FLOAT8OID,
|
2020-03-04 16:34:25 +01:00
|
|
|
sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE);
|
2005-04-07 01:56:07 +02:00
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
2000-07-17 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_avg(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float8_avg", 3);
|
2000-07-17 05:05:41 +02:00
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx = transvalues[1];
|
|
|
|
/* ignore Sxx */
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2013-04-20 17:04:41 +02:00
|
|
|
/* SQL defines AVG of no values to be NULL */
|
2000-07-17 05:05:41 +02:00
|
|
|
if (N == 0.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sx / N);
|
2000-07-17 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
2006-03-10 21:15:28 +01:00
|
|
|
float8_var_pop(PG_FUNCTION_ARGS)
|
2000-07-17 05:05:41 +02:00
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float8_var_pop", 3);
|
2006-03-10 21:15:28 +01:00
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
/* ignore Sx */
|
|
|
|
Sxx = transvalues[2];
|
2006-03-10 21:15:28 +01:00
|
|
|
|
|
|
|
/* Population variance is undefined when N is 0, so return NULL */
|
|
|
|
if (N == 0.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
2006-03-10 21:15:28 +01:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxx / N);
|
2006-03-10 21:15:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_var_samp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx;
|
2006-03-10 21:15:28 +01:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float8_var_samp", 3);
|
2000-07-17 05:05:41 +02:00
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
/* ignore Sx */
|
|
|
|
Sxx = transvalues[2];
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2003-04-21 02:22:24 +02:00
|
|
|
/* Sample variance is undefined when N is 0 or 1, so return NULL */
|
2000-07-17 05:05:41 +02:00
|
|
|
if (N <= 1.0)
|
2003-04-21 02:22:24 +02:00
|
|
|
PG_RETURN_NULL();
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
2001-12-11 03:02:12 +01:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxx / (N - 1.0));
|
2000-07-17 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
2006-03-10 21:15:28 +01:00
|
|
|
float8_stddev_pop(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx;
|
2006-03-10 21:15:28 +01:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
|
2006-03-10 21:15:28 +01:00
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
/* ignore Sx */
|
|
|
|
Sxx = transvalues[2];
|
2006-03-10 21:15:28 +01:00
|
|
|
|
|
|
|
/* Population stddev is undefined when N is 0, so return NULL */
|
|
|
|
if (N == 0.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
2006-03-10 21:15:28 +01:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(sqrt(Sxx / N));
|
2006-03-10 21:15:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_stddev_samp(PG_FUNCTION_ARGS)
|
2000-07-17 05:05:41 +02:00
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx;
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
|
2000-07-17 05:05:41 +02:00
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
/* ignore Sx */
|
|
|
|
Sxx = transvalues[2];
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2003-04-21 02:22:24 +02:00
|
|
|
/* Sample stddev is undefined when N is 0 or 1, so return NULL */
|
2000-07-17 05:05:41 +02:00
|
|
|
if (N <= 1.0)
|
2003-04-21 02:22:24 +02:00
|
|
|
PG_RETURN_NULL();
|
2000-07-17 05:05:41 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
2001-12-11 03:02:12 +01:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(sqrt(Sxx / (N - 1.0)));
|
2000-07-17 05:05:41 +02:00
|
|
|
}
|
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
/*
|
|
|
|
* =========================
|
|
|
|
* SQL2003 BINARY AGGREGATES
|
|
|
|
* =========================
|
|
|
|
*
|
2018-10-06 12:20:09 +02:00
|
|
|
* As with the preceding aggregates, we use the Youngs-Cramer algorithm to
|
|
|
|
* reduce rounding errors in the aggregate final functions.
|
|
|
|
*
|
2006-07-28 20:33:04 +02:00
|
|
|
* The transition datatype for all these aggregates is a 6-element array of
|
2018-10-06 12:20:09 +02:00
|
|
|
* float8, holding the values N, Sx=sum(X), Sxx=sum((X-Sx/N)^2), Sy=sum(Y),
|
|
|
|
* Syy=sum((Y-Sy/N)^2), Sxy=sum((X-Sx/N)*(Y-Sy/N)) in that order.
|
|
|
|
*
|
|
|
|
* Note that Y is the first argument to all these aggregates!
|
2006-07-28 20:33:04 +02:00
|
|
|
*
|
|
|
|
* It might seem attractive to optimize this by having multiple accumulator
|
2014-05-06 18:12:18 +02:00
|
|
|
* functions that only calculate the sums actually needed. But on most
|
2006-07-28 20:33:04 +02:00
|
|
|
* modern machines, a couple of extra floating-point multiplies will be
|
|
|
|
* insignificant compared to the other per-tuple overhead, so I've chosen
|
|
|
|
* to minimize code space instead.
|
|
|
|
*/
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_accum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 newvalY = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 newvalX = PG_GETARG_FLOAT8(2);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx,
|
|
|
|
Sxx,
|
|
|
|
Sy,
|
|
|
|
Syy,
|
|
|
|
Sxy,
|
|
|
|
tmpX,
|
|
|
|
tmpY,
|
|
|
|
scale;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx = transvalues[1];
|
|
|
|
Sxx = transvalues[2];
|
|
|
|
Sy = transvalues[3];
|
|
|
|
Syy = transvalues[4];
|
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/*
|
|
|
|
* Use the Youngs-Cramer algorithm to incorporate the new values into the
|
|
|
|
* transition values.
|
|
|
|
*/
|
2006-07-28 20:33:04 +02:00
|
|
|
N += 1.0;
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx += newvalX;
|
|
|
|
Sy += newvalY;
|
|
|
|
if (transvalues[0] > 0.0)
|
|
|
|
{
|
|
|
|
tmpX = newvalX * N - Sx;
|
|
|
|
tmpY = newvalY * N - Sy;
|
|
|
|
scale = 1.0 / (N * transvalues[0]);
|
|
|
|
Sxx += tmpX * tmpX * scale;
|
|
|
|
Syy += tmpY * tmpY * scale;
|
|
|
|
Sxy += tmpX * tmpY * scale;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Overflow check. We only report an overflow error when finite
|
|
|
|
* inputs lead to infinite results. Note also that Sxx, Syy and Sxy
|
|
|
|
* should be NaN if any of the relevant inputs are infinite, so we
|
|
|
|
* intentionally prevent them from becoming infinite.
|
|
|
|
*/
|
|
|
|
if (isinf(Sx) || isinf(Sxx) || isinf(Sy) || isinf(Syy) || isinf(Sxy))
|
|
|
|
{
|
|
|
|
if (((isinf(Sx) || isinf(Sxx)) &&
|
|
|
|
!isinf(transvalues[1]) && !isinf(newvalX)) ||
|
|
|
|
((isinf(Sy) || isinf(Syy)) &&
|
|
|
|
!isinf(transvalues[3]) && !isinf(newvalY)) ||
|
|
|
|
(isinf(Sxy) &&
|
|
|
|
!isinf(transvalues[1]) && !isinf(newvalX) &&
|
|
|
|
!isinf(transvalues[3]) && !isinf(newvalY)))
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
|
|
|
|
if (isinf(Sxx))
|
|
|
|
Sxx = get_float8_nan();
|
|
|
|
if (isinf(Syy))
|
|
|
|
Syy = get_float8_nan();
|
|
|
|
if (isinf(Sxy))
|
|
|
|
Sxy = get_float8_nan();
|
|
|
|
}
|
|
|
|
}
|
Fix behavior of float aggregates for single Inf or NaN inputs.
When there is just one non-null input value, and it is infinity or NaN,
aggregates such as stddev_pop and covar_pop should produce a NaN
result, because the calculation is not well-defined. They used to do
so, but since we adopted Youngs-Cramer aggregation in commit e954a727f,
they produced zero instead. That's an oversight, so fix it. Add tests
exercising these edge cases.
Affected aggregates are
var_pop(double precision)
stddev_pop(double precision)
var_pop(real)
stddev_pop(real)
regr_sxx(double precision,double precision)
regr_syy(double precision,double precision)
regr_sxy(double precision,double precision)
regr_r2(double precision,double precision)
regr_slope(double precision,double precision)
regr_intercept(double precision,double precision)
covar_pop(double precision,double precision)
corr(double precision,double precision)
Back-patch to v12 where the behavior change was accidentally introduced.
Report and patch by me; thanks to Dean Rasheed for review.
Discussion: https://postgr.es/m/353062.1591898766@sss.pgh.pa.us
2020-06-13 19:43:24 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* At the first input, we normally can leave Sxx et al as 0. However,
|
|
|
|
* if the first input is Inf or NaN, we'd better force the dependent
|
|
|
|
* sums to NaN; otherwise we will falsely report variance zero when
|
|
|
|
* there are no more inputs.
|
|
|
|
*/
|
|
|
|
if (isnan(newvalX) || isinf(newvalX))
|
|
|
|
Sxx = Sxy = get_float8_nan();
|
|
|
|
if (isnan(newvalY) || isinf(newvalY))
|
|
|
|
Syy = Sxy = get_float8_nan();
|
|
|
|
}
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
/*
|
2010-02-08 21:39:52 +01:00
|
|
|
* If we're invoked as an aggregate, we can cheat and modify our first
|
2006-07-28 20:33:04 +02:00
|
|
|
* parameter in-place to reduce palloc overhead. Otherwise we construct a
|
|
|
|
* new array with the updated transition data and return it.
|
|
|
|
*/
|
2010-02-08 21:39:52 +01:00
|
|
|
if (AggCheckCallContext(fcinfo, NULL))
|
2006-07-28 20:33:04 +02:00
|
|
|
{
|
|
|
|
transvalues[0] = N;
|
2018-10-06 12:20:09 +02:00
|
|
|
transvalues[1] = Sx;
|
|
|
|
transvalues[2] = Sxx;
|
|
|
|
transvalues[3] = Sy;
|
|
|
|
transvalues[4] = Syy;
|
|
|
|
transvalues[5] = Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(transarray);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Datum transdatums[6];
|
|
|
|
ArrayType *result;
|
|
|
|
|
|
|
|
transdatums[0] = Float8GetDatumFast(N);
|
2018-10-06 12:20:09 +02:00
|
|
|
transdatums[1] = Float8GetDatumFast(Sx);
|
|
|
|
transdatums[2] = Float8GetDatumFast(Sxx);
|
|
|
|
transdatums[3] = Float8GetDatumFast(Sy);
|
|
|
|
transdatums[4] = Float8GetDatumFast(Syy);
|
|
|
|
transdatums[5] = Float8GetDatumFast(Sxy);
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
result = construct_array(transdatums, 6,
|
|
|
|
FLOAT8OID,
|
2020-03-04 16:34:25 +01:00
|
|
|
sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE);
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-08 19:44:50 +02:00
|
|
|
/*
|
|
|
|
* float8_regr_combine
|
|
|
|
*
|
|
|
|
* An aggregate combine function used to combine two 6 fields
|
|
|
|
* aggregate transition data into a single transition data.
|
|
|
|
* This function is used only in two stage aggregation and
|
|
|
|
* shouldn't be called outside aggregate context.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
float8_regr_combine(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
|
|
|
|
float8 *transvalues1;
|
|
|
|
float8 *transvalues2;
|
2018-10-06 12:20:09 +02:00
|
|
|
float8 N1,
|
|
|
|
Sx1,
|
|
|
|
Sxx1,
|
|
|
|
Sy1,
|
|
|
|
Syy1,
|
|
|
|
Sxy1,
|
|
|
|
N2,
|
|
|
|
Sx2,
|
|
|
|
Sxx2,
|
|
|
|
Sy2,
|
|
|
|
Syy2,
|
|
|
|
Sxy2,
|
|
|
|
tmp1,
|
|
|
|
tmp2,
|
|
|
|
N,
|
|
|
|
Sx,
|
|
|
|
Sxx,
|
|
|
|
Sy,
|
|
|
|
Syy,
|
|
|
|
Sxy;
|
2016-04-08 19:44:50 +02:00
|
|
|
|
|
|
|
transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
|
|
|
|
transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
N1 = transvalues1[0];
|
|
|
|
Sx1 = transvalues1[1];
|
|
|
|
Sxx1 = transvalues1[2];
|
|
|
|
Sy1 = transvalues1[3];
|
|
|
|
Syy1 = transvalues1[4];
|
|
|
|
Sxy1 = transvalues1[5];
|
|
|
|
|
|
|
|
N2 = transvalues2[0];
|
|
|
|
Sx2 = transvalues2[1];
|
|
|
|
Sxx2 = transvalues2[2];
|
|
|
|
Sy2 = transvalues2[3];
|
|
|
|
Syy2 = transvalues2[4];
|
|
|
|
Sxy2 = transvalues2[5];
|
|
|
|
|
|
|
|
/*--------------------
|
|
|
|
* The transition values combine using a generalization of the
|
|
|
|
* Youngs-Cramer algorithm as follows:
|
|
|
|
*
|
|
|
|
* N = N1 + N2
|
|
|
|
* Sx = Sx1 + Sx2
|
|
|
|
* Sxx = Sxx1 + Sxx2 + N1 * N2 * (Sx1/N1 - Sx2/N2)^2 / N
|
|
|
|
* Sy = Sy1 + Sy2
|
|
|
|
* Syy = Syy1 + Syy2 + N1 * N2 * (Sy1/N1 - Sy2/N2)^2 / N
|
|
|
|
* Sxy = Sxy1 + Sxy2 + N1 * N2 * (Sx1/N1 - Sx2/N2) * (Sy1/N1 - Sy2/N2) / N
|
|
|
|
*
|
|
|
|
* It's worth handling the special cases N1 = 0 and N2 = 0 separately
|
|
|
|
* since those cases are trivial, and we then don't need to worry about
|
|
|
|
* division-by-zero errors in the general case.
|
|
|
|
*--------------------
|
|
|
|
*/
|
|
|
|
if (N1 == 0.0)
|
|
|
|
{
|
|
|
|
N = N2;
|
|
|
|
Sx = Sx2;
|
|
|
|
Sxx = Sxx2;
|
|
|
|
Sy = Sy2;
|
|
|
|
Syy = Syy2;
|
|
|
|
Sxy = Sxy2;
|
|
|
|
}
|
|
|
|
else if (N2 == 0.0)
|
|
|
|
{
|
|
|
|
N = N1;
|
|
|
|
Sx = Sx1;
|
|
|
|
Sxx = Sxx1;
|
|
|
|
Sy = Sy1;
|
|
|
|
Syy = Syy1;
|
|
|
|
Sxy = Sxy1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
N = N1 + N2;
|
|
|
|
Sx = float8_pl(Sx1, Sx2);
|
|
|
|
tmp1 = Sx1 / N1 - Sx2 / N2;
|
|
|
|
Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N;
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
|
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
Sy = float8_pl(Sy1, Sy2);
|
|
|
|
tmp2 = Sy1 / N1 - Sy2 / N2;
|
|
|
|
Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N;
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2))
|
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N;
|
Avoid a performance regression in float overflow/underflow detection.
Commit 6bf0bc842 replaced float.c's CHECKFLOATVAL() macro with static
inline subroutines, but that wasn't too well thought out. In the original
coding, the unlikely condition (isinf(result) or result == 0) was checked
first, and the inf_is_valid or zero_is_valid condition only afterwards.
The inline-subroutine coding caused that to be swapped around, which is
pretty horrid for performance because (a) in common cases the is_valid
condition is twice as expensive to evaluate (e.g., requiring two isinf()
calls not one) and (b) in common cases the is_valid condition is false,
requiring us to perform the unlikely-condition check anyway. Net result
is that one isinf() call becomes two or three, resulting in visible
performance loss as reported by Keisuke Kuroda.
The original fix proposal was to revert the replacement of the macro,
but on second thought, that macro was just a bad idea from the beginning:
if anything it's a net negative for readability of the code. So instead,
let's just open-code all the overflow/underflow tests, being careful to
test the unlikely condition first (and mark it unlikely() to help the
compiler get the point).
Also, rather than having N copies of the actual ereport() calls, collapse
those into out-of-line error subroutines to save some code space. This
does mean that the error file/line numbers won't be very helpful for
figuring out where the issue really is --- but we'd already burned that
bridge by putting the ereports into static inlines.
In HEAD, check_float[48]_val() are gone altogether. In v12, leave them
present in float.h but unused in the core code, just in case some
extension is depending on them.
Emre Hasegeli, with some kibitzing from me and Andres Freund
Discussion: https://postgr.es/m/CANDwggLe1Gc1OrRqvPfGE=kM9K0FSfia0hbeFCEmwabhLz95AA@mail.gmail.com
2020-02-13 19:37:43 +01:00
|
|
|
if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2))
|
|
|
|
float_overflow_error();
|
2018-10-06 12:20:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we're invoked as an aggregate, we can cheat and modify our first
|
|
|
|
* parameter in-place to reduce palloc overhead. Otherwise we construct a
|
|
|
|
* new array with the updated transition data and return it.
|
|
|
|
*/
|
|
|
|
if (AggCheckCallContext(fcinfo, NULL))
|
|
|
|
{
|
|
|
|
transvalues1[0] = N;
|
|
|
|
transvalues1[1] = Sx;
|
|
|
|
transvalues1[2] = Sxx;
|
|
|
|
transvalues1[3] = Sy;
|
|
|
|
transvalues1[4] = Syy;
|
|
|
|
transvalues1[5] = Sxy;
|
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(transarray1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Datum transdatums[6];
|
|
|
|
ArrayType *result;
|
|
|
|
|
|
|
|
transdatums[0] = Float8GetDatumFast(N);
|
|
|
|
transdatums[1] = Float8GetDatumFast(Sx);
|
|
|
|
transdatums[2] = Float8GetDatumFast(Sxx);
|
|
|
|
transdatums[3] = Float8GetDatumFast(Sy);
|
|
|
|
transdatums[4] = Float8GetDatumFast(Syy);
|
|
|
|
transdatums[5] = Float8GetDatumFast(Sxy);
|
2016-04-08 19:44:50 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
result = construct_array(transdatums, 6,
|
|
|
|
FLOAT8OID,
|
2020-03-04 16:34:25 +01:00
|
|
|
sizeof(float8), FLOAT8PASSBYVAL, TYPALIGN_DOUBLE);
|
2018-10-06 12:20:09 +02:00
|
|
|
|
|
|
|
PG_RETURN_ARRAYTYPE_P(result);
|
|
|
|
}
|
2016-04-08 19:44:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-28 20:33:04 +02:00
|
|
|
Datum
|
|
|
|
float8_regr_sxx(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx = transvalues[2];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
2006-07-28 20:33:04 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxx);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_syy(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Syy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Syy = transvalues[4];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Syy is guaranteed to be non-negative */
|
2006-07-28 20:33:04 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Syy);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_sxy(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_sxy", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
/* A negative result is valid here */
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxy);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_avgx(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_avgx", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx = transvalues[1];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sx / N);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_avgy(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_avgy", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sy = transvalues[3];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sy / N);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_covar_pop(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_covar_pop", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxy / N);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_covar_samp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_covar_samp", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is <= 1 we should return NULL */
|
|
|
|
if (N < 2.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxy / (N - 1.0));
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_corr(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx,
|
|
|
|
Syy,
|
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_corr", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx = transvalues[2];
|
|
|
|
Syy = transvalues[4];
|
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx and Syy are guaranteed to be non-negative */
|
|
|
|
|
|
|
|
/* per spec, return NULL for horizontal and vertical lines */
|
|
|
|
if (Sxx == 0 || Syy == 0)
|
2006-07-28 20:33:04 +02:00
|
|
|
PG_RETURN_NULL();
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxy / sqrt(Sxx * Syy));
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_r2(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx,
|
|
|
|
Syy,
|
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx = transvalues[2];
|
|
|
|
Syy = transvalues[4];
|
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx and Syy are guaranteed to be non-negative */
|
|
|
|
|
|
|
|
/* per spec, return NULL for a vertical line */
|
|
|
|
if (Sxx == 0)
|
2006-07-28 20:33:04 +02:00
|
|
|
PG_RETURN_NULL();
|
2018-10-06 12:20:09 +02:00
|
|
|
|
|
|
|
/* per spec, return 1.0 for a horizontal line */
|
|
|
|
if (Syy == 0)
|
2006-07-28 20:33:04 +02:00
|
|
|
PG_RETURN_FLOAT8(1.0);
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8((Sxy * Sxy) / (Sxx * Syy));
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_slope(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx,
|
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sxx = transvalues[2];
|
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
|
|
|
|
|
|
|
/* per spec, return NULL for a vertical line */
|
|
|
|
if (Sxx == 0)
|
2006-07-28 20:33:04 +02:00
|
|
|
PG_RETURN_NULL();
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8(Sxy / Sxx);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
float8_regr_intercept(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
float8 *transvalues;
|
2006-10-04 02:30:14 +02:00
|
|
|
float8 N,
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx,
|
|
|
|
Sxx,
|
|
|
|
Sy,
|
|
|
|
Sxy;
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
|
|
|
|
N = transvalues[0];
|
2018-10-06 12:20:09 +02:00
|
|
|
Sx = transvalues[1];
|
|
|
|
Sxx = transvalues[2];
|
|
|
|
Sy = transvalues[3];
|
|
|
|
Sxy = transvalues[5];
|
2006-07-28 20:33:04 +02:00
|
|
|
|
|
|
|
/* if N is 0 we should return NULL */
|
|
|
|
if (N < 1.0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
/* Note that Sxx is guaranteed to be non-negative */
|
|
|
|
|
|
|
|
/* per spec, return NULL for a vertical line */
|
|
|
|
if (Sxx == 0)
|
2006-07-28 20:33:04 +02:00
|
|
|
PG_RETURN_NULL();
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2018-10-06 12:20:09 +02:00
|
|
|
PG_RETURN_FLOAT8((Sy - Sx * Sxy / Sxx) / N);
|
2006-07-28 20:33:04 +02:00
|
|
|
}
|
|
|
|
|
2000-07-17 05:05:41 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ====================================
|
|
|
|
* MIXED-PRECISION ARITHMETIC OPERATORS
|
|
|
|
* ====================================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float48pl - returns arg1 + arg2
|
|
|
|
* float48mi - returns arg1 - arg2
|
|
|
|
* float48mul - returns arg1 * arg2
|
|
|
|
* float48div - returns arg1 / arg2
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48pl(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48mi(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48mul(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48div(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float84pl - returns arg1 + arg2
|
|
|
|
* float84mi - returns arg1 - arg2
|
|
|
|
* float84mul - returns arg1 * arg2
|
|
|
|
* float84div - returns arg1 / arg2
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84pl(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84mi(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84mul(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84div(PG_FUNCTION_ARGS)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ====================
|
|
|
|
* COMPARISON OPERATORS
|
|
|
|
* ====================
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48eq(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48ne(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48lt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48le(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48gt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float48ge(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float4 arg1 = PG_GETARG_FLOAT4(0);
|
|
|
|
float8 arg2 = PG_GETARG_FLOAT8(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-08-01 20:29:35 +02:00
|
|
|
* float84{eq,ne,lt,le,gt,ge} - float8/float4 comparison operations
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84eq(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84ne(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84lt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84le(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84gt(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2000-08-01 20:29:35 +02:00
|
|
|
Datum
|
|
|
|
float84ge(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-01 20:29:35 +02:00
|
|
|
float8 arg1 = PG_GETARG_FLOAT8(0);
|
|
|
|
float4 arg2 = PG_GETARG_FLOAT4(1);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2018-07-29 03:30:48 +02:00
|
|
|
PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2007-01-16 22:41:14 +01:00
|
|
|
/*
|
|
|
|
* Implements the float8 version of the width_bucket() function
|
|
|
|
* defined by SQL2003. See also width_bucket_numeric().
|
|
|
|
*
|
|
|
|
* 'bound1' and 'bound2' are the lower and upper bounds of the
|
|
|
|
* histogram's range, respectively. 'count' is the number of buckets
|
|
|
|
* in the histogram. width_bucket() returns an integer indicating the
|
|
|
|
* bucket number that 'operand' belongs to in an equiwidth histogram
|
|
|
|
* with the specified characteristics. An operand smaller than the
|
|
|
|
* lower bound is assigned to bucket 0. An operand greater than the
|
|
|
|
* upper bound is assigned to an additional bucket (with number
|
|
|
|
* count+1). We don't allow "NaN" for any of the float8 inputs, and we
|
|
|
|
* don't allow either of the histogram bounds to be +/- infinity.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
width_bucket_float8(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
float8 operand = PG_GETARG_FLOAT8(0);
|
|
|
|
float8 bound1 = PG_GETARG_FLOAT8(1);
|
|
|
|
float8 bound2 = PG_GETARG_FLOAT8(2);
|
|
|
|
int32 count = PG_GETARG_INT32(3);
|
|
|
|
int32 result;
|
2007-01-16 22:41:14 +01:00
|
|
|
|
|
|
|
if (count <= 0.0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
|
|
|
|
errmsg("count must be greater than zero")));
|
|
|
|
|
|
|
|
if (isnan(operand) || isnan(bound1) || isnan(bound2))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("operand, lower bound, and upper bound cannot be NaN")));
|
2007-01-16 22:41:14 +01:00
|
|
|
|
|
|
|
/* Note that we allow "operand" to be infinite */
|
2009-02-18 20:23:26 +01:00
|
|
|
if (isinf(bound1) || isinf(bound2))
|
2007-01-16 22:41:14 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
|
|
|
|
errmsg("lower and upper bounds must be finite")));
|
|
|
|
|
|
|
|
if (bound1 < bound2)
|
|
|
|
{
|
|
|
|
if (operand < bound1)
|
|
|
|
result = 0;
|
|
|
|
else if (operand >= bound2)
|
|
|
|
{
|
2017-12-13 01:32:31 +01:00
|
|
|
if (pg_add_s32_overflow(count, 1, &result))
|
2007-01-16 22:41:14 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("integer out of range")));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = ((float8) count * (operand - bound1) / (bound2 - bound1)) + 1;
|
|
|
|
}
|
|
|
|
else if (bound1 > bound2)
|
|
|
|
{
|
|
|
|
if (operand > bound1)
|
|
|
|
result = 0;
|
|
|
|
else if (operand <= bound2)
|
|
|
|
{
|
2017-12-13 01:32:31 +01:00
|
|
|
if (pg_add_s32_overflow(count, 1, &result))
|
2007-01-16 22:41:14 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
errmsg("integer out of range")));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = ((float8) count * (bound1 - operand) / (bound1 - bound2)) + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
|
|
|
|
errmsg("lower bound cannot equal upper bound")));
|
2007-11-15 22:14:46 +01:00
|
|
|
result = 0; /* keep the compiler quiet */
|
2007-01-16 22:41:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INT32(result);
|
|
|
|
}
|