LCOV - code coverage report
Current view: top level - src/backend/utils/adt - float.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 81.5 % 1738 1416
Test Date: 2026-01-26 10:56:24 Functions: 86.6 % 157 136
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 58.7 % 1076 632

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * float.c
       4                 :             :  *        Functions for the built-in floating-point types.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/backend/utils/adt/float.c
      12                 :             :  *
      13                 :             :  *-------------------------------------------------------------------------
      14                 :             :  */
      15                 :             : #include "postgres.h"
      16                 :             : 
      17                 :             : #include <ctype.h>
      18                 :             : #include <float.h>
      19                 :             : #include <math.h>
      20                 :             : #include <limits.h>
      21                 :             : 
      22                 :             : #include "catalog/pg_type.h"
      23                 :             : #include "common/int.h"
      24                 :             : #include "common/shortest_dec.h"
      25                 :             : #include "libpq/pqformat.h"
      26                 :             : #include "utils/array.h"
      27                 :             : #include "utils/float.h"
      28                 :             : #include "utils/fmgrprotos.h"
      29                 :             : #include "utils/sortsupport.h"
      30                 :             : 
      31                 :             : 
      32                 :             : /*
      33                 :             :  * Configurable GUC parameter
      34                 :             :  *
      35                 :             :  * If >0, use shortest-decimal format for output; this is both the default and
      36                 :             :  * allows for compatibility with clients that explicitly set a value here to
      37                 :             :  * get round-trip-accurate results. If 0 or less, then use the old, slow,
      38                 :             :  * decimal rounding method.
      39                 :             :  */
      40                 :             : int                     extra_float_digits = 1;
      41                 :             : 
      42                 :             : /* Cached constants for degree-based trig functions */
      43                 :             : static bool degree_consts_set = false;
      44                 :             : static float8 sin_30 = 0;
      45                 :             : static float8 one_minus_cos_60 = 0;
      46                 :             : static float8 asin_0_5 = 0;
      47                 :             : static float8 acos_0_5 = 0;
      48                 :             : static float8 atan_1_0 = 0;
      49                 :             : static float8 tan_45 = 0;
      50                 :             : static float8 cot_45 = 0;
      51                 :             : 
      52                 :             : /*
      53                 :             :  * These are intentionally not static; don't "fix" them.  They will never
      54                 :             :  * be referenced by other files, much less changed; but we don't want the
      55                 :             :  * compiler to know that, else it might try to precompute expressions
      56                 :             :  * involving them.  See comments for init_degree_constants().
      57                 :             :  *
      58                 :             :  * The additional extern declarations are to silence
      59                 :             :  * -Wmissing-variable-declarations.
      60                 :             :  */
      61                 :             : extern float8 degree_c_thirty;
      62                 :             : extern float8 degree_c_forty_five;
      63                 :             : extern float8 degree_c_sixty;
      64                 :             : extern float8 degree_c_one_half;
      65                 :             : extern float8 degree_c_one;
      66                 :             : float8          degree_c_thirty = 30.0;
      67                 :             : float8          degree_c_forty_five = 45.0;
      68                 :             : float8          degree_c_sixty = 60.0;
      69                 :             : float8          degree_c_one_half = 0.5;
      70                 :             : float8          degree_c_one = 1.0;
      71                 :             : 
      72                 :             : /* Local function prototypes */
      73                 :             : static double sind_q1(double x);
      74                 :             : static double cosd_q1(double x);
      75                 :             : static void init_degree_constants(void);
      76                 :             : 
      77                 :             : 
      78                 :             : /*
      79                 :             :  * We use these out-of-line ereport() calls to report float overflow,
      80                 :             :  * underflow, and zero-divide, because following our usual practice of
      81                 :             :  * repeating them at each call site would lead to a lot of code bloat.
      82                 :             :  *
      83                 :             :  * This does mean that you don't get a useful error location indicator.
      84                 :             :  */
      85                 :             : pg_noinline void
      86                 :          14 : float_overflow_error(void)
      87                 :             : {
      88   [ +  -  +  - ]:          14 :         ereport(ERROR,
      89                 :             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      90                 :             :                          errmsg("value out of range: overflow")));
      91                 :           0 : }
      92                 :             : 
      93                 :             : pg_noinline void
      94                 :           5 : float_underflow_error(void)
      95                 :             : {
      96   [ +  -  +  - ]:           5 :         ereport(ERROR,
      97                 :             :                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
      98                 :             :                          errmsg("value out of range: underflow")));
      99                 :           0 : }
     100                 :             : 
     101                 :             : pg_noinline void
     102                 :          12 : float_zero_divide_error(void)
     103                 :             : {
     104   [ +  -  +  - ]:          12 :         ereport(ERROR,
     105                 :             :                         (errcode(ERRCODE_DIVISION_BY_ZERO),
     106                 :             :                          errmsg("division by zero")));
     107                 :           0 : }
     108                 :             : 
     109                 :             : 
     110                 :             : /*
     111                 :             :  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
     112                 :             :  * represents (positive) infinity, and 0 otherwise. On some platforms,
     113                 :             :  * this is equivalent to the isinf() macro, but not everywhere: C99
     114                 :             :  * does not specify that isinf() needs to distinguish between positive
     115                 :             :  * and negative infinity.
     116                 :             :  */
     117                 :             : int
     118                 :           0 : is_infinite(double val)
     119                 :             : {
     120                 :           0 :         int                     inf = isinf(val);
     121                 :             : 
     122         [ #  # ]:           0 :         if (inf == 0)
     123                 :           0 :                 return 0;
     124         [ #  # ]:           0 :         else if (val > 0)
     125                 :           0 :                 return 1;
     126                 :             :         else
     127                 :           0 :                 return -1;
     128                 :           0 : }
     129                 :             : 
     130                 :             : 
     131                 :             : /* ========== USER I/O ROUTINES ========== */
     132                 :             : 
     133                 :             : 
     134                 :             : /*
     135                 :             :  *              float4in                - converts "num" to float4
     136                 :             :  *
     137                 :             :  * Note that this code now uses strtof(), where it used to use strtod().
     138                 :             :  *
     139                 :             :  * The motivation for using strtof() is to avoid a double-rounding problem:
     140                 :             :  * for certain decimal inputs, if you round the input correctly to a double,
     141                 :             :  * and then round the double to a float, the result is incorrect in that it
     142                 :             :  * does not match the result of rounding the decimal value to float directly.
     143                 :             :  *
     144                 :             :  * One of the best examples is 7.038531e-26:
     145                 :             :  *
     146                 :             :  * 0xAE43FDp-107 = 7.03853069185120912085...e-26
     147                 :             :  *      midpoint   7.03853100000000022281...e-26
     148                 :             :  * 0xAE43FEp-107 = 7.03853130814879132477...e-26
     149                 :             :  *
     150                 :             :  * making 0xAE43FDp-107 the correct float result, but if you do the conversion
     151                 :             :  * via a double, you get
     152                 :             :  *
     153                 :             :  * 0xAE43FD.7FFFFFF8p-107 = 7.03853099999999907487...e-26
     154                 :             :  *               midpoint   7.03853099999999964884...e-26
     155                 :             :  * 0xAE43FD.80000000p-107 = 7.03853100000000022281...e-26
     156                 :             :  * 0xAE43FD.80000008p-107 = 7.03853100000000137076...e-26
     157                 :             :  *
     158                 :             :  * so the value rounds to the double exactly on the midpoint between the two
     159                 :             :  * nearest floats, and then rounding again to a float gives the incorrect
     160                 :             :  * result of 0xAE43FEp-107.
     161                 :             :  *
     162                 :             :  */
     163                 :             : Datum
     164                 :        8416 : float4in(PG_FUNCTION_ARGS)
     165                 :             : {
     166                 :        8416 :         char       *num = PG_GETARG_CSTRING(0);
     167                 :             : 
     168                 :       16832 :         PG_RETURN_FLOAT4(float4in_internal(num, NULL, "real", num,
     169                 :             :                                                                            fcinfo->context));
     170                 :        8416 : }
     171                 :             : 
     172                 :             : /*
     173                 :             :  * float4in_internal - guts of float4in()
     174                 :             :  *
     175                 :             :  * This is exposed for use by functions that want a reasonably
     176                 :             :  * platform-independent way of inputting floats. The behavior is
     177                 :             :  * essentially like strtof + ereturn on error.
     178                 :             :  *
     179                 :             :  * Uses the same API as float8in_internal below, so most of its
     180                 :             :  * comments also apply here, except regarding use in geometric types.
     181                 :             :  */
     182                 :             : float4
     183                 :        8430 : float4in_internal(char *num, char **endptr_p,
     184                 :             :                                   const char *type_name, const char *orig_string,
     185                 :             :                                   struct Node *escontext)
     186                 :             : {
     187                 :        8430 :         float           val;
     188                 :        8430 :         char       *endptr;
     189                 :             : 
     190                 :             :         /*
     191                 :             :          * endptr points to the first character _after_ the sequence we recognized
     192                 :             :          * as a valid floating point number. orig_string points to the original
     193                 :             :          * input string.
     194                 :             :          */
     195                 :             : 
     196                 :             :         /* skip leading whitespace */
     197   [ +  +  +  + ]:        8465 :         while (*num != '\0' && isspace((unsigned char) *num))
     198                 :          35 :                 num++;
     199                 :             : 
     200                 :             :         /*
     201                 :             :          * Check for an empty-string input to begin with, to avoid the vagaries of
     202                 :             :          * strtod() on different platforms.
     203                 :             :          */
     204         [ +  + ]:        8430 :         if (*num == '\0')
     205         [ +  + ]:           4 :                 ereturn(escontext, 0,
     206                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     207                 :             :                                  errmsg("invalid input syntax for type %s: \"%s\"",
     208                 :             :                                                 type_name, orig_string)));
     209                 :             : 
     210                 :        8426 :         errno = 0;
     211                 :        8426 :         val = strtof(num, &endptr);
     212                 :             : 
     213                 :             :         /* did we not see anything that looks like a double? */
     214   [ +  +  +  + ]:        8426 :         if (endptr == num || errno != 0)
     215                 :             :         {
     216                 :          24 :                 int                     save_errno = errno;
     217                 :             : 
     218                 :             :                 /*
     219                 :             :                  * C99 requires that strtof() accept NaN, [+-]Infinity, and [+-]Inf,
     220                 :             :                  * but not all platforms support all of these (and some accept them
     221                 :             :                  * but set ERANGE anyway...)  Therefore, we check for these inputs
     222                 :             :                  * ourselves if strtof() fails.
     223                 :             :                  *
     224                 :             :                  * Note: C99 also requires hexadecimal input as well as some extended
     225                 :             :                  * forms of NaN, but we consider these forms unportable and don't try
     226                 :             :                  * to support them.  You can use 'em if your strtof() takes 'em.
     227                 :             :                  */
     228         [ +  - ]:          24 :                 if (pg_strncasecmp(num, "NaN", 3) == 0)
     229                 :             :                 {
     230                 :           0 :                         val = get_float4_nan();
     231                 :           0 :                         endptr = num + 3;
     232                 :           0 :                 }
     233         [ +  - ]:          24 :                 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
     234                 :             :                 {
     235                 :           0 :                         val = get_float4_infinity();
     236                 :           0 :                         endptr = num + 8;
     237                 :           0 :                 }
     238         [ +  - ]:          24 :                 else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
     239                 :             :                 {
     240                 :           0 :                         val = get_float4_infinity();
     241                 :           0 :                         endptr = num + 9;
     242                 :           0 :                 }
     243         [ +  - ]:          24 :                 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
     244                 :             :                 {
     245                 :           0 :                         val = -get_float4_infinity();
     246                 :           0 :                         endptr = num + 9;
     247                 :           0 :                 }
     248         [ +  - ]:          24 :                 else if (pg_strncasecmp(num, "inf", 3) == 0)
     249                 :             :                 {
     250                 :           0 :                         val = get_float4_infinity();
     251                 :           0 :                         endptr = num + 3;
     252                 :           0 :                 }
     253         [ +  - ]:          24 :                 else if (pg_strncasecmp(num, "+inf", 4) == 0)
     254                 :             :                 {
     255                 :           0 :                         val = get_float4_infinity();
     256                 :           0 :                         endptr = num + 4;
     257                 :           0 :                 }
     258         [ +  - ]:          24 :                 else if (pg_strncasecmp(num, "-inf", 4) == 0)
     259                 :             :                 {
     260                 :           0 :                         val = -get_float4_infinity();
     261                 :           0 :                         endptr = num + 4;
     262                 :           0 :                 }
     263         [ +  + ]:          24 :                 else if (save_errno == ERANGE)
     264                 :             :                 {
     265                 :             :                         /*
     266                 :             :                          * Some platforms return ERANGE for denormalized numbers (those
     267                 :             :                          * that are not zero, but are too close to zero to have full
     268                 :             :                          * precision).  We'd prefer not to throw error for that, so try to
     269                 :             :                          * detect whether it's a "real" out-of-range condition by checking
     270                 :             :                          * to see if the result is zero or huge.
     271                 :             :                          */
     272   [ +  +  +  + ]:          20 :                         if (val == 0.0 ||
     273                 :             : #if !defined(HUGE_VALF)
     274                 :             :                                 isinf(val)
     275                 :             : #else
     276         [ +  + ]:           7 :                                 (val >= HUGE_VALF || val <= -HUGE_VALF)
     277                 :             : #endif
     278                 :             :                                 )
     279                 :             :                         {
     280                 :             :                                 /* see comments in float8in_internal for rationale */
     281                 :          16 :                                 char       *errnumber = pstrdup(num);
     282                 :             : 
     283                 :          16 :                                 errnumber[endptr - num] = '\0';
     284                 :             : 
     285         [ +  + ]:          16 :                                 ereturn(escontext, 0,
     286                 :             :                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     287                 :             :                                                  errmsg("\"%s\" is out of range for type real",
     288                 :             :                                                                 errnumber)));
     289         [ +  - ]:           2 :                         }
     290                 :           1 :                 }
     291                 :             :                 else
     292         [ +  + ]:           7 :                         ereturn(escontext, 0,
     293                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     294                 :             :                                          errmsg("invalid input syntax for type %s: \"%s\"",
     295                 :             :                                                         type_name, orig_string)));
     296         [ +  + ]:           6 :         }
     297                 :             : 
     298                 :             :         /* skip trailing whitespace */
     299   [ +  +  +  + ]:        8436 :         while (*endptr != '\0' && isspace((unsigned char) *endptr))
     300                 :          33 :                 endptr++;
     301                 :             : 
     302                 :             :         /* report stopping point if wanted, else complain if not end of string */
     303         [ -  + ]:        8403 :         if (endptr_p)
     304                 :           0 :                 *endptr_p = endptr;
     305         [ +  + ]:        8403 :         else if (*endptr != '\0')
     306         [ +  + ]:          12 :                 ereturn(escontext, 0,
     307                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     308                 :             :                                  errmsg("invalid input syntax for type %s: \"%s\"",
     309                 :             :                                                 type_name, orig_string)));
     310                 :             : 
     311                 :        8391 :         return val;
     312                 :        8396 : }
     313                 :             : 
     314                 :             : /*
     315                 :             :  *              float4out               - converts a float4 number to a string
     316                 :             :  *                                                using a standard output format
     317                 :             :  */
     318                 :             : Datum
     319                 :        2197 : float4out(PG_FUNCTION_ARGS)
     320                 :             : {
     321                 :        2197 :         float4          num = PG_GETARG_FLOAT4(0);
     322                 :        2197 :         char       *ascii = (char *) palloc(32);
     323                 :        2197 :         int                     ndig = FLT_DIG + extra_float_digits;
     324                 :             : 
     325         [ +  + ]:        2197 :         if (extra_float_digits > 0)
     326                 :             :         {
     327                 :        2153 :                 float_to_shortest_decimal_buf(num, ascii);
     328                 :        2153 :                 PG_RETURN_CSTRING(ascii);
     329                 :             :         }
     330                 :             : 
     331                 :          44 :         (void) pg_strfromd(ascii, 32, ndig, num);
     332                 :          44 :         PG_RETURN_CSTRING(ascii);
     333                 :        2197 : }
     334                 :             : 
     335                 :             : /*
     336                 :             :  *              float4recv                      - converts external binary format to float4
     337                 :             :  */
     338                 :             : Datum
     339                 :           0 : float4recv(PG_FUNCTION_ARGS)
     340                 :             : {
     341                 :           0 :         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
     342                 :             : 
     343                 :           0 :         PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));
     344                 :           0 : }
     345                 :             : 
     346                 :             : /*
     347                 :             :  *              float4send                      - converts float4 to binary format
     348                 :             :  */
     349                 :             : Datum
     350                 :        1082 : float4send(PG_FUNCTION_ARGS)
     351                 :             : {
     352                 :        1082 :         float4          num = PG_GETARG_FLOAT4(0);
     353                 :        1082 :         StringInfoData buf;
     354                 :             : 
     355                 :        1082 :         pq_begintypsend(&buf);
     356                 :        1082 :         pq_sendfloat4(&buf, num);
     357                 :        2164 :         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     358                 :        1082 : }
     359                 :             : 
     360                 :             : /*
     361                 :             :  *              float8in                - converts "num" to float8
     362                 :             :  */
     363                 :             : Datum
     364                 :      112583 : float8in(PG_FUNCTION_ARGS)
     365                 :             : {
     366                 :      112583 :         char       *num = PG_GETARG_CSTRING(0);
     367                 :             : 
     368                 :      225166 :         PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num,
     369                 :             :                                                                            fcinfo->context));
     370                 :      112583 : }
     371                 :             : 
     372                 :             : /*
     373                 :             :  * float8in_internal - guts of float8in()
     374                 :             :  *
     375                 :             :  * This is exposed for use by functions that want a reasonably
     376                 :             :  * platform-independent way of inputting doubles.  The behavior is
     377                 :             :  * essentially like strtod + ereturn on error, but note the following
     378                 :             :  * differences:
     379                 :             :  * 1. Both leading and trailing whitespace are skipped.
     380                 :             :  * 2. If endptr_p is NULL, we report error if there's trailing junk.
     381                 :             :  * Otherwise, it's up to the caller to complain about trailing junk.
     382                 :             :  * 3. In event of a syntax error, the report mentions the given type_name
     383                 :             :  * and prints orig_string as the input; this is meant to support use of
     384                 :             :  * this function with types such as "box" and "point", where what we are
     385                 :             :  * parsing here is just a substring of orig_string.
     386                 :             :  *
     387                 :             :  * If escontext points to an ErrorSaveContext node, that is filled instead
     388                 :             :  * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
     389                 :             :  * to detect errors.
     390                 :             :  *
     391                 :             :  * "num" could validly be declared "const char *", but that results in an
     392                 :             :  * unreasonable amount of extra casting both here and in callers, so we don't.
     393                 :             :  */
     394                 :             : float8
     395                 :      150022 : float8in_internal(char *num, char **endptr_p,
     396                 :             :                                   const char *type_name, const char *orig_string,
     397                 :             :                                   struct Node *escontext)
     398                 :             : {
     399                 :      150022 :         double          val;
     400                 :      150022 :         char       *endptr;
     401                 :             : 
     402                 :             :         /* skip leading whitespace */
     403   [ +  +  +  + ]:      150231 :         while (*num != '\0' && isspace((unsigned char) *num))
     404                 :         209 :                 num++;
     405                 :             : 
     406                 :             :         /*
     407                 :             :          * Check for an empty-string input to begin with, to avoid the vagaries of
     408                 :             :          * strtod() on different platforms.
     409                 :             :          */
     410         [ +  + ]:      150022 :         if (*num == '\0')
     411         [ +  + ]:           5 :                 ereturn(escontext, 0,
     412                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     413                 :             :                                  errmsg("invalid input syntax for type %s: \"%s\"",
     414                 :             :                                                 type_name, orig_string)));
     415                 :             : 
     416                 :      150017 :         errno = 0;
     417                 :      150017 :         val = strtod(num, &endptr);
     418                 :             : 
     419                 :             :         /* did we not see anything that looks like a double? */
     420   [ +  +  +  + ]:      150017 :         if (endptr == num || errno != 0)
     421                 :             :         {
     422                 :          43 :                 int                     save_errno = errno;
     423                 :             : 
     424                 :             :                 /*
     425                 :             :                  * C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
     426                 :             :                  * but not all platforms support all of these (and some accept them
     427                 :             :                  * but set ERANGE anyway...)  Therefore, we check for these inputs
     428                 :             :                  * ourselves if strtod() fails.
     429                 :             :                  *
     430                 :             :                  * Note: C99 also requires hexadecimal input as well as some extended
     431                 :             :                  * forms of NaN, but we consider these forms unportable and don't try
     432                 :             :                  * to support them.  You can use 'em if your strtod() takes 'em.
     433                 :             :                  */
     434         [ +  - ]:          43 :                 if (pg_strncasecmp(num, "NaN", 3) == 0)
     435                 :             :                 {
     436                 :           0 :                         val = get_float8_nan();
     437                 :           0 :                         endptr = num + 3;
     438                 :           0 :                 }
     439         [ +  - ]:          43 :                 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
     440                 :             :                 {
     441                 :           0 :                         val = get_float8_infinity();
     442                 :           0 :                         endptr = num + 8;
     443                 :           0 :                 }
     444         [ +  - ]:          43 :                 else if (pg_strncasecmp(num, "+Infinity", 9) == 0)
     445                 :             :                 {
     446                 :           0 :                         val = get_float8_infinity();
     447                 :           0 :                         endptr = num + 9;
     448                 :           0 :                 }
     449         [ +  - ]:          43 :                 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
     450                 :             :                 {
     451                 :           0 :                         val = -get_float8_infinity();
     452                 :           0 :                         endptr = num + 9;
     453                 :           0 :                 }
     454         [ +  - ]:          43 :                 else if (pg_strncasecmp(num, "inf", 3) == 0)
     455                 :             :                 {
     456                 :           0 :                         val = get_float8_infinity();
     457                 :           0 :                         endptr = num + 3;
     458                 :           0 :                 }
     459         [ +  - ]:          43 :                 else if (pg_strncasecmp(num, "+inf", 4) == 0)
     460                 :             :                 {
     461                 :           0 :                         val = get_float8_infinity();
     462                 :           0 :                         endptr = num + 4;
     463                 :           0 :                 }
     464         [ +  - ]:          43 :                 else if (pg_strncasecmp(num, "-inf", 4) == 0)
     465                 :             :                 {
     466                 :           0 :                         val = -get_float8_infinity();
     467                 :           0 :                         endptr = num + 4;
     468                 :           0 :                 }
     469         [ +  + ]:          43 :                 else if (save_errno == ERANGE)
     470                 :             :                 {
     471                 :             :                         /*
     472                 :             :                          * Some platforms return ERANGE for denormalized numbers (those
     473                 :             :                          * that are not zero, but are too close to zero to have full
     474                 :             :                          * precision).  We'd prefer not to throw error for that, so try to
     475                 :             :                          * detect whether it's a "real" out-of-range condition by checking
     476                 :             :                          * to see if the result is zero or huge.
     477                 :             :                          *
     478                 :             :                          * On error, we intentionally complain about double precision not
     479                 :             :                          * the given type name, and we print only the part of the string
     480                 :             :                          * that is the current number.
     481                 :             :                          */
     482   [ +  +  +  +  :          21 :                         if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
                   +  + ]
     483                 :             :                         {
     484                 :          18 :                                 char       *errnumber = pstrdup(num);
     485                 :             : 
     486                 :          18 :                                 errnumber[endptr - num] = '\0';
     487         [ +  + ]:          18 :                                 ereturn(escontext, 0,
     488                 :             :                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
     489                 :             :                                                  errmsg("\"%s\" is out of range for type double precision",
     490                 :             :                                                                 errnumber)));
     491         [ +  - ]:           8 :                         }
     492                 :           3 :                 }
     493                 :             :                 else
     494         [ +  + ]:          22 :                         ereturn(escontext, 0,
     495                 :             :                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     496                 :             :                                          errmsg("invalid input syntax for type %s: \"%s\"",
     497                 :             :                                                         type_name, orig_string)));
     498         [ +  + ]:          25 :         }
     499                 :             : 
     500                 :             :         /* skip trailing whitespace */
     501   [ +  +  +  + ]:      150035 :         while (*endptr != '\0' && isspace((unsigned char) *endptr))
     502                 :          58 :                 endptr++;
     503                 :             : 
     504                 :             :         /* report stopping point if wanted, else complain if not end of string */
     505         [ +  + ]:      149977 :         if (endptr_p)
     506                 :       37372 :                 *endptr_p = endptr;
     507         [ +  + ]:      112605 :         else if (*endptr != '\0')
     508         [ +  + ]:          11 :                 ereturn(escontext, 0,
     509                 :             :                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     510                 :             :                                  errmsg("invalid input syntax for type %s: \"%s\"",
     511                 :             :                                                 type_name, orig_string)));
     512                 :             : 
     513                 :      149966 :         return val;
     514                 :      149990 : }
     515                 :             : 
     516                 :             : 
     517                 :             : /*
     518                 :             :  *              float8out               - converts float8 number to a string
     519                 :             :  *                                                using a standard output format
     520                 :             :  */
     521                 :             : Datum
     522                 :       18099 : float8out(PG_FUNCTION_ARGS)
     523                 :             : {
     524                 :       18099 :         float8          num = PG_GETARG_FLOAT8(0);
     525                 :             : 
     526                 :       36198 :         PG_RETURN_CSTRING(float8out_internal(num));
     527                 :       18099 : }
     528                 :             : 
     529                 :             : /*
     530                 :             :  * float8out_internal - guts of float8out()
     531                 :             :  *
     532                 :             :  * This is exposed for use by functions that want a reasonably
     533                 :             :  * platform-independent way of outputting doubles.
     534                 :             :  * The result is always palloc'd.
     535                 :             :  */
     536                 :             : char *
     537                 :       56939 : float8out_internal(double num)
     538                 :             : {
     539                 :       56939 :         char       *ascii = (char *) palloc(32);
     540                 :       56939 :         int                     ndig = DBL_DIG + extra_float_digits;
     541                 :             : 
     542         [ +  + ]:       56939 :         if (extra_float_digits > 0)
     543                 :             :         {
     544                 :       20708 :                 double_to_shortest_decimal_buf(num, ascii);
     545                 :       20708 :                 return ascii;
     546                 :             :         }
     547                 :             : 
     548                 :       36231 :         (void) pg_strfromd(ascii, 32, ndig, num);
     549                 :       36231 :         return ascii;
     550                 :       56939 : }
     551                 :             : 
     552                 :             : /*
     553                 :             :  *              float8recv                      - converts external binary format to float8
     554                 :             :  */
     555                 :             : Datum
     556                 :           3 : float8recv(PG_FUNCTION_ARGS)
     557                 :             : {
     558                 :           3 :         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
     559                 :             : 
     560                 :           6 :         PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));
     561                 :           3 : }
     562                 :             : 
     563                 :             : /*
     564                 :             :  *              float8send                      - converts float8 to binary format
     565                 :             :  */
     566                 :             : Datum
     567                 :         858 : float8send(PG_FUNCTION_ARGS)
     568                 :             : {
     569                 :         858 :         float8          num = PG_GETARG_FLOAT8(0);
     570                 :         858 :         StringInfoData buf;
     571                 :             : 
     572                 :         858 :         pq_begintypsend(&buf);
     573                 :         858 :         pq_sendfloat8(&buf, num);
     574                 :        1716 :         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     575                 :         858 : }
     576                 :             : 
     577                 :             : 
     578                 :             : /* ========== PUBLIC ROUTINES ========== */
     579                 :             : 
     580                 :             : 
     581                 :             : /*
     582                 :             :  *              ======================
     583                 :             :  *              FLOAT4 BASE OPERATIONS
     584                 :             :  *              ======================
     585                 :             :  */
     586                 :             : 
     587                 :             : /*
     588                 :             :  *              float4abs               - returns |arg1| (absolute value)
     589                 :             :  */
     590                 :             : Datum
     591                 :           5 : float4abs(PG_FUNCTION_ARGS)
     592                 :             : {
     593                 :           5 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     594                 :             : 
     595                 :          10 :         PG_RETURN_FLOAT4(fabsf(arg1));
     596                 :           5 : }
     597                 :             : 
     598                 :             : /*
     599                 :             :  *              float4um                - returns -arg1 (unary minus)
     600                 :             :  */
     601                 :             : Datum
     602                 :           1 : float4um(PG_FUNCTION_ARGS)
     603                 :             : {
     604                 :           1 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     605                 :           1 :         float4          result;
     606                 :             : 
     607                 :           1 :         result = -arg1;
     608                 :           2 :         PG_RETURN_FLOAT4(result);
     609                 :           1 : }
     610                 :             : 
     611                 :             : Datum
     612                 :           0 : float4up(PG_FUNCTION_ARGS)
     613                 :             : {
     614                 :           0 :         float4          arg = PG_GETARG_FLOAT4(0);
     615                 :             : 
     616                 :           0 :         PG_RETURN_FLOAT4(arg);
     617                 :           0 : }
     618                 :             : 
     619                 :             : Datum
     620                 :           3 : float4larger(PG_FUNCTION_ARGS)
     621                 :             : {
     622                 :           3 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     623                 :           3 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     624                 :           3 :         float4          result;
     625                 :             : 
     626         [ +  + ]:           3 :         if (float4_gt(arg1, arg2))
     627                 :           1 :                 result = arg1;
     628                 :             :         else
     629                 :           2 :                 result = arg2;
     630                 :           6 :         PG_RETURN_FLOAT4(result);
     631                 :           3 : }
     632                 :             : 
     633                 :             : Datum
     634                 :           0 : float4smaller(PG_FUNCTION_ARGS)
     635                 :             : {
     636                 :           0 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     637                 :           0 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     638                 :           0 :         float4          result;
     639                 :             : 
     640         [ #  # ]:           0 :         if (float4_lt(arg1, arg2))
     641                 :           0 :                 result = arg1;
     642                 :             :         else
     643                 :           0 :                 result = arg2;
     644                 :           0 :         PG_RETURN_FLOAT4(result);
     645                 :           0 : }
     646                 :             : 
     647                 :             : /*
     648                 :             :  *              ======================
     649                 :             :  *              FLOAT8 BASE OPERATIONS
     650                 :             :  *              ======================
     651                 :             :  */
     652                 :             : 
     653                 :             : /*
     654                 :             :  *              float8abs               - returns |arg1| (absolute value)
     655                 :             :  */
     656                 :             : Datum
     657                 :       12007 : float8abs(PG_FUNCTION_ARGS)
     658                 :             : {
     659                 :       12007 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     660                 :             : 
     661                 :       24014 :         PG_RETURN_FLOAT8(fabs(arg1));
     662                 :       12007 : }
     663                 :             : 
     664                 :             : 
     665                 :             : /*
     666                 :             :  *              float8um                - returns -arg1 (unary minus)
     667                 :             :  */
     668                 :             : Datum
     669                 :          45 : float8um(PG_FUNCTION_ARGS)
     670                 :             : {
     671                 :          45 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     672                 :          45 :         float8          result;
     673                 :             : 
     674                 :          45 :         result = -arg1;
     675                 :          90 :         PG_RETURN_FLOAT8(result);
     676                 :          45 : }
     677                 :             : 
     678                 :             : Datum
     679                 :           0 : float8up(PG_FUNCTION_ARGS)
     680                 :             : {
     681                 :           0 :         float8          arg = PG_GETARG_FLOAT8(0);
     682                 :             : 
     683                 :           0 :         PG_RETURN_FLOAT8(arg);
     684                 :           0 : }
     685                 :             : 
     686                 :             : Datum
     687                 :        2146 : float8larger(PG_FUNCTION_ARGS)
     688                 :             : {
     689                 :        2146 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     690                 :        2146 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     691                 :        2146 :         float8          result;
     692                 :             : 
     693         [ +  + ]:        2146 :         if (float8_gt(arg1, arg2))
     694                 :        2029 :                 result = arg1;
     695                 :             :         else
     696                 :         117 :                 result = arg2;
     697                 :        4292 :         PG_RETURN_FLOAT8(result);
     698                 :        2146 : }
     699                 :             : 
     700                 :             : Datum
     701                 :         192 : float8smaller(PG_FUNCTION_ARGS)
     702                 :             : {
     703                 :         192 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     704                 :         192 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     705                 :         192 :         float8          result;
     706                 :             : 
     707         [ +  + ]:         192 :         if (float8_lt(arg1, arg2))
     708                 :         148 :                 result = arg1;
     709                 :             :         else
     710                 :          44 :                 result = arg2;
     711                 :         384 :         PG_RETURN_FLOAT8(result);
     712                 :         192 : }
     713                 :             : 
     714                 :             : 
     715                 :             : /*
     716                 :             :  *              ====================
     717                 :             :  *              ARITHMETIC OPERATORS
     718                 :             :  *              ====================
     719                 :             :  */
     720                 :             : 
     721                 :             : /*
     722                 :             :  *              float4pl                - returns arg1 + arg2
     723                 :             :  *              float4mi                - returns arg1 - arg2
     724                 :             :  *              float4mul               - returns arg1 * arg2
     725                 :             :  *              float4div               - returns arg1 / arg2
     726                 :             :  */
     727                 :             : Datum
     728                 :           9 : float4pl(PG_FUNCTION_ARGS)
     729                 :             : {
     730                 :           9 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     731                 :           9 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     732                 :             : 
     733                 :          18 :         PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
     734                 :           9 : }
     735                 :             : 
     736                 :             : Datum
     737                 :           3 : float4mi(PG_FUNCTION_ARGS)
     738                 :             : {
     739                 :           3 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     740                 :           3 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     741                 :             : 
     742                 :           6 :         PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
     743                 :           3 : }
     744                 :             : 
     745                 :             : Datum
     746                 :           6 : float4mul(PG_FUNCTION_ARGS)
     747                 :             : {
     748                 :           6 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     749                 :           6 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     750                 :             : 
     751                 :          12 :         PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
     752                 :           6 : }
     753                 :             : 
     754                 :             : Datum
     755                 :           8 : float4div(PG_FUNCTION_ARGS)
     756                 :             : {
     757                 :           8 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     758                 :           8 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     759                 :             : 
     760                 :          16 :         PG_RETURN_FLOAT4(float4_div(arg1, arg2));
     761                 :           8 : }
     762                 :             : 
     763                 :             : /*
     764                 :             :  *              float8pl                - returns arg1 + arg2
     765                 :             :  *              float8mi                - returns arg1 - arg2
     766                 :             :  *              float8mul               - returns arg1 * arg2
     767                 :             :  *              float8div               - returns arg1 / arg2
     768                 :             :  */
     769                 :             : Datum
     770                 :        4921 : float8pl(PG_FUNCTION_ARGS)
     771                 :             : {
     772                 :        4921 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     773                 :        4921 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     774                 :             : 
     775                 :        9842 :         PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
     776                 :        4921 : }
     777                 :             : 
     778                 :             : Datum
     779                 :        2027 : float8mi(PG_FUNCTION_ARGS)
     780                 :             : {
     781                 :        2027 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     782                 :        2027 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     783                 :             : 
     784                 :        4054 :         PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
     785                 :        2027 : }
     786                 :             : 
     787                 :             : Datum
     788                 :        2323 : float8mul(PG_FUNCTION_ARGS)
     789                 :             : {
     790                 :        2323 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     791                 :        2323 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     792                 :             : 
     793                 :        4646 :         PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
     794                 :        2323 : }
     795                 :             : 
     796                 :             : Datum
     797                 :        2408 : float8div(PG_FUNCTION_ARGS)
     798                 :             : {
     799                 :        2408 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     800                 :        2408 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     801                 :             : 
     802                 :        4816 :         PG_RETURN_FLOAT8(float8_div(arg1, arg2));
     803                 :        2408 : }
     804                 :             : 
     805                 :             : 
     806                 :             : /*
     807                 :             :  *              ====================
     808                 :             :  *              COMPARISON OPERATORS
     809                 :             :  *              ====================
     810                 :             :  */
     811                 :             : 
     812                 :             : /*
     813                 :             :  *              float4{eq,ne,lt,le,gt,ge}               - float4/float4 comparison operations
     814                 :             :  */
     815                 :             : int
     816                 :       75763 : float4_cmp_internal(float4 a, float4 b)
     817                 :             : {
     818         [ +  + ]:       75763 :         if (float4_gt(a, b))
     819                 :        1948 :                 return 1;
     820         [ +  + ]:       73815 :         if (float4_lt(a, b))
     821                 :         986 :                 return -1;
     822                 :       72829 :         return 0;
     823                 :       75763 : }
     824                 :             : 
     825                 :             : Datum
     826                 :        3722 : float4eq(PG_FUNCTION_ARGS)
     827                 :             : {
     828                 :        3722 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     829                 :        3722 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     830                 :             : 
     831                 :        7444 :         PG_RETURN_BOOL(float4_eq(arg1, arg2));
     832                 :        3722 : }
     833                 :             : 
     834                 :             : Datum
     835                 :           5 : float4ne(PG_FUNCTION_ARGS)
     836                 :             : {
     837                 :           5 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     838                 :           5 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     839                 :             : 
     840                 :          10 :         PG_RETURN_BOOL(float4_ne(arg1, arg2));
     841                 :           5 : }
     842                 :             : 
     843                 :             : Datum
     844                 :       12335 : float4lt(PG_FUNCTION_ARGS)
     845                 :             : {
     846                 :       12335 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     847                 :       12335 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     848                 :             : 
     849                 :       24670 :         PG_RETURN_BOOL(float4_lt(arg1, arg2));
     850                 :       12335 : }
     851                 :             : 
     852                 :             : Datum
     853                 :         638 : float4le(PG_FUNCTION_ARGS)
     854                 :             : {
     855                 :         638 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     856                 :         638 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     857                 :             : 
     858                 :        1276 :         PG_RETURN_BOOL(float4_le(arg1, arg2));
     859                 :         638 : }
     860                 :             : 
     861                 :             : Datum
     862                 :         773 : float4gt(PG_FUNCTION_ARGS)
     863                 :             : {
     864                 :         773 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     865                 :         773 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     866                 :             : 
     867                 :        1546 :         PG_RETURN_BOOL(float4_gt(arg1, arg2));
     868                 :         773 : }
     869                 :             : 
     870                 :             : Datum
     871                 :         638 : float4ge(PG_FUNCTION_ARGS)
     872                 :             : {
     873                 :         638 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     874                 :         638 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     875                 :             : 
     876                 :        1276 :         PG_RETURN_BOOL(float4_ge(arg1, arg2));
     877                 :         638 : }
     878                 :             : 
     879                 :             : Datum
     880                 :         686 : btfloat4cmp(PG_FUNCTION_ARGS)
     881                 :             : {
     882                 :         686 :         float4          arg1 = PG_GETARG_FLOAT4(0);
     883                 :         686 :         float4          arg2 = PG_GETARG_FLOAT4(1);
     884                 :             : 
     885                 :        1372 :         PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
     886                 :         686 : }
     887                 :             : 
     888                 :             : static int
     889                 :       75077 : btfloat4fastcmp(Datum x, Datum y, SortSupport ssup)
     890                 :             : {
     891                 :       75077 :         float4          arg1 = DatumGetFloat4(x);
     892                 :       75077 :         float4          arg2 = DatumGetFloat4(y);
     893                 :             : 
     894                 :      150154 :         return float4_cmp_internal(arg1, arg2);
     895                 :       75077 : }
     896                 :             : 
     897                 :             : Datum
     898                 :          48 : btfloat4sortsupport(PG_FUNCTION_ARGS)
     899                 :             : {
     900                 :          48 :         SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     901                 :             : 
     902                 :          48 :         ssup->comparator = btfloat4fastcmp;
     903                 :          48 :         PG_RETURN_VOID();
     904                 :          48 : }
     905                 :             : 
     906                 :             : /*
     907                 :             :  *              float8{eq,ne,lt,le,gt,ge}               - float8/float8 comparison operations
     908                 :             :  */
     909                 :             : int
     910                 :     3746444 : float8_cmp_internal(float8 a, float8 b)
     911                 :             : {
     912         [ +  + ]:     3746444 :         if (float8_gt(a, b))
     913                 :     1373472 :                 return 1;
     914         [ +  + ]:     2372972 :         if (float8_lt(a, b))
     915                 :     2333197 :                 return -1;
     916                 :       39775 :         return 0;
     917                 :     3746444 : }
     918                 :             : 
     919                 :             : Datum
     920                 :       97934 : float8eq(PG_FUNCTION_ARGS)
     921                 :             : {
     922                 :       97934 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     923                 :       97934 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     924                 :             : 
     925                 :      195868 :         PG_RETURN_BOOL(float8_eq(arg1, arg2));
     926                 :       97934 : }
     927                 :             : 
     928                 :             : Datum
     929                 :          59 : float8ne(PG_FUNCTION_ARGS)
     930                 :             : {
     931                 :          59 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     932                 :          59 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     933                 :             : 
     934                 :         118 :         PG_RETURN_BOOL(float8_ne(arg1, arg2));
     935                 :          59 : }
     936                 :             : 
     937                 :             : Datum
     938                 :       27864 : float8lt(PG_FUNCTION_ARGS)
     939                 :             : {
     940                 :       27864 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     941                 :       27864 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     942                 :             : 
     943                 :       55728 :         PG_RETURN_BOOL(float8_lt(arg1, arg2));
     944                 :       27864 : }
     945                 :             : 
     946                 :             : Datum
     947                 :         800 : float8le(PG_FUNCTION_ARGS)
     948                 :             : {
     949                 :         800 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     950                 :         800 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     951                 :             : 
     952                 :        1600 :         PG_RETURN_BOOL(float8_le(arg1, arg2));
     953                 :         800 : }
     954                 :             : 
     955                 :             : Datum
     956                 :        4891 : float8gt(PG_FUNCTION_ARGS)
     957                 :             : {
     958                 :        4891 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     959                 :        4891 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     960                 :             : 
     961                 :        9782 :         PG_RETURN_BOOL(float8_gt(arg1, arg2));
     962                 :        4891 : }
     963                 :             : 
     964                 :             : Datum
     965                 :        3363 : float8ge(PG_FUNCTION_ARGS)
     966                 :             : {
     967                 :        3363 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     968                 :        3363 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     969                 :             : 
     970                 :        6726 :         PG_RETURN_BOOL(float8_ge(arg1, arg2));
     971                 :        3363 : }
     972                 :             : 
     973                 :             : Datum
     974                 :         495 : btfloat8cmp(PG_FUNCTION_ARGS)
     975                 :             : {
     976                 :         495 :         float8          arg1 = PG_GETARG_FLOAT8(0);
     977                 :         495 :         float8          arg2 = PG_GETARG_FLOAT8(1);
     978                 :             : 
     979                 :         990 :         PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
     980                 :         495 : }
     981                 :             : 
     982                 :             : static int
     983                 :      973676 : btfloat8fastcmp(Datum x, Datum y, SortSupport ssup)
     984                 :             : {
     985                 :      973676 :         float8          arg1 = DatumGetFloat8(x);
     986                 :      973676 :         float8          arg2 = DatumGetFloat8(y);
     987                 :             : 
     988                 :     1947352 :         return float8_cmp_internal(arg1, arg2);
     989                 :      973676 : }
     990                 :             : 
     991                 :             : Datum
     992                 :         165 : btfloat8sortsupport(PG_FUNCTION_ARGS)
     993                 :             : {
     994                 :         165 :         SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
     995                 :             : 
     996                 :         165 :         ssup->comparator = btfloat8fastcmp;
     997                 :         165 :         PG_RETURN_VOID();
     998                 :         165 : }
     999                 :             : 
    1000                 :             : Datum
    1001                 :           0 : btfloat48cmp(PG_FUNCTION_ARGS)
    1002                 :             : {
    1003                 :           0 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    1004                 :           0 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    1005                 :             : 
    1006                 :             :         /* widen float4 to float8 and then compare */
    1007                 :           0 :         PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
    1008                 :           0 : }
    1009                 :             : 
    1010                 :             : Datum
    1011                 :           0 : btfloat84cmp(PG_FUNCTION_ARGS)
    1012                 :             : {
    1013                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1014                 :           0 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    1015                 :             : 
    1016                 :             :         /* widen float4 to float8 and then compare */
    1017                 :           0 :         PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
    1018                 :           0 : }
    1019                 :             : 
    1020                 :             : /*
    1021                 :             :  * in_range support function for float8.
    1022                 :             :  *
    1023                 :             :  * Note: we needn't supply a float8_float4 variant, as implicit coercion
    1024                 :             :  * of the offset value takes care of that scenario just as well.
    1025                 :             :  */
    1026                 :             : Datum
    1027                 :         512 : in_range_float8_float8(PG_FUNCTION_ARGS)
    1028                 :             : {
    1029                 :         512 :         float8          val = PG_GETARG_FLOAT8(0);
    1030                 :         512 :         float8          base = PG_GETARG_FLOAT8(1);
    1031                 :         512 :         float8          offset = PG_GETARG_FLOAT8(2);
    1032                 :         512 :         bool            sub = PG_GETARG_BOOL(3);
    1033                 :         512 :         bool            less = PG_GETARG_BOOL(4);
    1034                 :         512 :         float8          sum;
    1035                 :             : 
    1036                 :             :         /*
    1037                 :             :          * Reject negative or NaN offset.  Negative is per spec, and NaN is
    1038                 :             :          * because appropriate semantics for that seem non-obvious.
    1039                 :             :          */
    1040   [ +  +  +  -  :         512 :         if (isnan(offset) || offset < 0)
                   +  + ]
    1041   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1042                 :             :                                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    1043                 :             :                                  errmsg("invalid preceding or following size in window function")));
    1044                 :             : 
    1045                 :             :         /*
    1046                 :             :          * Deal with cases where val and/or base is NaN, following the rule that
    1047                 :             :          * NaN sorts after non-NaN (cf float8_cmp_internal).  The offset cannot
    1048                 :             :          * affect the conclusion.
    1049                 :             :          */
    1050   [ +  +  +  +  :         511 :         if (isnan(val))
                   +  - ]
    1051                 :             :         {
    1052   [ -  +  +  +  :         351 :                 if (isnan(base))
                   +  - ]
    1053                 :          52 :                         PG_RETURN_BOOL(true);   /* NAN = NAN */
    1054                 :             :                 else
    1055                 :          21 :                         PG_RETURN_BOOL(!less);  /* NAN > non-NAN */
    1056                 :             :         }
    1057   [ -  +  +  +  :         160 :         else if (isnan(base))
                   +  - ]
    1058                 :             :         {
    1059                 :         299 :                 PG_RETURN_BOOL(less);   /* non-NAN < NAN */
    1060                 :             :         }
    1061                 :             : 
    1062                 :             :         /*
    1063                 :             :          * Deal with cases where both base and offset are infinite, and computing
    1064                 :             :          * base +/- offset would produce NaN.  This corresponds to a window frame
    1065                 :             :          * whose boundary infinitely precedes +inf or infinitely follows -inf,
    1066                 :             :          * which is not well-defined.  For consistency with other cases involving
    1067                 :             :          * infinities, such as the fact that +inf infinitely follows +inf, we
    1068                 :             :          * choose to assume that +inf infinitely precedes +inf and -inf infinitely
    1069                 :             :          * follows -inf, and therefore that all finite and infinite values are in
    1070                 :             :          * such a window frame.
    1071                 :             :          *
    1072                 :             :          * offset is known positive, so we need only check the sign of base in
    1073                 :             :          * this test.
    1074                 :             :          */
    1075   [ +  +  +  +  :         139 :         if (isinf(offset) && isinf(base) &&
                   +  + ]
    1076         [ +  + ]:          34 :                 (sub ? base > 0 : base < 0))
    1077                 :          29 :                 PG_RETURN_BOOL(true);
    1078                 :             : 
    1079                 :             :         /*
    1080                 :             :          * Otherwise it should be safe to compute base +/- offset.  We trust the
    1081                 :             :          * FPU to cope if an input is +/-inf or the true sum would overflow, and
    1082                 :             :          * produce a suitably signed infinity, which will compare properly against
    1083                 :             :          * val whether or not that's infinity.
    1084                 :             :          */
    1085         [ +  + ]:         110 :         if (sub)
    1086                 :          60 :                 sum = base - offset;
    1087                 :             :         else
    1088                 :          50 :                 sum = base + offset;
    1089                 :             : 
    1090         [ +  + ]:         110 :         if (less)
    1091                 :          43 :                 PG_RETURN_BOOL(val <= sum);
    1092                 :             :         else
    1093                 :          67 :                 PG_RETURN_BOOL(val >= sum);
    1094                 :         511 : }
    1095                 :             : 
    1096                 :             : /*
    1097                 :             :  * in_range support function for float4.
    1098                 :             :  *
    1099                 :             :  * We would need a float4_float8 variant in any case, so we supply that and
    1100                 :             :  * let implicit coercion take care of the float4_float4 case.
    1101                 :             :  */
    1102                 :             : Datum
    1103                 :         192 : in_range_float4_float8(PG_FUNCTION_ARGS)
    1104                 :             : {
    1105                 :         192 :         float4          val = PG_GETARG_FLOAT4(0);
    1106                 :         192 :         float4          base = PG_GETARG_FLOAT4(1);
    1107                 :         192 :         float8          offset = PG_GETARG_FLOAT8(2);
    1108                 :         192 :         bool            sub = PG_GETARG_BOOL(3);
    1109                 :         192 :         bool            less = PG_GETARG_BOOL(4);
    1110                 :         192 :         float8          sum;
    1111                 :             : 
    1112                 :             :         /*
    1113                 :             :          * Reject negative or NaN offset.  Negative is per spec, and NaN is
    1114                 :             :          * because appropriate semantics for that seem non-obvious.
    1115                 :             :          */
    1116   [ +  -  +  -  :         192 :         if (isnan(offset) || offset < 0)
                   +  + ]
    1117   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1118                 :             :                                 (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
    1119                 :             :                                  errmsg("invalid preceding or following size in window function")));
    1120                 :             : 
    1121                 :             :         /*
    1122                 :             :          * Deal with cases where val and/or base is NaN, following the rule that
    1123                 :             :          * NaN sorts after non-NaN (cf float8_cmp_internal).  The offset cannot
    1124                 :             :          * affect the conclusion.
    1125                 :             :          */
    1126   [ +  -  +  +  :         191 :         if (isnan(val))
                   #  # ]
    1127                 :             :         {
    1128   [ +  -  +  +  :          31 :                 if (isnan(base))
                   #  # ]
    1129                 :          10 :                         PG_RETURN_BOOL(true);   /* NAN = NAN */
    1130                 :             :                 else
    1131                 :          21 :                         PG_RETURN_BOOL(!less);  /* NAN > non-NAN */
    1132                 :             :         }
    1133   [ +  -  +  +  :         160 :         else if (isnan(base))
                   #  # ]
    1134                 :             :         {
    1135                 :          21 :                 PG_RETURN_BOOL(less);   /* non-NAN < NAN */
    1136                 :             :         }
    1137                 :             : 
    1138                 :             :         /*
    1139                 :             :          * Deal with cases where both base and offset are infinite, and computing
    1140                 :             :          * base +/- offset would produce NaN.  This corresponds to a window frame
    1141                 :             :          * whose boundary infinitely precedes +inf or infinitely follows -inf,
    1142                 :             :          * which is not well-defined.  For consistency with other cases involving
    1143                 :             :          * infinities, such as the fact that +inf infinitely follows +inf, we
    1144                 :             :          * choose to assume that +inf infinitely precedes +inf and -inf infinitely
    1145                 :             :          * follows -inf, and therefore that all finite and infinite values are in
    1146                 :             :          * such a window frame.
    1147                 :             :          *
    1148                 :             :          * offset is known positive, so we need only check the sign of base in
    1149                 :             :          * this test.
    1150                 :             :          */
    1151   [ +  +  +  +  :         139 :         if (isinf(offset) && isinf(base) &&
                   +  + ]
    1152         [ +  + ]:          34 :                 (sub ? base > 0 : base < 0))
    1153                 :          29 :                 PG_RETURN_BOOL(true);
    1154                 :             : 
    1155                 :             :         /*
    1156                 :             :          * Otherwise it should be safe to compute base +/- offset.  We trust the
    1157                 :             :          * FPU to cope if an input is +/-inf or the true sum would overflow, and
    1158                 :             :          * produce a suitably signed infinity, which will compare properly against
    1159                 :             :          * val whether or not that's infinity.
    1160                 :             :          */
    1161         [ +  + ]:         110 :         if (sub)
    1162                 :          60 :                 sum = base - offset;
    1163                 :             :         else
    1164                 :          50 :                 sum = base + offset;
    1165                 :             : 
    1166         [ +  + ]:         110 :         if (less)
    1167                 :          43 :                 PG_RETURN_BOOL(val <= sum);
    1168                 :             :         else
    1169                 :          67 :                 PG_RETURN_BOOL(val >= sum);
    1170                 :         191 : }
    1171                 :             : 
    1172                 :             : 
    1173                 :             : /*
    1174                 :             :  *              ===================
    1175                 :             :  *              CONVERSION ROUTINES
    1176                 :             :  *              ===================
    1177                 :             :  */
    1178                 :             : 
    1179                 :             : /*
    1180                 :             :  *              ftod                    - converts a float4 number to a float8 number
    1181                 :             :  */
    1182                 :             : Datum
    1183                 :          49 : ftod(PG_FUNCTION_ARGS)
    1184                 :             : {
    1185                 :          49 :         float4          num = PG_GETARG_FLOAT4(0);
    1186                 :             : 
    1187                 :          98 :         PG_RETURN_FLOAT8((float8) num);
    1188                 :          49 : }
    1189                 :             : 
    1190                 :             : 
    1191                 :             : /*
    1192                 :             :  *              dtof                    - converts a float8 number to a float4 number
    1193                 :             :  */
    1194                 :             : Datum
    1195                 :           8 : dtof(PG_FUNCTION_ARGS)
    1196                 :             : {
    1197                 :           8 :         float8          num = PG_GETARG_FLOAT8(0);
    1198                 :           8 :         float4          result;
    1199                 :             : 
    1200                 :           8 :         result = (float4) num;
    1201   [ +  +  -  + ]:           8 :         if (unlikely(isinf(result)) && !isinf(num))
    1202                 :           2 :                 float_overflow_error();
    1203   [ +  +  -  + ]:           6 :         if (unlikely(result == 0.0f) && num != 0.0)
    1204                 :           2 :                 float_underflow_error();
    1205                 :             : 
    1206                 :           8 :         PG_RETURN_FLOAT4(result);
    1207                 :           4 : }
    1208                 :             : 
    1209                 :             : 
    1210                 :             : /*
    1211                 :             :  *              dtoi4                   - converts a float8 number to an int4 number
    1212                 :             :  */
    1213                 :             : Datum
    1214                 :         177 : dtoi4(PG_FUNCTION_ARGS)
    1215                 :             : {
    1216                 :         177 :         float8          num = PG_GETARG_FLOAT8(0);
    1217                 :             : 
    1218                 :             :         /*
    1219                 :             :          * Get rid of any fractional part in the input.  This is so we don't fail
    1220                 :             :          * on just-out-of-range values that would round into range.  Note
    1221                 :             :          * assumption that rint() will pass through a NaN or Inf unchanged.
    1222                 :             :          */
    1223                 :         177 :         num = rint(num);
    1224                 :             : 
    1225                 :             :         /* Range check */
    1226   [ -  +  +  +  :         177 :         if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT32(num)))
          +  -  +  +  +  
                      + ]
    1227   [ +  -  +  - ]:           4 :                 ereport(ERROR,
    1228                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1229                 :             :                                  errmsg("integer out of range")));
    1230                 :             : 
    1231                 :        1050 :         PG_RETURN_INT32((int32) num);
    1232                 :         525 : }
    1233                 :             : 
    1234                 :             : 
    1235                 :             : /*
    1236                 :             :  *              dtoi2                   - converts a float8 number to an int2 number
    1237                 :             :  */
    1238                 :             : Datum
    1239                 :          15 : dtoi2(PG_FUNCTION_ARGS)
    1240                 :             : {
    1241                 :          15 :         float8          num = PG_GETARG_FLOAT8(0);
    1242                 :             : 
    1243                 :             :         /*
    1244                 :             :          * Get rid of any fractional part in the input.  This is so we don't fail
    1245                 :             :          * on just-out-of-range values that would round into range.  Note
    1246                 :             :          * assumption that rint() will pass through a NaN or Inf unchanged.
    1247                 :             :          */
    1248                 :          15 :         num = rint(num);
    1249                 :             : 
    1250                 :             :         /* Range check */
    1251   [ -  +  +  +  :          15 :         if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT16(num)))
          +  -  +  +  +  
                      + ]
    1252   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    1253                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1254                 :             :                                  errmsg("smallint out of range")));
    1255                 :             : 
    1256                 :          86 :         PG_RETURN_INT16((int16) num);
    1257                 :          43 : }
    1258                 :             : 
    1259                 :             : 
    1260                 :             : /*
    1261                 :             :  *              i4tod                   - converts an int4 number to a float8 number
    1262                 :             :  */
    1263                 :             : Datum
    1264                 :      360899 : i4tod(PG_FUNCTION_ARGS)
    1265                 :             : {
    1266                 :      360899 :         int32           num = PG_GETARG_INT32(0);
    1267                 :             : 
    1268                 :      721798 :         PG_RETURN_FLOAT8((float8) num);
    1269                 :      360899 : }
    1270                 :             : 
    1271                 :             : 
    1272                 :             : /*
    1273                 :             :  *              i2tod                   - converts an int2 number to a float8 number
    1274                 :             :  */
    1275                 :             : Datum
    1276                 :          41 : i2tod(PG_FUNCTION_ARGS)
    1277                 :             : {
    1278                 :          41 :         int16           num = PG_GETARG_INT16(0);
    1279                 :             : 
    1280                 :          82 :         PG_RETURN_FLOAT8((float8) num);
    1281                 :          41 : }
    1282                 :             : 
    1283                 :             : 
    1284                 :             : /*
    1285                 :             :  *              ftoi4                   - converts a float4 number to an int4 number
    1286                 :             :  */
    1287                 :             : Datum
    1288                 :           4 : ftoi4(PG_FUNCTION_ARGS)
    1289                 :             : {
    1290                 :           4 :         float4          num = PG_GETARG_FLOAT4(0);
    1291                 :             : 
    1292                 :             :         /*
    1293                 :             :          * Get rid of any fractional part in the input.  This is so we don't fail
    1294                 :             :          * on just-out-of-range values that would round into range.  Note
    1295                 :             :          * assumption that rint() will pass through a NaN or Inf unchanged.
    1296                 :             :          */
    1297                 :           4 :         num = rint(num);
    1298                 :             : 
    1299                 :             :         /* Range check */
    1300   [ +  -  -  +  :           4 :         if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT32(num)))
          #  #  +  +  +  
                      + ]
    1301   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    1302                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1303                 :             :                                  errmsg("integer out of range")));
    1304                 :             : 
    1305                 :           4 :         PG_RETURN_INT32((int32) num);
    1306                 :           2 : }
    1307                 :             : 
    1308                 :             : 
    1309                 :             : /*
    1310                 :             :  *              ftoi2                   - converts a float4 number to an int2 number
    1311                 :             :  */
    1312                 :             : Datum
    1313                 :           4 : ftoi2(PG_FUNCTION_ARGS)
    1314                 :             : {
    1315                 :           4 :         float4          num = PG_GETARG_FLOAT4(0);
    1316                 :             : 
    1317                 :             :         /*
    1318                 :             :          * Get rid of any fractional part in the input.  This is so we don't fail
    1319                 :             :          * on just-out-of-range values that would round into range.  Note
    1320                 :             :          * assumption that rint() will pass through a NaN or Inf unchanged.
    1321                 :             :          */
    1322                 :           4 :         num = rint(num);
    1323                 :             : 
    1324                 :             :         /* Range check */
    1325   [ +  -  -  +  :           4 :         if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT16(num)))
          #  #  +  +  +  
                      + ]
    1326   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    1327                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1328                 :             :                                  errmsg("smallint out of range")));
    1329                 :             : 
    1330                 :           4 :         PG_RETURN_INT16((int16) num);
    1331                 :           2 : }
    1332                 :             : 
    1333                 :             : 
    1334                 :             : /*
    1335                 :             :  *              i4tof                   - converts an int4 number to a float4 number
    1336                 :             :  */
    1337                 :             : Datum
    1338                 :          76 : i4tof(PG_FUNCTION_ARGS)
    1339                 :             : {
    1340                 :          76 :         int32           num = PG_GETARG_INT32(0);
    1341                 :             : 
    1342                 :         152 :         PG_RETURN_FLOAT4((float4) num);
    1343                 :          76 : }
    1344                 :             : 
    1345                 :             : 
    1346                 :             : /*
    1347                 :             :  *              i2tof                   - converts an int2 number to a float4 number
    1348                 :             :  */
    1349                 :             : Datum
    1350                 :           0 : i2tof(PG_FUNCTION_ARGS)
    1351                 :             : {
    1352                 :           0 :         int16           num = PG_GETARG_INT16(0);
    1353                 :             : 
    1354                 :           0 :         PG_RETURN_FLOAT4((float4) num);
    1355                 :           0 : }
    1356                 :             : 
    1357                 :             : 
    1358                 :             : /*
    1359                 :             :  *              =======================
    1360                 :             :  *              RANDOM FLOAT8 OPERATORS
    1361                 :             :  *              =======================
    1362                 :             :  */
    1363                 :             : 
    1364                 :             : /*
    1365                 :             :  *              dround                  - returns       ROUND(arg1)
    1366                 :             :  */
    1367                 :             : Datum
    1368                 :        3256 : dround(PG_FUNCTION_ARGS)
    1369                 :             : {
    1370                 :        3256 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1371                 :             : 
    1372                 :        6512 :         PG_RETURN_FLOAT8(rint(arg1));
    1373                 :        3256 : }
    1374                 :             : 
    1375                 :             : /*
    1376                 :             :  *              dceil                   - returns the smallest integer greater than or
    1377                 :             :  *                                                equal to the specified float
    1378                 :             :  */
    1379                 :             : Datum
    1380                 :          10 : dceil(PG_FUNCTION_ARGS)
    1381                 :             : {
    1382                 :          10 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1383                 :             : 
    1384                 :          20 :         PG_RETURN_FLOAT8(ceil(arg1));
    1385                 :          10 : }
    1386                 :             : 
    1387                 :             : /*
    1388                 :             :  *              dfloor                  - returns the largest integer lesser than or
    1389                 :             :  *                                                equal to the specified float
    1390                 :             :  */
    1391                 :             : Datum
    1392                 :          10 : dfloor(PG_FUNCTION_ARGS)
    1393                 :             : {
    1394                 :          10 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1395                 :             : 
    1396                 :          20 :         PG_RETURN_FLOAT8(floor(arg1));
    1397                 :          10 : }
    1398                 :             : 
    1399                 :             : /*
    1400                 :             :  *              dsign                   - returns -1 if the argument is less than 0, 0
    1401                 :             :  *                                                if the argument is equal to 0, and 1 if the
    1402                 :             :  *                                                argument is greater than zero.
    1403                 :             :  */
    1404                 :             : Datum
    1405                 :           5 : dsign(PG_FUNCTION_ARGS)
    1406                 :             : {
    1407                 :           5 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1408                 :           5 :         float8          result;
    1409                 :             : 
    1410         [ +  + ]:           5 :         if (arg1 > 0)
    1411                 :           3 :                 result = 1.0;
    1412         [ +  + ]:           2 :         else if (arg1 < 0)
    1413                 :           1 :                 result = -1.0;
    1414                 :             :         else
    1415                 :           1 :                 result = 0.0;
    1416                 :             : 
    1417                 :          10 :         PG_RETURN_FLOAT8(result);
    1418                 :           5 : }
    1419                 :             : 
    1420                 :             : /*
    1421                 :             :  *              dtrunc                  - returns truncation-towards-zero of arg1,
    1422                 :             :  *                                                arg1 >= 0 ... the greatest integer less
    1423                 :             :  *                                                                              than or equal to arg1
    1424                 :             :  *                                                arg1 < 0   ... the least integer greater
    1425                 :             :  *                                                                              than or equal to arg1
    1426                 :             :  */
    1427                 :             : Datum
    1428                 :           5 : dtrunc(PG_FUNCTION_ARGS)
    1429                 :             : {
    1430                 :           5 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1431                 :           5 :         float8          result;
    1432                 :             : 
    1433         [ +  + ]:           5 :         if (arg1 >= 0)
    1434                 :           4 :                 result = floor(arg1);
    1435                 :             :         else
    1436                 :           1 :                 result = -floor(-arg1);
    1437                 :             : 
    1438                 :          10 :         PG_RETURN_FLOAT8(result);
    1439                 :           5 : }
    1440                 :             : 
    1441                 :             : 
    1442                 :             : /*
    1443                 :             :  *              dsqrt                   - returns square root of arg1
    1444                 :             :  */
    1445                 :             : Datum
    1446                 :          11 : dsqrt(PG_FUNCTION_ARGS)
    1447                 :             : {
    1448                 :          11 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1449                 :          11 :         float8          result;
    1450                 :             : 
    1451         [ +  - ]:          11 :         if (arg1 < 0)
    1452   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1453                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
    1454                 :             :                                  errmsg("cannot take square root of a negative number")));
    1455                 :             : 
    1456                 :          11 :         result = sqrt(arg1);
    1457   [ -  +  #  # ]:          11 :         if (unlikely(isinf(result)) && !isinf(arg1))
    1458                 :           0 :                 float_overflow_error();
    1459   [ -  +  #  # ]:          11 :         if (unlikely(result == 0.0) && arg1 != 0.0)
    1460                 :           0 :                 float_underflow_error();
    1461                 :             : 
    1462                 :          22 :         PG_RETURN_FLOAT8(result);
    1463                 :          11 : }
    1464                 :             : 
    1465                 :             : 
    1466                 :             : /*
    1467                 :             :  *              dcbrt                   - returns cube root of arg1
    1468                 :             :  */
    1469                 :             : Datum
    1470                 :           6 : dcbrt(PG_FUNCTION_ARGS)
    1471                 :             : {
    1472                 :           6 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1473                 :           6 :         float8          result;
    1474                 :             : 
    1475                 :           6 :         result = cbrt(arg1);
    1476   [ -  +  #  # ]:           6 :         if (unlikely(isinf(result)) && !isinf(arg1))
    1477                 :           0 :                 float_overflow_error();
    1478   [ +  +  +  - ]:           6 :         if (unlikely(result == 0.0) && arg1 != 0.0)
    1479                 :           0 :                 float_underflow_error();
    1480                 :             : 
    1481                 :          12 :         PG_RETURN_FLOAT8(result);
    1482                 :           6 : }
    1483                 :             : 
    1484                 :             : 
    1485                 :             : /*
    1486                 :             :  *              dpow                    - returns pow(arg1,arg2)
    1487                 :             :  */
    1488                 :             : Datum
    1489                 :         693 : dpow(PG_FUNCTION_ARGS)
    1490                 :             : {
    1491                 :         693 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1492                 :         693 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    1493                 :         693 :         float8          result;
    1494                 :             : 
    1495                 :             :         /*
    1496                 :             :          * The POSIX spec says that NaN ^ 0 = 1, and 1 ^ NaN = 1, while all other
    1497                 :             :          * cases with NaN inputs yield NaN (with no error).  Many older platforms
    1498                 :             :          * get one or more of these cases wrong, so deal with them via explicit
    1499                 :             :          * logic rather than trusting pow(3).
    1500                 :             :          */
    1501   [ +  +  +  +  :         693 :         if (isnan(arg1))
                   +  - ]
    1502                 :             :         {
    1503   [ -  +  +  -  :         219 :                 if (isnan(arg2) || arg2 != 0.0)
                   +  + ]
    1504                 :           4 :                         PG_RETURN_FLOAT8(get_float8_nan());
    1505                 :           1 :                 PG_RETURN_FLOAT8(1.0);
    1506                 :             :         }
    1507   [ +  +  +  +  :         474 :         if (isnan(arg2))
                   +  - ]
    1508                 :             :         {
    1509         [ +  + ]:         213 :                 if (arg1 != 1.0)
    1510                 :           2 :                         PG_RETURN_FLOAT8(get_float8_nan());
    1511                 :           1 :                 PG_RETURN_FLOAT8(1.0);
    1512                 :             :         }
    1513                 :             : 
    1514                 :             :         /*
    1515                 :             :          * The SQL spec requires that we emit a particular SQLSTATE error code for
    1516                 :             :          * certain error conditions.  Specifically, we don't return a
    1517                 :             :          * divide-by-zero error code for 0 ^ -1.
    1518                 :             :          */
    1519   [ +  +  +  + ]:         261 :         if (arg1 == 0 && arg2 < 0)
    1520   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1521                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
    1522                 :             :                                  errmsg("zero raised to a negative power is undefined")));
    1523   [ +  +  +  + ]:         260 :         if (arg1 < 0 && floor(arg2) != arg2)
    1524   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1525                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
    1526                 :             :                                  errmsg("a negative number raised to a non-integer power yields a complex result")));
    1527                 :             : 
    1528                 :             :         /*
    1529                 :             :          * We don't trust the platform's pow() to handle infinity cases per POSIX
    1530                 :             :          * spec either, so deal with those explicitly too.  It's easier to handle
    1531                 :             :          * infinite y first, so that it doesn't matter if x is also infinite.
    1532                 :             :          */
    1533         [ +  + ]:         259 :         if (isinf(arg2))
    1534                 :             :         {
    1535                 :          17 :                 float8          absx = fabs(arg1);
    1536                 :             : 
    1537         [ +  + ]:          17 :                 if (absx == 1.0)
    1538                 :           4 :                         result = 1.0;
    1539         [ +  + ]:          13 :                 else if (arg2 > 0.0) /* y = +Inf */
    1540                 :             :                 {
    1541         [ +  + ]:           7 :                         if (absx > 1.0)
    1542                 :           4 :                                 result = arg2;
    1543                 :             :                         else
    1544                 :           3 :                                 result = 0.0;
    1545                 :           7 :                 }
    1546                 :             :                 else                                    /* y = -Inf */
    1547                 :             :                 {
    1548         [ +  + ]:           6 :                         if (absx > 1.0)
    1549                 :           4 :                                 result = 0.0;
    1550                 :             :                         else
    1551                 :           2 :                                 result = -arg2;
    1552                 :             :                 }
    1553                 :          17 :         }
    1554         [ +  + ]:         242 :         else if (isinf(arg1))
    1555                 :             :         {
    1556         [ +  + ]:           8 :                 if (arg2 == 0.0)
    1557                 :           2 :                         result = 1.0;
    1558         [ +  + ]:           6 :                 else if (arg1 > 0.0) /* x = +Inf */
    1559                 :             :                 {
    1560         [ +  + ]:           2 :                         if (arg2 > 0.0)
    1561                 :           1 :                                 result = arg1;
    1562                 :             :                         else
    1563                 :           1 :                                 result = 0.0;
    1564                 :           2 :                 }
    1565                 :             :                 else                                    /* x = -Inf */
    1566                 :             :                 {
    1567                 :             :                         /*
    1568                 :             :                          * Per POSIX, the sign of the result depends on whether y is an
    1569                 :             :                          * odd integer.  Since x < 0, we already know from the previous
    1570                 :             :                          * domain check that y is an integer.  It is odd if y/2 is not
    1571                 :             :                          * also an integer.
    1572                 :             :                          */
    1573                 :           4 :                         float8          halfy = arg2 / 2;       /* should be computed exactly */
    1574                 :           4 :                         bool            yisoddinteger = (floor(halfy) != halfy);
    1575                 :             : 
    1576         [ +  + ]:           4 :                         if (arg2 > 0.0)
    1577         [ +  + ]:           2 :                                 result = yisoddinteger ? arg1 : -arg1;
    1578                 :             :                         else
    1579                 :           2 :                                 result = yisoddinteger ? -0.0 : 0.0;
    1580                 :           4 :                 }
    1581                 :           8 :         }
    1582                 :             :         else
    1583                 :             :         {
    1584                 :             :                 /*
    1585                 :             :                  * pow() sets errno on only some platforms, depending on whether it
    1586                 :             :                  * follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we must check both
    1587                 :             :                  * errno and invalid output values.  (We can't rely on just the
    1588                 :             :                  * latter, either; some old platforms return a large-but-finite
    1589                 :             :                  * HUGE_VAL when reporting overflow.)
    1590                 :             :                  */
    1591                 :         234 :                 errno = 0;
    1592                 :         234 :                 result = pow(arg1, arg2);
    1593   [ +  +  -  +  :         234 :                 if (errno == EDOM || isnan(result))
             +  +  +  - ]
    1594                 :             :                 {
    1595                 :             :                         /*
    1596                 :             :                          * We handled all possible domain errors above, so this should be
    1597                 :             :                          * impossible.  However, old glibc versions on x86 have a bug that
    1598                 :             :                          * causes them to fail this way for abs(y) greater than 2^63:
    1599                 :             :                          *
    1600                 :             :                          * https://sourceware.org/bugzilla/show_bug.cgi?id=3866
    1601                 :             :                          *
    1602                 :             :                          * Hence, if we get here, assume y is finite but large (large
    1603                 :             :                          * enough to be certainly even). The result should be 0 if x == 0,
    1604                 :             :                          * 1.0 if abs(x) == 1.0, otherwise an overflow or underflow error.
    1605                 :             :                          */
    1606         [ #  # ]:         312 :                         if (arg1 == 0.0)
    1607                 :           0 :                                 result = 0.0;   /* we already verified y is positive */
    1608                 :             :                         else
    1609                 :             :                         {
    1610                 :           0 :                                 float8          absx = fabs(arg1);
    1611                 :             : 
    1612         [ #  # ]:           0 :                                 if (absx == 1.0)
    1613                 :           0 :                                         result = 1.0;
    1614   [ #  #  #  # ]:           0 :                                 else if (arg2 >= 0.0 ? (absx > 1.0) : (absx < 1.0))
    1615                 :           0 :                                         float_overflow_error();
    1616                 :             :                                 else
    1617                 :           0 :                                         float_underflow_error();
    1618                 :           0 :                         }
    1619                 :           0 :                 }
    1620         [ +  - ]:          78 :                 else if (errno == ERANGE)
    1621                 :             :                 {
    1622         [ #  # ]:           0 :                         if (result != 0.0)
    1623                 :           0 :                                 float_overflow_error();
    1624                 :             :                         else
    1625                 :           0 :                                 float_underflow_error();
    1626                 :             :                 }
    1627                 :             :                 else
    1628                 :             :                 {
    1629         [ +  + ]:          78 :                         if (unlikely(isinf(result)))
    1630                 :           1 :                                 float_overflow_error();
    1631   [ +  +  +  - ]:          77 :                         if (unlikely(result == 0.0) && arg1 != 0.0)
    1632                 :           0 :                                 float_underflow_error();
    1633                 :             :                 }
    1634                 :             :         }
    1635                 :             : 
    1636                 :         102 :         PG_RETURN_FLOAT8(result);
    1637                 :         110 : }
    1638                 :             : 
    1639                 :             : 
    1640                 :             : /*
    1641                 :             :  *              dexp                    - returns the exponential function of arg1
    1642                 :             :  */
    1643                 :             : Datum
    1644                 :           9 : dexp(PG_FUNCTION_ARGS)
    1645                 :             : {
    1646                 :           9 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1647                 :           9 :         float8          result;
    1648                 :             : 
    1649                 :             :         /*
    1650                 :             :          * Handle NaN and Inf cases explicitly.  This avoids needing to assume
    1651                 :             :          * that the platform's exp() conforms to POSIX for these cases, and it
    1652                 :             :          * removes some edge cases for the overflow checks below.
    1653                 :             :          */
    1654   [ -  +  +  +  :           9 :         if (isnan(arg1))
                   +  - ]
    1655                 :          17 :                 result = arg1;
    1656         [ +  + ]:           8 :         else if (isinf(arg1))
    1657                 :             :         {
    1658                 :             :                 /* Per POSIX, exp(-Inf) is 0 */
    1659         [ +  + ]:           2 :                 result = (arg1 > 0.0) ? arg1 : 0;
    1660                 :           2 :         }
    1661                 :             :         else
    1662                 :             :         {
    1663                 :             :                 /*
    1664                 :             :                  * On some platforms, exp() will not set errno but just return Inf or
    1665                 :             :                  * zero to report overflow/underflow; therefore, test both cases.
    1666                 :             :                  */
    1667                 :           6 :                 errno = 0;
    1668                 :           6 :                 result = exp(arg1);
    1669         [ +  - ]:           6 :                 if (unlikely(errno == ERANGE))
    1670                 :             :                 {
    1671         [ #  # ]:           0 :                         if (result != 0.0)
    1672                 :           0 :                                 float_overflow_error();
    1673                 :             :                         else
    1674                 :           0 :                                 float_underflow_error();
    1675                 :             :                 }
    1676         [ +  - ]:           6 :                 else if (unlikely(isinf(result)))
    1677                 :           0 :                         float_overflow_error();
    1678         [ +  + ]:           6 :                 else if (unlikely(result == 0.0))
    1679                 :           1 :                         float_underflow_error();
    1680                 :             :         }
    1681                 :             : 
    1682                 :          48 :         PG_RETURN_FLOAT8(result);
    1683                 :          24 : }
    1684                 :             : 
    1685                 :             : 
    1686                 :             : /*
    1687                 :             :  *              dlog1                   - returns the natural logarithm of arg1
    1688                 :             :  */
    1689                 :             : Datum
    1690                 :           5 : dlog1(PG_FUNCTION_ARGS)
    1691                 :             : {
    1692                 :           5 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1693                 :           5 :         float8          result;
    1694                 :             : 
    1695                 :             :         /*
    1696                 :             :          * Emit particular SQLSTATE error codes for ln(). This is required by the
    1697                 :             :          * SQL standard.
    1698                 :             :          */
    1699         [ +  + ]:           5 :         if (arg1 == 0.0)
    1700   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1701                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
    1702                 :             :                                  errmsg("cannot take logarithm of zero")));
    1703         [ +  + ]:           4 :         if (arg1 < 0)
    1704   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    1705                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
    1706                 :             :                                  errmsg("cannot take logarithm of a negative number")));
    1707                 :             : 
    1708                 :           3 :         result = log(arg1);
    1709   [ -  +  #  # ]:           3 :         if (unlikely(isinf(result)) && !isinf(arg1))
    1710                 :           0 :                 float_overflow_error();
    1711   [ -  +  #  # ]:           3 :         if (unlikely(result == 0.0) && arg1 != 1.0)
    1712                 :           0 :                 float_underflow_error();
    1713                 :             : 
    1714                 :           6 :         PG_RETURN_FLOAT8(result);
    1715                 :           3 : }
    1716                 :             : 
    1717                 :             : 
    1718                 :             : /*
    1719                 :             :  *              dlog10                  - returns the base 10 logarithm of arg1
    1720                 :             :  */
    1721                 :             : Datum
    1722                 :           0 : dlog10(PG_FUNCTION_ARGS)
    1723                 :             : {
    1724                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1725                 :           0 :         float8          result;
    1726                 :             : 
    1727                 :             :         /*
    1728                 :             :          * Emit particular SQLSTATE error codes for log(). The SQL spec doesn't
    1729                 :             :          * define log(), but it does define ln(), so it makes sense to emit the
    1730                 :             :          * same error code for an analogous error condition.
    1731                 :             :          */
    1732         [ #  # ]:           0 :         if (arg1 == 0.0)
    1733   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1734                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
    1735                 :             :                                  errmsg("cannot take logarithm of zero")));
    1736         [ #  # ]:           0 :         if (arg1 < 0)
    1737   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1738                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
    1739                 :             :                                  errmsg("cannot take logarithm of a negative number")));
    1740                 :             : 
    1741                 :           0 :         result = log10(arg1);
    1742   [ #  #  #  # ]:           0 :         if (unlikely(isinf(result)) && !isinf(arg1))
    1743                 :           0 :                 float_overflow_error();
    1744   [ #  #  #  # ]:           0 :         if (unlikely(result == 0.0) && arg1 != 1.0)
    1745                 :           0 :                 float_underflow_error();
    1746                 :             : 
    1747                 :           0 :         PG_RETURN_FLOAT8(result);
    1748                 :           0 : }
    1749                 :             : 
    1750                 :             : 
    1751                 :             : /*
    1752                 :             :  *              dacos                   - returns the arccos of arg1 (radians)
    1753                 :             :  */
    1754                 :             : Datum
    1755                 :           0 : dacos(PG_FUNCTION_ARGS)
    1756                 :             : {
    1757                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1758                 :           0 :         float8          result;
    1759                 :             : 
    1760                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1761   [ #  #  #  #  :           0 :         if (isnan(arg1))
                   #  # ]
    1762                 :           0 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1763                 :             : 
    1764                 :             :         /*
    1765                 :             :          * The principal branch of the inverse cosine function maps values in the
    1766                 :             :          * range [-1, 1] to values in the range [0, Pi], so we should reject any
    1767                 :             :          * inputs outside that range and the result will always be finite.
    1768                 :             :          */
    1769         [ #  # ]:           0 :         if (arg1 < -1.0 || arg1 > 1.0)
    1770   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1771                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1772                 :             :                                  errmsg("input is out of range")));
    1773                 :             : 
    1774                 :           0 :         result = acos(arg1);
    1775         [ #  # ]:           0 :         if (unlikely(isinf(result)))
    1776                 :           0 :                 float_overflow_error();
    1777                 :             : 
    1778                 :           0 :         PG_RETURN_FLOAT8(result);
    1779                 :           0 : }
    1780                 :             : 
    1781                 :             : 
    1782                 :             : /*
    1783                 :             :  *              dasin                   - returns the arcsin of arg1 (radians)
    1784                 :             :  */
    1785                 :             : Datum
    1786                 :           0 : dasin(PG_FUNCTION_ARGS)
    1787                 :             : {
    1788                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1789                 :           0 :         float8          result;
    1790                 :             : 
    1791                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1792   [ #  #  #  #  :           0 :         if (isnan(arg1))
                   #  # ]
    1793                 :           0 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1794                 :             : 
    1795                 :             :         /*
    1796                 :             :          * The principal branch of the inverse sine function maps values in the
    1797                 :             :          * range [-1, 1] to values in the range [-Pi/2, Pi/2], so we should reject
    1798                 :             :          * any inputs outside that range and the result will always be finite.
    1799                 :             :          */
    1800         [ #  # ]:           0 :         if (arg1 < -1.0 || arg1 > 1.0)
    1801   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1802                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1803                 :             :                                  errmsg("input is out of range")));
    1804                 :             : 
    1805                 :           0 :         result = asin(arg1);
    1806         [ #  # ]:           0 :         if (unlikely(isinf(result)))
    1807                 :           0 :                 float_overflow_error();
    1808                 :             : 
    1809                 :           0 :         PG_RETURN_FLOAT8(result);
    1810                 :           0 : }
    1811                 :             : 
    1812                 :             : 
    1813                 :             : /*
    1814                 :             :  *              datan                   - returns the arctan of arg1 (radians)
    1815                 :             :  */
    1816                 :             : Datum
    1817                 :           0 : datan(PG_FUNCTION_ARGS)
    1818                 :             : {
    1819                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1820                 :           0 :         float8          result;
    1821                 :             : 
    1822                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1823   [ #  #  #  #  :           0 :         if (isnan(arg1))
                   #  # ]
    1824                 :           0 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1825                 :             : 
    1826                 :             :         /*
    1827                 :             :          * The principal branch of the inverse tangent function maps all inputs to
    1828                 :             :          * values in the range [-Pi/2, Pi/2], so the result should always be
    1829                 :             :          * finite, even if the input is infinite.
    1830                 :             :          */
    1831                 :           0 :         result = atan(arg1);
    1832         [ #  # ]:           0 :         if (unlikely(isinf(result)))
    1833                 :           0 :                 float_overflow_error();
    1834                 :             : 
    1835                 :           0 :         PG_RETURN_FLOAT8(result);
    1836                 :           0 : }
    1837                 :             : 
    1838                 :             : 
    1839                 :             : /*
    1840                 :             :  *              atan2                   - returns the arctan of arg1/arg2 (radians)
    1841                 :             :  */
    1842                 :             : Datum
    1843                 :           0 : datan2(PG_FUNCTION_ARGS)
    1844                 :             : {
    1845                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1846                 :           0 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    1847                 :           0 :         float8          result;
    1848                 :             : 
    1849                 :             :         /* Per the POSIX spec, return NaN if either input is NaN */
    1850   [ #  #  #  #  :           0 :         if (isnan(arg1) || isnan(arg2))
          #  #  #  #  #  
                #  #  # ]
    1851                 :           0 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1852                 :             : 
    1853                 :             :         /*
    1854                 :             :          * atan2 maps all inputs to values in the range [-Pi, Pi], so the result
    1855                 :             :          * should always be finite, even if the inputs are infinite.
    1856                 :             :          */
    1857                 :           0 :         result = atan2(arg1, arg2);
    1858         [ #  # ]:           0 :         if (unlikely(isinf(result)))
    1859                 :           0 :                 float_overflow_error();
    1860                 :             : 
    1861                 :           0 :         PG_RETURN_FLOAT8(result);
    1862                 :           0 : }
    1863                 :             : 
    1864                 :             : 
    1865                 :             : /*
    1866                 :             :  *              dcos                    - returns the cosine of arg1 (radians)
    1867                 :             :  */
    1868                 :             : Datum
    1869                 :           4 : dcos(PG_FUNCTION_ARGS)
    1870                 :             : {
    1871                 :           4 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1872                 :           4 :         float8          result;
    1873                 :             : 
    1874                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1875   [ -  +  +  +  :           4 :         if (isnan(arg1))
                   +  - ]
    1876                 :           8 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1877                 :             : 
    1878                 :             :         /*
    1879                 :             :          * cos() is periodic and so theoretically can work for all finite inputs,
    1880                 :             :          * but some implementations may choose to throw error if the input is so
    1881                 :             :          * large that there are no significant digits in the result.  So we should
    1882                 :             :          * check for errors.  POSIX allows an error to be reported either via
    1883                 :             :          * errno or via fetestexcept(), but currently we only support checking
    1884                 :             :          * errno.  (fetestexcept() is rumored to report underflow unreasonably
    1885                 :             :          * early on some platforms, so it's not clear that believing it would be a
    1886                 :             :          * net improvement anyway.)
    1887                 :             :          *
    1888                 :             :          * For infinite inputs, POSIX specifies that the trigonometric functions
    1889                 :             :          * should return a domain error; but we won't notice that unless the
    1890                 :             :          * platform reports via errno, so also explicitly test for infinite
    1891                 :             :          * inputs.
    1892                 :             :          */
    1893                 :           4 :         errno = 0;
    1894                 :           4 :         result = cos(arg1);
    1895         [ +  - ]:           4 :         if (errno != 0 || isinf(arg1))
    1896   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1897                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1898                 :             :                                  errmsg("input is out of range")));
    1899         [ +  - ]:           4 :         if (unlikely(isinf(result)))
    1900                 :           0 :                 float_overflow_error();
    1901                 :             : 
    1902                 :           4 :         PG_RETURN_FLOAT8(result);
    1903                 :          12 : }
    1904                 :             : 
    1905                 :             : 
    1906                 :             : /*
    1907                 :             :  *              dcot                    - returns the cotangent of arg1 (radians)
    1908                 :             :  */
    1909                 :             : Datum
    1910                 :           0 : dcot(PG_FUNCTION_ARGS)
    1911                 :             : {
    1912                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1913                 :           0 :         float8          result;
    1914                 :             : 
    1915                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1916   [ #  #  #  #  :           0 :         if (isnan(arg1))
                   #  # ]
    1917                 :           0 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1918                 :             : 
    1919                 :             :         /* Be sure to throw an error if the input is infinite --- see dcos() */
    1920                 :           0 :         errno = 0;
    1921                 :           0 :         result = tan(arg1);
    1922         [ #  # ]:           0 :         if (errno != 0 || isinf(arg1))
    1923   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1924                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1925                 :             :                                  errmsg("input is out of range")));
    1926                 :             : 
    1927                 :           0 :         result = 1.0 / result;
    1928                 :             :         /* Not checking for overflow because cot(0) == Inf */
    1929                 :             : 
    1930                 :           0 :         PG_RETURN_FLOAT8(result);
    1931                 :           0 : }
    1932                 :             : 
    1933                 :             : 
    1934                 :             : /*
    1935                 :             :  *              dsin                    - returns the sine of arg1 (radians)
    1936                 :             :  */
    1937                 :             : Datum
    1938                 :          23 : dsin(PG_FUNCTION_ARGS)
    1939                 :             : {
    1940                 :          23 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1941                 :          23 :         float8          result;
    1942                 :             : 
    1943                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1944   [ -  +  +  +  :          23 :         if (isnan(arg1))
                   +  - ]
    1945                 :          46 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1946                 :             : 
    1947                 :             :         /* Be sure to throw an error if the input is infinite --- see dcos() */
    1948                 :          23 :         errno = 0;
    1949                 :          23 :         result = sin(arg1);
    1950         [ +  - ]:          23 :         if (errno != 0 || isinf(arg1))
    1951   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1952                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1953                 :             :                                  errmsg("input is out of range")));
    1954         [ +  - ]:          23 :         if (unlikely(isinf(result)))
    1955                 :           0 :                 float_overflow_error();
    1956                 :             : 
    1957                 :          23 :         PG_RETURN_FLOAT8(result);
    1958                 :          69 : }
    1959                 :             : 
    1960                 :             : 
    1961                 :             : /*
    1962                 :             :  *              dtan                    - returns the tangent of arg1 (radians)
    1963                 :             :  */
    1964                 :             : Datum
    1965                 :           0 : dtan(PG_FUNCTION_ARGS)
    1966                 :             : {
    1967                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    1968                 :           0 :         float8          result;
    1969                 :             : 
    1970                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    1971   [ #  #  #  #  :           0 :         if (isnan(arg1))
                   #  # ]
    1972                 :           0 :                 PG_RETURN_FLOAT8(get_float8_nan());
    1973                 :             : 
    1974                 :             :         /* Be sure to throw an error if the input is infinite --- see dcos() */
    1975                 :           0 :         errno = 0;
    1976                 :           0 :         result = tan(arg1);
    1977         [ #  # ]:           0 :         if (errno != 0 || isinf(arg1))
    1978   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1979                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    1980                 :             :                                  errmsg("input is out of range")));
    1981                 :             :         /* Not checking for overflow because tan(pi/2) == Inf */
    1982                 :             : 
    1983                 :           0 :         PG_RETURN_FLOAT8(result);
    1984                 :           0 : }
    1985                 :             : 
    1986                 :             : 
    1987                 :             : /* ========== DEGREE-BASED TRIGONOMETRIC FUNCTIONS ========== */
    1988                 :             : 
    1989                 :             : 
    1990                 :             : /*
    1991                 :             :  * Initialize the cached constants declared at the head of this file
    1992                 :             :  * (sin_30 etc).  The fact that we need those at all, let alone need this
    1993                 :             :  * Rube-Goldberg-worthy method of initializing them, is because there are
    1994                 :             :  * compilers out there that will precompute expressions such as sin(constant)
    1995                 :             :  * using a sin() function different from what will be used at runtime.  If we
    1996                 :             :  * want exact results, we must ensure that none of the scaling constants used
    1997                 :             :  * in the degree-based trig functions are computed that way.  To do so, we
    1998                 :             :  * compute them from the variables degree_c_thirty etc, which are also really
    1999                 :             :  * constants, but the compiler cannot assume that.
    2000                 :             :  *
    2001                 :             :  * Other hazards we are trying to forestall with this kluge include the
    2002                 :             :  * possibility that compilers will rearrange the expressions, or compute
    2003                 :             :  * some intermediate results in registers wider than a standard double.
    2004                 :             :  *
    2005                 :             :  * In the places where we use these constants, the typical pattern is like
    2006                 :             :  *              volatile float8 sin_x = sin(x * RADIANS_PER_DEGREE);
    2007                 :             :  *              return (sin_x / sin_30);
    2008                 :             :  * where we hope to get a value of exactly 1.0 from the division when x = 30.
    2009                 :             :  * The volatile temporary variable is needed on machines with wide float
    2010                 :             :  * registers, to ensure that the result of sin(x) is rounded to double width
    2011                 :             :  * the same as the value of sin_30 has been.  Experimentation with gcc shows
    2012                 :             :  * that marking the temp variable volatile is necessary to make the store and
    2013                 :             :  * reload actually happen; hopefully the same trick works for other compilers.
    2014                 :             :  * (gcc's documentation suggests using the -ffloat-store compiler switch to
    2015                 :             :  * ensure this, but that is compiler-specific and it also pessimizes code in
    2016                 :             :  * many places where we don't care about this.)
    2017                 :             :  */
    2018                 :             : static void
    2019                 :           1 : init_degree_constants(void)
    2020                 :             : {
    2021                 :           1 :         sin_30 = sin(degree_c_thirty * RADIANS_PER_DEGREE);
    2022                 :           1 :         one_minus_cos_60 = 1.0 - cos(degree_c_sixty * RADIANS_PER_DEGREE);
    2023                 :           1 :         asin_0_5 = asin(degree_c_one_half);
    2024                 :           1 :         acos_0_5 = acos(degree_c_one_half);
    2025                 :           1 :         atan_1_0 = atan(degree_c_one);
    2026                 :           1 :         tan_45 = sind_q1(degree_c_forty_five) / cosd_q1(degree_c_forty_five);
    2027                 :           1 :         cot_45 = cosd_q1(degree_c_forty_five) / sind_q1(degree_c_forty_five);
    2028                 :           1 :         degree_consts_set = true;
    2029                 :           1 : }
    2030                 :             : 
    2031                 :             : #define INIT_DEGREE_CONSTANTS() \
    2032                 :             : do { \
    2033                 :             :         if (!degree_consts_set) \
    2034                 :             :                 init_degree_constants(); \
    2035                 :             : } while(0)
    2036                 :             : 
    2037                 :             : 
    2038                 :             : /*
    2039                 :             :  *              asind_q1                - returns the inverse sine of x in degrees, for x in
    2040                 :             :  *                                                the range [0, 1].  The result is an angle in the
    2041                 :             :  *                                                first quadrant --- [0, 90] degrees.
    2042                 :             :  *
    2043                 :             :  *                                                For the 3 special case inputs (0, 0.5 and 1), this
    2044                 :             :  *                                                function will return exact values (0, 30 and 90
    2045                 :             :  *                                                degrees respectively).
    2046                 :             :  */
    2047                 :             : static double
    2048                 :          14 : asind_q1(double x)
    2049                 :             : {
    2050                 :             :         /*
    2051                 :             :          * Stitch together inverse sine and cosine functions for the ranges [0,
    2052                 :             :          * 0.5] and (0.5, 1].  Each expression below is guaranteed to return
    2053                 :             :          * exactly 30 for x=0.5, so the result is a continuous monotonic function
    2054                 :             :          * over the full range.
    2055                 :             :          */
    2056         [ +  + ]:          14 :         if (x <= 0.5)
    2057                 :             :         {
    2058                 :           8 :                 volatile float8 asin_x = asin(x);
    2059                 :             : 
    2060                 :           8 :                 return (asin_x / asin_0_5) * 30.0;
    2061                 :           8 :         }
    2062                 :             :         else
    2063                 :             :         {
    2064                 :           6 :                 volatile float8 acos_x = acos(x);
    2065                 :             : 
    2066                 :           6 :                 return 90.0 - (acos_x / acos_0_5) * 60.0;
    2067                 :           6 :         }
    2068                 :          14 : }
    2069                 :             : 
    2070                 :             : 
    2071                 :             : /*
    2072                 :             :  *              acosd_q1                - returns the inverse cosine of x in degrees, for x in
    2073                 :             :  *                                                the range [0, 1].  The result is an angle in the
    2074                 :             :  *                                                first quadrant --- [0, 90] degrees.
    2075                 :             :  *
    2076                 :             :  *                                                For the 3 special case inputs (0, 0.5 and 1), this
    2077                 :             :  *                                                function will return exact values (0, 60 and 90
    2078                 :             :  *                                                degrees respectively).
    2079                 :             :  */
    2080                 :             : static double
    2081                 :           6 : acosd_q1(double x)
    2082                 :             : {
    2083                 :             :         /*
    2084                 :             :          * Stitch together inverse sine and cosine functions for the ranges [0,
    2085                 :             :          * 0.5] and (0.5, 1].  Each expression below is guaranteed to return
    2086                 :             :          * exactly 60 for x=0.5, so the result is a continuous monotonic function
    2087                 :             :          * over the full range.
    2088                 :             :          */
    2089         [ +  + ]:           6 :         if (x <= 0.5)
    2090                 :             :         {
    2091                 :           4 :                 volatile float8 asin_x = asin(x);
    2092                 :             : 
    2093                 :           4 :                 return 90.0 - (asin_x / asin_0_5) * 30.0;
    2094                 :           4 :         }
    2095                 :             :         else
    2096                 :             :         {
    2097                 :           2 :                 volatile float8 acos_x = acos(x);
    2098                 :             : 
    2099                 :           2 :                 return (acos_x / acos_0_5) * 60.0;
    2100                 :           2 :         }
    2101                 :           6 : }
    2102                 :             : 
    2103                 :             : 
    2104                 :             : /*
    2105                 :             :  *              dacosd                  - returns the arccos of arg1 (degrees)
    2106                 :             :  */
    2107                 :             : Datum
    2108                 :          10 : dacosd(PG_FUNCTION_ARGS)
    2109                 :             : {
    2110                 :          10 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2111                 :          10 :         float8          result;
    2112                 :             : 
    2113                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    2114   [ -  +  +  +  :          10 :         if (isnan(arg1))
                   +  - ]
    2115                 :          20 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2116                 :             : 
    2117         [ +  - ]:          10 :         INIT_DEGREE_CONSTANTS();
    2118                 :             : 
    2119                 :             :         /*
    2120                 :             :          * The principal branch of the inverse cosine function maps values in the
    2121                 :             :          * range [-1, 1] to values in the range [0, 180], so we should reject any
    2122                 :             :          * inputs outside that range and the result will always be finite.
    2123                 :             :          */
    2124         [ +  - ]:          10 :         if (arg1 < -1.0 || arg1 > 1.0)
    2125   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2126                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2127                 :             :                                  errmsg("input is out of range")));
    2128                 :             : 
    2129         [ +  + ]:          10 :         if (arg1 >= 0.0)
    2130                 :           6 :                 result = acosd_q1(arg1);
    2131                 :             :         else
    2132                 :           4 :                 result = 90.0 + asind_q1(-arg1);
    2133                 :             : 
    2134         [ +  - ]:          10 :         if (unlikely(isinf(result)))
    2135                 :           0 :                 float_overflow_error();
    2136                 :             : 
    2137                 :          10 :         PG_RETURN_FLOAT8(result);
    2138                 :          30 : }
    2139                 :             : 
    2140                 :             : 
    2141                 :             : /*
    2142                 :             :  *              dasind                  - returns the arcsin of arg1 (degrees)
    2143                 :             :  */
    2144                 :             : Datum
    2145                 :          10 : dasind(PG_FUNCTION_ARGS)
    2146                 :             : {
    2147                 :          10 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2148                 :          10 :         float8          result;
    2149                 :             : 
    2150                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    2151   [ -  +  +  +  :          10 :         if (isnan(arg1))
                   +  - ]
    2152                 :          20 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2153                 :             : 
    2154         [ +  - ]:          10 :         INIT_DEGREE_CONSTANTS();
    2155                 :             : 
    2156                 :             :         /*
    2157                 :             :          * The principal branch of the inverse sine function maps values in the
    2158                 :             :          * range [-1, 1] to values in the range [-90, 90], so we should reject any
    2159                 :             :          * inputs outside that range and the result will always be finite.
    2160                 :             :          */
    2161         [ +  - ]:          10 :         if (arg1 < -1.0 || arg1 > 1.0)
    2162   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2163                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2164                 :             :                                  errmsg("input is out of range")));
    2165                 :             : 
    2166         [ +  + ]:          10 :         if (arg1 >= 0.0)
    2167                 :           6 :                 result = asind_q1(arg1);
    2168                 :             :         else
    2169                 :           4 :                 result = -asind_q1(-arg1);
    2170                 :             : 
    2171         [ +  - ]:          10 :         if (unlikely(isinf(result)))
    2172                 :           0 :                 float_overflow_error();
    2173                 :             : 
    2174                 :          10 :         PG_RETURN_FLOAT8(result);
    2175                 :          30 : }
    2176                 :             : 
    2177                 :             : 
    2178                 :             : /*
    2179                 :             :  *              datand                  - returns the arctan of arg1 (degrees)
    2180                 :             :  */
    2181                 :             : Datum
    2182                 :          10 : datand(PG_FUNCTION_ARGS)
    2183                 :             : {
    2184                 :          10 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2185                 :          10 :         float8          result;
    2186                 :          10 :         volatile float8 atan_arg1;
    2187                 :             : 
    2188                 :             :         /* Per the POSIX spec, return NaN if the input is NaN */
    2189   [ -  +  +  +  :          10 :         if (isnan(arg1))
                   +  - ]
    2190                 :          20 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2191                 :             : 
    2192         [ +  - ]:          10 :         INIT_DEGREE_CONSTANTS();
    2193                 :             : 
    2194                 :             :         /*
    2195                 :             :          * The principal branch of the inverse tangent function maps all inputs to
    2196                 :             :          * values in the range [-90, 90], so the result should always be finite,
    2197                 :             :          * even if the input is infinite.  Additionally, we take care to ensure
    2198                 :             :          * than when arg1 is 1, the result is exactly 45.
    2199                 :             :          */
    2200                 :          10 :         atan_arg1 = atan(arg1);
    2201                 :          10 :         result = (atan_arg1 / atan_1_0) * 45.0;
    2202                 :             : 
    2203         [ +  - ]:          10 :         if (unlikely(isinf(result)))
    2204                 :           0 :                 float_overflow_error();
    2205                 :             : 
    2206                 :          10 :         PG_RETURN_FLOAT8(result);
    2207                 :          30 : }
    2208                 :             : 
    2209                 :             : 
    2210                 :             : /*
    2211                 :             :  *              atan2d                  - returns the arctan of arg1/arg2 (degrees)
    2212                 :             :  */
    2213                 :             : Datum
    2214                 :          10 : datan2d(PG_FUNCTION_ARGS)
    2215                 :             : {
    2216                 :          10 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2217                 :          10 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    2218                 :          10 :         float8          result;
    2219                 :          10 :         volatile float8 atan2_arg1_arg2;
    2220                 :             : 
    2221                 :             :         /* Per the POSIX spec, return NaN if either input is NaN */
    2222   [ -  +  +  +  :          10 :         if (isnan(arg1) || isnan(arg2))
          +  -  -  +  +  
                +  +  - ]
    2223                 :          40 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2224                 :             : 
    2225         [ +  - ]:          10 :         INIT_DEGREE_CONSTANTS();
    2226                 :             : 
    2227                 :             :         /*
    2228                 :             :          * atan2d maps all inputs to values in the range [-180, 180], so the
    2229                 :             :          * result should always be finite, even if the inputs are infinite.
    2230                 :             :          *
    2231                 :             :          * Note: this coding assumes that atan(1.0) is a suitable scaling constant
    2232                 :             :          * to get an exact result from atan2().  This might well fail on us at
    2233                 :             :          * some point, requiring us to decide exactly what inputs we think we're
    2234                 :             :          * going to guarantee an exact result for.
    2235                 :             :          */
    2236                 :          10 :         atan2_arg1_arg2 = atan2(arg1, arg2);
    2237                 :          10 :         result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
    2238                 :             : 
    2239         [ +  - ]:          10 :         if (unlikely(isinf(result)))
    2240                 :           0 :                 float_overflow_error();
    2241                 :             : 
    2242                 :          10 :         PG_RETURN_FLOAT8(result);
    2243                 :          50 : }
    2244                 :             : 
    2245                 :             : 
    2246                 :             : /*
    2247                 :             :  *              sind_0_to_30    - returns the sine of an angle that lies between 0 and
    2248                 :             :  *                                                30 degrees.  This will return exactly 0 when x is 0,
    2249                 :             :  *                                                and exactly 0.5 when x is 30 degrees.
    2250                 :             :  */
    2251                 :             : static double
    2252                 :          53 : sind_0_to_30(double x)
    2253                 :             : {
    2254                 :          53 :         volatile float8 sin_x = sin(x * RADIANS_PER_DEGREE);
    2255                 :             : 
    2256                 :         106 :         return (sin_x / sin_30) / 2.0;
    2257                 :          53 : }
    2258                 :             : 
    2259                 :             : 
    2260                 :             : /*
    2261                 :             :  *              cosd_0_to_60    - returns the cosine of an angle that lies between 0
    2262                 :             :  *                                                and 60 degrees.  This will return exactly 1 when x
    2263                 :             :  *                                                is 0, and exactly 0.5 when x is 60 degrees.
    2264                 :             :  */
    2265                 :             : static double
    2266                 :          89 : cosd_0_to_60(double x)
    2267                 :             : {
    2268                 :          89 :         volatile float8 one_minus_cos_x = 1.0 - cos(x * RADIANS_PER_DEGREE);
    2269                 :             : 
    2270                 :         178 :         return 1.0 - (one_minus_cos_x / one_minus_cos_60) / 2.0;
    2271                 :          89 : }
    2272                 :             : 
    2273                 :             : 
    2274                 :             : /*
    2275                 :             :  *              sind_q1                 - returns the sine of an angle in the first quadrant
    2276                 :             :  *                                                (0 to 90 degrees).
    2277                 :             :  */
    2278                 :             : static double
    2279                 :          71 : sind_q1(double x)
    2280                 :             : {
    2281                 :             :         /*
    2282                 :             :          * Stitch together the sine and cosine functions for the ranges [0, 30]
    2283                 :             :          * and (30, 90].  These guarantee to return exact answers at their
    2284                 :             :          * endpoints, so the overall result is a continuous monotonic function
    2285                 :             :          * that gives exact results when x = 0, 30 and 90 degrees.
    2286                 :             :          */
    2287         [ +  + ]:          71 :         if (x <= 30.0)
    2288                 :          35 :                 return sind_0_to_30(x);
    2289                 :             :         else
    2290                 :          36 :                 return cosd_0_to_60(90.0 - x);
    2291                 :          71 : }
    2292                 :             : 
    2293                 :             : 
    2294                 :             : /*
    2295                 :             :  *              cosd_q1                 - returns the cosine of an angle in the first quadrant
    2296                 :             :  *                                                (0 to 90 degrees).
    2297                 :             :  */
    2298                 :             : static double
    2299                 :          71 : cosd_q1(double x)
    2300                 :             : {
    2301                 :             :         /*
    2302                 :             :          * Stitch together the sine and cosine functions for the ranges [0, 60]
    2303                 :             :          * and (60, 90].  These guarantee to return exact answers at their
    2304                 :             :          * endpoints, so the overall result is a continuous monotonic function
    2305                 :             :          * that gives exact results when x = 0, 60 and 90 degrees.
    2306                 :             :          */
    2307         [ +  + ]:          71 :         if (x <= 60.0)
    2308                 :          53 :                 return cosd_0_to_60(x);
    2309                 :             :         else
    2310                 :          18 :                 return sind_0_to_30(90.0 - x);
    2311                 :          71 : }
    2312                 :             : 
    2313                 :             : 
    2314                 :             : /*
    2315                 :             :  *              dcosd                   - returns the cosine of arg1 (degrees)
    2316                 :             :  */
    2317                 :             : Datum
    2318                 :          33 : dcosd(PG_FUNCTION_ARGS)
    2319                 :             : {
    2320                 :          33 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2321                 :          33 :         float8          result;
    2322                 :          33 :         int                     sign = 1;
    2323                 :             : 
    2324                 :             :         /*
    2325                 :             :          * Per the POSIX spec, return NaN if the input is NaN and throw an error
    2326                 :             :          * if the input is infinite.
    2327                 :             :          */
    2328   [ -  +  +  +  :          33 :         if (isnan(arg1))
                   +  - ]
    2329                 :          66 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2330                 :             : 
    2331         [ +  - ]:          33 :         if (isinf(arg1))
    2332   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2333                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2334                 :             :                                  errmsg("input is out of range")));
    2335                 :             : 
    2336         [ +  - ]:          33 :         INIT_DEGREE_CONSTANTS();
    2337                 :             : 
    2338                 :             :         /* Reduce the range of the input to [0,90] degrees */
    2339                 :          33 :         arg1 = fmod(arg1, 360.0);
    2340                 :             : 
    2341         [ +  - ]:          33 :         if (arg1 < 0.0)
    2342                 :             :         {
    2343                 :             :                 /* cosd(-x) = cosd(x) */
    2344                 :           0 :                 arg1 = -arg1;
    2345                 :           0 :         }
    2346                 :             : 
    2347         [ +  + ]:          33 :         if (arg1 > 180.0)
    2348                 :             :         {
    2349                 :             :                 /* cosd(360-x) = cosd(x) */
    2350                 :           9 :                 arg1 = 360.0 - arg1;
    2351                 :           9 :         }
    2352                 :             : 
    2353         [ +  + ]:          33 :         if (arg1 > 90.0)
    2354                 :             :         {
    2355                 :             :                 /* cosd(180-x) = -cosd(x) */
    2356                 :           9 :                 arg1 = 180.0 - arg1;
    2357                 :           9 :                 sign = -sign;
    2358                 :           9 :         }
    2359                 :             : 
    2360                 :          33 :         result = sign * cosd_q1(arg1);
    2361                 :             : 
    2362         [ +  - ]:          33 :         if (unlikely(isinf(result)))
    2363                 :           0 :                 float_overflow_error();
    2364                 :             : 
    2365                 :          33 :         PG_RETURN_FLOAT8(result);
    2366                 :          99 : }
    2367                 :             : 
    2368                 :             : 
    2369                 :             : /*
    2370                 :             :  *              dcotd                   - returns the cotangent of arg1 (degrees)
    2371                 :             :  */
    2372                 :             : Datum
    2373                 :          18 : dcotd(PG_FUNCTION_ARGS)
    2374                 :             : {
    2375                 :          18 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2376                 :          18 :         float8          result;
    2377                 :          18 :         volatile float8 cot_arg1;
    2378                 :          18 :         int                     sign = 1;
    2379                 :             : 
    2380                 :             :         /*
    2381                 :             :          * Per the POSIX spec, return NaN if the input is NaN and throw an error
    2382                 :             :          * if the input is infinite.
    2383                 :             :          */
    2384   [ -  +  +  +  :          18 :         if (isnan(arg1))
                   +  - ]
    2385                 :          36 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2386                 :             : 
    2387         [ +  - ]:          18 :         if (isinf(arg1))
    2388   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2389                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2390                 :             :                                  errmsg("input is out of range")));
    2391                 :             : 
    2392         [ +  - ]:          18 :         INIT_DEGREE_CONSTANTS();
    2393                 :             : 
    2394                 :             :         /* Reduce the range of the input to [0,90] degrees */
    2395                 :          18 :         arg1 = fmod(arg1, 360.0);
    2396                 :             : 
    2397         [ +  - ]:          18 :         if (arg1 < 0.0)
    2398                 :             :         {
    2399                 :             :                 /* cotd(-x) = -cotd(x) */
    2400                 :           0 :                 arg1 = -arg1;
    2401                 :           0 :                 sign = -sign;
    2402                 :           0 :         }
    2403                 :             : 
    2404         [ +  + ]:          18 :         if (arg1 > 180.0)
    2405                 :             :         {
    2406                 :             :                 /* cotd(360-x) = -cotd(x) */
    2407                 :           6 :                 arg1 = 360.0 - arg1;
    2408                 :           6 :                 sign = -sign;
    2409                 :           6 :         }
    2410                 :             : 
    2411         [ +  + ]:          18 :         if (arg1 > 90.0)
    2412                 :             :         {
    2413                 :             :                 /* cotd(180-x) = -cotd(x) */
    2414                 :           6 :                 arg1 = 180.0 - arg1;
    2415                 :           6 :                 sign = -sign;
    2416                 :           6 :         }
    2417                 :             : 
    2418                 :          18 :         cot_arg1 = cosd_q1(arg1) / sind_q1(arg1);
    2419                 :          18 :         result = sign * (cot_arg1 / cot_45);
    2420                 :             : 
    2421                 :             :         /*
    2422                 :             :          * On some machines we get cotd(270) = minus zero, but this isn't always
    2423                 :             :          * true.  For portability, and because the user constituency for this
    2424                 :             :          * function probably doesn't want minus zero, force it to plain zero.
    2425                 :             :          */
    2426         [ +  + ]:          18 :         if (result == 0.0)
    2427                 :           4 :                 result = 0.0;
    2428                 :             : 
    2429                 :             :         /* Not checking for overflow because cotd(0) == Inf */
    2430                 :             : 
    2431                 :          18 :         PG_RETURN_FLOAT8(result);
    2432                 :          54 : }
    2433                 :             : 
    2434                 :             : 
    2435                 :             : /*
    2436                 :             :  *              dsind                   - returns the sine of arg1 (degrees)
    2437                 :             :  */
    2438                 :             : Datum
    2439                 :          33 : dsind(PG_FUNCTION_ARGS)
    2440                 :             : {
    2441                 :          33 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2442                 :          33 :         float8          result;
    2443                 :          33 :         int                     sign = 1;
    2444                 :             : 
    2445                 :             :         /*
    2446                 :             :          * Per the POSIX spec, return NaN if the input is NaN and throw an error
    2447                 :             :          * if the input is infinite.
    2448                 :             :          */
    2449   [ -  +  +  +  :          33 :         if (isnan(arg1))
                   +  - ]
    2450                 :          66 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2451                 :             : 
    2452         [ +  - ]:          33 :         if (isinf(arg1))
    2453   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2454                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2455                 :             :                                  errmsg("input is out of range")));
    2456                 :             : 
    2457         [ +  + ]:          33 :         INIT_DEGREE_CONSTANTS();
    2458                 :             : 
    2459                 :             :         /* Reduce the range of the input to [0,90] degrees */
    2460                 :          33 :         arg1 = fmod(arg1, 360.0);
    2461                 :             : 
    2462         [ +  - ]:          33 :         if (arg1 < 0.0)
    2463                 :             :         {
    2464                 :             :                 /* sind(-x) = -sind(x) */
    2465                 :           0 :                 arg1 = -arg1;
    2466                 :           0 :                 sign = -sign;
    2467                 :           0 :         }
    2468                 :             : 
    2469         [ +  + ]:          33 :         if (arg1 > 180.0)
    2470                 :             :         {
    2471                 :             :                 /* sind(360-x) = -sind(x) */
    2472                 :           9 :                 arg1 = 360.0 - arg1;
    2473                 :           9 :                 sign = -sign;
    2474                 :           9 :         }
    2475                 :             : 
    2476         [ +  + ]:          33 :         if (arg1 > 90.0)
    2477                 :             :         {
    2478                 :             :                 /* sind(180-x) = sind(x) */
    2479                 :           9 :                 arg1 = 180.0 - arg1;
    2480                 :           9 :         }
    2481                 :             : 
    2482                 :          33 :         result = sign * sind_q1(arg1);
    2483                 :             : 
    2484         [ +  - ]:          33 :         if (unlikely(isinf(result)))
    2485                 :           0 :                 float_overflow_error();
    2486                 :             : 
    2487                 :          33 :         PG_RETURN_FLOAT8(result);
    2488                 :          99 : }
    2489                 :             : 
    2490                 :             : 
    2491                 :             : /*
    2492                 :             :  *              dtand                   - returns the tangent of arg1 (degrees)
    2493                 :             :  */
    2494                 :             : Datum
    2495                 :          18 : dtand(PG_FUNCTION_ARGS)
    2496                 :             : {
    2497                 :          18 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2498                 :          18 :         float8          result;
    2499                 :          18 :         volatile float8 tan_arg1;
    2500                 :          18 :         int                     sign = 1;
    2501                 :             : 
    2502                 :             :         /*
    2503                 :             :          * Per the POSIX spec, return NaN if the input is NaN and throw an error
    2504                 :             :          * if the input is infinite.
    2505                 :             :          */
    2506   [ -  +  +  +  :          18 :         if (isnan(arg1))
                   +  - ]
    2507                 :          36 :                 PG_RETURN_FLOAT8(get_float8_nan());
    2508                 :             : 
    2509         [ +  - ]:          18 :         if (isinf(arg1))
    2510   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    2511                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2512                 :             :                                  errmsg("input is out of range")));
    2513                 :             : 
    2514         [ +  - ]:          18 :         INIT_DEGREE_CONSTANTS();
    2515                 :             : 
    2516                 :             :         /* Reduce the range of the input to [0,90] degrees */
    2517                 :          18 :         arg1 = fmod(arg1, 360.0);
    2518                 :             : 
    2519         [ +  - ]:          18 :         if (arg1 < 0.0)
    2520                 :             :         {
    2521                 :             :                 /* tand(-x) = -tand(x) */
    2522                 :           0 :                 arg1 = -arg1;
    2523                 :           0 :                 sign = -sign;
    2524                 :           0 :         }
    2525                 :             : 
    2526         [ +  + ]:          18 :         if (arg1 > 180.0)
    2527                 :             :         {
    2528                 :             :                 /* tand(360-x) = -tand(x) */
    2529                 :           6 :                 arg1 = 360.0 - arg1;
    2530                 :           6 :                 sign = -sign;
    2531                 :           6 :         }
    2532                 :             : 
    2533         [ +  + ]:          18 :         if (arg1 > 90.0)
    2534                 :             :         {
    2535                 :             :                 /* tand(180-x) = -tand(x) */
    2536                 :           6 :                 arg1 = 180.0 - arg1;
    2537                 :           6 :                 sign = -sign;
    2538                 :           6 :         }
    2539                 :             : 
    2540                 :          18 :         tan_arg1 = sind_q1(arg1) / cosd_q1(arg1);
    2541                 :          18 :         result = sign * (tan_arg1 / tan_45);
    2542                 :             : 
    2543                 :             :         /*
    2544                 :             :          * On some machines we get tand(180) = minus zero, but this isn't always
    2545                 :             :          * true.  For portability, and because the user constituency for this
    2546                 :             :          * function probably doesn't want minus zero, force it to plain zero.
    2547                 :             :          */
    2548         [ +  + ]:          18 :         if (result == 0.0)
    2549                 :           6 :                 result = 0.0;
    2550                 :             : 
    2551                 :             :         /* Not checking for overflow because tand(90) == Inf */
    2552                 :             : 
    2553                 :          18 :         PG_RETURN_FLOAT8(result);
    2554                 :          54 : }
    2555                 :             : 
    2556                 :             : 
    2557                 :             : /*
    2558                 :             :  *              degrees         - returns degrees converted from radians
    2559                 :             :  */
    2560                 :             : Datum
    2561                 :           0 : degrees(PG_FUNCTION_ARGS)
    2562                 :             : {
    2563                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2564                 :             : 
    2565                 :           0 :         PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
    2566                 :           0 : }
    2567                 :             : 
    2568                 :             : 
    2569                 :             : /*
    2570                 :             :  *              dpi                             - returns the constant PI
    2571                 :             :  */
    2572                 :             : Datum
    2573                 :           4 : dpi(PG_FUNCTION_ARGS)
    2574                 :             : {
    2575                 :           4 :         PG_RETURN_FLOAT8(M_PI);
    2576                 :             : }
    2577                 :             : 
    2578                 :             : 
    2579                 :             : /*
    2580                 :             :  *              radians         - returns radians converted from degrees
    2581                 :             :  */
    2582                 :             : Datum
    2583                 :           0 : radians(PG_FUNCTION_ARGS)
    2584                 :             : {
    2585                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2586                 :             : 
    2587                 :           0 :         PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
    2588                 :           0 : }
    2589                 :             : 
    2590                 :             : 
    2591                 :             : /* ========== HYPERBOLIC FUNCTIONS ========== */
    2592                 :             : 
    2593                 :             : 
    2594                 :             : /*
    2595                 :             :  *              dsinh                   - returns the hyperbolic sine of arg1
    2596                 :             :  */
    2597                 :             : Datum
    2598                 :           4 : dsinh(PG_FUNCTION_ARGS)
    2599                 :             : {
    2600                 :           4 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2601                 :           4 :         float8          result;
    2602                 :             : 
    2603                 :           4 :         errno = 0;
    2604                 :           4 :         result = sinh(arg1);
    2605                 :             : 
    2606                 :             :         /*
    2607                 :             :          * if an ERANGE error occurs, it means there is an overflow.  For sinh,
    2608                 :             :          * the result should be either -infinity or infinity, depending on the
    2609                 :             :          * sign of arg1.
    2610                 :             :          */
    2611         [ +  - ]:           4 :         if (errno == ERANGE)
    2612                 :             :         {
    2613         [ #  # ]:           0 :                 if (arg1 < 0)
    2614                 :           0 :                         result = -get_float8_infinity();
    2615                 :             :                 else
    2616                 :           0 :                         result = get_float8_infinity();
    2617                 :           0 :         }
    2618                 :             : 
    2619                 :           8 :         PG_RETURN_FLOAT8(result);
    2620                 :           4 : }
    2621                 :             : 
    2622                 :             : 
    2623                 :             : /*
    2624                 :             :  *              dcosh                   - returns the hyperbolic cosine of arg1
    2625                 :             :  */
    2626                 :             : Datum
    2627                 :           4 : dcosh(PG_FUNCTION_ARGS)
    2628                 :             : {
    2629                 :           4 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2630                 :           4 :         float8          result;
    2631                 :             : 
    2632                 :           4 :         errno = 0;
    2633                 :           4 :         result = cosh(arg1);
    2634                 :             : 
    2635                 :             :         /*
    2636                 :             :          * if an ERANGE error occurs, it means there is an overflow.  As cosh is
    2637                 :             :          * always positive, it always means the result is positive infinity.
    2638                 :             :          */
    2639         [ +  - ]:           4 :         if (errno == ERANGE)
    2640                 :           0 :                 result = get_float8_infinity();
    2641                 :             : 
    2642         [ +  - ]:           4 :         if (unlikely(result == 0.0))
    2643                 :           0 :                 float_underflow_error();
    2644                 :             : 
    2645                 :           8 :         PG_RETURN_FLOAT8(result);
    2646                 :           4 : }
    2647                 :             : 
    2648                 :             : /*
    2649                 :             :  *              dtanh                   - returns the hyperbolic tangent of arg1
    2650                 :             :  */
    2651                 :             : Datum
    2652                 :           4 : dtanh(PG_FUNCTION_ARGS)
    2653                 :             : {
    2654                 :           4 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2655                 :           4 :         float8          result;
    2656                 :             : 
    2657                 :             :         /*
    2658                 :             :          * For tanh, we don't need an errno check because it never overflows.
    2659                 :             :          */
    2660                 :           4 :         result = tanh(arg1);
    2661                 :             : 
    2662         [ +  - ]:           4 :         if (unlikely(isinf(result)))
    2663                 :           0 :                 float_overflow_error();
    2664                 :             : 
    2665                 :           8 :         PG_RETURN_FLOAT8(result);
    2666                 :           4 : }
    2667                 :             : 
    2668                 :             : /*
    2669                 :             :  *              dasinh                  - returns the inverse hyperbolic sine of arg1
    2670                 :             :  */
    2671                 :             : Datum
    2672                 :           4 : dasinh(PG_FUNCTION_ARGS)
    2673                 :             : {
    2674                 :           4 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2675                 :           4 :         float8          result;
    2676                 :             : 
    2677                 :             :         /*
    2678                 :             :          * For asinh, we don't need an errno check because it never overflows.
    2679                 :             :          */
    2680                 :           4 :         result = asinh(arg1);
    2681                 :             : 
    2682                 :           8 :         PG_RETURN_FLOAT8(result);
    2683                 :           4 : }
    2684                 :             : 
    2685                 :             : /*
    2686                 :             :  *              dacosh                  - returns the inverse hyperbolic cosine of arg1
    2687                 :             :  */
    2688                 :             : Datum
    2689                 :           3 : dacosh(PG_FUNCTION_ARGS)
    2690                 :             : {
    2691                 :           3 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2692                 :           3 :         float8          result;
    2693                 :             : 
    2694                 :             :         /*
    2695                 :             :          * acosh is only defined for inputs >= 1.0.  By checking this ourselves,
    2696                 :             :          * we need not worry about checking for an EDOM error, which is a good
    2697                 :             :          * thing because some implementations will report that for NaN. Otherwise,
    2698                 :             :          * no error is possible.
    2699                 :             :          */
    2700         [ +  + ]:           3 :         if (arg1 < 1.0)
    2701   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    2702                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2703                 :             :                                  errmsg("input is out of range")));
    2704                 :             : 
    2705                 :           2 :         result = acosh(arg1);
    2706                 :             : 
    2707                 :           4 :         PG_RETURN_FLOAT8(result);
    2708                 :           2 : }
    2709                 :             : 
    2710                 :             : /*
    2711                 :             :  *              datanh                  - returns the inverse hyperbolic tangent of arg1
    2712                 :             :  */
    2713                 :             : Datum
    2714                 :           4 : datanh(PG_FUNCTION_ARGS)
    2715                 :             : {
    2716                 :           4 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2717                 :           4 :         float8          result;
    2718                 :             : 
    2719                 :             :         /*
    2720                 :             :          * atanh is only defined for inputs between -1 and 1.  By checking this
    2721                 :             :          * ourselves, we need not worry about checking for an EDOM error, which is
    2722                 :             :          * a good thing because some implementations will report that for NaN.
    2723                 :             :          */
    2724         [ +  + ]:           4 :         if (arg1 < -1.0 || arg1 > 1.0)
    2725   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    2726                 :             :                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    2727                 :             :                                  errmsg("input is out of range")));
    2728                 :             : 
    2729                 :             :         /*
    2730                 :             :          * Also handle the infinity cases ourselves; this is helpful because old
    2731                 :             :          * glibc versions may produce the wrong errno for this.  All other inputs
    2732                 :             :          * cannot produce an error.
    2733                 :             :          */
    2734         [ -  + ]:           2 :         if (arg1 == -1.0)
    2735                 :           0 :                 result = -get_float8_infinity();
    2736         [ -  + ]:           2 :         else if (arg1 == 1.0)
    2737                 :           0 :                 result = get_float8_infinity();
    2738                 :             :         else
    2739                 :           2 :                 result = atanh(arg1);
    2740                 :             : 
    2741                 :           4 :         PG_RETURN_FLOAT8(result);
    2742                 :           2 : }
    2743                 :             : 
    2744                 :             : 
    2745                 :             : /* ========== ERROR FUNCTIONS ========== */
    2746                 :             : 
    2747                 :             : 
    2748                 :             : /*
    2749                 :             :  *              derf                    - returns the error function: erf(arg1)
    2750                 :             :  */
    2751                 :             : Datum
    2752                 :        1022 : derf(PG_FUNCTION_ARGS)
    2753                 :             : {
    2754                 :        1022 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2755                 :        1022 :         float8          result;
    2756                 :             : 
    2757                 :             :         /*
    2758                 :             :          * For erf, we don't need an errno check because it never overflows.
    2759                 :             :          */
    2760                 :        1022 :         result = erf(arg1);
    2761                 :             : 
    2762         [ +  - ]:        1022 :         if (unlikely(isinf(result)))
    2763                 :           0 :                 float_overflow_error();
    2764                 :             : 
    2765                 :        2044 :         PG_RETURN_FLOAT8(result);
    2766                 :        1022 : }
    2767                 :             : 
    2768                 :             : /*
    2769                 :             :  *              derfc                   - returns the complementary error function: 1 - erf(arg1)
    2770                 :             :  */
    2771                 :             : Datum
    2772                 :          22 : derfc(PG_FUNCTION_ARGS)
    2773                 :             : {
    2774                 :          22 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2775                 :          22 :         float8          result;
    2776                 :             : 
    2777                 :             :         /*
    2778                 :             :          * For erfc, we don't need an errno check because it never overflows.
    2779                 :             :          */
    2780                 :          22 :         result = erfc(arg1);
    2781                 :             : 
    2782         [ +  - ]:          22 :         if (unlikely(isinf(result)))
    2783                 :           0 :                 float_overflow_error();
    2784                 :             : 
    2785                 :          44 :         PG_RETURN_FLOAT8(result);
    2786                 :          22 : }
    2787                 :             : 
    2788                 :             : 
    2789                 :             : /* ========== GAMMA FUNCTIONS ========== */
    2790                 :             : 
    2791                 :             : 
    2792                 :             : /*
    2793                 :             :  *              dgamma                  - returns the gamma function of arg1
    2794                 :             :  */
    2795                 :             : Datum
    2796                 :          13 : dgamma(PG_FUNCTION_ARGS)
    2797                 :             : {
    2798                 :          13 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2799                 :          13 :         float8          result;
    2800                 :             : 
    2801                 :             :         /*
    2802                 :             :          * Handle NaN and Inf cases explicitly.  This simplifies the overflow
    2803                 :             :          * checks on platforms that do not set errno.
    2804                 :             :          */
    2805   [ -  +  +  +  :          13 :         if (isnan(arg1))
                   +  - ]
    2806                 :          26 :                 result = arg1;
    2807         [ +  + ]:          13 :         else if (isinf(arg1))
    2808                 :             :         {
    2809                 :             :                 /* Per POSIX, an input of -Inf causes a domain error */
    2810         [ +  + ]:           2 :                 if (arg1 < 0)
    2811                 :             :                 {
    2812                 :           1 :                         float_overflow_error();
    2813                 :             :                         result = get_float8_nan();      /* keep compiler quiet */
    2814                 :             :                 }
    2815                 :             :                 else
    2816                 :           1 :                         result = arg1;
    2817                 :           1 :         }
    2818                 :             :         else
    2819                 :             :         {
    2820                 :             :                 /*
    2821                 :             :                  * Note: the POSIX/C99 gamma function is called "tgamma", not "gamma".
    2822                 :             :                  *
    2823                 :             :                  * On some platforms, tgamma() will not set errno but just return Inf,
    2824                 :             :                  * NaN, or zero to report overflow/underflow; therefore, test those
    2825                 :             :                  * cases explicitly (note that, like the exponential function, the
    2826                 :             :                  * gamma function has no zeros).
    2827                 :             :                  */
    2828                 :          11 :                 errno = 0;
    2829                 :          11 :                 result = tgamma(arg1);
    2830                 :             : 
    2831   [ +  +  -  +  :          11 :                 if (errno != 0 || isinf(result) || isnan(result))
                   +  - ]
    2832                 :             :                 {
    2833         [ +  - ]:           3 :                         if (result != 0.0)
    2834                 :           3 :                                 float_overflow_error();
    2835                 :             :                         else
    2836                 :           0 :                                 float_underflow_error();
    2837                 :             :                 }
    2838         [ +  + ]:           8 :                 else if (result == 0.0)
    2839                 :           1 :                         float_underflow_error();
    2840                 :             :         }
    2841                 :             : 
    2842                 :          68 :         PG_RETURN_FLOAT8(result);
    2843                 :          34 : }
    2844                 :             : 
    2845                 :             : 
    2846                 :             : /*
    2847                 :             :  *              dlgamma                 - natural logarithm of absolute value of gamma of arg1
    2848                 :             :  */
    2849                 :             : Datum
    2850                 :          14 : dlgamma(PG_FUNCTION_ARGS)
    2851                 :             : {
    2852                 :          14 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    2853                 :          14 :         float8          result;
    2854                 :             : 
    2855                 :             :         /*
    2856                 :             :          * Note: lgamma may not be thread-safe because it may write to a global
    2857                 :             :          * variable signgam, which may not be thread-local. However, this doesn't
    2858                 :             :          * matter to us, since we don't use signgam.
    2859                 :             :          */
    2860                 :          14 :         errno = 0;
    2861                 :          14 :         result = lgamma(arg1);
    2862                 :             : 
    2863                 :             :         /*
    2864                 :             :          * If an ERANGE error occurs, it means there was an overflow or a pole
    2865                 :             :          * error (which happens for zero and negative integer inputs).
    2866                 :             :          *
    2867                 :             :          * On some platforms, lgamma() will not set errno but just return infinity
    2868                 :             :          * to report overflow, but it should never underflow.
    2869                 :             :          */
    2870   [ +  +  +  + ]:          14 :         if (errno == ERANGE || (isinf(result) && !isinf(arg1)))
    2871                 :           3 :                 float_overflow_error();
    2872                 :             : 
    2873                 :          22 :         PG_RETURN_FLOAT8(result);
    2874                 :          11 : }
    2875                 :             : 
    2876                 :             : 
    2877                 :             : 
    2878                 :             : /*
    2879                 :             :  *              =========================
    2880                 :             :  *              FLOAT AGGREGATE OPERATORS
    2881                 :             :  *              =========================
    2882                 :             :  *
    2883                 :             :  *              float8_accum            - accumulate for AVG(), variance aggregates, etc.
    2884                 :             :  *              float4_accum            - same, but input data is float4
    2885                 :             :  *              float8_avg                      - produce final result for float AVG()
    2886                 :             :  *              float8_var_samp         - produce final result for float VAR_SAMP()
    2887                 :             :  *              float8_var_pop          - produce final result for float VAR_POP()
    2888                 :             :  *              float8_stddev_samp      - produce final result for float STDDEV_SAMP()
    2889                 :             :  *              float8_stddev_pop       - produce final result for float STDDEV_POP()
    2890                 :             :  *
    2891                 :             :  * The naive schoolbook implementation of these aggregates works by
    2892                 :             :  * accumulating sum(X) and sum(X^2).  However, this approach suffers from
    2893                 :             :  * large rounding errors in the final computation of quantities like the
    2894                 :             :  * population variance (N*sum(X^2) - sum(X)^2) / N^2, since each of the
    2895                 :             :  * intermediate terms is potentially very large, while the difference is often
    2896                 :             :  * quite small.
    2897                 :             :  *
    2898                 :             :  * Instead we use the Youngs-Cramer algorithm [1] which works by accumulating
    2899                 :             :  * Sx=sum(X) and Sxx=sum((X-Sx/N)^2), using a numerically stable algorithm to
    2900                 :             :  * incrementally update those quantities.  The final computations of each of
    2901                 :             :  * the aggregate values is then trivial and gives more accurate results (for
    2902                 :             :  * example, the population variance is just Sxx/N).  This algorithm is also
    2903                 :             :  * fairly easy to generalize to allow parallel execution without loss of
    2904                 :             :  * precision (see, for example, [2]).  For more details, and a comparison of
    2905                 :             :  * this with other algorithms, see [3].
    2906                 :             :  *
    2907                 :             :  * The transition datatype for all these aggregates is a 3-element array
    2908                 :             :  * of float8, holding the values N, Sx, Sxx in that order.
    2909                 :             :  *
    2910                 :             :  * Note that we represent N as a float to avoid having to build a special
    2911                 :             :  * datatype.  Given a reasonable floating-point implementation, there should
    2912                 :             :  * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
    2913                 :             :  * user will have doubtless lost interest anyway...)
    2914                 :             :  *
    2915                 :             :  * [1] Some Results Relevant to Choice of Sum and Sum-of-Product Algorithms,
    2916                 :             :  * E. A. Youngs and E. M. Cramer, Technometrics Vol 13, No 3, August 1971.
    2917                 :             :  *
    2918                 :             :  * [2] Updating Formulae and a Pairwise Algorithm for Computing Sample
    2919                 :             :  * Variances, T. F. Chan, G. H. Golub & R. J. LeVeque, COMPSTAT 1982.
    2920                 :             :  *
    2921                 :             :  * [3] Numerically Stable Parallel Computation of (Co-)Variance, Erich
    2922                 :             :  * Schubert and Michael Gertz, Proceedings of the 30th International
    2923                 :             :  * Conference on Scientific and Statistical Database Management, 2018.
    2924                 :             :  */
    2925                 :             : 
    2926                 :             : static float8 *
    2927                 :        8315 : check_float8_array(ArrayType *transarray, const char *caller, int n)
    2928                 :             : {
    2929                 :             :         /*
    2930                 :             :          * We expect the input to be an N-element float array; verify that. We
    2931                 :             :          * don't need to use deconstruct_array() since the array data is just
    2932                 :             :          * going to look like a C array of N float8 values.
    2933                 :             :          */
    2934         [ +  - ]:        8315 :         if (ARR_NDIM(transarray) != 1 ||
    2935                 :        8315 :                 ARR_DIMS(transarray)[0] != n ||
    2936                 :        8315 :                 ARR_HASNULL(transarray) ||
    2937                 :        8315 :                 ARR_ELEMTYPE(transarray) != FLOAT8OID)
    2938   [ #  #  #  # ]:           0 :                 elog(ERROR, "%s: expected %d-element float8 array", caller, n);
    2939         [ -  + ]:        8315 :         return (float8 *) ARR_DATA_PTR(transarray);
    2940                 :             : }
    2941                 :             : 
    2942                 :             : /*
    2943                 :             :  * float8_combine
    2944                 :             :  *
    2945                 :             :  * An aggregate combine function used to combine two 3 fields
    2946                 :             :  * aggregate transition data into a single transition data.
    2947                 :             :  * This function is used only in two stage aggregation and
    2948                 :             :  * shouldn't be called outside aggregate context.
    2949                 :             :  */
    2950                 :             : Datum
    2951                 :          67 : float8_combine(PG_FUNCTION_ARGS)
    2952                 :             : {
    2953                 :          67 :         ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
    2954                 :          67 :         ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
    2955                 :          67 :         float8     *transvalues1;
    2956                 :          67 :         float8     *transvalues2;
    2957                 :          67 :         float8          N1,
    2958                 :             :                                 Sx1,
    2959                 :             :                                 Sxx1,
    2960                 :             :                                 N2,
    2961                 :             :                                 Sx2,
    2962                 :             :                                 Sxx2,
    2963                 :             :                                 tmp,
    2964                 :             :                                 N,
    2965                 :             :                                 Sx,
    2966                 :             :                                 Sxx;
    2967                 :             : 
    2968                 :          67 :         transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
    2969                 :          67 :         transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
    2970                 :             : 
    2971                 :          67 :         N1 = transvalues1[0];
    2972                 :          67 :         Sx1 = transvalues1[1];
    2973                 :          67 :         Sxx1 = transvalues1[2];
    2974                 :             : 
    2975                 :          67 :         N2 = transvalues2[0];
    2976                 :          67 :         Sx2 = transvalues2[1];
    2977                 :          67 :         Sxx2 = transvalues2[2];
    2978                 :             : 
    2979                 :             :         /*--------------------
    2980                 :             :          * The transition values combine using a generalization of the
    2981                 :             :          * Youngs-Cramer algorithm as follows:
    2982                 :             :          *
    2983                 :             :          *      N = N1 + N2
    2984                 :             :          *      Sx = Sx1 + Sx2
    2985                 :             :          *      Sxx = Sxx1 + Sxx2 + N1 * N2 * (Sx1/N1 - Sx2/N2)^2 / N;
    2986                 :             :          *
    2987                 :             :          * It's worth handling the special cases N1 = 0 and N2 = 0 separately
    2988                 :             :          * since those cases are trivial, and we then don't need to worry about
    2989                 :             :          * division-by-zero errors in the general case.
    2990                 :             :          *--------------------
    2991                 :             :          */
    2992         [ +  + ]:          67 :         if (N1 == 0.0)
    2993                 :             :         {
    2994                 :          65 :                 N = N2;
    2995                 :          65 :                 Sx = Sx2;
    2996                 :          65 :                 Sxx = Sxx2;
    2997                 :          65 :         }
    2998         [ +  + ]:           2 :         else if (N2 == 0.0)
    2999                 :             :         {
    3000                 :           1 :                 N = N1;
    3001                 :           1 :                 Sx = Sx1;
    3002                 :           1 :                 Sxx = Sxx1;
    3003                 :           1 :         }
    3004                 :             :         else
    3005                 :             :         {
    3006                 :           1 :                 N = N1 + N2;
    3007                 :           1 :                 Sx = float8_pl(Sx1, Sx2);
    3008                 :           1 :                 tmp = Sx1 / N1 - Sx2 / N2;
    3009                 :           1 :                 Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N;
    3010   [ -  +  #  #  :           1 :                 if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
                   #  # ]
    3011                 :           0 :                         float_overflow_error();
    3012                 :             :         }
    3013                 :             : 
    3014                 :             :         /*
    3015                 :             :          * If we're invoked as an aggregate, we can cheat and modify our first
    3016                 :             :          * parameter in-place to reduce palloc overhead. Otherwise we construct a
    3017                 :             :          * new array with the updated transition data and return it.
    3018                 :             :          */
    3019         [ +  + ]:          67 :         if (AggCheckCallContext(fcinfo, NULL))
    3020                 :             :         {
    3021                 :          64 :                 transvalues1[0] = N;
    3022                 :          64 :                 transvalues1[1] = Sx;
    3023                 :          64 :                 transvalues1[2] = Sxx;
    3024                 :             : 
    3025                 :          64 :                 PG_RETURN_ARRAYTYPE_P(transarray1);
    3026                 :             :         }
    3027                 :             :         else
    3028                 :             :         {
    3029                 :           3 :                 Datum           transdatums[3];
    3030                 :           3 :                 ArrayType  *result;
    3031                 :             : 
    3032                 :           3 :                 transdatums[0] = Float8GetDatumFast(N);
    3033                 :           3 :                 transdatums[1] = Float8GetDatumFast(Sx);
    3034                 :           3 :                 transdatums[2] = Float8GetDatumFast(Sxx);
    3035                 :             : 
    3036                 :           3 :                 result = construct_array_builtin(transdatums, 3, FLOAT8OID);
    3037                 :             : 
    3038                 :           3 :                 PG_RETURN_ARRAYTYPE_P(result);
    3039                 :           3 :         }
    3040                 :          67 : }
    3041                 :             : 
    3042                 :             : Datum
    3043                 :        7727 : float8_accum(PG_FUNCTION_ARGS)
    3044                 :             : {
    3045                 :        7727 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3046                 :        7727 :         float8          newval = PG_GETARG_FLOAT8(1);
    3047                 :        7727 :         float8     *transvalues;
    3048                 :        7727 :         float8          N,
    3049                 :             :                                 Sx,
    3050                 :             :                                 Sxx,
    3051                 :             :                                 tmp;
    3052                 :             : 
    3053                 :        7727 :         transvalues = check_float8_array(transarray, "float8_accum", 3);
    3054                 :        7727 :         N = transvalues[0];
    3055                 :        7727 :         Sx = transvalues[1];
    3056                 :        7727 :         Sxx = transvalues[2];
    3057                 :             : 
    3058                 :             :         /*
    3059                 :             :          * Use the Youngs-Cramer algorithm to incorporate the new value into the
    3060                 :             :          * transition values.
    3061                 :             :          */
    3062                 :        7727 :         N += 1.0;
    3063                 :        7727 :         Sx += newval;
    3064         [ +  + ]:        7727 :         if (transvalues[0] > 0.0)
    3065                 :             :         {
    3066                 :        7634 :                 tmp = newval * N - Sx;
    3067                 :        7634 :                 Sxx += tmp * tmp / (N * transvalues[0]);
    3068                 :             : 
    3069                 :             :                 /*
    3070                 :             :                  * Overflow check.  We only report an overflow error when finite
    3071                 :             :                  * inputs lead to infinite results.  Note also that Sxx should be NaN
    3072                 :             :                  * if any of the inputs are infinite, so we intentionally prevent Sxx
    3073                 :             :                  * from becoming infinite.
    3074                 :             :                  */
    3075   [ +  +  -  + ]:        7634 :                 if (isinf(Sx) || isinf(Sxx))
    3076                 :             :                 {
    3077   [ +  +  +  - ]:           4 :                         if (!isinf(transvalues[1]) && !isinf(newval))
    3078                 :           0 :                                 float_overflow_error();
    3079                 :             : 
    3080                 :           4 :                         Sxx = get_float8_nan();
    3081                 :           4 :                 }
    3082                 :        7634 :         }
    3083                 :             :         else
    3084                 :             :         {
    3085                 :             :                 /*
    3086                 :             :                  * At the first input, we normally can leave Sxx as 0.  However, if
    3087                 :             :                  * the first input is Inf or NaN, we'd better force Sxx to NaN;
    3088                 :             :                  * otherwise we will falsely report variance zero when there are no
    3089                 :             :                  * more inputs.
    3090                 :             :                  */
    3091   [ -  +  +  +  :          93 :                 if (isnan(newval) || isinf(newval))
                   +  - ]
    3092                 :         178 :                         Sxx = get_float8_nan();
    3093                 :             :         }
    3094                 :             : 
    3095                 :             :         /*
    3096                 :             :          * If we're invoked as an aggregate, we can cheat and modify our first
    3097                 :             :          * parameter in-place to reduce palloc overhead. Otherwise we construct a
    3098                 :             :          * new array with the updated transition data and return it.
    3099                 :             :          */
    3100         [ +  + ]:        7727 :         if (AggCheckCallContext(fcinfo, NULL))
    3101                 :             :         {
    3102                 :        7726 :                 transvalues[0] = N;
    3103                 :        7726 :                 transvalues[1] = Sx;
    3104                 :        7726 :                 transvalues[2] = Sxx;
    3105                 :             : 
    3106                 :        7726 :                 PG_RETURN_ARRAYTYPE_P(transarray);
    3107                 :             :         }
    3108                 :             :         else
    3109                 :             :         {
    3110                 :           1 :                 Datum           transdatums[3];
    3111                 :           1 :                 ArrayType  *result;
    3112                 :             : 
    3113                 :           1 :                 transdatums[0] = Float8GetDatumFast(N);
    3114                 :           1 :                 transdatums[1] = Float8GetDatumFast(Sx);
    3115                 :           1 :                 transdatums[2] = Float8GetDatumFast(Sxx);
    3116                 :             : 
    3117                 :           1 :                 result = construct_array_builtin(transdatums, 3, FLOAT8OID);
    3118                 :             : 
    3119                 :           1 :                 PG_RETURN_ARRAYTYPE_P(result);
    3120                 :           1 :         }
    3121                 :        7727 : }
    3122                 :             : 
    3123                 :             : Datum
    3124                 :          48 : float4_accum(PG_FUNCTION_ARGS)
    3125                 :             : {
    3126                 :          48 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3127                 :             : 
    3128                 :             :         /* do computations as float8 */
    3129                 :          48 :         float8          newval = PG_GETARG_FLOAT4(1);
    3130                 :          48 :         float8     *transvalues;
    3131                 :          48 :         float8          N,
    3132                 :             :                                 Sx,
    3133                 :             :                                 Sxx,
    3134                 :             :                                 tmp;
    3135                 :             : 
    3136                 :          48 :         transvalues = check_float8_array(transarray, "float4_accum", 3);
    3137                 :          48 :         N = transvalues[0];
    3138                 :          48 :         Sx = transvalues[1];
    3139                 :          48 :         Sxx = transvalues[2];
    3140                 :             : 
    3141                 :             :         /*
    3142                 :             :          * Use the Youngs-Cramer algorithm to incorporate the new value into the
    3143                 :             :          * transition values.
    3144                 :             :          */
    3145                 :          48 :         N += 1.0;
    3146                 :          48 :         Sx += newval;
    3147         [ +  + ]:          48 :         if (transvalues[0] > 0.0)
    3148                 :             :         {
    3149                 :          34 :                 tmp = newval * N - Sx;
    3150                 :          34 :                 Sxx += tmp * tmp / (N * transvalues[0]);
    3151                 :             : 
    3152                 :             :                 /*
    3153                 :             :                  * Overflow check.  We only report an overflow error when finite
    3154                 :             :                  * inputs lead to infinite results.  Note also that Sxx should be NaN
    3155                 :             :                  * if any of the inputs are infinite, so we intentionally prevent Sxx
    3156                 :             :                  * from becoming infinite.
    3157                 :             :                  */
    3158   [ +  -  -  + ]:          34 :                 if (isinf(Sx) || isinf(Sxx))
    3159                 :             :                 {
    3160   [ #  #  #  # ]:           0 :                         if (!isinf(transvalues[1]) && !isinf(newval))
    3161                 :           0 :                                 float_overflow_error();
    3162                 :             : 
    3163                 :           0 :                         Sxx = get_float8_nan();
    3164                 :           0 :                 }
    3165                 :          34 :         }
    3166                 :             :         else
    3167                 :             :         {
    3168                 :             :                 /*
    3169                 :             :                  * At the first input, we normally can leave Sxx as 0.  However, if
    3170                 :             :                  * the first input is Inf or NaN, we'd better force Sxx to NaN;
    3171                 :             :                  * otherwise we will falsely report variance zero when there are no
    3172                 :             :                  * more inputs.
    3173                 :             :                  */
    3174   [ -  +  +  +  :          14 :                 if (isnan(newval) || isinf(newval))
                   +  - ]
    3175                 :          24 :                         Sxx = get_float8_nan();
    3176                 :             :         }
    3177                 :             : 
    3178                 :             :         /*
    3179                 :             :          * If we're invoked as an aggregate, we can cheat and modify our first
    3180                 :             :          * parameter in-place to reduce palloc overhead. Otherwise we construct a
    3181                 :             :          * new array with the updated transition data and return it.
    3182                 :             :          */
    3183         [ +  - ]:          48 :         if (AggCheckCallContext(fcinfo, NULL))
    3184                 :             :         {
    3185                 :          48 :                 transvalues[0] = N;
    3186                 :          48 :                 transvalues[1] = Sx;
    3187                 :          48 :                 transvalues[2] = Sxx;
    3188                 :             : 
    3189                 :          48 :                 PG_RETURN_ARRAYTYPE_P(transarray);
    3190                 :             :         }
    3191                 :             :         else
    3192                 :             :         {
    3193                 :           0 :                 Datum           transdatums[3];
    3194                 :           0 :                 ArrayType  *result;
    3195                 :             : 
    3196                 :           0 :                 transdatums[0] = Float8GetDatumFast(N);
    3197                 :           0 :                 transdatums[1] = Float8GetDatumFast(Sx);
    3198                 :           0 :                 transdatums[2] = Float8GetDatumFast(Sxx);
    3199                 :             : 
    3200                 :           0 :                 result = construct_array_builtin(transdatums, 3, FLOAT8OID);
    3201                 :             : 
    3202                 :           0 :                 PG_RETURN_ARRAYTYPE_P(result);
    3203                 :           0 :         }
    3204                 :          48 : }
    3205                 :             : 
    3206                 :             : Datum
    3207                 :          84 : float8_avg(PG_FUNCTION_ARGS)
    3208                 :             : {
    3209                 :          84 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3210                 :          84 :         float8     *transvalues;
    3211                 :          84 :         float8          N,
    3212                 :             :                                 Sx;
    3213                 :             : 
    3214                 :          84 :         transvalues = check_float8_array(transarray, "float8_avg", 3);
    3215                 :          84 :         N = transvalues[0];
    3216                 :          84 :         Sx = transvalues[1];
    3217                 :             :         /* ignore Sxx */
    3218                 :             : 
    3219                 :             :         /* SQL defines AVG of no values to be NULL */
    3220         [ +  + ]:          84 :         if (N == 0.0)
    3221                 :           2 :                 PG_RETURN_NULL();
    3222                 :             : 
    3223                 :          82 :         PG_RETURN_FLOAT8(Sx / N);
    3224                 :          84 : }
    3225                 :             : 
    3226                 :             : Datum
    3227                 :          14 : float8_var_pop(PG_FUNCTION_ARGS)
    3228                 :             : {
    3229                 :          14 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3230                 :          14 :         float8     *transvalues;
    3231                 :          14 :         float8          N,
    3232                 :             :                                 Sxx;
    3233                 :             : 
    3234                 :          14 :         transvalues = check_float8_array(transarray, "float8_var_pop", 3);
    3235                 :          14 :         N = transvalues[0];
    3236                 :             :         /* ignore Sx */
    3237                 :          14 :         Sxx = transvalues[2];
    3238                 :             : 
    3239                 :             :         /* Population variance is undefined when N is 0, so return NULL */
    3240         [ +  - ]:          14 :         if (N == 0.0)
    3241                 :           0 :                 PG_RETURN_NULL();
    3242                 :             : 
    3243                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3244                 :             : 
    3245                 :          14 :         PG_RETURN_FLOAT8(Sxx / N);
    3246                 :          14 : }
    3247                 :             : 
    3248                 :             : Datum
    3249                 :           7 : float8_var_samp(PG_FUNCTION_ARGS)
    3250                 :             : {
    3251                 :           7 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3252                 :           7 :         float8     *transvalues;
    3253                 :           7 :         float8          N,
    3254                 :             :                                 Sxx;
    3255                 :             : 
    3256                 :           7 :         transvalues = check_float8_array(transarray, "float8_var_samp", 3);
    3257                 :           7 :         N = transvalues[0];
    3258                 :             :         /* ignore Sx */
    3259                 :           7 :         Sxx = transvalues[2];
    3260                 :             : 
    3261                 :             :         /* Sample variance is undefined when N is 0 or 1, so return NULL */
    3262         [ +  + ]:           7 :         if (N <= 1.0)
    3263                 :           6 :                 PG_RETURN_NULL();
    3264                 :             : 
    3265                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3266                 :             : 
    3267                 :           1 :         PG_RETURN_FLOAT8(Sxx / (N - 1.0));
    3268                 :           7 : }
    3269                 :             : 
    3270                 :             : Datum
    3271                 :           7 : float8_stddev_pop(PG_FUNCTION_ARGS)
    3272                 :             : {
    3273                 :           7 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3274                 :           7 :         float8     *transvalues;
    3275                 :           7 :         float8          N,
    3276                 :             :                                 Sxx;
    3277                 :             : 
    3278                 :           7 :         transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
    3279                 :           7 :         N = transvalues[0];
    3280                 :             :         /* ignore Sx */
    3281                 :           7 :         Sxx = transvalues[2];
    3282                 :             : 
    3283                 :             :         /* Population stddev is undefined when N is 0, so return NULL */
    3284         [ +  - ]:           7 :         if (N == 0.0)
    3285                 :           0 :                 PG_RETURN_NULL();
    3286                 :             : 
    3287                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3288                 :             : 
    3289                 :           7 :         PG_RETURN_FLOAT8(sqrt(Sxx / N));
    3290                 :           7 : }
    3291                 :             : 
    3292                 :             : Datum
    3293                 :           8 : float8_stddev_samp(PG_FUNCTION_ARGS)
    3294                 :             : {
    3295                 :           8 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3296                 :           8 :         float8     *transvalues;
    3297                 :           8 :         float8          N,
    3298                 :             :                                 Sxx;
    3299                 :             : 
    3300                 :           8 :         transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
    3301                 :           8 :         N = transvalues[0];
    3302                 :             :         /* ignore Sx */
    3303                 :           8 :         Sxx = transvalues[2];
    3304                 :             : 
    3305                 :             :         /* Sample stddev is undefined when N is 0 or 1, so return NULL */
    3306         [ +  + ]:           8 :         if (N <= 1.0)
    3307                 :           6 :                 PG_RETURN_NULL();
    3308                 :             : 
    3309                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3310                 :             : 
    3311                 :           2 :         PG_RETURN_FLOAT8(sqrt(Sxx / (N - 1.0)));
    3312                 :           8 : }
    3313                 :             : 
    3314                 :             : /*
    3315                 :             :  *              =========================
    3316                 :             :  *              SQL2003 BINARY AGGREGATES
    3317                 :             :  *              =========================
    3318                 :             :  *
    3319                 :             :  * As with the preceding aggregates, we use the Youngs-Cramer algorithm to
    3320                 :             :  * reduce rounding errors in the aggregate final functions.
    3321                 :             :  *
    3322                 :             :  * The transition datatype for all these aggregates is an 8-element array of
    3323                 :             :  * float8, holding the values N, Sx=sum(X), Sxx=sum((X-Sx/N)^2), Sy=sum(Y),
    3324                 :             :  * Syy=sum((Y-Sy/N)^2), Sxy=sum((X-Sx/N)*(Y-Sy/N)), commonX, and commonY
    3325                 :             :  * in that order.
    3326                 :             :  *
    3327                 :             :  * commonX is defined as the common X value if all the X values were the same,
    3328                 :             :  * else NaN; likewise for commonY.  This is useful for deciding whether corr()
    3329                 :             :  * and related functions should return NULL.  This representation cannot
    3330                 :             :  * distinguish the-values-were-all-NaN from the-values-were-not-all-the-same,
    3331                 :             :  * but that's okay because for this purpose we use the IEEE float arithmetic
    3332                 :             :  * principle that two NaNs are never equal.  The SQL standard doesn't mention
    3333                 :             :  * NaNs, but it says that NULL is to be returned when N*sum(X*X) equals
    3334                 :             :  * sum(X)*sum(X) (etc), and that shouldn't be considered true for NaNs.
    3335                 :             :  * Testing this as written in the spec would be highly subject to roundoff
    3336                 :             :  * error, so instead we directly track whether all the inputs are equal.
    3337                 :             :  *
    3338                 :             :  * Note that Y is the first argument to all these aggregates!
    3339                 :             :  *
    3340                 :             :  * It might seem attractive to optimize this by having multiple accumulator
    3341                 :             :  * functions that only calculate the sums actually needed.  But on most
    3342                 :             :  * modern machines, a couple of extra floating-point multiplies will be
    3343                 :             :  * insignificant compared to the other per-tuple overhead, so I've chosen
    3344                 :             :  * to minimize code space instead.
    3345                 :             :  */
    3346                 :             : 
    3347                 :             : Datum
    3348                 :         235 : float8_regr_accum(PG_FUNCTION_ARGS)
    3349                 :             : {
    3350                 :         235 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3351                 :         235 :         float8          newvalY = PG_GETARG_FLOAT8(1);
    3352                 :         235 :         float8          newvalX = PG_GETARG_FLOAT8(2);
    3353                 :         235 :         float8     *transvalues;
    3354                 :         235 :         float8          N,
    3355                 :             :                                 Sx,
    3356                 :             :                                 Sxx,
    3357                 :             :                                 Sy,
    3358                 :             :                                 Syy,
    3359                 :             :                                 Sxy,
    3360                 :             :                                 commonX,
    3361                 :             :                                 commonY,
    3362                 :             :                                 tmpX,
    3363                 :             :                                 tmpY,
    3364                 :             :                                 scale;
    3365                 :             : 
    3366                 :         235 :         transvalues = check_float8_array(transarray, "float8_regr_accum", 8);
    3367                 :         235 :         N = transvalues[0];
    3368                 :         235 :         Sx = transvalues[1];
    3369                 :         235 :         Sxx = transvalues[2];
    3370                 :         235 :         Sy = transvalues[3];
    3371                 :         235 :         Syy = transvalues[4];
    3372                 :         235 :         Sxy = transvalues[5];
    3373                 :         235 :         commonX = transvalues[6];
    3374                 :         235 :         commonY = transvalues[7];
    3375                 :             : 
    3376                 :             :         /*
    3377                 :             :          * Use the Youngs-Cramer algorithm to incorporate the new values into the
    3378                 :             :          * transition values.
    3379                 :             :          */
    3380                 :         235 :         N += 1.0;
    3381                 :         235 :         Sx += newvalX;
    3382                 :         235 :         Sy += newvalY;
    3383         [ +  + ]:         235 :         if (transvalues[0] > 0.0)
    3384                 :             :         {
    3385                 :             :                 /*
    3386                 :             :                  * Check to see if we have seen distinct inputs.  We can use a test
    3387                 :             :                  * that's a bit cheaper than float8_ne() because if commonX is already
    3388                 :             :                  * NaN, it does not matter whether the != test returns true or not.
    3389                 :             :                  */
    3390   [ +  +  -  +  :         171 :                 if (newvalX != commonX || isnan(newvalX))
             +  +  +  - ]
    3391                 :         183 :                         commonX = get_float8_nan();
    3392   [ +  +  -  +  :         195 :                 if (newvalY != commonY || isnan(newvalY))
             +  +  +  - ]
    3393                 :         429 :                         commonY = get_float8_nan();
    3394                 :             : 
    3395                 :         389 :                 tmpX = newvalX * N - Sx;
    3396                 :         389 :                 tmpY = newvalY * N - Sy;
    3397                 :         389 :                 scale = 1.0 / (N * transvalues[0]);
    3398                 :             : 
    3399                 :             :                 /*
    3400                 :             :                  * If we have not seen distinct inputs, then Sxx, Syy, and/or Sxy
    3401                 :             :                  * should remain zero (since Sx's exact value would be N * commonX,
    3402                 :             :                  * etc).  Updating them would just create the possibility of injecting
    3403                 :             :                  * roundoff error, and we need exact zero results so that the final
    3404                 :             :                  * functions will return NULL in the right cases.
    3405                 :             :                  */
    3406   [ +  +  +  +  :         389 :                 if (isnan(commonX))
                   +  - ]
    3407                 :         243 :                         Sxx += tmpX * tmpX * scale;
    3408   [ +  +  +  +  :         329 :                 if (isnan(commonY))
                   +  - ]
    3409                 :         271 :                         Syy += tmpY * tmpY * scale;
    3410   [ -  +  +  +  :         213 :                 if (isnan(commonX) && isnan(commonY))
          +  -  -  +  +  
                +  +  - ]
    3411                 :         241 :                         Sxy += tmpX * tmpY * scale;
    3412                 :             : 
    3413                 :             :                 /*
    3414                 :             :                  * Overflow check.  We only report an overflow error when finite
    3415                 :             :                  * inputs lead to infinite results.  Note also that Sxx, Syy and Sxy
    3416                 :             :                  * should be NaN if any of the relevant inputs are infinite, so we
    3417                 :             :                  * intentionally prevent them from becoming infinite.
    3418                 :             :                  */
    3419   [ +  -  +  -  :         213 :                 if (isinf(Sx) || isinf(Sxx) || isinf(Sy) || isinf(Syy) || isinf(Sxy))
          +  -  +  -  -  
                      + ]
    3420                 :             :                 {
    3421         [ #  # ]:           0 :                         if (((isinf(Sx) || isinf(Sxx)) &&
    3422   [ #  #  #  # ]:           0 :                                  !isinf(transvalues[1]) && !isinf(newvalX)) ||
    3423         [ #  # ]:           0 :                                 ((isinf(Sy) || isinf(Syy)) &&
    3424         [ #  # ]:           0 :                                  !isinf(transvalues[3]) && !isinf(newvalY)) ||
    3425         [ #  # ]:           0 :                                 (isinf(Sxy) &&
    3426   [ #  #  #  # ]:           0 :                                  !isinf(transvalues[1]) && !isinf(newvalX) &&
    3427         [ #  # ]:           0 :                                  !isinf(transvalues[3]) && !isinf(newvalY)))
    3428                 :           0 :                                 float_overflow_error();
    3429                 :             : 
    3430         [ #  # ]:           0 :                         if (isinf(Sxx))
    3431                 :           0 :                                 Sxx = get_float8_nan();
    3432         [ #  # ]:           0 :                         if (isinf(Syy))
    3433                 :           0 :                                 Syy = get_float8_nan();
    3434         [ #  # ]:           0 :                         if (isinf(Sxy))
    3435                 :           0 :                                 Sxy = get_float8_nan();
    3436                 :           0 :                 }
    3437                 :         213 :         }
    3438                 :             :         else
    3439                 :             :         {
    3440                 :             :                 /*
    3441                 :             :                  * At the first input, we normally can leave Sxx et al as 0.  However,
    3442                 :             :                  * if the first input is Inf or NaN, we'd better force the dependent
    3443                 :             :                  * sums to NaN; otherwise we will falsely report variance zero when
    3444                 :             :                  * there are no more inputs.
    3445                 :             :                  */
    3446   [ +  +  +  +  :          64 :                 if (isnan(newvalX) || isinf(newvalX))
                   +  - ]
    3447                 :          45 :                         Sxx = Sxy = get_float8_nan();
    3448   [ -  +  +  +  :          26 :                 if (isnan(newvalY) || isinf(newvalY))
                   +  - ]
    3449                 :          51 :                         Syy = Sxy = get_float8_nan();
    3450                 :             : 
    3451                 :          26 :                 commonX = newvalX;
    3452                 :          26 :                 commonY = newvalY;
    3453                 :             :         }
    3454                 :             : 
    3455                 :             :         /*
    3456                 :             :          * If we're invoked as an aggregate, we can cheat and modify our first
    3457                 :             :          * parameter in-place to reduce palloc overhead. Otherwise we construct a
    3458                 :             :          * new array with the updated transition data and return it.
    3459                 :             :          */
    3460         [ +  + ]:         239 :         if (AggCheckCallContext(fcinfo, NULL))
    3461                 :             :         {
    3462                 :         238 :                 transvalues[0] = N;
    3463                 :         238 :                 transvalues[1] = Sx;
    3464                 :         238 :                 transvalues[2] = Sxx;
    3465                 :         238 :                 transvalues[3] = Sy;
    3466                 :         238 :                 transvalues[4] = Syy;
    3467                 :         238 :                 transvalues[5] = Sxy;
    3468                 :         238 :                 transvalues[6] = commonX;
    3469                 :         238 :                 transvalues[7] = commonY;
    3470                 :             : 
    3471                 :         238 :                 PG_RETURN_ARRAYTYPE_P(transarray);
    3472                 :             :         }
    3473                 :             :         else
    3474                 :             :         {
    3475                 :           1 :                 Datum           transdatums[8];
    3476                 :           1 :                 ArrayType  *result;
    3477                 :             : 
    3478                 :           1 :                 transdatums[0] = Float8GetDatumFast(N);
    3479                 :           1 :                 transdatums[1] = Float8GetDatumFast(Sx);
    3480                 :           1 :                 transdatums[2] = Float8GetDatumFast(Sxx);
    3481                 :           1 :                 transdatums[3] = Float8GetDatumFast(Sy);
    3482                 :           1 :                 transdatums[4] = Float8GetDatumFast(Syy);
    3483                 :           1 :                 transdatums[5] = Float8GetDatumFast(Sxy);
    3484                 :           1 :                 transdatums[6] = Float8GetDatumFast(commonX);
    3485                 :           1 :                 transdatums[7] = Float8GetDatumFast(commonY);
    3486                 :             : 
    3487                 :           1 :                 result = construct_array_builtin(transdatums, 8, FLOAT8OID);
    3488                 :             : 
    3489                 :           1 :                 PG_RETURN_ARRAYTYPE_P(result);
    3490                 :           1 :         }
    3491                 :         239 : }
    3492                 :             : 
    3493                 :             : /*
    3494                 :             :  * float8_regr_combine
    3495                 :             :  *
    3496                 :             :  * An aggregate combine function used to combine two 8-fields
    3497                 :             :  * aggregate transition data into a single transition data.
    3498                 :             :  * This function is used only in two stage aggregation and
    3499                 :             :  * shouldn't be called outside aggregate context.
    3500                 :             :  */
    3501                 :             : Datum
    3502                 :           3 : float8_regr_combine(PG_FUNCTION_ARGS)
    3503                 :             : {
    3504                 :           3 :         ArrayType  *transarray1 = PG_GETARG_ARRAYTYPE_P(0);
    3505                 :           3 :         ArrayType  *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
    3506                 :           3 :         float8     *transvalues1;
    3507                 :           3 :         float8     *transvalues2;
    3508                 :           3 :         float8          N1,
    3509                 :             :                                 Sx1,
    3510                 :             :                                 Sxx1,
    3511                 :             :                                 Sy1,
    3512                 :             :                                 Syy1,
    3513                 :             :                                 Sxy1,
    3514                 :             :                                 Cx1,
    3515                 :             :                                 Cy1,
    3516                 :             :                                 N2,
    3517                 :             :                                 Sx2,
    3518                 :             :                                 Sxx2,
    3519                 :             :                                 Sy2,
    3520                 :             :                                 Syy2,
    3521                 :             :                                 Sxy2,
    3522                 :             :                                 Cx2,
    3523                 :             :                                 Cy2,
    3524                 :             :                                 tmp1,
    3525                 :             :                                 tmp2,
    3526                 :             :                                 N,
    3527                 :             :                                 Sx,
    3528                 :             :                                 Sxx,
    3529                 :             :                                 Sy,
    3530                 :             :                                 Syy,
    3531                 :             :                                 Sxy,
    3532                 :             :                                 Cx,
    3533                 :             :                                 Cy;
    3534                 :             : 
    3535                 :           3 :         transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 8);
    3536                 :           3 :         transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 8);
    3537                 :             : 
    3538                 :           3 :         N1 = transvalues1[0];
    3539                 :           3 :         Sx1 = transvalues1[1];
    3540                 :           3 :         Sxx1 = transvalues1[2];
    3541                 :           3 :         Sy1 = transvalues1[3];
    3542                 :           3 :         Syy1 = transvalues1[4];
    3543                 :           3 :         Sxy1 = transvalues1[5];
    3544                 :           3 :         Cx1 = transvalues1[6];
    3545                 :           3 :         Cy1 = transvalues1[7];
    3546                 :             : 
    3547                 :           3 :         N2 = transvalues2[0];
    3548                 :           3 :         Sx2 = transvalues2[1];
    3549                 :           3 :         Sxx2 = transvalues2[2];
    3550                 :           3 :         Sy2 = transvalues2[3];
    3551                 :           3 :         Syy2 = transvalues2[4];
    3552                 :           3 :         Sxy2 = transvalues2[5];
    3553                 :           3 :         Cx2 = transvalues2[6];
    3554                 :           3 :         Cy2 = transvalues2[7];
    3555                 :             : 
    3556                 :             :         /*--------------------
    3557                 :             :          * The transition values combine using a generalization of the
    3558                 :             :          * Youngs-Cramer algorithm as follows:
    3559                 :             :          *
    3560                 :             :          *      N = N1 + N2
    3561                 :             :          *      Sx = Sx1 + Sx2
    3562                 :             :          *      Sxx = Sxx1 + Sxx2 + N1 * N2 * (Sx1/N1 - Sx2/N2)^2 / N
    3563                 :             :          *      Sy = Sy1 + Sy2
    3564                 :             :          *      Syy = Syy1 + Syy2 + N1 * N2 * (Sy1/N1 - Sy2/N2)^2 / N
    3565                 :             :          *      Sxy = Sxy1 + Sxy2 + N1 * N2 * (Sx1/N1 - Sx2/N2) * (Sy1/N1 - Sy2/N2) / N
    3566                 :             :          *
    3567                 :             :          * It's worth handling the special cases N1 = 0 and N2 = 0 separately
    3568                 :             :          * since those cases are trivial, and we then don't need to worry about
    3569                 :             :          * division-by-zero errors in the general case.
    3570                 :             :          *--------------------
    3571                 :             :          */
    3572         [ +  + ]:           3 :         if (N1 == 0.0)
    3573                 :             :         {
    3574                 :           1 :                 N = N2;
    3575                 :           1 :                 Sx = Sx2;
    3576                 :           1 :                 Sxx = Sxx2;
    3577                 :           1 :                 Sy = Sy2;
    3578                 :           1 :                 Syy = Syy2;
    3579                 :           1 :                 Sxy = Sxy2;
    3580                 :           1 :                 Cx = Cx2;
    3581                 :           1 :                 Cy = Cy2;
    3582                 :           1 :         }
    3583         [ +  + ]:           2 :         else if (N2 == 0.0)
    3584                 :             :         {
    3585                 :           1 :                 N = N1;
    3586                 :           1 :                 Sx = Sx1;
    3587                 :           1 :                 Sxx = Sxx1;
    3588                 :           1 :                 Sy = Sy1;
    3589                 :           1 :                 Syy = Syy1;
    3590                 :           1 :                 Sxy = Sxy1;
    3591                 :           1 :                 Cx = Cx1;
    3592                 :           1 :                 Cy = Cy1;
    3593                 :           1 :         }
    3594                 :             :         else
    3595                 :             :         {
    3596                 :           1 :                 N = N1 + N2;
    3597                 :           1 :                 Sx = float8_pl(Sx1, Sx2);
    3598                 :           1 :                 tmp1 = Sx1 / N1 - Sx2 / N2;
    3599                 :           1 :                 Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N;
    3600   [ -  +  #  #  :           1 :                 if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
                   #  # ]
    3601                 :           0 :                         float_overflow_error();
    3602                 :           1 :                 Sy = float8_pl(Sy1, Sy2);
    3603                 :           1 :                 tmp2 = Sy1 / N1 - Sy2 / N2;
    3604                 :           1 :                 Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N;
    3605   [ -  +  #  #  :           1 :                 if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2))
                   #  # ]
    3606                 :           0 :                         float_overflow_error();
    3607                 :           1 :                 Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N;
    3608   [ -  +  #  #  :           1 :                 if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2))
                   #  # ]
    3609                 :           0 :                         float_overflow_error();
    3610         [ +  - ]:           1 :                 if (float8_eq(Cx1, Cx2))
    3611                 :           1 :                         Cx = Cx1;
    3612                 :             :                 else
    3613                 :           0 :                         Cx = get_float8_nan();
    3614         [ -  + ]:           1 :                 if (float8_eq(Cy1, Cy2))
    3615                 :           0 :                         Cy = Cy1;
    3616                 :             :                 else
    3617                 :           1 :                         Cy = get_float8_nan();
    3618                 :             :         }
    3619                 :             : 
    3620                 :             :         /*
    3621                 :             :          * If we're invoked as an aggregate, we can cheat and modify our first
    3622                 :             :          * parameter in-place to reduce palloc overhead. Otherwise we construct a
    3623                 :             :          * new array with the updated transition data and return it.
    3624                 :             :          */
    3625         [ -  + ]:           3 :         if (AggCheckCallContext(fcinfo, NULL))
    3626                 :             :         {
    3627                 :           0 :                 transvalues1[0] = N;
    3628                 :           0 :                 transvalues1[1] = Sx;
    3629                 :           0 :                 transvalues1[2] = Sxx;
    3630                 :           0 :                 transvalues1[3] = Sy;
    3631                 :           0 :                 transvalues1[4] = Syy;
    3632                 :           0 :                 transvalues1[5] = Sxy;
    3633                 :           0 :                 transvalues1[6] = Cx;
    3634                 :           0 :                 transvalues1[7] = Cy;
    3635                 :             : 
    3636                 :           0 :                 PG_RETURN_ARRAYTYPE_P(transarray1);
    3637                 :             :         }
    3638                 :             :         else
    3639                 :             :         {
    3640                 :           3 :                 Datum           transdatums[8];
    3641                 :           3 :                 ArrayType  *result;
    3642                 :             : 
    3643                 :           3 :                 transdatums[0] = Float8GetDatumFast(N);
    3644                 :           3 :                 transdatums[1] = Float8GetDatumFast(Sx);
    3645                 :           3 :                 transdatums[2] = Float8GetDatumFast(Sxx);
    3646                 :           3 :                 transdatums[3] = Float8GetDatumFast(Sy);
    3647                 :           3 :                 transdatums[4] = Float8GetDatumFast(Syy);
    3648                 :           3 :                 transdatums[5] = Float8GetDatumFast(Sxy);
    3649                 :           3 :                 transdatums[6] = Float8GetDatumFast(Cx);
    3650                 :           3 :                 transdatums[7] = Float8GetDatumFast(Cy);
    3651                 :             : 
    3652                 :           3 :                 result = construct_array_builtin(transdatums, 8, FLOAT8OID);
    3653                 :             : 
    3654                 :           3 :                 PG_RETURN_ARRAYTYPE_P(result);
    3655                 :           3 :         }
    3656                 :           3 : }
    3657                 :             : 
    3658                 :             : 
    3659                 :             : Datum
    3660                 :           5 : float8_regr_sxx(PG_FUNCTION_ARGS)
    3661                 :             : {
    3662                 :           5 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3663                 :           5 :         float8     *transvalues;
    3664                 :           5 :         float8          N,
    3665                 :             :                                 Sxx;
    3666                 :             : 
    3667                 :           5 :         transvalues = check_float8_array(transarray, "float8_regr_sxx", 8);
    3668                 :           5 :         N = transvalues[0];
    3669                 :           5 :         Sxx = transvalues[2];
    3670                 :             : 
    3671                 :             :         /* if N is 0 we should return NULL */
    3672         [ +  - ]:           5 :         if (N < 1.0)
    3673                 :           0 :                 PG_RETURN_NULL();
    3674                 :             : 
    3675                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3676                 :             : 
    3677                 :           5 :         PG_RETURN_FLOAT8(Sxx);
    3678                 :           5 : }
    3679                 :             : 
    3680                 :             : Datum
    3681                 :           5 : float8_regr_syy(PG_FUNCTION_ARGS)
    3682                 :             : {
    3683                 :           5 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3684                 :           5 :         float8     *transvalues;
    3685                 :           5 :         float8          N,
    3686                 :             :                                 Syy;
    3687                 :             : 
    3688                 :           5 :         transvalues = check_float8_array(transarray, "float8_regr_syy", 8);
    3689                 :           5 :         N = transvalues[0];
    3690                 :           5 :         Syy = transvalues[4];
    3691                 :             : 
    3692                 :             :         /* if N is 0 we should return NULL */
    3693         [ +  - ]:           5 :         if (N < 1.0)
    3694                 :           0 :                 PG_RETURN_NULL();
    3695                 :             : 
    3696                 :             :         /* Note that Syy is guaranteed to be non-negative */
    3697                 :             : 
    3698                 :           5 :         PG_RETURN_FLOAT8(Syy);
    3699                 :           5 : }
    3700                 :             : 
    3701                 :             : Datum
    3702                 :           5 : float8_regr_sxy(PG_FUNCTION_ARGS)
    3703                 :             : {
    3704                 :           5 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3705                 :           5 :         float8     *transvalues;
    3706                 :           5 :         float8          N,
    3707                 :             :                                 Sxy;
    3708                 :             : 
    3709                 :           5 :         transvalues = check_float8_array(transarray, "float8_regr_sxy", 8);
    3710                 :           5 :         N = transvalues[0];
    3711                 :           5 :         Sxy = transvalues[5];
    3712                 :             : 
    3713                 :             :         /* if N is 0 we should return NULL */
    3714         [ +  - ]:           5 :         if (N < 1.0)
    3715                 :           0 :                 PG_RETURN_NULL();
    3716                 :             : 
    3717                 :             :         /* A negative result is valid here */
    3718                 :             : 
    3719                 :           5 :         PG_RETURN_FLOAT8(Sxy);
    3720                 :           5 : }
    3721                 :             : 
    3722                 :             : Datum
    3723                 :           1 : float8_regr_avgx(PG_FUNCTION_ARGS)
    3724                 :             : {
    3725                 :           1 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3726                 :           1 :         float8     *transvalues;
    3727                 :           1 :         float8          N,
    3728                 :             :                                 Sx,
    3729                 :             :                                 commonX;
    3730                 :             : 
    3731                 :           1 :         transvalues = check_float8_array(transarray, "float8_regr_avgx", 8);
    3732                 :           1 :         N = transvalues[0];
    3733                 :           1 :         Sx = transvalues[1];
    3734                 :           1 :         commonX = transvalues[6];
    3735                 :             : 
    3736                 :             :         /* if N is 0 we should return NULL */
    3737         [ +  - ]:           1 :         if (N < 1.0)
    3738                 :           0 :                 PG_RETURN_NULL();
    3739                 :             : 
    3740                 :             :         /* if all inputs were the same just return that, avoiding roundoff error */
    3741   [ -  +  #  #  :           1 :         if (!isnan(commonX))
                   +  - ]
    3742                 :           0 :                 PG_RETURN_FLOAT8(commonX);
    3743                 :             : 
    3744                 :           1 :         PG_RETURN_FLOAT8(Sx / N);
    3745                 :           1 : }
    3746                 :             : 
    3747                 :             : Datum
    3748                 :           1 : float8_regr_avgy(PG_FUNCTION_ARGS)
    3749                 :             : {
    3750                 :           1 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3751                 :           1 :         float8     *transvalues;
    3752                 :           1 :         float8          N,
    3753                 :             :                                 Sy,
    3754                 :             :                                 commonY;
    3755                 :             : 
    3756                 :           1 :         transvalues = check_float8_array(transarray, "float8_regr_avgy", 8);
    3757                 :           1 :         N = transvalues[0];
    3758                 :           1 :         Sy = transvalues[3];
    3759                 :           1 :         commonY = transvalues[7];
    3760                 :             : 
    3761                 :             :         /* if N is 0 we should return NULL */
    3762         [ +  - ]:           1 :         if (N < 1.0)
    3763                 :           0 :                 PG_RETURN_NULL();
    3764                 :             : 
    3765                 :             :         /* if all inputs were the same just return that, avoiding roundoff error */
    3766   [ -  +  #  #  :           1 :         if (!isnan(commonY))
                   +  - ]
    3767                 :           0 :                 PG_RETURN_FLOAT8(commonY);
    3768                 :             : 
    3769                 :           1 :         PG_RETURN_FLOAT8(Sy / N);
    3770                 :           1 : }
    3771                 :             : 
    3772                 :             : Datum
    3773                 :           4 : float8_covar_pop(PG_FUNCTION_ARGS)
    3774                 :             : {
    3775                 :           4 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3776                 :           4 :         float8     *transvalues;
    3777                 :           4 :         float8          N,
    3778                 :             :                                 Sxy;
    3779                 :             : 
    3780                 :           4 :         transvalues = check_float8_array(transarray, "float8_covar_pop", 8);
    3781                 :           4 :         N = transvalues[0];
    3782                 :           4 :         Sxy = transvalues[5];
    3783                 :             : 
    3784                 :             :         /* if N is 0 we should return NULL */
    3785         [ +  - ]:           4 :         if (N < 1.0)
    3786                 :           0 :                 PG_RETURN_NULL();
    3787                 :             : 
    3788                 :           4 :         PG_RETURN_FLOAT8(Sxy / N);
    3789                 :           4 : }
    3790                 :             : 
    3791                 :             : Datum
    3792                 :           4 : float8_covar_samp(PG_FUNCTION_ARGS)
    3793                 :             : {
    3794                 :           4 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3795                 :           4 :         float8     *transvalues;
    3796                 :           4 :         float8          N,
    3797                 :             :                                 Sxy;
    3798                 :             : 
    3799                 :           4 :         transvalues = check_float8_array(transarray, "float8_covar_samp", 8);
    3800                 :           4 :         N = transvalues[0];
    3801                 :           4 :         Sxy = transvalues[5];
    3802                 :             : 
    3803                 :             :         /* if N is <= 1 we should return NULL */
    3804         [ +  + ]:           4 :         if (N < 2.0)
    3805                 :           3 :                 PG_RETURN_NULL();
    3806                 :             : 
    3807                 :           1 :         PG_RETURN_FLOAT8(Sxy / (N - 1.0));
    3808                 :           4 : }
    3809                 :             : 
    3810                 :             : Datum
    3811                 :           9 : float8_corr(PG_FUNCTION_ARGS)
    3812                 :             : {
    3813                 :           9 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3814                 :           9 :         float8     *transvalues;
    3815                 :           9 :         float8          N,
    3816                 :             :                                 Sxx,
    3817                 :             :                                 Syy,
    3818                 :             :                                 Sxy,
    3819                 :             :                                 product,
    3820                 :             :                                 sqrtproduct,
    3821                 :             :                                 result;
    3822                 :             : 
    3823                 :           9 :         transvalues = check_float8_array(transarray, "float8_corr", 8);
    3824                 :           9 :         N = transvalues[0];
    3825                 :           9 :         Sxx = transvalues[2];
    3826                 :           9 :         Syy = transvalues[4];
    3827                 :           9 :         Sxy = transvalues[5];
    3828                 :             : 
    3829                 :             :         /* if N is 0 we should return NULL */
    3830         [ +  - ]:           9 :         if (N < 1.0)
    3831                 :           0 :                 PG_RETURN_NULL();
    3832                 :             : 
    3833                 :             :         /* Note that Sxx and Syy are guaranteed to be non-negative */
    3834                 :             : 
    3835                 :             :         /* per spec, return NULL for horizontal and vertical lines */
    3836   [ +  +  +  + ]:           9 :         if (Sxx == 0 || Syy == 0)
    3837                 :           4 :                 PG_RETURN_NULL();
    3838                 :             : 
    3839                 :             :         /*
    3840                 :             :          * The product Sxx * Syy might underflow or overflow.  If so, we can
    3841                 :             :          * recover by computing sqrt(Sxx) * sqrt(Syy) instead of sqrt(Sxx * Syy).
    3842                 :             :          * However, the double sqrt() calculation is a bit slower and less
    3843                 :             :          * accurate, so don't do it if we don't have to.
    3844                 :             :          */
    3845                 :           5 :         product = Sxx * Syy;
    3846   [ +  +  -  + ]:           5 :         if (product == 0 || isinf(product))
    3847                 :           2 :                 sqrtproduct = sqrt(Sxx) * sqrt(Syy);
    3848                 :             :         else
    3849                 :           3 :                 sqrtproduct = sqrt(product);
    3850                 :           5 :         result = Sxy / sqrtproduct;
    3851                 :             : 
    3852                 :             :         /*
    3853                 :             :          * Despite all these precautions, this formula can yield results outside
    3854                 :             :          * [-1, 1] due to roundoff error.  Clamp it to the expected range.
    3855                 :             :          */
    3856         [ -  + ]:           5 :         if (result < -1)
    3857                 :           0 :                 result = -1;
    3858         [ +  + ]:           5 :         else if (result > 1)
    3859                 :           1 :                 result = 1;
    3860                 :             : 
    3861                 :           5 :         PG_RETURN_FLOAT8(result);
    3862                 :           9 : }
    3863                 :             : 
    3864                 :             : Datum
    3865                 :           3 : float8_regr_r2(PG_FUNCTION_ARGS)
    3866                 :             : {
    3867                 :           3 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3868                 :           3 :         float8     *transvalues;
    3869                 :           3 :         float8          N,
    3870                 :             :                                 Sxx,
    3871                 :             :                                 Syy,
    3872                 :             :                                 Sxy;
    3873                 :             : 
    3874                 :           3 :         transvalues = check_float8_array(transarray, "float8_regr_r2", 8);
    3875                 :           3 :         N = transvalues[0];
    3876                 :           3 :         Sxx = transvalues[2];
    3877                 :           3 :         Syy = transvalues[4];
    3878                 :           3 :         Sxy = transvalues[5];
    3879                 :             : 
    3880                 :             :         /* if N is 0 we should return NULL */
    3881         [ +  - ]:           3 :         if (N < 1.0)
    3882                 :           0 :                 PG_RETURN_NULL();
    3883                 :             : 
    3884                 :             :         /* Note that Sxx and Syy are guaranteed to be non-negative */
    3885                 :             : 
    3886                 :             :         /* per spec, return NULL for a vertical line */
    3887         [ +  + ]:           3 :         if (Sxx == 0)
    3888                 :           1 :                 PG_RETURN_NULL();
    3889                 :             : 
    3890                 :             :         /* per spec, return 1.0 for a horizontal line */
    3891         [ +  + ]:           2 :         if (Syy == 0)
    3892                 :           1 :                 PG_RETURN_FLOAT8(1.0);
    3893                 :             : 
    3894                 :           1 :         PG_RETURN_FLOAT8((Sxy * Sxy) / (Sxx * Syy));
    3895                 :           3 : }
    3896                 :             : 
    3897                 :             : Datum
    3898                 :           2 : float8_regr_slope(PG_FUNCTION_ARGS)
    3899                 :             : {
    3900                 :           2 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3901                 :           2 :         float8     *transvalues;
    3902                 :           2 :         float8          N,
    3903                 :             :                                 Sxx,
    3904                 :             :                                 Sxy;
    3905                 :             : 
    3906                 :           2 :         transvalues = check_float8_array(transarray, "float8_regr_slope", 8);
    3907                 :           2 :         N = transvalues[0];
    3908                 :           2 :         Sxx = transvalues[2];
    3909                 :           2 :         Sxy = transvalues[5];
    3910                 :             : 
    3911                 :             :         /* if N is 0 we should return NULL */
    3912         [ +  - ]:           2 :         if (N < 1.0)
    3913                 :           0 :                 PG_RETURN_NULL();
    3914                 :             : 
    3915                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3916                 :             : 
    3917                 :             :         /* per spec, return NULL for a vertical line */
    3918         [ +  + ]:           2 :         if (Sxx == 0)
    3919                 :           1 :                 PG_RETURN_NULL();
    3920                 :             : 
    3921                 :           1 :         PG_RETURN_FLOAT8(Sxy / Sxx);
    3922                 :           2 : }
    3923                 :             : 
    3924                 :             : Datum
    3925                 :           2 : float8_regr_intercept(PG_FUNCTION_ARGS)
    3926                 :             : {
    3927                 :           2 :         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
    3928                 :           2 :         float8     *transvalues;
    3929                 :           2 :         float8          N,
    3930                 :             :                                 Sx,
    3931                 :             :                                 Sxx,
    3932                 :             :                                 Sy,
    3933                 :             :                                 Sxy;
    3934                 :             : 
    3935                 :           2 :         transvalues = check_float8_array(transarray, "float8_regr_intercept", 8);
    3936                 :           2 :         N = transvalues[0];
    3937                 :           2 :         Sx = transvalues[1];
    3938                 :           2 :         Sxx = transvalues[2];
    3939                 :           2 :         Sy = transvalues[3];
    3940                 :           2 :         Sxy = transvalues[5];
    3941                 :             : 
    3942                 :             :         /* if N is 0 we should return NULL */
    3943         [ +  - ]:           2 :         if (N < 1.0)
    3944                 :           0 :                 PG_RETURN_NULL();
    3945                 :             : 
    3946                 :             :         /* Note that Sxx is guaranteed to be non-negative */
    3947                 :             : 
    3948                 :             :         /* per spec, return NULL for a vertical line */
    3949         [ +  + ]:           2 :         if (Sxx == 0)
    3950                 :           1 :                 PG_RETURN_NULL();
    3951                 :             : 
    3952                 :           1 :         PG_RETURN_FLOAT8((Sy - Sx * Sxy / Sxx) / N);
    3953                 :           2 : }
    3954                 :             : 
    3955                 :             : 
    3956                 :             : /*
    3957                 :             :  *              ====================================
    3958                 :             :  *              MIXED-PRECISION ARITHMETIC OPERATORS
    3959                 :             :  *              ====================================
    3960                 :             :  */
    3961                 :             : 
    3962                 :             : /*
    3963                 :             :  *              float48pl               - returns arg1 + arg2
    3964                 :             :  *              float48mi               - returns arg1 - arg2
    3965                 :             :  *              float48mul              - returns arg1 * arg2
    3966                 :             :  *              float48div              - returns arg1 / arg2
    3967                 :             :  */
    3968                 :             : Datum
    3969                 :           4 : float48pl(PG_FUNCTION_ARGS)
    3970                 :             : {
    3971                 :           4 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    3972                 :           4 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    3973                 :             : 
    3974                 :           8 :         PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
    3975                 :           4 : }
    3976                 :             : 
    3977                 :             : Datum
    3978                 :           1 : float48mi(PG_FUNCTION_ARGS)
    3979                 :             : {
    3980                 :           1 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    3981                 :           1 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    3982                 :             : 
    3983                 :           2 :         PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
    3984                 :           1 : }
    3985                 :             : 
    3986                 :             : Datum
    3987                 :           0 : float48mul(PG_FUNCTION_ARGS)
    3988                 :             : {
    3989                 :           0 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    3990                 :           0 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    3991                 :             : 
    3992                 :           0 :         PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
    3993                 :           0 : }
    3994                 :             : 
    3995                 :             : Datum
    3996                 :           1 : float48div(PG_FUNCTION_ARGS)
    3997                 :             : {
    3998                 :           1 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    3999                 :           1 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4000                 :             : 
    4001                 :           2 :         PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
    4002                 :           1 : }
    4003                 :             : 
    4004                 :             : /*
    4005                 :             :  *              float84pl               - returns arg1 + arg2
    4006                 :             :  *              float84mi               - returns arg1 - arg2
    4007                 :             :  *              float84mul              - returns arg1 * arg2
    4008                 :             :  *              float84div              - returns arg1 / arg2
    4009                 :             :  */
    4010                 :             : Datum
    4011                 :           2 : float84pl(PG_FUNCTION_ARGS)
    4012                 :             : {
    4013                 :           2 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4014                 :           2 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4015                 :             : 
    4016                 :           4 :         PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
    4017                 :           2 : }
    4018                 :             : 
    4019                 :             : Datum
    4020                 :           0 : float84mi(PG_FUNCTION_ARGS)
    4021                 :             : {
    4022                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4023                 :           0 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4024                 :             : 
    4025                 :           0 :         PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
    4026                 :           0 : }
    4027                 :             : 
    4028                 :             : Datum
    4029                 :           0 : float84mul(PG_FUNCTION_ARGS)
    4030                 :             : {
    4031                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4032                 :           0 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4033                 :             : 
    4034                 :           0 :         PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
    4035                 :           0 : }
    4036                 :             : 
    4037                 :             : Datum
    4038                 :           1 : float84div(PG_FUNCTION_ARGS)
    4039                 :             : {
    4040                 :           1 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4041                 :           1 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4042                 :             : 
    4043                 :           2 :         PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
    4044                 :           1 : }
    4045                 :             : 
    4046                 :             : /*
    4047                 :             :  *              ====================
    4048                 :             :  *              COMPARISON OPERATORS
    4049                 :             :  *              ====================
    4050                 :             :  */
    4051                 :             : 
    4052                 :             : /*
    4053                 :             :  *              float48{eq,ne,lt,le,gt,ge}              - float4/float8 comparison operations
    4054                 :             :  */
    4055                 :             : Datum
    4056                 :         314 : float48eq(PG_FUNCTION_ARGS)
    4057                 :             : {
    4058                 :         314 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    4059                 :         314 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4060                 :             : 
    4061                 :         628 :         PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
    4062                 :         314 : }
    4063                 :             : 
    4064                 :             : Datum
    4065                 :        3378 : float48ne(PG_FUNCTION_ARGS)
    4066                 :             : {
    4067                 :        3378 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    4068                 :        3378 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4069                 :             : 
    4070                 :        6756 :         PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
    4071                 :        3378 : }
    4072                 :             : 
    4073                 :             : Datum
    4074                 :         529 : float48lt(PG_FUNCTION_ARGS)
    4075                 :             : {
    4076                 :         529 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    4077                 :         529 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4078                 :             : 
    4079                 :        1058 :         PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
    4080                 :         529 : }
    4081                 :             : 
    4082                 :             : Datum
    4083                 :        4247 : float48le(PG_FUNCTION_ARGS)
    4084                 :             : {
    4085                 :        4247 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    4086                 :        4247 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4087                 :             : 
    4088                 :        8494 :         PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
    4089                 :        4247 : }
    4090                 :             : 
    4091                 :             : Datum
    4092                 :         565 : float48gt(PG_FUNCTION_ARGS)
    4093                 :             : {
    4094                 :         565 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    4095                 :         565 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4096                 :             : 
    4097                 :        1130 :         PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
    4098                 :         565 : }
    4099                 :             : 
    4100                 :             : Datum
    4101                 :         633 : float48ge(PG_FUNCTION_ARGS)
    4102                 :             : {
    4103                 :         633 :         float4          arg1 = PG_GETARG_FLOAT4(0);
    4104                 :         633 :         float8          arg2 = PG_GETARG_FLOAT8(1);
    4105                 :             : 
    4106                 :        1266 :         PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
    4107                 :         633 : }
    4108                 :             : 
    4109                 :             : /*
    4110                 :             :  *              float84{eq,ne,lt,le,gt,ge}              - float8/float4 comparison operations
    4111                 :             :  */
    4112                 :             : Datum
    4113                 :         302 : float84eq(PG_FUNCTION_ARGS)
    4114                 :             : {
    4115                 :         302 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4116                 :         302 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4117                 :             : 
    4118                 :         604 :         PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
    4119                 :         302 : }
    4120                 :             : 
    4121                 :             : Datum
    4122                 :           0 : float84ne(PG_FUNCTION_ARGS)
    4123                 :             : {
    4124                 :           0 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4125                 :           0 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4126                 :             : 
    4127                 :           0 :         PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
    4128                 :           0 : }
    4129                 :             : 
    4130                 :             : Datum
    4131                 :         533 : float84lt(PG_FUNCTION_ARGS)
    4132                 :             : {
    4133                 :         533 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4134                 :         533 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4135                 :             : 
    4136                 :        1066 :         PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
    4137                 :         533 : }
    4138                 :             : 
    4139                 :             : Datum
    4140                 :         633 : float84le(PG_FUNCTION_ARGS)
    4141                 :             : {
    4142                 :         633 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4143                 :         633 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4144                 :             : 
    4145                 :        1266 :         PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
    4146                 :         633 : }
    4147                 :             : 
    4148                 :             : Datum
    4149                 :         533 : float84gt(PG_FUNCTION_ARGS)
    4150                 :             : {
    4151                 :         533 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4152                 :         533 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4153                 :             : 
    4154                 :        1066 :         PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
    4155                 :         533 : }
    4156                 :             : 
    4157                 :             : Datum
    4158                 :         534 : float84ge(PG_FUNCTION_ARGS)
    4159                 :             : {
    4160                 :         534 :         float8          arg1 = PG_GETARG_FLOAT8(0);
    4161                 :         534 :         float4          arg2 = PG_GETARG_FLOAT4(1);
    4162                 :             : 
    4163                 :        1068 :         PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
    4164                 :         534 : }
    4165                 :             : 
    4166                 :             : /*
    4167                 :             :  * Implements the float8 version of the width_bucket() function
    4168                 :             :  * defined by SQL2003. See also width_bucket_numeric().
    4169                 :             :  *
    4170                 :             :  * 'bound1' and 'bound2' are the lower and upper bounds of the
    4171                 :             :  * histogram's range, respectively. 'count' is the number of buckets
    4172                 :             :  * in the histogram. width_bucket() returns an integer indicating the
    4173                 :             :  * bucket number that 'operand' belongs to in an equiwidth histogram
    4174                 :             :  * with the specified characteristics. An operand smaller than the
    4175                 :             :  * lower bound is assigned to bucket 0. An operand greater than or equal
    4176                 :             :  * to the upper bound is assigned to an additional bucket (with number
    4177                 :             :  * count+1). We don't allow the histogram bounds to be NaN or +/- infinity,
    4178                 :             :  * but we do allow those values for the operand (taking NaN to be larger
    4179                 :             :  * than any other value, as we do in comparisons).
    4180                 :             :  */
    4181                 :             : Datum
    4182                 :         147 : width_bucket_float8(PG_FUNCTION_ARGS)
    4183                 :             : {
    4184                 :         147 :         float8          operand = PG_GETARG_FLOAT8(0);
    4185                 :         147 :         float8          bound1 = PG_GETARG_FLOAT8(1);
    4186                 :         147 :         float8          bound2 = PG_GETARG_FLOAT8(2);
    4187                 :         147 :         int32           count = PG_GETARG_INT32(3);
    4188                 :         147 :         int32           result;
    4189                 :             : 
    4190         [ +  + ]:         147 :         if (count <= 0)
    4191   [ +  -  +  - ]:           2 :                 ereport(ERROR,
    4192                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
    4193                 :             :                                  errmsg("count must be greater than zero")));
    4194                 :             : 
    4195   [ +  +  +  +  :         145 :         if (isnan(bound1) || isnan(bound2))
          +  -  -  +  +  
                      - ]
    4196   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    4197                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
    4198                 :             :                                  errmsg("lower and upper bounds cannot be NaN")));
    4199                 :             : 
    4200         [ +  + ]:         142 :         if (isinf(bound1) || isinf(bound2))
    4201   [ +  -  +  - ]:           3 :                 ereport(ERROR,
    4202                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
    4203                 :             :                                  errmsg("lower and upper bounds must be finite")));
    4204                 :             : 
    4205         [ +  + ]:         139 :         if (bound1 < bound2)
    4206                 :             :         {
    4207   [ -  +  +  +  :         100 :                 if (isnan(operand) || operand >= bound2)
                   +  - ]
    4208                 :             :                 {
    4209         [ +  + ]:         179 :                         if (pg_add_s32_overflow(count, 1, &result))
    4210   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    4211                 :             :                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    4212                 :             :                                                  errmsg("integer out of range")));
    4213                 :         178 :                 }
    4214         [ +  + ]:          79 :                 else if (operand < bound1)
    4215                 :          19 :                         result = 0;
    4216                 :             :                 else
    4217                 :             :                 {
    4218         [ +  + ]:          60 :                         if (!isinf(bound2 - bound1))
    4219                 :             :                         {
    4220                 :             :                                 /* The quotient is surely in [0,1], so this can't overflow */
    4221                 :          57 :                                 result = count * ((operand - bound1) / (bound2 - bound1));
    4222                 :          57 :                         }
    4223                 :             :                         else
    4224                 :             :                         {
    4225                 :             :                                 /*
    4226                 :             :                                  * We get here if bound2 - bound1 overflows DBL_MAX.  Since
    4227                 :             :                                  * both bounds are finite, their difference can't exceed twice
    4228                 :             :                                  * DBL_MAX; so we can perform the computation without overflow
    4229                 :             :                                  * by dividing all the inputs by 2.  That should be exact too,
    4230                 :             :                                  * except in the case where a very small operand underflows to
    4231                 :             :                                  * zero, which would have negligible impact on the result
    4232                 :             :                                  * given such large bounds.
    4233                 :             :                                  */
    4234                 :           3 :                                 result = count * ((operand / 2 - bound1 / 2) / (bound2 / 2 - bound1 / 2));
    4235                 :             :                         }
    4236                 :             :                         /* The quotient could round to 1.0, which would be a lie */
    4237         [ +  + ]:          60 :                         if (result >= count)
    4238                 :           1 :                                 result = count - 1;
    4239                 :             :                         /* Having done that, we can add 1 without fear of overflow */
    4240                 :          60 :                         result++;
    4241                 :             :                 }
    4242                 :         257 :         }
    4243         [ +  + ]:          39 :         else if (bound1 > bound2)
    4244                 :             :         {
    4245   [ -  +  +  +  :          38 :                 if (isnan(operand) || operand > bound1)
                   +  - ]
    4246                 :          74 :                         result = 0;
    4247         [ +  + ]:          36 :                 else if (operand <= bound2)
    4248                 :             :                 {
    4249         [ +  + ]:           5 :                         if (pg_add_s32_overflow(count, 1, &result))
    4250   [ +  -  +  - ]:           1 :                                 ereport(ERROR,
    4251                 :             :                                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
    4252                 :             :                                                  errmsg("integer out of range")));
    4253                 :           4 :                 }
    4254                 :             :                 else
    4255                 :             :                 {
    4256         [ +  + ]:          31 :                         if (!isinf(bound1 - bound2))
    4257                 :          28 :                                 result = count * ((bound1 - operand) / (bound1 - bound2));
    4258                 :             :                         else
    4259                 :           3 :                                 result = count * ((bound1 / 2 - operand / 2) / (bound1 / 2 - bound2 / 2));
    4260         [ +  + ]:          31 :                         if (result >= count)
    4261                 :           1 :                                 result = count - 1;
    4262                 :          31 :                         result++;
    4263                 :             :                 }
    4264                 :         109 :         }
    4265                 :             :         else
    4266                 :             :         {
    4267   [ +  -  +  - ]:           1 :                 ereport(ERROR,
    4268                 :             :                                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
    4269                 :             :                                  errmsg("lower bound cannot equal upper bound")));
    4270                 :           0 :                 result = 0;                             /* keep the compiler quiet */
    4271                 :             :         }
    4272                 :             : 
    4273                 :         732 :         PG_RETURN_INT32(result);
    4274                 :         366 : }
        

Generated by: LCOV version 2.3.2-1