LCOV - code coverage report
Current view: top level - src/backend/utils/adt - float.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1085 1335 81.3 %
Date: 2024-11-21 08:14:44 Functions: 139 155 89.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14