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

Generated by: LCOV version 2.0-1