LCOV - code coverage report
Current view: top level - src/backend/utils/adt - float.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 83.3 % 1433 1193
Test Date: 2026-07-22 12:15:41 Functions: 91.2 % 160 146
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 64.0 % 904 579

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

Generated by: LCOV version 2.0-1