LCOV - code coverage report
Current view: top level - src/backend/utils/adt - float.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 1099 1361 80.7 %
Date: 2023-12-05 08:11:01 Functions: 141 159 88.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14