Header And Logo

PostgreSQL
| The world's most advanced open source database.

float.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * float.c
00004  *    Functions for the built-in floating-point types.
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/float.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include <ctype.h>
00018 #include <float.h>
00019 #include <math.h>
00020 #include <limits.h>
00021 
00022 #include "catalog/pg_type.h"
00023 #include "libpq/pqformat.h"
00024 #include "utils/array.h"
00025 #include "utils/builtins.h"
00026 #include "utils/sortsupport.h"
00027 
00028 
00029 #ifndef M_PI
00030 /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
00031 #define M_PI 3.14159265358979323846
00032 #endif
00033 
00034 /* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
00035  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
00036  */
00037 #if defined(WIN32) && !defined(NAN)
00038 static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
00039 
00040 #define NAN (*(const double *) nan)
00041 #endif
00042 
00043 /* not sure what the following should be, but better to make it over-sufficient */
00044 #define MAXFLOATWIDTH   64
00045 #define MAXDOUBLEWIDTH  128
00046 
00047 /*
00048  * check to see if a float4/8 val has underflowed or overflowed
00049  */
00050 #define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)         \
00051 do {                                                            \
00052     if (isinf(val) && !(inf_is_valid))                          \
00053         ereport(ERROR,                                          \
00054                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),   \
00055           errmsg("value out of range: overflow")));             \
00056                                                                 \
00057     if ((val) == 0.0 && !(zero_is_valid))                       \
00058         ereport(ERROR,                                          \
00059                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),   \
00060          errmsg("value out of range: underflow")));             \
00061 } while(0)
00062 
00063 
00064 /* ========== USER I/O ROUTINES ========== */
00065 
00066 
00067 /* Configurable GUC parameter */
00068 int         extra_float_digits = 0;     /* Added to DBL_DIG or FLT_DIG */
00069 
00070 
00071 static int  float4_cmp_internal(float4 a, float4 b);
00072 static int  float8_cmp_internal(float8 a, float8 b);
00073 
00074 #ifndef HAVE_CBRT
00075 /*
00076  * Some machines (in particular, some versions of AIX) have an extern
00077  * declaration for cbrt() in <math.h> but fail to provide the actual
00078  * function, which causes configure to not set HAVE_CBRT.  Furthermore,
00079  * their compilers spit up at the mismatch between extern declaration
00080  * and static definition.  We work around that here by the expedient
00081  * of a #define to make the actual name of the static function different.
00082  */
00083 #define cbrt my_cbrt
00084 static double cbrt(double x);
00085 #endif   /* HAVE_CBRT */
00086 
00087 
00088 /*
00089  * Routines to provide reasonably platform-independent handling of
00090  * infinity and NaN.  We assume that isinf() and isnan() are available
00091  * and work per spec.  (On some platforms, we have to supply our own;
00092  * see src/port.)  However, generating an Infinity or NaN in the first
00093  * place is less well standardized; pre-C99 systems tend not to have C99's
00094  * INFINITY and NAN macros.  We centralize our workarounds for this here.
00095  */
00096 
00097 double
00098 get_float8_infinity(void)
00099 {
00100 #ifdef INFINITY
00101     /* C99 standard way */
00102     return (double) INFINITY;
00103 #else
00104 
00105     /*
00106      * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
00107      * largest normal double.  We assume forcing an overflow will get us a
00108      * true infinity.
00109      */
00110     return (double) (HUGE_VAL * HUGE_VAL);
00111 #endif
00112 }
00113 
00114 float
00115 get_float4_infinity(void)
00116 {
00117 #ifdef INFINITY
00118     /* C99 standard way */
00119     return (float) INFINITY;
00120 #else
00121 
00122     /*
00123      * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
00124      * largest normal double.  We assume forcing an overflow will get us a
00125      * true infinity.
00126      */
00127     return (float) (HUGE_VAL * HUGE_VAL);
00128 #endif
00129 }
00130 
00131 double
00132 get_float8_nan(void)
00133 {
00134     /* (double) NAN doesn't work on some NetBSD/MIPS releases */
00135 #if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
00136     /* C99 standard way */
00137     return (double) NAN;
00138 #else
00139     /* Assume we can get a NAN via zero divide */
00140     return (double) (0.0 / 0.0);
00141 #endif
00142 }
00143 
00144 float
00145 get_float4_nan(void)
00146 {
00147 #ifdef NAN
00148     /* C99 standard way */
00149     return (float) NAN;
00150 #else
00151     /* Assume we can get a NAN via zero divide */
00152     return (float) (0.0 / 0.0);
00153 #endif
00154 }
00155 
00156 
00157 /*
00158  * Returns -1 if 'val' represents negative infinity, 1 if 'val'
00159  * represents (positive) infinity, and 0 otherwise. On some platforms,
00160  * this is equivalent to the isinf() macro, but not everywhere: C99
00161  * does not specify that isinf() needs to distinguish between positive
00162  * and negative infinity.
00163  */
00164 int
00165 is_infinite(double val)
00166 {
00167     int         inf = isinf(val);
00168 
00169     if (inf == 0)
00170         return 0;
00171     else if (val > 0)
00172         return 1;
00173     else
00174         return -1;
00175 }
00176 
00177 
00178 /*
00179  *      float4in        - converts "num" to float
00180  *                        restricted syntax:
00181  *                        {<sp>} [+|-] {digit} [.{digit}] [<exp>]
00182  *                        where <sp> is a space, digit is 0-9,
00183  *                        <exp> is "e" or "E" followed by an integer.
00184  */
00185 Datum
00186 float4in(PG_FUNCTION_ARGS)
00187 {
00188     char       *num = PG_GETARG_CSTRING(0);
00189     char       *orig_num;
00190     double      val;
00191     char       *endptr;
00192 
00193     /*
00194      * endptr points to the first character _after_ the sequence we recognized
00195      * as a valid floating point number. orig_num points to the original input
00196      * string.
00197      */
00198     orig_num = num;
00199 
00200     /*
00201      * Check for an empty-string input to begin with, to avoid the vagaries of
00202      * strtod() on different platforms.
00203      */
00204     if (*num == '\0')
00205         ereport(ERROR,
00206                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00207                  errmsg("invalid input syntax for type real: \"%s\"",
00208                         orig_num)));
00209 
00210     /* skip leading whitespace */
00211     while (*num != '\0' && isspace((unsigned char) *num))
00212         num++;
00213 
00214     errno = 0;
00215     val = strtod(num, &endptr);
00216 
00217     /* did we not see anything that looks like a double? */
00218     if (endptr == num || errno != 0)
00219     {
00220         int         save_errno = errno;
00221 
00222         /*
00223          * C99 requires that strtod() accept NaN and [-]Infinity, but not all
00224          * platforms support that yet (and some accept them but set ERANGE
00225          * anyway...)  Therefore, we check for these inputs ourselves.
00226          */
00227         if (pg_strncasecmp(num, "NaN", 3) == 0)
00228         {
00229             val = get_float4_nan();
00230             endptr = num + 3;
00231         }
00232         else if (pg_strncasecmp(num, "Infinity", 8) == 0)
00233         {
00234             val = get_float4_infinity();
00235             endptr = num + 8;
00236         }
00237         else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
00238         {
00239             val = -get_float4_infinity();
00240             endptr = num + 9;
00241         }
00242         else if (save_errno == ERANGE)
00243         {
00244             /*
00245              * Some platforms return ERANGE for denormalized numbers (those
00246              * that are not zero, but are too close to zero to have full
00247              * precision).  We'd prefer not to throw error for that, so try to
00248              * detect whether it's a "real" out-of-range condition by checking
00249              * to see if the result is zero or huge.
00250              */
00251             if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
00252                 ereport(ERROR,
00253                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00254                          errmsg("\"%s\" is out of range for type real",
00255                                 orig_num)));
00256         }
00257         else
00258             ereport(ERROR,
00259                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00260                      errmsg("invalid input syntax for type real: \"%s\"",
00261                             orig_num)));
00262     }
00263 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
00264     else
00265     {
00266         /*
00267          * Many versions of Solaris have a bug wherein strtod sets endptr to
00268          * point one byte beyond the end of the string when given "inf" or
00269          * "infinity".
00270          */
00271         if (endptr != num && endptr[-1] == '\0')
00272             endptr--;
00273     }
00274 #endif   /* HAVE_BUGGY_SOLARIS_STRTOD */
00275 
00276 #ifdef HAVE_BUGGY_IRIX_STRTOD
00277 
00278     /*
00279      * In some IRIX versions, strtod() recognizes only "inf", so if the input
00280      * is "infinity" we have to skip over "inity".  Also, it may return
00281      * positive infinity for "-inf".
00282      */
00283     if (isinf(val))
00284     {
00285         if (pg_strncasecmp(num, "Infinity", 8) == 0)
00286         {
00287             val = get_float4_infinity();
00288             endptr = num + 8;
00289         }
00290         else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
00291         {
00292             val = -get_float4_infinity();
00293             endptr = num + 9;
00294         }
00295         else if (pg_strncasecmp(num, "-inf", 4) == 0)
00296         {
00297             val = -get_float4_infinity();
00298             endptr = num + 4;
00299         }
00300     }
00301 #endif   /* HAVE_BUGGY_IRIX_STRTOD */
00302 
00303     /* skip trailing whitespace */
00304     while (*endptr != '\0' && isspace((unsigned char) *endptr))
00305         endptr++;
00306 
00307     /* if there is any junk left at the end of the string, bail out */
00308     if (*endptr != '\0')
00309         ereport(ERROR,
00310                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00311                  errmsg("invalid input syntax for type real: \"%s\"",
00312                         orig_num)));
00313 
00314     /*
00315      * if we get here, we have a legal double, still need to check to see if
00316      * it's a legal float4
00317      */
00318     CHECKFLOATVAL((float4) val, isinf(val), val == 0);
00319 
00320     PG_RETURN_FLOAT4((float4) val);
00321 }
00322 
00323 /*
00324  *      float4out       - converts a float4 number to a string
00325  *                        using a standard output format
00326  */
00327 Datum
00328 float4out(PG_FUNCTION_ARGS)
00329 {
00330     float4      num = PG_GETARG_FLOAT4(0);
00331     char       *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
00332 
00333     if (isnan(num))
00334         PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
00335 
00336     switch (is_infinite(num))
00337     {
00338         case 1:
00339             strcpy(ascii, "Infinity");
00340             break;
00341         case -1:
00342             strcpy(ascii, "-Infinity");
00343             break;
00344         default:
00345             {
00346                 int         ndig = FLT_DIG + extra_float_digits;
00347 
00348                 if (ndig < 1)
00349                     ndig = 1;
00350 
00351                 snprintf(ascii, MAXFLOATWIDTH + 1, "%.*g", ndig, num);
00352             }
00353     }
00354 
00355     PG_RETURN_CSTRING(ascii);
00356 }
00357 
00358 /*
00359  *      float4recv          - converts external binary format to float4
00360  */
00361 Datum
00362 float4recv(PG_FUNCTION_ARGS)
00363 {
00364     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00365 
00366     PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));
00367 }
00368 
00369 /*
00370  *      float4send          - converts float4 to binary format
00371  */
00372 Datum
00373 float4send(PG_FUNCTION_ARGS)
00374 {
00375     float4      num = PG_GETARG_FLOAT4(0);
00376     StringInfoData buf;
00377 
00378     pq_begintypsend(&buf);
00379     pq_sendfloat4(&buf, num);
00380     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00381 }
00382 
00383 /*
00384  *      float8in        - converts "num" to float8
00385  *                        restricted syntax:
00386  *                        {<sp>} [+|-] {digit} [.{digit}] [<exp>]
00387  *                        where <sp> is a space, digit is 0-9,
00388  *                        <exp> is "e" or "E" followed by an integer.
00389  */
00390 Datum
00391 float8in(PG_FUNCTION_ARGS)
00392 {
00393     char       *num = PG_GETARG_CSTRING(0);
00394     char       *orig_num;
00395     double      val;
00396     char       *endptr;
00397 
00398     /*
00399      * endptr points to the first character _after_ the sequence we recognized
00400      * as a valid floating point number. orig_num points to the original input
00401      * string.
00402      */
00403     orig_num = num;
00404 
00405     /*
00406      * Check for an empty-string input to begin with, to avoid the vagaries of
00407      * strtod() on different platforms.
00408      */
00409     if (*num == '\0')
00410         ereport(ERROR,
00411                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00412              errmsg("invalid input syntax for type double precision: \"%s\"",
00413                     orig_num)));
00414 
00415     /* skip leading whitespace */
00416     while (*num != '\0' && isspace((unsigned char) *num))
00417         num++;
00418 
00419     errno = 0;
00420     val = strtod(num, &endptr);
00421 
00422     /* did we not see anything that looks like a double? */
00423     if (endptr == num || errno != 0)
00424     {
00425         int         save_errno = errno;
00426 
00427         /*
00428          * C99 requires that strtod() accept NaN and [-]Infinity, but not all
00429          * platforms support that yet (and some accept them but set ERANGE
00430          * anyway...)  Therefore, we check for these inputs ourselves.
00431          */
00432         if (pg_strncasecmp(num, "NaN", 3) == 0)
00433         {
00434             val = get_float8_nan();
00435             endptr = num + 3;
00436         }
00437         else if (pg_strncasecmp(num, "Infinity", 8) == 0)
00438         {
00439             val = get_float8_infinity();
00440             endptr = num + 8;
00441         }
00442         else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
00443         {
00444             val = -get_float8_infinity();
00445             endptr = num + 9;
00446         }
00447         else if (save_errno == ERANGE)
00448         {
00449             /*
00450              * Some platforms return ERANGE for denormalized numbers (those
00451              * that are not zero, but are too close to zero to have full
00452              * precision).  We'd prefer not to throw error for that, so try to
00453              * detect whether it's a "real" out-of-range condition by checking
00454              * to see if the result is zero or huge.
00455              */
00456             if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
00457                 ereport(ERROR,
00458                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
00459                    errmsg("\"%s\" is out of range for type double precision",
00460                           orig_num)));
00461         }
00462         else
00463             ereport(ERROR,
00464                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00465              errmsg("invalid input syntax for type double precision: \"%s\"",
00466                     orig_num)));
00467     }
00468 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
00469     else
00470     {
00471         /*
00472          * Many versions of Solaris have a bug wherein strtod sets endptr to
00473          * point one byte beyond the end of the string when given "inf" or
00474          * "infinity".
00475          */
00476         if (endptr != num && endptr[-1] == '\0')
00477             endptr--;
00478     }
00479 #endif   /* HAVE_BUGGY_SOLARIS_STRTOD */
00480 
00481 #ifdef HAVE_BUGGY_IRIX_STRTOD
00482 
00483     /*
00484      * In some IRIX versions, strtod() recognizes only "inf", so if the input
00485      * is "infinity" we have to skip over "inity".  Also, it may return
00486      * positive infinity for "-inf".
00487      */
00488     if (isinf(val))
00489     {
00490         if (pg_strncasecmp(num, "Infinity", 8) == 0)
00491         {
00492             val = get_float8_infinity();
00493             endptr = num + 8;
00494         }
00495         else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
00496         {
00497             val = -get_float8_infinity();
00498             endptr = num + 9;
00499         }
00500         else if (pg_strncasecmp(num, "-inf", 4) == 0)
00501         {
00502             val = -get_float8_infinity();
00503             endptr = num + 4;
00504         }
00505     }
00506 #endif   /* HAVE_BUGGY_IRIX_STRTOD */
00507 
00508     /* skip trailing whitespace */
00509     while (*endptr != '\0' && isspace((unsigned char) *endptr))
00510         endptr++;
00511 
00512     /* if there is any junk left at the end of the string, bail out */
00513     if (*endptr != '\0')
00514         ereport(ERROR,
00515                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00516              errmsg("invalid input syntax for type double precision: \"%s\"",
00517                     orig_num)));
00518 
00519     CHECKFLOATVAL(val, true, true);
00520 
00521     PG_RETURN_FLOAT8(val);
00522 }
00523 
00524 /*
00525  *      float8out       - converts float8 number to a string
00526  *                        using a standard output format
00527  */
00528 Datum
00529 float8out(PG_FUNCTION_ARGS)
00530 {
00531     float8      num = PG_GETARG_FLOAT8(0);
00532     char       *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
00533 
00534     if (isnan(num))
00535         PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
00536 
00537     switch (is_infinite(num))
00538     {
00539         case 1:
00540             strcpy(ascii, "Infinity");
00541             break;
00542         case -1:
00543             strcpy(ascii, "-Infinity");
00544             break;
00545         default:
00546             {
00547                 int         ndig = DBL_DIG + extra_float_digits;
00548 
00549                 if (ndig < 1)
00550                     ndig = 1;
00551 
00552                 snprintf(ascii, MAXDOUBLEWIDTH + 1, "%.*g", ndig, num);
00553             }
00554     }
00555 
00556     PG_RETURN_CSTRING(ascii);
00557 }
00558 
00559 /*
00560  *      float8recv          - converts external binary format to float8
00561  */
00562 Datum
00563 float8recv(PG_FUNCTION_ARGS)
00564 {
00565     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00566 
00567     PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));
00568 }
00569 
00570 /*
00571  *      float8send          - converts float8 to binary format
00572  */
00573 Datum
00574 float8send(PG_FUNCTION_ARGS)
00575 {
00576     float8      num = PG_GETARG_FLOAT8(0);
00577     StringInfoData buf;
00578 
00579     pq_begintypsend(&buf);
00580     pq_sendfloat8(&buf, num);
00581     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00582 }
00583 
00584 
00585 /* ========== PUBLIC ROUTINES ========== */
00586 
00587 
00588 /*
00589  *      ======================
00590  *      FLOAT4 BASE OPERATIONS
00591  *      ======================
00592  */
00593 
00594 /*
00595  *      float4abs       - returns |arg1| (absolute value)
00596  */
00597 Datum
00598 float4abs(PG_FUNCTION_ARGS)
00599 {
00600     float4      arg1 = PG_GETARG_FLOAT4(0);
00601 
00602     PG_RETURN_FLOAT4((float4) fabs(arg1));
00603 }
00604 
00605 /*
00606  *      float4um        - returns -arg1 (unary minus)
00607  */
00608 Datum
00609 float4um(PG_FUNCTION_ARGS)
00610 {
00611     float4      arg1 = PG_GETARG_FLOAT4(0);
00612     float4      result;
00613 
00614     result = -arg1;
00615     PG_RETURN_FLOAT4(result);
00616 }
00617 
00618 Datum
00619 float4up(PG_FUNCTION_ARGS)
00620 {
00621     float4      arg = PG_GETARG_FLOAT4(0);
00622 
00623     PG_RETURN_FLOAT4(arg);
00624 }
00625 
00626 Datum
00627 float4larger(PG_FUNCTION_ARGS)
00628 {
00629     float4      arg1 = PG_GETARG_FLOAT4(0);
00630     float4      arg2 = PG_GETARG_FLOAT4(1);
00631     float4      result;
00632 
00633     if (float4_cmp_internal(arg1, arg2) > 0)
00634         result = arg1;
00635     else
00636         result = arg2;
00637     PG_RETURN_FLOAT4(result);
00638 }
00639 
00640 Datum
00641 float4smaller(PG_FUNCTION_ARGS)
00642 {
00643     float4      arg1 = PG_GETARG_FLOAT4(0);
00644     float4      arg2 = PG_GETARG_FLOAT4(1);
00645     float4      result;
00646 
00647     if (float4_cmp_internal(arg1, arg2) < 0)
00648         result = arg1;
00649     else
00650         result = arg2;
00651     PG_RETURN_FLOAT4(result);
00652 }
00653 
00654 /*
00655  *      ======================
00656  *      FLOAT8 BASE OPERATIONS
00657  *      ======================
00658  */
00659 
00660 /*
00661  *      float8abs       - returns |arg1| (absolute value)
00662  */
00663 Datum
00664 float8abs(PG_FUNCTION_ARGS)
00665 {
00666     float8      arg1 = PG_GETARG_FLOAT8(0);
00667 
00668     PG_RETURN_FLOAT8(fabs(arg1));
00669 }
00670 
00671 
00672 /*
00673  *      float8um        - returns -arg1 (unary minus)
00674  */
00675 Datum
00676 float8um(PG_FUNCTION_ARGS)
00677 {
00678     float8      arg1 = PG_GETARG_FLOAT8(0);
00679     float8      result;
00680 
00681     result = -arg1;
00682     PG_RETURN_FLOAT8(result);
00683 }
00684 
00685 Datum
00686 float8up(PG_FUNCTION_ARGS)
00687 {
00688     float8      arg = PG_GETARG_FLOAT8(0);
00689 
00690     PG_RETURN_FLOAT8(arg);
00691 }
00692 
00693 Datum
00694 float8larger(PG_FUNCTION_ARGS)
00695 {
00696     float8      arg1 = PG_GETARG_FLOAT8(0);
00697     float8      arg2 = PG_GETARG_FLOAT8(1);
00698     float8      result;
00699 
00700     if (float8_cmp_internal(arg1, arg2) > 0)
00701         result = arg1;
00702     else
00703         result = arg2;
00704     PG_RETURN_FLOAT8(result);
00705 }
00706 
00707 Datum
00708 float8smaller(PG_FUNCTION_ARGS)
00709 {
00710     float8      arg1 = PG_GETARG_FLOAT8(0);
00711     float8      arg2 = PG_GETARG_FLOAT8(1);
00712     float8      result;
00713 
00714     if (float8_cmp_internal(arg1, arg2) < 0)
00715         result = arg1;
00716     else
00717         result = arg2;
00718     PG_RETURN_FLOAT8(result);
00719 }
00720 
00721 
00722 /*
00723  *      ====================
00724  *      ARITHMETIC OPERATORS
00725  *      ====================
00726  */
00727 
00728 /*
00729  *      float4pl        - returns arg1 + arg2
00730  *      float4mi        - returns arg1 - arg2
00731  *      float4mul       - returns arg1 * arg2
00732  *      float4div       - returns arg1 / arg2
00733  */
00734 Datum
00735 float4pl(PG_FUNCTION_ARGS)
00736 {
00737     float4      arg1 = PG_GETARG_FLOAT4(0);
00738     float4      arg2 = PG_GETARG_FLOAT4(1);
00739     float4      result;
00740 
00741     result = arg1 + arg2;
00742 
00743     /*
00744      * There isn't any way to check for underflow of addition/subtraction
00745      * because numbers near the underflow value have already been rounded to
00746      * the point where we can't detect that the two values were originally
00747      * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
00748      * 1.4013e-45.
00749      */
00750     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
00751     PG_RETURN_FLOAT4(result);
00752 }
00753 
00754 Datum
00755 float4mi(PG_FUNCTION_ARGS)
00756 {
00757     float4      arg1 = PG_GETARG_FLOAT4(0);
00758     float4      arg2 = PG_GETARG_FLOAT4(1);
00759     float4      result;
00760 
00761     result = arg1 - arg2;
00762     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
00763     PG_RETURN_FLOAT4(result);
00764 }
00765 
00766 Datum
00767 float4mul(PG_FUNCTION_ARGS)
00768 {
00769     float4      arg1 = PG_GETARG_FLOAT4(0);
00770     float4      arg2 = PG_GETARG_FLOAT4(1);
00771     float4      result;
00772 
00773     result = arg1 * arg2;
00774     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
00775                   arg1 == 0 || arg2 == 0);
00776     PG_RETURN_FLOAT4(result);
00777 }
00778 
00779 Datum
00780 float4div(PG_FUNCTION_ARGS)
00781 {
00782     float4      arg1 = PG_GETARG_FLOAT4(0);
00783     float4      arg2 = PG_GETARG_FLOAT4(1);
00784     float4      result;
00785 
00786     if (arg2 == 0.0)
00787         ereport(ERROR,
00788                 (errcode(ERRCODE_DIVISION_BY_ZERO),
00789                  errmsg("division by zero")));
00790 
00791     result = arg1 / arg2;
00792 
00793     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
00794     PG_RETURN_FLOAT4(result);
00795 }
00796 
00797 /*
00798  *      float8pl        - returns arg1 + arg2
00799  *      float8mi        - returns arg1 - arg2
00800  *      float8mul       - returns arg1 * arg2
00801  *      float8div       - returns arg1 / arg2
00802  */
00803 Datum
00804 float8pl(PG_FUNCTION_ARGS)
00805 {
00806     float8      arg1 = PG_GETARG_FLOAT8(0);
00807     float8      arg2 = PG_GETARG_FLOAT8(1);
00808     float8      result;
00809 
00810     result = arg1 + arg2;
00811 
00812     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
00813     PG_RETURN_FLOAT8(result);
00814 }
00815 
00816 Datum
00817 float8mi(PG_FUNCTION_ARGS)
00818 {
00819     float8      arg1 = PG_GETARG_FLOAT8(0);
00820     float8      arg2 = PG_GETARG_FLOAT8(1);
00821     float8      result;
00822 
00823     result = arg1 - arg2;
00824 
00825     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
00826     PG_RETURN_FLOAT8(result);
00827 }
00828 
00829 Datum
00830 float8mul(PG_FUNCTION_ARGS)
00831 {
00832     float8      arg1 = PG_GETARG_FLOAT8(0);
00833     float8      arg2 = PG_GETARG_FLOAT8(1);
00834     float8      result;
00835 
00836     result = arg1 * arg2;
00837 
00838     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
00839                   arg1 == 0 || arg2 == 0);
00840     PG_RETURN_FLOAT8(result);
00841 }
00842 
00843 Datum
00844 float8div(PG_FUNCTION_ARGS)
00845 {
00846     float8      arg1 = PG_GETARG_FLOAT8(0);
00847     float8      arg2 = PG_GETARG_FLOAT8(1);
00848     float8      result;
00849 
00850     if (arg2 == 0.0)
00851         ereport(ERROR,
00852                 (errcode(ERRCODE_DIVISION_BY_ZERO),
00853                  errmsg("division by zero")));
00854 
00855     result = arg1 / arg2;
00856 
00857     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
00858     PG_RETURN_FLOAT8(result);
00859 }
00860 
00861 
00862 /*
00863  *      ====================
00864  *      COMPARISON OPERATORS
00865  *      ====================
00866  */
00867 
00868 /*
00869  *      float4{eq,ne,lt,le,gt,ge}       - float4/float4 comparison operations
00870  */
00871 static int
00872 float4_cmp_internal(float4 a, float4 b)
00873 {
00874     /*
00875      * We consider all NANs to be equal and larger than any non-NAN. This is
00876      * somewhat arbitrary; the important thing is to have a consistent sort
00877      * order.
00878      */
00879     if (isnan(a))
00880     {
00881         if (isnan(b))
00882             return 0;           /* NAN = NAN */
00883         else
00884             return 1;           /* NAN > non-NAN */
00885     }
00886     else if (isnan(b))
00887     {
00888         return -1;              /* non-NAN < NAN */
00889     }
00890     else
00891     {
00892         if (a > b)
00893             return 1;
00894         else if (a < b)
00895             return -1;
00896         else
00897             return 0;
00898     }
00899 }
00900 
00901 Datum
00902 float4eq(PG_FUNCTION_ARGS)
00903 {
00904     float4      arg1 = PG_GETARG_FLOAT4(0);
00905     float4      arg2 = PG_GETARG_FLOAT4(1);
00906 
00907     PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
00908 }
00909 
00910 Datum
00911 float4ne(PG_FUNCTION_ARGS)
00912 {
00913     float4      arg1 = PG_GETARG_FLOAT4(0);
00914     float4      arg2 = PG_GETARG_FLOAT4(1);
00915 
00916     PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
00917 }
00918 
00919 Datum
00920 float4lt(PG_FUNCTION_ARGS)
00921 {
00922     float4      arg1 = PG_GETARG_FLOAT4(0);
00923     float4      arg2 = PG_GETARG_FLOAT4(1);
00924 
00925     PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
00926 }
00927 
00928 Datum
00929 float4le(PG_FUNCTION_ARGS)
00930 {
00931     float4      arg1 = PG_GETARG_FLOAT4(0);
00932     float4      arg2 = PG_GETARG_FLOAT4(1);
00933 
00934     PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
00935 }
00936 
00937 Datum
00938 float4gt(PG_FUNCTION_ARGS)
00939 {
00940     float4      arg1 = PG_GETARG_FLOAT4(0);
00941     float4      arg2 = PG_GETARG_FLOAT4(1);
00942 
00943     PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
00944 }
00945 
00946 Datum
00947 float4ge(PG_FUNCTION_ARGS)
00948 {
00949     float4      arg1 = PG_GETARG_FLOAT4(0);
00950     float4      arg2 = PG_GETARG_FLOAT4(1);
00951 
00952     PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
00953 }
00954 
00955 Datum
00956 btfloat4cmp(PG_FUNCTION_ARGS)
00957 {
00958     float4      arg1 = PG_GETARG_FLOAT4(0);
00959     float4      arg2 = PG_GETARG_FLOAT4(1);
00960 
00961     PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
00962 }
00963 
00964 static int
00965 btfloat4fastcmp(Datum x, Datum y, SortSupport ssup)
00966 {
00967     float4      arg1 = DatumGetFloat4(x);
00968     float4      arg2 = DatumGetFloat4(y);
00969 
00970     return float4_cmp_internal(arg1, arg2);
00971 }
00972 
00973 Datum
00974 btfloat4sortsupport(PG_FUNCTION_ARGS)
00975 {
00976     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
00977 
00978     ssup->comparator = btfloat4fastcmp;
00979     PG_RETURN_VOID();
00980 }
00981 
00982 /*
00983  *      float8{eq,ne,lt,le,gt,ge}       - float8/float8 comparison operations
00984  */
00985 static int
00986 float8_cmp_internal(float8 a, float8 b)
00987 {
00988     /*
00989      * We consider all NANs to be equal and larger than any non-NAN. This is
00990      * somewhat arbitrary; the important thing is to have a consistent sort
00991      * order.
00992      */
00993     if (isnan(a))
00994     {
00995         if (isnan(b))
00996             return 0;           /* NAN = NAN */
00997         else
00998             return 1;           /* NAN > non-NAN */
00999     }
01000     else if (isnan(b))
01001     {
01002         return -1;              /* non-NAN < NAN */
01003     }
01004     else
01005     {
01006         if (a > b)
01007             return 1;
01008         else if (a < b)
01009             return -1;
01010         else
01011             return 0;
01012     }
01013 }
01014 
01015 Datum
01016 float8eq(PG_FUNCTION_ARGS)
01017 {
01018     float8      arg1 = PG_GETARG_FLOAT8(0);
01019     float8      arg2 = PG_GETARG_FLOAT8(1);
01020 
01021     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
01022 }
01023 
01024 Datum
01025 float8ne(PG_FUNCTION_ARGS)
01026 {
01027     float8      arg1 = PG_GETARG_FLOAT8(0);
01028     float8      arg2 = PG_GETARG_FLOAT8(1);
01029 
01030     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
01031 }
01032 
01033 Datum
01034 float8lt(PG_FUNCTION_ARGS)
01035 {
01036     float8      arg1 = PG_GETARG_FLOAT8(0);
01037     float8      arg2 = PG_GETARG_FLOAT8(1);
01038 
01039     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
01040 }
01041 
01042 Datum
01043 float8le(PG_FUNCTION_ARGS)
01044 {
01045     float8      arg1 = PG_GETARG_FLOAT8(0);
01046     float8      arg2 = PG_GETARG_FLOAT8(1);
01047 
01048     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
01049 }
01050 
01051 Datum
01052 float8gt(PG_FUNCTION_ARGS)
01053 {
01054     float8      arg1 = PG_GETARG_FLOAT8(0);
01055     float8      arg2 = PG_GETARG_FLOAT8(1);
01056 
01057     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
01058 }
01059 
01060 Datum
01061 float8ge(PG_FUNCTION_ARGS)
01062 {
01063     float8      arg1 = PG_GETARG_FLOAT8(0);
01064     float8      arg2 = PG_GETARG_FLOAT8(1);
01065 
01066     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
01067 }
01068 
01069 Datum
01070 btfloat8cmp(PG_FUNCTION_ARGS)
01071 {
01072     float8      arg1 = PG_GETARG_FLOAT8(0);
01073     float8      arg2 = PG_GETARG_FLOAT8(1);
01074 
01075     PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
01076 }
01077 
01078 static int
01079 btfloat8fastcmp(Datum x, Datum y, SortSupport ssup)
01080 {
01081     float8      arg1 = DatumGetFloat8(x);
01082     float8      arg2 = DatumGetFloat8(y);
01083 
01084     return float8_cmp_internal(arg1, arg2);
01085 }
01086 
01087 Datum
01088 btfloat8sortsupport(PG_FUNCTION_ARGS)
01089 {
01090     SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
01091 
01092     ssup->comparator = btfloat8fastcmp;
01093     PG_RETURN_VOID();
01094 }
01095 
01096 Datum
01097 btfloat48cmp(PG_FUNCTION_ARGS)
01098 {
01099     float4      arg1 = PG_GETARG_FLOAT4(0);
01100     float8      arg2 = PG_GETARG_FLOAT8(1);
01101 
01102     /* widen float4 to float8 and then compare */
01103     PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
01104 }
01105 
01106 Datum
01107 btfloat84cmp(PG_FUNCTION_ARGS)
01108 {
01109     float8      arg1 = PG_GETARG_FLOAT8(0);
01110     float4      arg2 = PG_GETARG_FLOAT4(1);
01111 
01112     /* widen float4 to float8 and then compare */
01113     PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
01114 }
01115 
01116 
01117 /*
01118  *      ===================
01119  *      CONVERSION ROUTINES
01120  *      ===================
01121  */
01122 
01123 /*
01124  *      ftod            - converts a float4 number to a float8 number
01125  */
01126 Datum
01127 ftod(PG_FUNCTION_ARGS)
01128 {
01129     float4      num = PG_GETARG_FLOAT4(0);
01130 
01131     PG_RETURN_FLOAT8((float8) num);
01132 }
01133 
01134 
01135 /*
01136  *      dtof            - converts a float8 number to a float4 number
01137  */
01138 Datum
01139 dtof(PG_FUNCTION_ARGS)
01140 {
01141     float8      num = PG_GETARG_FLOAT8(0);
01142 
01143     CHECKFLOATVAL((float4) num, isinf(num), num == 0);
01144 
01145     PG_RETURN_FLOAT4((float4) num);
01146 }
01147 
01148 
01149 /*
01150  *      dtoi4           - converts a float8 number to an int4 number
01151  */
01152 Datum
01153 dtoi4(PG_FUNCTION_ARGS)
01154 {
01155     float8      num = PG_GETARG_FLOAT8(0);
01156     int32       result;
01157 
01158     /* 'Inf' is handled by INT_MAX */
01159     if (num < INT_MIN || num > INT_MAX || isnan(num))
01160         ereport(ERROR,
01161                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01162                  errmsg("integer out of range")));
01163 
01164     result = (int32) rint(num);
01165     PG_RETURN_INT32(result);
01166 }
01167 
01168 
01169 /*
01170  *      dtoi2           - converts a float8 number to an int2 number
01171  */
01172 Datum
01173 dtoi2(PG_FUNCTION_ARGS)
01174 {
01175     float8      num = PG_GETARG_FLOAT8(0);
01176 
01177     if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
01178         ereport(ERROR,
01179                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01180                  errmsg("smallint out of range")));
01181 
01182     PG_RETURN_INT16((int16) rint(num));
01183 }
01184 
01185 
01186 /*
01187  *      i4tod           - converts an int4 number to a float8 number
01188  */
01189 Datum
01190 i4tod(PG_FUNCTION_ARGS)
01191 {
01192     int32       num = PG_GETARG_INT32(0);
01193 
01194     PG_RETURN_FLOAT8((float8) num);
01195 }
01196 
01197 
01198 /*
01199  *      i2tod           - converts an int2 number to a float8 number
01200  */
01201 Datum
01202 i2tod(PG_FUNCTION_ARGS)
01203 {
01204     int16       num = PG_GETARG_INT16(0);
01205 
01206     PG_RETURN_FLOAT8((float8) num);
01207 }
01208 
01209 
01210 /*
01211  *      ftoi4           - converts a float4 number to an int4 number
01212  */
01213 Datum
01214 ftoi4(PG_FUNCTION_ARGS)
01215 {
01216     float4      num = PG_GETARG_FLOAT4(0);
01217 
01218     if (num < INT_MIN || num > INT_MAX || isnan(num))
01219         ereport(ERROR,
01220                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01221                  errmsg("integer out of range")));
01222 
01223     PG_RETURN_INT32((int32) rint(num));
01224 }
01225 
01226 
01227 /*
01228  *      ftoi2           - converts a float4 number to an int2 number
01229  */
01230 Datum
01231 ftoi2(PG_FUNCTION_ARGS)
01232 {
01233     float4      num = PG_GETARG_FLOAT4(0);
01234 
01235     if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
01236         ereport(ERROR,
01237                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01238                  errmsg("smallint out of range")));
01239 
01240     PG_RETURN_INT16((int16) rint(num));
01241 }
01242 
01243 
01244 /*
01245  *      i4tof           - converts an int4 number to a float4 number
01246  */
01247 Datum
01248 i4tof(PG_FUNCTION_ARGS)
01249 {
01250     int32       num = PG_GETARG_INT32(0);
01251 
01252     PG_RETURN_FLOAT4((float4) num);
01253 }
01254 
01255 
01256 /*
01257  *      i2tof           - converts an int2 number to a float4 number
01258  */
01259 Datum
01260 i2tof(PG_FUNCTION_ARGS)
01261 {
01262     int16       num = PG_GETARG_INT16(0);
01263 
01264     PG_RETURN_FLOAT4((float4) num);
01265 }
01266 
01267 
01268 /*
01269  *      =======================
01270  *      RANDOM FLOAT8 OPERATORS
01271  *      =======================
01272  */
01273 
01274 /*
01275  *      dround          - returns   ROUND(arg1)
01276  */
01277 Datum
01278 dround(PG_FUNCTION_ARGS)
01279 {
01280     float8      arg1 = PG_GETARG_FLOAT8(0);
01281 
01282     PG_RETURN_FLOAT8(rint(arg1));
01283 }
01284 
01285 /*
01286  *      dceil           - returns the smallest integer greater than or
01287  *                        equal to the specified float
01288  */
01289 Datum
01290 dceil(PG_FUNCTION_ARGS)
01291 {
01292     float8      arg1 = PG_GETARG_FLOAT8(0);
01293 
01294     PG_RETURN_FLOAT8(ceil(arg1));
01295 }
01296 
01297 /*
01298  *      dfloor          - returns the largest integer lesser than or
01299  *                        equal to the specified float
01300  */
01301 Datum
01302 dfloor(PG_FUNCTION_ARGS)
01303 {
01304     float8      arg1 = PG_GETARG_FLOAT8(0);
01305 
01306     PG_RETURN_FLOAT8(floor(arg1));
01307 }
01308 
01309 /*
01310  *      dsign           - returns -1 if the argument is less than 0, 0
01311  *                        if the argument is equal to 0, and 1 if the
01312  *                        argument is greater than zero.
01313  */
01314 Datum
01315 dsign(PG_FUNCTION_ARGS)
01316 {
01317     float8      arg1 = PG_GETARG_FLOAT8(0);
01318     float8      result;
01319 
01320     if (arg1 > 0)
01321         result = 1.0;
01322     else if (arg1 < 0)
01323         result = -1.0;
01324     else
01325         result = 0.0;
01326 
01327     PG_RETURN_FLOAT8(result);
01328 }
01329 
01330 /*
01331  *      dtrunc          - returns truncation-towards-zero of arg1,
01332  *                        arg1 >= 0 ... the greatest integer less
01333  *                                      than or equal to arg1
01334  *                        arg1 < 0  ... the least integer greater
01335  *                                      than or equal to arg1
01336  */
01337 Datum
01338 dtrunc(PG_FUNCTION_ARGS)
01339 {
01340     float8      arg1 = PG_GETARG_FLOAT8(0);
01341     float8      result;
01342 
01343     if (arg1 >= 0)
01344         result = floor(arg1);
01345     else
01346         result = -floor(-arg1);
01347 
01348     PG_RETURN_FLOAT8(result);
01349 }
01350 
01351 
01352 /*
01353  *      dsqrt           - returns square root of arg1
01354  */
01355 Datum
01356 dsqrt(PG_FUNCTION_ARGS)
01357 {
01358     float8      arg1 = PG_GETARG_FLOAT8(0);
01359     float8      result;
01360 
01361     if (arg1 < 0)
01362         ereport(ERROR,
01363                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
01364                  errmsg("cannot take square root of a negative number")));
01365 
01366     result = sqrt(arg1);
01367 
01368     CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
01369     PG_RETURN_FLOAT8(result);
01370 }
01371 
01372 
01373 /*
01374  *      dcbrt           - returns cube root of arg1
01375  */
01376 Datum
01377 dcbrt(PG_FUNCTION_ARGS)
01378 {
01379     float8      arg1 = PG_GETARG_FLOAT8(0);
01380     float8      result;
01381 
01382     result = cbrt(arg1);
01383     CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
01384     PG_RETURN_FLOAT8(result);
01385 }
01386 
01387 
01388 /*
01389  *      dpow            - returns pow(arg1,arg2)
01390  */
01391 Datum
01392 dpow(PG_FUNCTION_ARGS)
01393 {
01394     float8      arg1 = PG_GETARG_FLOAT8(0);
01395     float8      arg2 = PG_GETARG_FLOAT8(1);
01396     float8      result;
01397 
01398     /*
01399      * The SQL spec requires that we emit a particular SQLSTATE error code for
01400      * certain error conditions.  Specifically, we don't return a
01401      * divide-by-zero error code for 0 ^ -1.
01402      */
01403     if (arg1 == 0 && arg2 < 0)
01404         ereport(ERROR,
01405                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
01406                  errmsg("zero raised to a negative power is undefined")));
01407     if (arg1 < 0 && floor(arg2) != arg2)
01408         ereport(ERROR,
01409                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
01410                  errmsg("a negative number raised to a non-integer power yields a complex result")));
01411 
01412     /*
01413      * pow() sets errno only on some platforms, depending on whether it
01414      * follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using
01415      * errno.  However, some platform/CPU combinations return errno == EDOM
01416      * and result == Nan for negative arg1 and very large arg2 (they must be
01417      * using something different from our floor() test to decide it's
01418      * invalid).  Other platforms (HPPA) return errno == ERANGE and a large
01419      * (HUGE_VAL) but finite result to signal overflow.
01420      */
01421     errno = 0;
01422     result = pow(arg1, arg2);
01423     if (errno == EDOM && isnan(result))
01424     {
01425         if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
01426             /* The sign of Inf is not significant in this case. */
01427             result = get_float8_infinity();
01428         else if (fabs(arg1) != 1)
01429             result = 0;
01430         else
01431             result = 1;
01432     }
01433     else if (errno == ERANGE && result != 0 && !isinf(result))
01434         result = get_float8_infinity();
01435 
01436     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
01437     PG_RETURN_FLOAT8(result);
01438 }
01439 
01440 
01441 /*
01442  *      dexp            - returns the exponential function of arg1
01443  */
01444 Datum
01445 dexp(PG_FUNCTION_ARGS)
01446 {
01447     float8      arg1 = PG_GETARG_FLOAT8(0);
01448     float8      result;
01449 
01450     errno = 0;
01451     result = exp(arg1);
01452     if (errno == ERANGE && result != 0 && !isinf(result))
01453         result = get_float8_infinity();
01454 
01455     CHECKFLOATVAL(result, isinf(arg1), false);
01456     PG_RETURN_FLOAT8(result);
01457 }
01458 
01459 
01460 /*
01461  *      dlog1           - returns the natural logarithm of arg1
01462  */
01463 Datum
01464 dlog1(PG_FUNCTION_ARGS)
01465 {
01466     float8      arg1 = PG_GETARG_FLOAT8(0);
01467     float8      result;
01468 
01469     /*
01470      * Emit particular SQLSTATE error codes for ln(). This is required by the
01471      * SQL standard.
01472      */
01473     if (arg1 == 0.0)
01474         ereport(ERROR,
01475                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
01476                  errmsg("cannot take logarithm of zero")));
01477     if (arg1 < 0)
01478         ereport(ERROR,
01479                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
01480                  errmsg("cannot take logarithm of a negative number")));
01481 
01482     result = log(arg1);
01483 
01484     CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
01485     PG_RETURN_FLOAT8(result);
01486 }
01487 
01488 
01489 /*
01490  *      dlog10          - returns the base 10 logarithm of arg1
01491  */
01492 Datum
01493 dlog10(PG_FUNCTION_ARGS)
01494 {
01495     float8      arg1 = PG_GETARG_FLOAT8(0);
01496     float8      result;
01497 
01498     /*
01499      * Emit particular SQLSTATE error codes for log(). The SQL spec doesn't
01500      * define log(), but it does define ln(), so it makes sense to emit the
01501      * same error code for an analogous error condition.
01502      */
01503     if (arg1 == 0.0)
01504         ereport(ERROR,
01505                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
01506                  errmsg("cannot take logarithm of zero")));
01507     if (arg1 < 0)
01508         ereport(ERROR,
01509                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
01510                  errmsg("cannot take logarithm of a negative number")));
01511 
01512     result = log10(arg1);
01513 
01514     CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
01515     PG_RETURN_FLOAT8(result);
01516 }
01517 
01518 
01519 /*
01520  *      dacos           - returns the arccos of arg1 (radians)
01521  */
01522 Datum
01523 dacos(PG_FUNCTION_ARGS)
01524 {
01525     float8      arg1 = PG_GETARG_FLOAT8(0);
01526     float8      result;
01527 
01528     /*
01529      * We use errno here because the trigonometric functions are cyclic and
01530      * hard to check for underflow.
01531      */
01532     errno = 0;
01533     result = acos(arg1);
01534     if (errno != 0)
01535         ereport(ERROR,
01536                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01537                  errmsg("input is out of range")));
01538 
01539     CHECKFLOATVAL(result, isinf(arg1), true);
01540     PG_RETURN_FLOAT8(result);
01541 }
01542 
01543 
01544 /*
01545  *      dasin           - returns the arcsin of arg1 (radians)
01546  */
01547 Datum
01548 dasin(PG_FUNCTION_ARGS)
01549 {
01550     float8      arg1 = PG_GETARG_FLOAT8(0);
01551     float8      result;
01552 
01553     errno = 0;
01554     result = asin(arg1);
01555     if (errno != 0)
01556         ereport(ERROR,
01557                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01558                  errmsg("input is out of range")));
01559 
01560     CHECKFLOATVAL(result, isinf(arg1), true);
01561     PG_RETURN_FLOAT8(result);
01562 }
01563 
01564 
01565 /*
01566  *      datan           - returns the arctan of arg1 (radians)
01567  */
01568 Datum
01569 datan(PG_FUNCTION_ARGS)
01570 {
01571     float8      arg1 = PG_GETARG_FLOAT8(0);
01572     float8      result;
01573 
01574     errno = 0;
01575     result = atan(arg1);
01576     if (errno != 0)
01577         ereport(ERROR,
01578                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01579                  errmsg("input is out of range")));
01580 
01581     CHECKFLOATVAL(result, isinf(arg1), true);
01582     PG_RETURN_FLOAT8(result);
01583 }
01584 
01585 
01586 /*
01587  *      atan2           - returns the arctan2 of arg1 (radians)
01588  */
01589 Datum
01590 datan2(PG_FUNCTION_ARGS)
01591 {
01592     float8      arg1 = PG_GETARG_FLOAT8(0);
01593     float8      arg2 = PG_GETARG_FLOAT8(1);
01594     float8      result;
01595 
01596     errno = 0;
01597     result = atan2(arg1, arg2);
01598     if (errno != 0)
01599         ereport(ERROR,
01600                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01601                  errmsg("input is out of range")));
01602 
01603     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
01604     PG_RETURN_FLOAT8(result);
01605 }
01606 
01607 
01608 /*
01609  *      dcos            - returns the cosine of arg1 (radians)
01610  */
01611 Datum
01612 dcos(PG_FUNCTION_ARGS)
01613 {
01614     float8      arg1 = PG_GETARG_FLOAT8(0);
01615     float8      result;
01616 
01617     errno = 0;
01618     result = cos(arg1);
01619     if (errno != 0)
01620         ereport(ERROR,
01621                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01622                  errmsg("input is out of range")));
01623 
01624     CHECKFLOATVAL(result, isinf(arg1), true);
01625     PG_RETURN_FLOAT8(result);
01626 }
01627 
01628 
01629 /*
01630  *      dcot            - returns the cotangent of arg1 (radians)
01631  */
01632 Datum
01633 dcot(PG_FUNCTION_ARGS)
01634 {
01635     float8      arg1 = PG_GETARG_FLOAT8(0);
01636     float8      result;
01637 
01638     errno = 0;
01639     result = tan(arg1);
01640     if (errno != 0)
01641         ereport(ERROR,
01642                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01643                  errmsg("input is out of range")));
01644 
01645     result = 1.0 / result;
01646     CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */ , true);
01647     PG_RETURN_FLOAT8(result);
01648 }
01649 
01650 
01651 /*
01652  *      dsin            - returns the sine of arg1 (radians)
01653  */
01654 Datum
01655 dsin(PG_FUNCTION_ARGS)
01656 {
01657     float8      arg1 = PG_GETARG_FLOAT8(0);
01658     float8      result;
01659 
01660     errno = 0;
01661     result = sin(arg1);
01662     if (errno != 0)
01663         ereport(ERROR,
01664                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01665                  errmsg("input is out of range")));
01666 
01667     CHECKFLOATVAL(result, isinf(arg1), true);
01668     PG_RETURN_FLOAT8(result);
01669 }
01670 
01671 
01672 /*
01673  *      dtan            - returns the tangent of arg1 (radians)
01674  */
01675 Datum
01676 dtan(PG_FUNCTION_ARGS)
01677 {
01678     float8      arg1 = PG_GETARG_FLOAT8(0);
01679     float8      result;
01680 
01681     errno = 0;
01682     result = tan(arg1);
01683     if (errno != 0)
01684         ereport(ERROR,
01685                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01686                  errmsg("input is out of range")));
01687 
01688     CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
01689     PG_RETURN_FLOAT8(result);
01690 }
01691 
01692 
01693 /*
01694  *      degrees     - returns degrees converted from radians
01695  */
01696 Datum
01697 degrees(PG_FUNCTION_ARGS)
01698 {
01699     float8      arg1 = PG_GETARG_FLOAT8(0);
01700     float8      result;
01701 
01702     result = arg1 * (180.0 / M_PI);
01703 
01704     CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
01705     PG_RETURN_FLOAT8(result);
01706 }
01707 
01708 
01709 /*
01710  *      dpi             - returns the constant PI
01711  */
01712 Datum
01713 dpi(PG_FUNCTION_ARGS)
01714 {
01715     PG_RETURN_FLOAT8(M_PI);
01716 }
01717 
01718 
01719 /*
01720  *      radians     - returns radians converted from degrees
01721  */
01722 Datum
01723 radians(PG_FUNCTION_ARGS)
01724 {
01725     float8      arg1 = PG_GETARG_FLOAT8(0);
01726     float8      result;
01727 
01728     result = arg1 * (M_PI / 180.0);
01729 
01730     CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
01731     PG_RETURN_FLOAT8(result);
01732 }
01733 
01734 
01735 /*
01736  *      drandom     - returns a random number
01737  */
01738 Datum
01739 drandom(PG_FUNCTION_ARGS)
01740 {
01741     float8      result;
01742 
01743     /* result [0.0 - 1.0) */
01744     result = (double) random() / ((double) MAX_RANDOM_VALUE + 1);
01745 
01746     PG_RETURN_FLOAT8(result);
01747 }
01748 
01749 
01750 /*
01751  *      setseed     - set seed for the random number generator
01752  */
01753 Datum
01754 setseed(PG_FUNCTION_ARGS)
01755 {
01756     float8      seed = PG_GETARG_FLOAT8(0);
01757     int         iseed;
01758 
01759     if (seed < -1 || seed > 1)
01760         elog(ERROR, "setseed parameter %f out of range [-1,1]", seed);
01761 
01762     iseed = (int) (seed * MAX_RANDOM_VALUE);
01763     srandom((unsigned int) iseed);
01764 
01765     PG_RETURN_VOID();
01766 }
01767 
01768 
01769 
01770 /*
01771  *      =========================
01772  *      FLOAT AGGREGATE OPERATORS
01773  *      =========================
01774  *
01775  *      float8_accum        - accumulate for AVG(), variance aggregates, etc.
01776  *      float4_accum        - same, but input data is float4
01777  *      float8_avg          - produce final result for float AVG()
01778  *      float8_var_samp     - produce final result for float VAR_SAMP()
01779  *      float8_var_pop      - produce final result for float VAR_POP()
01780  *      float8_stddev_samp  - produce final result for float STDDEV_SAMP()
01781  *      float8_stddev_pop   - produce final result for float STDDEV_POP()
01782  *
01783  * The transition datatype for all these aggregates is a 3-element array
01784  * of float8, holding the values N, sum(X), sum(X*X) in that order.
01785  *
01786  * Note that we represent N as a float to avoid having to build a special
01787  * datatype.  Given a reasonable floating-point implementation, there should
01788  * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
01789  * user will have doubtless lost interest anyway...)
01790  */
01791 
01792 static float8 *
01793 check_float8_array(ArrayType *transarray, const char *caller, int n)
01794 {
01795     /*
01796      * We expect the input to be an N-element float array; verify that. We
01797      * don't need to use deconstruct_array() since the array data is just
01798      * going to look like a C array of N float8 values.
01799      */
01800     if (ARR_NDIM(transarray) != 1 ||
01801         ARR_DIMS(transarray)[0] != n ||
01802         ARR_HASNULL(transarray) ||
01803         ARR_ELEMTYPE(transarray) != FLOAT8OID)
01804         elog(ERROR, "%s: expected %d-element float8 array", caller, n);
01805     return (float8 *) ARR_DATA_PTR(transarray);
01806 }
01807 
01808 Datum
01809 float8_accum(PG_FUNCTION_ARGS)
01810 {
01811     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
01812     float8      newval = PG_GETARG_FLOAT8(1);
01813     float8     *transvalues;
01814     float8      N,
01815                 sumX,
01816                 sumX2;
01817 
01818     transvalues = check_float8_array(transarray, "float8_accum", 3);
01819     N = transvalues[0];
01820     sumX = transvalues[1];
01821     sumX2 = transvalues[2];
01822 
01823     N += 1.0;
01824     sumX += newval;
01825     CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
01826     sumX2 += newval * newval;
01827     CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
01828 
01829     /*
01830      * If we're invoked as an aggregate, we can cheat and modify our first
01831      * parameter in-place to reduce palloc overhead. Otherwise we construct a
01832      * new array with the updated transition data and return it.
01833      */
01834     if (AggCheckCallContext(fcinfo, NULL))
01835     {
01836         transvalues[0] = N;
01837         transvalues[1] = sumX;
01838         transvalues[2] = sumX2;
01839 
01840         PG_RETURN_ARRAYTYPE_P(transarray);
01841     }
01842     else
01843     {
01844         Datum       transdatums[3];
01845         ArrayType  *result;
01846 
01847         transdatums[0] = Float8GetDatumFast(N);
01848         transdatums[1] = Float8GetDatumFast(sumX);
01849         transdatums[2] = Float8GetDatumFast(sumX2);
01850 
01851         result = construct_array(transdatums, 3,
01852                                  FLOAT8OID,
01853                                  sizeof(float8), FLOAT8PASSBYVAL, 'd');
01854 
01855         PG_RETURN_ARRAYTYPE_P(result);
01856     }
01857 }
01858 
01859 Datum
01860 float4_accum(PG_FUNCTION_ARGS)
01861 {
01862     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
01863 
01864     /* do computations as float8 */
01865     float8      newval = PG_GETARG_FLOAT4(1);
01866     float8     *transvalues;
01867     float8      N,
01868                 sumX,
01869                 sumX2;
01870 
01871     transvalues = check_float8_array(transarray, "float4_accum", 3);
01872     N = transvalues[0];
01873     sumX = transvalues[1];
01874     sumX2 = transvalues[2];
01875 
01876     N += 1.0;
01877     sumX += newval;
01878     CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
01879     sumX2 += newval * newval;
01880     CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
01881 
01882     /*
01883      * If we're invoked as an aggregate, we can cheat and modify our first
01884      * parameter in-place to reduce palloc overhead. Otherwise we construct a
01885      * new array with the updated transition data and return it.
01886      */
01887     if (AggCheckCallContext(fcinfo, NULL))
01888     {
01889         transvalues[0] = N;
01890         transvalues[1] = sumX;
01891         transvalues[2] = sumX2;
01892 
01893         PG_RETURN_ARRAYTYPE_P(transarray);
01894     }
01895     else
01896     {
01897         Datum       transdatums[3];
01898         ArrayType  *result;
01899 
01900         transdatums[0] = Float8GetDatumFast(N);
01901         transdatums[1] = Float8GetDatumFast(sumX);
01902         transdatums[2] = Float8GetDatumFast(sumX2);
01903 
01904         result = construct_array(transdatums, 3,
01905                                  FLOAT8OID,
01906                                  sizeof(float8), FLOAT8PASSBYVAL, 'd');
01907 
01908         PG_RETURN_ARRAYTYPE_P(result);
01909     }
01910 }
01911 
01912 Datum
01913 float8_avg(PG_FUNCTION_ARGS)
01914 {
01915     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
01916     float8     *transvalues;
01917     float8      N,
01918                 sumX;
01919 
01920     transvalues = check_float8_array(transarray, "float8_avg", 3);
01921     N = transvalues[0];
01922     sumX = transvalues[1];
01923     /* ignore sumX2 */
01924 
01925     /* SQL defines AVG of no values to be NULL */
01926     if (N == 0.0)
01927         PG_RETURN_NULL();
01928 
01929     PG_RETURN_FLOAT8(sumX / N);
01930 }
01931 
01932 Datum
01933 float8_var_pop(PG_FUNCTION_ARGS)
01934 {
01935     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
01936     float8     *transvalues;
01937     float8      N,
01938                 sumX,
01939                 sumX2,
01940                 numerator;
01941 
01942     transvalues = check_float8_array(transarray, "float8_var_pop", 3);
01943     N = transvalues[0];
01944     sumX = transvalues[1];
01945     sumX2 = transvalues[2];
01946 
01947     /* Population variance is undefined when N is 0, so return NULL */
01948     if (N == 0.0)
01949         PG_RETURN_NULL();
01950 
01951     numerator = N * sumX2 - sumX * sumX;
01952     CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
01953 
01954     /* Watch out for roundoff error producing a negative numerator */
01955     if (numerator <= 0.0)
01956         PG_RETURN_FLOAT8(0.0);
01957 
01958     PG_RETURN_FLOAT8(numerator / (N * N));
01959 }
01960 
01961 Datum
01962 float8_var_samp(PG_FUNCTION_ARGS)
01963 {
01964     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
01965     float8     *transvalues;
01966     float8      N,
01967                 sumX,
01968                 sumX2,
01969                 numerator;
01970 
01971     transvalues = check_float8_array(transarray, "float8_var_samp", 3);
01972     N = transvalues[0];
01973     sumX = transvalues[1];
01974     sumX2 = transvalues[2];
01975 
01976     /* Sample variance is undefined when N is 0 or 1, so return NULL */
01977     if (N <= 1.0)
01978         PG_RETURN_NULL();
01979 
01980     numerator = N * sumX2 - sumX * sumX;
01981     CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
01982 
01983     /* Watch out for roundoff error producing a negative numerator */
01984     if (numerator <= 0.0)
01985         PG_RETURN_FLOAT8(0.0);
01986 
01987     PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
01988 }
01989 
01990 Datum
01991 float8_stddev_pop(PG_FUNCTION_ARGS)
01992 {
01993     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
01994     float8     *transvalues;
01995     float8      N,
01996                 sumX,
01997                 sumX2,
01998                 numerator;
01999 
02000     transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
02001     N = transvalues[0];
02002     sumX = transvalues[1];
02003     sumX2 = transvalues[2];
02004 
02005     /* Population stddev is undefined when N is 0, so return NULL */
02006     if (N == 0.0)
02007         PG_RETURN_NULL();
02008 
02009     numerator = N * sumX2 - sumX * sumX;
02010     CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
02011 
02012     /* Watch out for roundoff error producing a negative numerator */
02013     if (numerator <= 0.0)
02014         PG_RETURN_FLOAT8(0.0);
02015 
02016     PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
02017 }
02018 
02019 Datum
02020 float8_stddev_samp(PG_FUNCTION_ARGS)
02021 {
02022     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02023     float8     *transvalues;
02024     float8      N,
02025                 sumX,
02026                 sumX2,
02027                 numerator;
02028 
02029     transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
02030     N = transvalues[0];
02031     sumX = transvalues[1];
02032     sumX2 = transvalues[2];
02033 
02034     /* Sample stddev is undefined when N is 0 or 1, so return NULL */
02035     if (N <= 1.0)
02036         PG_RETURN_NULL();
02037 
02038     numerator = N * sumX2 - sumX * sumX;
02039     CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
02040 
02041     /* Watch out for roundoff error producing a negative numerator */
02042     if (numerator <= 0.0)
02043         PG_RETURN_FLOAT8(0.0);
02044 
02045     PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
02046 }
02047 
02048 /*
02049  *      =========================
02050  *      SQL2003 BINARY AGGREGATES
02051  *      =========================
02052  *
02053  * The transition datatype for all these aggregates is a 6-element array of
02054  * float8, holding the values N, sum(X), sum(X*X), sum(Y), sum(Y*Y), sum(X*Y)
02055  * in that order.  Note that Y is the first argument to the aggregates!
02056  *
02057  * It might seem attractive to optimize this by having multiple accumulator
02058  * functions that only calculate the sums actually needed.  But on most
02059  * modern machines, a couple of extra floating-point multiplies will be
02060  * insignificant compared to the other per-tuple overhead, so I've chosen
02061  * to minimize code space instead.
02062  */
02063 
02064 Datum
02065 float8_regr_accum(PG_FUNCTION_ARGS)
02066 {
02067     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02068     float8      newvalY = PG_GETARG_FLOAT8(1);
02069     float8      newvalX = PG_GETARG_FLOAT8(2);
02070     float8     *transvalues;
02071     float8      N,
02072                 sumX,
02073                 sumX2,
02074                 sumY,
02075                 sumY2,
02076                 sumXY;
02077 
02078     transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
02079     N = transvalues[0];
02080     sumX = transvalues[1];
02081     sumX2 = transvalues[2];
02082     sumY = transvalues[3];
02083     sumY2 = transvalues[4];
02084     sumXY = transvalues[5];
02085 
02086     N += 1.0;
02087     sumX += newvalX;
02088     CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
02089     sumX2 += newvalX * newvalX;
02090     CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
02091     sumY += newvalY;
02092     CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
02093     sumY2 += newvalY * newvalY;
02094     CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
02095     sumXY += newvalX * newvalY;
02096     CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
02097                   isinf(newvalY), true);
02098 
02099     /*
02100      * If we're invoked as an aggregate, we can cheat and modify our first
02101      * parameter in-place to reduce palloc overhead. Otherwise we construct a
02102      * new array with the updated transition data and return it.
02103      */
02104     if (AggCheckCallContext(fcinfo, NULL))
02105     {
02106         transvalues[0] = N;
02107         transvalues[1] = sumX;
02108         transvalues[2] = sumX2;
02109         transvalues[3] = sumY;
02110         transvalues[4] = sumY2;
02111         transvalues[5] = sumXY;
02112 
02113         PG_RETURN_ARRAYTYPE_P(transarray);
02114     }
02115     else
02116     {
02117         Datum       transdatums[6];
02118         ArrayType  *result;
02119 
02120         transdatums[0] = Float8GetDatumFast(N);
02121         transdatums[1] = Float8GetDatumFast(sumX);
02122         transdatums[2] = Float8GetDatumFast(sumX2);
02123         transdatums[3] = Float8GetDatumFast(sumY);
02124         transdatums[4] = Float8GetDatumFast(sumY2);
02125         transdatums[5] = Float8GetDatumFast(sumXY);
02126 
02127         result = construct_array(transdatums, 6,
02128                                  FLOAT8OID,
02129                                  sizeof(float8), FLOAT8PASSBYVAL, 'd');
02130 
02131         PG_RETURN_ARRAYTYPE_P(result);
02132     }
02133 }
02134 
02135 Datum
02136 float8_regr_sxx(PG_FUNCTION_ARGS)
02137 {
02138     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02139     float8     *transvalues;
02140     float8      N,
02141                 sumX,
02142                 sumX2,
02143                 numerator;
02144 
02145     transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
02146     N = transvalues[0];
02147     sumX = transvalues[1];
02148     sumX2 = transvalues[2];
02149 
02150     /* if N is 0 we should return NULL */
02151     if (N < 1.0)
02152         PG_RETURN_NULL();
02153 
02154     numerator = N * sumX2 - sumX * sumX;
02155     CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
02156 
02157     /* Watch out for roundoff error producing a negative numerator */
02158     if (numerator <= 0.0)
02159         PG_RETURN_FLOAT8(0.0);
02160 
02161     PG_RETURN_FLOAT8(numerator / N);
02162 }
02163 
02164 Datum
02165 float8_regr_syy(PG_FUNCTION_ARGS)
02166 {
02167     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02168     float8     *transvalues;
02169     float8      N,
02170                 sumY,
02171                 sumY2,
02172                 numerator;
02173 
02174     transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
02175     N = transvalues[0];
02176     sumY = transvalues[3];
02177     sumY2 = transvalues[4];
02178 
02179     /* if N is 0 we should return NULL */
02180     if (N < 1.0)
02181         PG_RETURN_NULL();
02182 
02183     numerator = N * sumY2 - sumY * sumY;
02184     CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
02185 
02186     /* Watch out for roundoff error producing a negative numerator */
02187     if (numerator <= 0.0)
02188         PG_RETURN_FLOAT8(0.0);
02189 
02190     PG_RETURN_FLOAT8(numerator / N);
02191 }
02192 
02193 Datum
02194 float8_regr_sxy(PG_FUNCTION_ARGS)
02195 {
02196     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02197     float8     *transvalues;
02198     float8      N,
02199                 sumX,
02200                 sumY,
02201                 sumXY,
02202                 numerator;
02203 
02204     transvalues = check_float8_array(transarray, "float8_regr_sxy", 6);
02205     N = transvalues[0];
02206     sumX = transvalues[1];
02207     sumY = transvalues[3];
02208     sumXY = transvalues[5];
02209 
02210     /* if N is 0 we should return NULL */
02211     if (N < 1.0)
02212         PG_RETURN_NULL();
02213 
02214     numerator = N * sumXY - sumX * sumY;
02215     CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
02216                   isinf(sumY), true);
02217 
02218     /* A negative result is valid here */
02219 
02220     PG_RETURN_FLOAT8(numerator / N);
02221 }
02222 
02223 Datum
02224 float8_regr_avgx(PG_FUNCTION_ARGS)
02225 {
02226     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02227     float8     *transvalues;
02228     float8      N,
02229                 sumX;
02230 
02231     transvalues = check_float8_array(transarray, "float8_regr_avgx", 6);
02232     N = transvalues[0];
02233     sumX = transvalues[1];
02234 
02235     /* if N is 0 we should return NULL */
02236     if (N < 1.0)
02237         PG_RETURN_NULL();
02238 
02239     PG_RETURN_FLOAT8(sumX / N);
02240 }
02241 
02242 Datum
02243 float8_regr_avgy(PG_FUNCTION_ARGS)
02244 {
02245     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02246     float8     *transvalues;
02247     float8      N,
02248                 sumY;
02249 
02250     transvalues = check_float8_array(transarray, "float8_regr_avgy", 6);
02251     N = transvalues[0];
02252     sumY = transvalues[3];
02253 
02254     /* if N is 0 we should return NULL */
02255     if (N < 1.0)
02256         PG_RETURN_NULL();
02257 
02258     PG_RETURN_FLOAT8(sumY / N);
02259 }
02260 
02261 Datum
02262 float8_covar_pop(PG_FUNCTION_ARGS)
02263 {
02264     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02265     float8     *transvalues;
02266     float8      N,
02267                 sumX,
02268                 sumY,
02269                 sumXY,
02270                 numerator;
02271 
02272     transvalues = check_float8_array(transarray, "float8_covar_pop", 6);
02273     N = transvalues[0];
02274     sumX = transvalues[1];
02275     sumY = transvalues[3];
02276     sumXY = transvalues[5];
02277 
02278     /* if N is 0 we should return NULL */
02279     if (N < 1.0)
02280         PG_RETURN_NULL();
02281 
02282     numerator = N * sumXY - sumX * sumY;
02283     CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
02284                   isinf(sumY), true);
02285 
02286     PG_RETURN_FLOAT8(numerator / (N * N));
02287 }
02288 
02289 Datum
02290 float8_covar_samp(PG_FUNCTION_ARGS)
02291 {
02292     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02293     float8     *transvalues;
02294     float8      N,
02295                 sumX,
02296                 sumY,
02297                 sumXY,
02298                 numerator;
02299 
02300     transvalues = check_float8_array(transarray, "float8_covar_samp", 6);
02301     N = transvalues[0];
02302     sumX = transvalues[1];
02303     sumY = transvalues[3];
02304     sumXY = transvalues[5];
02305 
02306     /* if N is <= 1 we should return NULL */
02307     if (N < 2.0)
02308         PG_RETURN_NULL();
02309 
02310     numerator = N * sumXY - sumX * sumY;
02311     CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
02312                   isinf(sumY), true);
02313 
02314     PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
02315 }
02316 
02317 Datum
02318 float8_corr(PG_FUNCTION_ARGS)
02319 {
02320     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02321     float8     *transvalues;
02322     float8      N,
02323                 sumX,
02324                 sumX2,
02325                 sumY,
02326                 sumY2,
02327                 sumXY,
02328                 numeratorX,
02329                 numeratorY,
02330                 numeratorXY;
02331 
02332     transvalues = check_float8_array(transarray, "float8_corr", 6);
02333     N = transvalues[0];
02334     sumX = transvalues[1];
02335     sumX2 = transvalues[2];
02336     sumY = transvalues[3];
02337     sumY2 = transvalues[4];
02338     sumXY = transvalues[5];
02339 
02340     /* if N is 0 we should return NULL */
02341     if (N < 1.0)
02342         PG_RETURN_NULL();
02343 
02344     numeratorX = N * sumX2 - sumX * sumX;
02345     CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
02346     numeratorY = N * sumY2 - sumY * sumY;
02347     CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
02348     numeratorXY = N * sumXY - sumX * sumY;
02349     CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
02350                   isinf(sumY), true);
02351     if (numeratorX <= 0 || numeratorY <= 0)
02352         PG_RETURN_NULL();
02353 
02354     PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
02355 }
02356 
02357 Datum
02358 float8_regr_r2(PG_FUNCTION_ARGS)
02359 {
02360     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02361     float8     *transvalues;
02362     float8      N,
02363                 sumX,
02364                 sumX2,
02365                 sumY,
02366                 sumY2,
02367                 sumXY,
02368                 numeratorX,
02369                 numeratorY,
02370                 numeratorXY;
02371 
02372     transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
02373     N = transvalues[0];
02374     sumX = transvalues[1];
02375     sumX2 = transvalues[2];
02376     sumY = transvalues[3];
02377     sumY2 = transvalues[4];
02378     sumXY = transvalues[5];
02379 
02380     /* if N is 0 we should return NULL */
02381     if (N < 1.0)
02382         PG_RETURN_NULL();
02383 
02384     numeratorX = N * sumX2 - sumX * sumX;
02385     CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
02386     numeratorY = N * sumY2 - sumY * sumY;
02387     CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
02388     numeratorXY = N * sumXY - sumX * sumY;
02389     CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
02390                   isinf(sumY), true);
02391     if (numeratorX <= 0)
02392         PG_RETURN_NULL();
02393     /* per spec, horizontal line produces 1.0 */
02394     if (numeratorY <= 0)
02395         PG_RETURN_FLOAT8(1.0);
02396 
02397     PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
02398                      (numeratorX * numeratorY));
02399 }
02400 
02401 Datum
02402 float8_regr_slope(PG_FUNCTION_ARGS)
02403 {
02404     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02405     float8     *transvalues;
02406     float8      N,
02407                 sumX,
02408                 sumX2,
02409                 sumY,
02410                 sumXY,
02411                 numeratorX,
02412                 numeratorXY;
02413 
02414     transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
02415     N = transvalues[0];
02416     sumX = transvalues[1];
02417     sumX2 = transvalues[2];
02418     sumY = transvalues[3];
02419     sumXY = transvalues[5];
02420 
02421     /* if N is 0 we should return NULL */
02422     if (N < 1.0)
02423         PG_RETURN_NULL();
02424 
02425     numeratorX = N * sumX2 - sumX * sumX;
02426     CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
02427     numeratorXY = N * sumXY - sumX * sumY;
02428     CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
02429                   isinf(sumY), true);
02430     if (numeratorX <= 0)
02431         PG_RETURN_NULL();
02432 
02433     PG_RETURN_FLOAT8(numeratorXY / numeratorX);
02434 }
02435 
02436 Datum
02437 float8_regr_intercept(PG_FUNCTION_ARGS)
02438 {
02439     ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
02440     float8     *transvalues;
02441     float8      N,
02442                 sumX,
02443                 sumX2,
02444                 sumY,
02445                 sumXY,
02446                 numeratorX,
02447                 numeratorXXY;
02448 
02449     transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
02450     N = transvalues[0];
02451     sumX = transvalues[1];
02452     sumX2 = transvalues[2];
02453     sumY = transvalues[3];
02454     sumXY = transvalues[5];
02455 
02456     /* if N is 0 we should return NULL */
02457     if (N < 1.0)
02458         PG_RETURN_NULL();
02459 
02460     numeratorX = N * sumX2 - sumX * sumX;
02461     CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
02462     numeratorXXY = sumY * sumX2 - sumX * sumXY;
02463     CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
02464                   isinf(sumX) || isinf(sumXY), true);
02465     if (numeratorX <= 0)
02466         PG_RETURN_NULL();
02467 
02468     PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
02469 }
02470 
02471 
02472 /*
02473  *      ====================================
02474  *      MIXED-PRECISION ARITHMETIC OPERATORS
02475  *      ====================================
02476  */
02477 
02478 /*
02479  *      float48pl       - returns arg1 + arg2
02480  *      float48mi       - returns arg1 - arg2
02481  *      float48mul      - returns arg1 * arg2
02482  *      float48div      - returns arg1 / arg2
02483  */
02484 Datum
02485 float48pl(PG_FUNCTION_ARGS)
02486 {
02487     float4      arg1 = PG_GETARG_FLOAT4(0);
02488     float8      arg2 = PG_GETARG_FLOAT8(1);
02489     float8      result;
02490 
02491     result = arg1 + arg2;
02492     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
02493     PG_RETURN_FLOAT8(result);
02494 }
02495 
02496 Datum
02497 float48mi(PG_FUNCTION_ARGS)
02498 {
02499     float4      arg1 = PG_GETARG_FLOAT4(0);
02500     float8      arg2 = PG_GETARG_FLOAT8(1);
02501     float8      result;
02502 
02503     result = arg1 - arg2;
02504     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
02505     PG_RETURN_FLOAT8(result);
02506 }
02507 
02508 Datum
02509 float48mul(PG_FUNCTION_ARGS)
02510 {
02511     float4      arg1 = PG_GETARG_FLOAT4(0);
02512     float8      arg2 = PG_GETARG_FLOAT8(1);
02513     float8      result;
02514 
02515     result = arg1 * arg2;
02516     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
02517                   arg1 == 0 || arg2 == 0);
02518     PG_RETURN_FLOAT8(result);
02519 }
02520 
02521 Datum
02522 float48div(PG_FUNCTION_ARGS)
02523 {
02524     float4      arg1 = PG_GETARG_FLOAT4(0);
02525     float8      arg2 = PG_GETARG_FLOAT8(1);
02526     float8      result;
02527 
02528     if (arg2 == 0.0)
02529         ereport(ERROR,
02530                 (errcode(ERRCODE_DIVISION_BY_ZERO),
02531                  errmsg("division by zero")));
02532 
02533     result = arg1 / arg2;
02534     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
02535     PG_RETURN_FLOAT8(result);
02536 }
02537 
02538 /*
02539  *      float84pl       - returns arg1 + arg2
02540  *      float84mi       - returns arg1 - arg2
02541  *      float84mul      - returns arg1 * arg2
02542  *      float84div      - returns arg1 / arg2
02543  */
02544 Datum
02545 float84pl(PG_FUNCTION_ARGS)
02546 {
02547     float8      arg1 = PG_GETARG_FLOAT8(0);
02548     float4      arg2 = PG_GETARG_FLOAT4(1);
02549     float8      result;
02550 
02551     result = arg1 + arg2;
02552 
02553     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
02554     PG_RETURN_FLOAT8(result);
02555 }
02556 
02557 Datum
02558 float84mi(PG_FUNCTION_ARGS)
02559 {
02560     float8      arg1 = PG_GETARG_FLOAT8(0);
02561     float4      arg2 = PG_GETARG_FLOAT4(1);
02562     float8      result;
02563 
02564     result = arg1 - arg2;
02565 
02566     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
02567     PG_RETURN_FLOAT8(result);
02568 }
02569 
02570 Datum
02571 float84mul(PG_FUNCTION_ARGS)
02572 {
02573     float8      arg1 = PG_GETARG_FLOAT8(0);
02574     float4      arg2 = PG_GETARG_FLOAT4(1);
02575     float8      result;
02576 
02577     result = arg1 * arg2;
02578 
02579     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
02580                   arg1 == 0 || arg2 == 0);
02581     PG_RETURN_FLOAT8(result);
02582 }
02583 
02584 Datum
02585 float84div(PG_FUNCTION_ARGS)
02586 {
02587     float8      arg1 = PG_GETARG_FLOAT8(0);
02588     float4      arg2 = PG_GETARG_FLOAT4(1);
02589     float8      result;
02590 
02591     if (arg2 == 0.0)
02592         ereport(ERROR,
02593                 (errcode(ERRCODE_DIVISION_BY_ZERO),
02594                  errmsg("division by zero")));
02595 
02596     result = arg1 / arg2;
02597 
02598     CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
02599     PG_RETURN_FLOAT8(result);
02600 }
02601 
02602 /*
02603  *      ====================
02604  *      COMPARISON OPERATORS
02605  *      ====================
02606  */
02607 
02608 /*
02609  *      float48{eq,ne,lt,le,gt,ge}      - float4/float8 comparison operations
02610  */
02611 Datum
02612 float48eq(PG_FUNCTION_ARGS)
02613 {
02614     float4      arg1 = PG_GETARG_FLOAT4(0);
02615     float8      arg2 = PG_GETARG_FLOAT8(1);
02616 
02617     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
02618 }
02619 
02620 Datum
02621 float48ne(PG_FUNCTION_ARGS)
02622 {
02623     float4      arg1 = PG_GETARG_FLOAT4(0);
02624     float8      arg2 = PG_GETARG_FLOAT8(1);
02625 
02626     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
02627 }
02628 
02629 Datum
02630 float48lt(PG_FUNCTION_ARGS)
02631 {
02632     float4      arg1 = PG_GETARG_FLOAT4(0);
02633     float8      arg2 = PG_GETARG_FLOAT8(1);
02634 
02635     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
02636 }
02637 
02638 Datum
02639 float48le(PG_FUNCTION_ARGS)
02640 {
02641     float4      arg1 = PG_GETARG_FLOAT4(0);
02642     float8      arg2 = PG_GETARG_FLOAT8(1);
02643 
02644     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
02645 }
02646 
02647 Datum
02648 float48gt(PG_FUNCTION_ARGS)
02649 {
02650     float4      arg1 = PG_GETARG_FLOAT4(0);
02651     float8      arg2 = PG_GETARG_FLOAT8(1);
02652 
02653     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
02654 }
02655 
02656 Datum
02657 float48ge(PG_FUNCTION_ARGS)
02658 {
02659     float4      arg1 = PG_GETARG_FLOAT4(0);
02660     float8      arg2 = PG_GETARG_FLOAT8(1);
02661 
02662     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
02663 }
02664 
02665 /*
02666  *      float84{eq,ne,lt,le,gt,ge}      - float8/float4 comparison operations
02667  */
02668 Datum
02669 float84eq(PG_FUNCTION_ARGS)
02670 {
02671     float8      arg1 = PG_GETARG_FLOAT8(0);
02672     float4      arg2 = PG_GETARG_FLOAT4(1);
02673 
02674     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
02675 }
02676 
02677 Datum
02678 float84ne(PG_FUNCTION_ARGS)
02679 {
02680     float8      arg1 = PG_GETARG_FLOAT8(0);
02681     float4      arg2 = PG_GETARG_FLOAT4(1);
02682 
02683     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
02684 }
02685 
02686 Datum
02687 float84lt(PG_FUNCTION_ARGS)
02688 {
02689     float8      arg1 = PG_GETARG_FLOAT8(0);
02690     float4      arg2 = PG_GETARG_FLOAT4(1);
02691 
02692     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
02693 }
02694 
02695 Datum
02696 float84le(PG_FUNCTION_ARGS)
02697 {
02698     float8      arg1 = PG_GETARG_FLOAT8(0);
02699     float4      arg2 = PG_GETARG_FLOAT4(1);
02700 
02701     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
02702 }
02703 
02704 Datum
02705 float84gt(PG_FUNCTION_ARGS)
02706 {
02707     float8      arg1 = PG_GETARG_FLOAT8(0);
02708     float4      arg2 = PG_GETARG_FLOAT4(1);
02709 
02710     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
02711 }
02712 
02713 Datum
02714 float84ge(PG_FUNCTION_ARGS)
02715 {
02716     float8      arg1 = PG_GETARG_FLOAT8(0);
02717     float4      arg2 = PG_GETARG_FLOAT4(1);
02718 
02719     PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
02720 }
02721 
02722 /*
02723  * Implements the float8 version of the width_bucket() function
02724  * defined by SQL2003. See also width_bucket_numeric().
02725  *
02726  * 'bound1' and 'bound2' are the lower and upper bounds of the
02727  * histogram's range, respectively. 'count' is the number of buckets
02728  * in the histogram. width_bucket() returns an integer indicating the
02729  * bucket number that 'operand' belongs to in an equiwidth histogram
02730  * with the specified characteristics. An operand smaller than the
02731  * lower bound is assigned to bucket 0. An operand greater than the
02732  * upper bound is assigned to an additional bucket (with number
02733  * count+1). We don't allow "NaN" for any of the float8 inputs, and we
02734  * don't allow either of the histogram bounds to be +/- infinity.
02735  */
02736 Datum
02737 width_bucket_float8(PG_FUNCTION_ARGS)
02738 {
02739     float8      operand = PG_GETARG_FLOAT8(0);
02740     float8      bound1 = PG_GETARG_FLOAT8(1);
02741     float8      bound2 = PG_GETARG_FLOAT8(2);
02742     int32       count = PG_GETARG_INT32(3);
02743     int32       result;
02744 
02745     if (count <= 0.0)
02746         ereport(ERROR,
02747                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
02748                  errmsg("count must be greater than zero")));
02749 
02750     if (isnan(operand) || isnan(bound1) || isnan(bound2))
02751         ereport(ERROR,
02752                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
02753              errmsg("operand, lower bound, and upper bound cannot be NaN")));
02754 
02755     /* Note that we allow "operand" to be infinite */
02756     if (isinf(bound1) || isinf(bound2))
02757         ereport(ERROR,
02758                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
02759                  errmsg("lower and upper bounds must be finite")));
02760 
02761     if (bound1 < bound2)
02762     {
02763         if (operand < bound1)
02764             result = 0;
02765         else if (operand >= bound2)
02766         {
02767             result = count + 1;
02768             /* check for overflow */
02769             if (result < count)
02770                 ereport(ERROR,
02771                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
02772                          errmsg("integer out of range")));
02773         }
02774         else
02775             result = ((float8) count * (operand - bound1) / (bound2 - bound1)) + 1;
02776     }
02777     else if (bound1 > bound2)
02778     {
02779         if (operand > bound1)
02780             result = 0;
02781         else if (operand <= bound2)
02782         {
02783             result = count + 1;
02784             /* check for overflow */
02785             if (result < count)
02786                 ereport(ERROR,
02787                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
02788                          errmsg("integer out of range")));
02789         }
02790         else
02791             result = ((float8) count * (bound1 - operand) / (bound1 - bound2)) + 1;
02792     }
02793     else
02794     {
02795         ereport(ERROR,
02796                 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
02797                  errmsg("lower bound cannot equal upper bound")));
02798         result = 0;             /* keep the compiler quiet */
02799     }
02800 
02801     PG_RETURN_INT32(result);
02802 }
02803 
02804 /* ========== PRIVATE ROUTINES ========== */
02805 
02806 #ifndef HAVE_CBRT
02807 
02808 static double
02809 cbrt(double x)
02810 {
02811     int         isneg = (x < 0.0);
02812     double      absx = fabs(x);
02813     double      tmpres = pow(absx, (double) 1.0 / (double) 3.0);
02814 
02815     /*
02816      * The result is somewhat inaccurate --- not really pow()'s fault, as the
02817      * exponent it's handed contains roundoff error.  We can improve the
02818      * accuracy by doing one iteration of Newton's formula.  Beware of zero
02819      * input however.
02820      */
02821     if (tmpres > 0.0)
02822         tmpres -= (tmpres - absx / (tmpres * tmpres)) / (double) 3.0;
02823 
02824     return isneg ? -tmpres : tmpres;
02825 }
02826 
02827 #endif   /* !HAVE_CBRT */