1 /*-------------------------------------------------------------------------
4 * Functions for the built-in floating-point types.
6 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/float.c
13 *-------------------------------------------------------------------------
22 #include "catalog/pg_type.h"
23 #include "libpq/pqformat.h"
24 #include "utils/array.h"
25 #include "utils/builtins.h"
29 /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
30 #define M_PI 3.14159265358979323846
33 /* Visual C++ etc lacks NAN, and won't accept 0.0/0.0. NAN definition from
34 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
36 #if defined(WIN32) && !defined(NAN)
37 static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
39 #define NAN (*(const double *) nan)
42 /* not sure what the following should be, but better to make it over-sufficient */
43 #define MAXFLOATWIDTH 64
44 #define MAXDOUBLEWIDTH 128
47 * check to see if a float4/8 val has underflowed or overflowed
49 #define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid) \
51 if (isinf(val) && !(inf_is_valid)) \
53 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \
54 errmsg("value out of range: overflow"))); \
56 if ((val) == 0.0 && !(zero_is_valid)) \
58 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \
59 errmsg("value out of range: underflow"))); \
63 /* ========== USER I/O ROUTINES ========== */
66 /* Configurable GUC parameter */
67 int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
70 static int float4_cmp_internal(float4 a, float4 b);
71 static int float8_cmp_internal(float8 a, float8 b);
75 * Some machines (in particular, some versions of AIX) have an extern
76 * declaration for cbrt() in <math.h> but fail to provide the actual
77 * function, which causes configure to not set HAVE_CBRT. Furthermore,
78 * their compilers spit up at the mismatch between extern declaration
79 * and static definition. We work around that here by the expedient
80 * of a #define to make the actual name of the static function different.
83 static double cbrt(double x);
84 #endif /* HAVE_CBRT */
88 * Routines to provide reasonably platform-independent handling of
89 * infinity and NaN. We assume that isinf() and isnan() are available
90 * and work per spec. (On some platforms, we have to supply our own;
91 * see src/port.) However, generating an Infinity or NaN in the first
92 * place is less well standardized; pre-C99 systems tend not to have C99's
93 * INFINITY and NAN macros. We centralize our workarounds for this here.
97 get_float8_infinity(void)
100 /* C99 standard way */
101 return (double) INFINITY;
105 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
106 * largest normal double. We assume forcing an overflow will get us a
109 return (double) (HUGE_VAL * HUGE_VAL);
114 get_float4_infinity(void)
117 /* C99 standard way */
118 return (float) INFINITY;
122 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
123 * largest normal double. We assume forcing an overflow will get us a
126 return (float) (HUGE_VAL * HUGE_VAL);
133 /* (double) NAN doesn't work on some NetBSD/MIPS releases */
134 #if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
135 /* C99 standard way */
138 /* Assume we can get a NAN via zero divide */
139 return (double) (0.0 / 0.0);
147 /* C99 standard way */
150 /* Assume we can get a NAN via zero divide */
151 return (float) (0.0 / 0.0);
157 * Returns -1 if 'val' represents negative infinity, 1 if 'val'
158 * represents (positive) infinity, and 0 otherwise. On some platforms,
159 * this is equivalent to the isinf() macro, but not everywhere: C99
160 * does not specify that isinf() needs to distinguish between positive
161 * and negative infinity.
164 is_infinite(double val)
166 int inf = isinf(val);
178 * float4in - converts "num" to float
180 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
181 * where <sp> is a space, digit is 0-9,
182 * <exp> is "e" or "E" followed by an integer.
185 float4in(PG_FUNCTION_ARGS)
187 char *num = PG_GETARG_CSTRING(0);
193 * endptr points to the first character _after_ the sequence we recognized
194 * as a valid floating point number. orig_num points to the original input
200 * Check for an empty-string input to begin with, to avoid the vagaries of
201 * strtod() on different platforms.
205 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
206 errmsg("invalid input syntax for type real: \"%s\"",
209 /* skip leading whitespace */
210 while (*num != '\0' && isspace((unsigned char) *num))
214 val = strtod(num, &endptr);
216 /* did we not see anything that looks like a double? */
217 if (endptr == num || errno != 0)
220 * C99 requires that strtod() accept NaN and [-]Infinity, but not all
221 * platforms support that yet (and some accept them but set ERANGE
222 * anyway...) Therefore, we check for these inputs ourselves.
224 if (pg_strncasecmp(num, "NaN", 3) == 0)
226 val = get_float4_nan();
229 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
231 val = get_float4_infinity();
234 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
236 val = -get_float4_infinity();
239 else if (errno == ERANGE)
241 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
242 errmsg("\"%s\" is out of range for type real",
246 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
247 errmsg("invalid input syntax for type real: \"%s\"",
250 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
254 * Many versions of Solaris have a bug wherein strtod sets endptr to
255 * point one byte beyond the end of the string when given "inf" or
258 if (endptr != num && endptr[-1] == '\0')
261 #endif /* HAVE_BUGGY_SOLARIS_STRTOD */
263 #ifdef HAVE_BUGGY_IRIX_STRTOD
266 * In some IRIX versions, strtod() recognizes only "inf", so if the input
267 * is "infinity" we have to skip over "inity". Also, it may return
268 * positive infinity for "-inf".
272 if (pg_strncasecmp(num, "Infinity", 8) == 0)
274 val = get_float4_infinity();
277 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
279 val = -get_float4_infinity();
282 else if (pg_strncasecmp(num, "-inf", 4) == 0)
284 val = -get_float4_infinity();
288 #endif /* HAVE_BUGGY_IRIX_STRTOD */
290 /* skip trailing whitespace */
291 while (*endptr != '\0' && isspace((unsigned char) *endptr))
294 /* if there is any junk left at the end of the string, bail out */
297 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
298 errmsg("invalid input syntax for type real: \"%s\"",
302 * if we get here, we have a legal double, still need to check to see if
303 * it's a legal float4
305 CHECKFLOATVAL((float4) val, isinf(val), val == 0);
307 PG_RETURN_FLOAT4((float4) val);
311 * float4out - converts a float4 number to a string
312 * using a standard output format
315 float4out(PG_FUNCTION_ARGS)
317 float4 num = PG_GETARG_FLOAT4(0);
318 char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
321 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
323 switch (is_infinite(num))
326 strcpy(ascii, "Infinity");
329 strcpy(ascii, "-Infinity");
333 int ndig = FLT_DIG + extra_float_digits;
338 snprintf(ascii, MAXFLOATWIDTH + 1, "%.*g", ndig, num);
342 PG_RETURN_CSTRING(ascii);
346 * float4recv - converts external binary format to float4
349 float4recv(PG_FUNCTION_ARGS)
351 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
353 PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));
357 * float4send - converts float4 to binary format
360 float4send(PG_FUNCTION_ARGS)
362 float4 num = PG_GETARG_FLOAT4(0);
365 pq_begintypsend(&buf);
366 pq_sendfloat4(&buf, num);
367 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
371 * float8in - converts "num" to float8
373 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
374 * where <sp> is a space, digit is 0-9,
375 * <exp> is "e" or "E" followed by an integer.
378 float8in(PG_FUNCTION_ARGS)
380 char *num = PG_GETARG_CSTRING(0);
386 * endptr points to the first character _after_ the sequence we recognized
387 * as a valid floating point number. orig_num points to the original input
393 * Check for an empty-string input to begin with, to avoid the vagaries of
394 * strtod() on different platforms.
398 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
399 errmsg("invalid input syntax for type double precision: \"%s\"",
402 /* skip leading whitespace */
403 while (*num != '\0' && isspace((unsigned char) *num))
407 val = strtod(num, &endptr);
409 /* did we not see anything that looks like a double? */
410 if (endptr == num || errno != 0)
413 * C99 requires that strtod() accept NaN and [-]Infinity, but not all
414 * platforms support that yet (and some accept them but set ERANGE
415 * anyway...) Therefore, we check for these inputs ourselves.
417 if (pg_strncasecmp(num, "NaN", 3) == 0)
419 val = get_float8_nan();
422 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
424 val = get_float8_infinity();
427 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
429 val = -get_float8_infinity();
432 else if (errno == ERANGE)
434 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
435 errmsg("\"%s\" is out of range for type double precision",
439 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
440 errmsg("invalid input syntax for type double precision: \"%s\"",
443 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
447 * Many versions of Solaris have a bug wherein strtod sets endptr to
448 * point one byte beyond the end of the string when given "inf" or
451 if (endptr != num && endptr[-1] == '\0')
454 #endif /* HAVE_BUGGY_SOLARIS_STRTOD */
456 #ifdef HAVE_BUGGY_IRIX_STRTOD
459 * In some IRIX versions, strtod() recognizes only "inf", so if the input
460 * is "infinity" we have to skip over "inity". Also, it may return
461 * positive infinity for "-inf".
465 if (pg_strncasecmp(num, "Infinity", 8) == 0)
467 val = get_float8_infinity();
470 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
472 val = -get_float8_infinity();
475 else if (pg_strncasecmp(num, "-inf", 4) == 0)
477 val = -get_float8_infinity();
481 #endif /* HAVE_BUGGY_IRIX_STRTOD */
483 /* skip trailing whitespace */
484 while (*endptr != '\0' && isspace((unsigned char) *endptr))
487 /* if there is any junk left at the end of the string, bail out */
490 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
491 errmsg("invalid input syntax for type double precision: \"%s\"",
494 CHECKFLOATVAL(val, true, true);
496 PG_RETURN_FLOAT8(val);
500 * float8out - converts float8 number to a string
501 * using a standard output format
504 float8out(PG_FUNCTION_ARGS)
506 float8 num = PG_GETARG_FLOAT8(0);
507 char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
510 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
512 switch (is_infinite(num))
515 strcpy(ascii, "Infinity");
518 strcpy(ascii, "-Infinity");
522 int ndig = DBL_DIG + extra_float_digits;
527 snprintf(ascii, MAXDOUBLEWIDTH + 1, "%.*g", ndig, num);
531 PG_RETURN_CSTRING(ascii);
535 * float8recv - converts external binary format to float8
538 float8recv(PG_FUNCTION_ARGS)
540 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
542 PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));
546 * float8send - converts float8 to binary format
549 float8send(PG_FUNCTION_ARGS)
551 float8 num = PG_GETARG_FLOAT8(0);
554 pq_begintypsend(&buf);
555 pq_sendfloat8(&buf, num);
556 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
560 /* ========== PUBLIC ROUTINES ========== */
564 * ======================
565 * FLOAT4 BASE OPERATIONS
566 * ======================
570 * float4abs - returns |arg1| (absolute value)
573 float4abs(PG_FUNCTION_ARGS)
575 float4 arg1 = PG_GETARG_FLOAT4(0);
577 PG_RETURN_FLOAT4((float4) fabs(arg1));
581 * float4um - returns -arg1 (unary minus)
584 float4um(PG_FUNCTION_ARGS)
586 float4 arg1 = PG_GETARG_FLOAT4(0);
590 PG_RETURN_FLOAT4(result);
594 float4up(PG_FUNCTION_ARGS)
596 float4 arg = PG_GETARG_FLOAT4(0);
598 PG_RETURN_FLOAT4(arg);
602 float4larger(PG_FUNCTION_ARGS)
604 float4 arg1 = PG_GETARG_FLOAT4(0);
605 float4 arg2 = PG_GETARG_FLOAT4(1);
608 if (float4_cmp_internal(arg1, arg2) > 0)
612 PG_RETURN_FLOAT4(result);
616 float4smaller(PG_FUNCTION_ARGS)
618 float4 arg1 = PG_GETARG_FLOAT4(0);
619 float4 arg2 = PG_GETARG_FLOAT4(1);
622 if (float4_cmp_internal(arg1, arg2) < 0)
626 PG_RETURN_FLOAT4(result);
630 * ======================
631 * FLOAT8 BASE OPERATIONS
632 * ======================
636 * float8abs - returns |arg1| (absolute value)
639 float8abs(PG_FUNCTION_ARGS)
641 float8 arg1 = PG_GETARG_FLOAT8(0);
643 PG_RETURN_FLOAT8(fabs(arg1));
648 * float8um - returns -arg1 (unary minus)
651 float8um(PG_FUNCTION_ARGS)
653 float8 arg1 = PG_GETARG_FLOAT8(0);
657 PG_RETURN_FLOAT8(result);
661 float8up(PG_FUNCTION_ARGS)
663 float8 arg = PG_GETARG_FLOAT8(0);
665 PG_RETURN_FLOAT8(arg);
669 float8larger(PG_FUNCTION_ARGS)
671 float8 arg1 = PG_GETARG_FLOAT8(0);
672 float8 arg2 = PG_GETARG_FLOAT8(1);
675 if (float8_cmp_internal(arg1, arg2) > 0)
679 PG_RETURN_FLOAT8(result);
683 float8smaller(PG_FUNCTION_ARGS)
685 float8 arg1 = PG_GETARG_FLOAT8(0);
686 float8 arg2 = PG_GETARG_FLOAT8(1);
689 if (float8_cmp_internal(arg1, arg2) < 0)
693 PG_RETURN_FLOAT8(result);
698 * ====================
699 * ARITHMETIC OPERATORS
700 * ====================
704 * float4pl - returns arg1 + arg2
705 * float4mi - returns arg1 - arg2
706 * float4mul - returns arg1 * arg2
707 * float4div - returns arg1 / arg2
710 float4pl(PG_FUNCTION_ARGS)
712 float4 arg1 = PG_GETARG_FLOAT4(0);
713 float4 arg2 = PG_GETARG_FLOAT4(1);
716 result = arg1 + arg2;
719 * There isn't any way to check for underflow of addition/subtraction
720 * because numbers near the underflow value have already been rounded to
721 * the point where we can't detect that the two values were originally
722 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
725 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
726 PG_RETURN_FLOAT4(result);
730 float4mi(PG_FUNCTION_ARGS)
732 float4 arg1 = PG_GETARG_FLOAT4(0);
733 float4 arg2 = PG_GETARG_FLOAT4(1);
736 result = arg1 - arg2;
737 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
738 PG_RETURN_FLOAT4(result);
742 float4mul(PG_FUNCTION_ARGS)
744 float4 arg1 = PG_GETARG_FLOAT4(0);
745 float4 arg2 = PG_GETARG_FLOAT4(1);
748 result = arg1 * arg2;
749 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
750 arg1 == 0 || arg2 == 0);
751 PG_RETURN_FLOAT4(result);
755 float4div(PG_FUNCTION_ARGS)
757 float4 arg1 = PG_GETARG_FLOAT4(0);
758 float4 arg2 = PG_GETARG_FLOAT4(1);
763 (errcode(ERRCODE_DIVISION_BY_ZERO),
764 errmsg("division by zero")));
766 result = arg1 / arg2;
768 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
769 PG_RETURN_FLOAT4(result);
773 * float8pl - returns arg1 + arg2
774 * float8mi - returns arg1 - arg2
775 * float8mul - returns arg1 * arg2
776 * float8div - returns arg1 / arg2
779 float8pl(PG_FUNCTION_ARGS)
781 float8 arg1 = PG_GETARG_FLOAT8(0);
782 float8 arg2 = PG_GETARG_FLOAT8(1);
785 result = arg1 + arg2;
787 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
788 PG_RETURN_FLOAT8(result);
792 float8mi(PG_FUNCTION_ARGS)
794 float8 arg1 = PG_GETARG_FLOAT8(0);
795 float8 arg2 = PG_GETARG_FLOAT8(1);
798 result = arg1 - arg2;
800 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
801 PG_RETURN_FLOAT8(result);
805 float8mul(PG_FUNCTION_ARGS)
807 float8 arg1 = PG_GETARG_FLOAT8(0);
808 float8 arg2 = PG_GETARG_FLOAT8(1);
811 result = arg1 * arg2;
813 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
814 arg1 == 0 || arg2 == 0);
815 PG_RETURN_FLOAT8(result);
819 float8div(PG_FUNCTION_ARGS)
821 float8 arg1 = PG_GETARG_FLOAT8(0);
822 float8 arg2 = PG_GETARG_FLOAT8(1);
827 (errcode(ERRCODE_DIVISION_BY_ZERO),
828 errmsg("division by zero")));
830 result = arg1 / arg2;
832 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
833 PG_RETURN_FLOAT8(result);
838 * ====================
839 * COMPARISON OPERATORS
840 * ====================
844 * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
847 float4_cmp_internal(float4 a, float4 b)
850 * We consider all NANs to be equal and larger than any non-NAN. This is
851 * somewhat arbitrary; the important thing is to have a consistent sort
857 return 0; /* NAN = NAN */
859 return 1; /* NAN > non-NAN */
863 return -1; /* non-NAN < NAN */
877 float4eq(PG_FUNCTION_ARGS)
879 float4 arg1 = PG_GETARG_FLOAT4(0);
880 float4 arg2 = PG_GETARG_FLOAT4(1);
882 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
886 float4ne(PG_FUNCTION_ARGS)
888 float4 arg1 = PG_GETARG_FLOAT4(0);
889 float4 arg2 = PG_GETARG_FLOAT4(1);
891 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
895 float4lt(PG_FUNCTION_ARGS)
897 float4 arg1 = PG_GETARG_FLOAT4(0);
898 float4 arg2 = PG_GETARG_FLOAT4(1);
900 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
904 float4le(PG_FUNCTION_ARGS)
906 float4 arg1 = PG_GETARG_FLOAT4(0);
907 float4 arg2 = PG_GETARG_FLOAT4(1);
909 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
913 float4gt(PG_FUNCTION_ARGS)
915 float4 arg1 = PG_GETARG_FLOAT4(0);
916 float4 arg2 = PG_GETARG_FLOAT4(1);
918 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
922 float4ge(PG_FUNCTION_ARGS)
924 float4 arg1 = PG_GETARG_FLOAT4(0);
925 float4 arg2 = PG_GETARG_FLOAT4(1);
927 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
931 btfloat4cmp(PG_FUNCTION_ARGS)
933 float4 arg1 = PG_GETARG_FLOAT4(0);
934 float4 arg2 = PG_GETARG_FLOAT4(1);
936 PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
940 * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
943 float8_cmp_internal(float8 a, float8 b)
946 * We consider all NANs to be equal and larger than any non-NAN. This is
947 * somewhat arbitrary; the important thing is to have a consistent sort
953 return 0; /* NAN = NAN */
955 return 1; /* NAN > non-NAN */
959 return -1; /* non-NAN < NAN */
973 float8eq(PG_FUNCTION_ARGS)
975 float8 arg1 = PG_GETARG_FLOAT8(0);
976 float8 arg2 = PG_GETARG_FLOAT8(1);
978 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
982 float8ne(PG_FUNCTION_ARGS)
984 float8 arg1 = PG_GETARG_FLOAT8(0);
985 float8 arg2 = PG_GETARG_FLOAT8(1);
987 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
991 float8lt(PG_FUNCTION_ARGS)
993 float8 arg1 = PG_GETARG_FLOAT8(0);
994 float8 arg2 = PG_GETARG_FLOAT8(1);
996 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
1000 float8le(PG_FUNCTION_ARGS)
1002 float8 arg1 = PG_GETARG_FLOAT8(0);
1003 float8 arg2 = PG_GETARG_FLOAT8(1);
1005 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1009 float8gt(PG_FUNCTION_ARGS)
1011 float8 arg1 = PG_GETARG_FLOAT8(0);
1012 float8 arg2 = PG_GETARG_FLOAT8(1);
1014 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1018 float8ge(PG_FUNCTION_ARGS)
1020 float8 arg1 = PG_GETARG_FLOAT8(0);
1021 float8 arg2 = PG_GETARG_FLOAT8(1);
1023 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1027 btfloat8cmp(PG_FUNCTION_ARGS)
1029 float8 arg1 = PG_GETARG_FLOAT8(0);
1030 float8 arg2 = PG_GETARG_FLOAT8(1);
1032 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
1036 btfloat48cmp(PG_FUNCTION_ARGS)
1038 float4 arg1 = PG_GETARG_FLOAT4(0);
1039 float8 arg2 = PG_GETARG_FLOAT8(1);
1041 /* widen float4 to float8 and then compare */
1042 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
1046 btfloat84cmp(PG_FUNCTION_ARGS)
1048 float8 arg1 = PG_GETARG_FLOAT8(0);
1049 float4 arg2 = PG_GETARG_FLOAT4(1);
1051 /* widen float4 to float8 and then compare */
1052 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
1057 * ===================
1058 * CONVERSION ROUTINES
1059 * ===================
1063 * ftod - converts a float4 number to a float8 number
1066 ftod(PG_FUNCTION_ARGS)
1068 float4 num = PG_GETARG_FLOAT4(0);
1070 PG_RETURN_FLOAT8((float8) num);
1075 * dtof - converts a float8 number to a float4 number
1078 dtof(PG_FUNCTION_ARGS)
1080 float8 num = PG_GETARG_FLOAT8(0);
1082 CHECKFLOATVAL((float4) num, isinf(num), num == 0);
1084 PG_RETURN_FLOAT4((float4) num);
1089 * dtoi4 - converts a float8 number to an int4 number
1092 dtoi4(PG_FUNCTION_ARGS)
1094 float8 num = PG_GETARG_FLOAT8(0);
1097 /* 'Inf' is handled by INT_MAX */
1098 if (num < INT_MIN || num > INT_MAX || isnan(num))
1100 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1101 errmsg("integer out of range")));
1103 result = (int32) rint(num);
1104 PG_RETURN_INT32(result);
1109 * dtoi2 - converts a float8 number to an int2 number
1112 dtoi2(PG_FUNCTION_ARGS)
1114 float8 num = PG_GETARG_FLOAT8(0);
1116 if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
1118 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1119 errmsg("smallint out of range")));
1121 PG_RETURN_INT16((int16) rint(num));
1126 * i4tod - converts an int4 number to a float8 number
1129 i4tod(PG_FUNCTION_ARGS)
1131 int32 num = PG_GETARG_INT32(0);
1133 PG_RETURN_FLOAT8((float8) num);
1138 * i2tod - converts an int2 number to a float8 number
1141 i2tod(PG_FUNCTION_ARGS)
1143 int16 num = PG_GETARG_INT16(0);
1145 PG_RETURN_FLOAT8((float8) num);
1150 * ftoi4 - converts a float4 number to an int4 number
1153 ftoi4(PG_FUNCTION_ARGS)
1155 float4 num = PG_GETARG_FLOAT4(0);
1157 if (num < INT_MIN || num > INT_MAX || isnan(num))
1159 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1160 errmsg("integer out of range")));
1162 PG_RETURN_INT32((int32) rint(num));
1167 * ftoi2 - converts a float4 number to an int2 number
1170 ftoi2(PG_FUNCTION_ARGS)
1172 float4 num = PG_GETARG_FLOAT4(0);
1174 if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
1176 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1177 errmsg("smallint out of range")));
1179 PG_RETURN_INT16((int16) rint(num));
1184 * i4tof - converts an int4 number to a float4 number
1187 i4tof(PG_FUNCTION_ARGS)
1189 int32 num = PG_GETARG_INT32(0);
1191 PG_RETURN_FLOAT4((float4) num);
1196 * i2tof - converts an int2 number to a float4 number
1199 i2tof(PG_FUNCTION_ARGS)
1201 int16 num = PG_GETARG_INT16(0);
1203 PG_RETURN_FLOAT4((float4) num);
1208 * =======================
1209 * RANDOM FLOAT8 OPERATORS
1210 * =======================
1214 * dround - returns ROUND(arg1)
1217 dround(PG_FUNCTION_ARGS)
1219 float8 arg1 = PG_GETARG_FLOAT8(0);
1221 PG_RETURN_FLOAT8(rint(arg1));
1225 * dceil - returns the smallest integer greater than or
1226 * equal to the specified float
1229 dceil(PG_FUNCTION_ARGS)
1231 float8 arg1 = PG_GETARG_FLOAT8(0);
1233 PG_RETURN_FLOAT8(ceil(arg1));
1237 * dfloor - returns the largest integer lesser than or
1238 * equal to the specified float
1241 dfloor(PG_FUNCTION_ARGS)
1243 float8 arg1 = PG_GETARG_FLOAT8(0);
1245 PG_RETURN_FLOAT8(floor(arg1));
1249 * dsign - returns -1 if the argument is less than 0, 0
1250 * if the argument is equal to 0, and 1 if the
1251 * argument is greater than zero.
1254 dsign(PG_FUNCTION_ARGS)
1256 float8 arg1 = PG_GETARG_FLOAT8(0);
1266 PG_RETURN_FLOAT8(result);
1270 * dtrunc - returns truncation-towards-zero of arg1,
1271 * arg1 >= 0 ... the greatest integer less
1272 * than or equal to arg1
1273 * arg1 < 0 ... the least integer greater
1274 * than or equal to arg1
1277 dtrunc(PG_FUNCTION_ARGS)
1279 float8 arg1 = PG_GETARG_FLOAT8(0);
1283 result = floor(arg1);
1285 result = -floor(-arg1);
1287 PG_RETURN_FLOAT8(result);
1292 * dsqrt - returns square root of arg1
1295 dsqrt(PG_FUNCTION_ARGS)
1297 float8 arg1 = PG_GETARG_FLOAT8(0);
1302 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
1303 errmsg("cannot take square root of a negative number")));
1305 result = sqrt(arg1);
1307 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1308 PG_RETURN_FLOAT8(result);
1313 * dcbrt - returns cube root of arg1
1316 dcbrt(PG_FUNCTION_ARGS)
1318 float8 arg1 = PG_GETARG_FLOAT8(0);
1321 result = cbrt(arg1);
1322 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1323 PG_RETURN_FLOAT8(result);
1328 * dpow - returns pow(arg1,arg2)
1331 dpow(PG_FUNCTION_ARGS)
1333 float8 arg1 = PG_GETARG_FLOAT8(0);
1334 float8 arg2 = PG_GETARG_FLOAT8(1);
1338 * The SQL spec requires that we emit a particular SQLSTATE error code for
1339 * certain error conditions. Specifically, we don't return a
1340 * divide-by-zero error code for 0 ^ -1.
1342 if (arg1 == 0 && arg2 < 0)
1344 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
1345 errmsg("zero raised to a negative power is undefined")));
1346 if (arg1 < 0 && floor(arg2) != arg2)
1348 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
1349 errmsg("a negative number raised to a non-integer power yields a complex result")));
1352 * pow() sets errno only on some platforms, depending on whether it
1353 * follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using
1354 * errno. However, some platform/CPU combinations return errno == EDOM
1355 * and result == Nan for negative arg1 and very large arg2 (they must be
1356 * using something different from our floor() test to decide it's
1357 * invalid). Other platforms (HPPA) return errno == ERANGE and a large
1358 * (HUGE_VAL) but finite result to signal overflow.
1361 result = pow(arg1, arg2);
1362 if (errno == EDOM && isnan(result))
1364 if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
1365 /* The sign of Inf is not significant in this case. */
1366 result = get_float8_infinity();
1367 else if (fabs(arg1) != 1)
1372 else if (errno == ERANGE && result != 0 && !isinf(result))
1373 result = get_float8_infinity();
1375 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
1376 PG_RETURN_FLOAT8(result);
1381 * dexp - returns the exponential function of arg1
1384 dexp(PG_FUNCTION_ARGS)
1386 float8 arg1 = PG_GETARG_FLOAT8(0);
1391 if (errno == ERANGE && result != 0 && !isinf(result))
1392 result = get_float8_infinity();
1394 CHECKFLOATVAL(result, isinf(arg1), false);
1395 PG_RETURN_FLOAT8(result);
1400 * dlog1 - returns the natural logarithm of arg1
1403 dlog1(PG_FUNCTION_ARGS)
1405 float8 arg1 = PG_GETARG_FLOAT8(0);
1409 * Emit particular SQLSTATE error codes for ln(). This is required by the
1414 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1415 errmsg("cannot take logarithm of zero")));
1418 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1419 errmsg("cannot take logarithm of a negative number")));
1423 CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
1424 PG_RETURN_FLOAT8(result);
1429 * dlog10 - returns the base 10 logarithm of arg1
1432 dlog10(PG_FUNCTION_ARGS)
1434 float8 arg1 = PG_GETARG_FLOAT8(0);
1438 * Emit particular SQLSTATE error codes for log(). The SQL spec doesn't
1439 * define log(), but it does define ln(), so it makes sense to emit the
1440 * same error code for an analogous error condition.
1444 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1445 errmsg("cannot take logarithm of zero")));
1448 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1449 errmsg("cannot take logarithm of a negative number")));
1451 result = log10(arg1);
1453 CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
1454 PG_RETURN_FLOAT8(result);
1459 * dacos - returns the arccos of arg1 (radians)
1462 dacos(PG_FUNCTION_ARGS)
1464 float8 arg1 = PG_GETARG_FLOAT8(0);
1468 * We use errno here because the trigonometric functions are cyclic and
1469 * hard to check for underflow.
1472 result = acos(arg1);
1475 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1476 errmsg("input is out of range")));
1478 CHECKFLOATVAL(result, isinf(arg1), true);
1479 PG_RETURN_FLOAT8(result);
1484 * dasin - returns the arcsin of arg1 (radians)
1487 dasin(PG_FUNCTION_ARGS)
1489 float8 arg1 = PG_GETARG_FLOAT8(0);
1493 result = asin(arg1);
1496 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1497 errmsg("input is out of range")));
1499 CHECKFLOATVAL(result, isinf(arg1), true);
1500 PG_RETURN_FLOAT8(result);
1505 * datan - returns the arctan of arg1 (radians)
1508 datan(PG_FUNCTION_ARGS)
1510 float8 arg1 = PG_GETARG_FLOAT8(0);
1514 result = atan(arg1);
1517 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1518 errmsg("input is out of range")));
1520 CHECKFLOATVAL(result, isinf(arg1), true);
1521 PG_RETURN_FLOAT8(result);
1526 * atan2 - returns the arctan2 of arg1 (radians)
1529 datan2(PG_FUNCTION_ARGS)
1531 float8 arg1 = PG_GETARG_FLOAT8(0);
1532 float8 arg2 = PG_GETARG_FLOAT8(1);
1536 result = atan2(arg1, arg2);
1539 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1540 errmsg("input is out of range")));
1542 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
1543 PG_RETURN_FLOAT8(result);
1548 * dcos - returns the cosine of arg1 (radians)
1551 dcos(PG_FUNCTION_ARGS)
1553 float8 arg1 = PG_GETARG_FLOAT8(0);
1560 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1561 errmsg("input is out of range")));
1563 CHECKFLOATVAL(result, isinf(arg1), true);
1564 PG_RETURN_FLOAT8(result);
1569 * dcot - returns the cotangent of arg1 (radians)
1572 dcot(PG_FUNCTION_ARGS)
1574 float8 arg1 = PG_GETARG_FLOAT8(0);
1581 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1582 errmsg("input is out of range")));
1584 result = 1.0 / result;
1585 CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */ , true);
1586 PG_RETURN_FLOAT8(result);
1591 * dsin - returns the sine of arg1 (radians)
1594 dsin(PG_FUNCTION_ARGS)
1596 float8 arg1 = PG_GETARG_FLOAT8(0);
1603 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1604 errmsg("input is out of range")));
1606 CHECKFLOATVAL(result, isinf(arg1), true);
1607 PG_RETURN_FLOAT8(result);
1612 * dtan - returns the tangent of arg1 (radians)
1615 dtan(PG_FUNCTION_ARGS)
1617 float8 arg1 = PG_GETARG_FLOAT8(0);
1624 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1625 errmsg("input is out of range")));
1627 CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
1628 PG_RETURN_FLOAT8(result);
1633 * degrees - returns degrees converted from radians
1636 degrees(PG_FUNCTION_ARGS)
1638 float8 arg1 = PG_GETARG_FLOAT8(0);
1641 result = arg1 * (180.0 / M_PI);
1643 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1644 PG_RETURN_FLOAT8(result);
1649 * dpi - returns the constant PI
1652 dpi(PG_FUNCTION_ARGS)
1654 PG_RETURN_FLOAT8(M_PI);
1659 * radians - returns radians converted from degrees
1662 radians(PG_FUNCTION_ARGS)
1664 float8 arg1 = PG_GETARG_FLOAT8(0);
1667 result = arg1 * (M_PI / 180.0);
1669 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1670 PG_RETURN_FLOAT8(result);
1675 * drandom - returns a random number
1678 drandom(PG_FUNCTION_ARGS)
1682 /* result [0.0 - 1.0) */
1683 result = (double) random() / ((double) MAX_RANDOM_VALUE + 1);
1685 PG_RETURN_FLOAT8(result);
1690 * setseed - set seed for the random number generator
1693 setseed(PG_FUNCTION_ARGS)
1695 float8 seed = PG_GETARG_FLOAT8(0);
1698 if (seed < -1 || seed > 1)
1699 elog(ERROR, "setseed parameter %f out of range [-1,1]", seed);
1701 iseed = (int) (seed * MAX_RANDOM_VALUE);
1702 srandom((unsigned int) iseed);
1710 * =========================
1711 * FLOAT AGGREGATE OPERATORS
1712 * =========================
1714 * float8_accum - accumulate for AVG(), variance aggregates, etc.
1715 * float4_accum - same, but input data is float4
1716 * float8_avg - produce final result for float AVG()
1717 * float8_var_samp - produce final result for float VAR_SAMP()
1718 * float8_var_pop - produce final result for float VAR_POP()
1719 * float8_stddev_samp - produce final result for float STDDEV_SAMP()
1720 * float8_stddev_pop - produce final result for float STDDEV_POP()
1722 * The transition datatype for all these aggregates is a 3-element array
1723 * of float8, holding the values N, sum(X), sum(X*X) in that order.
1725 * Note that we represent N as a float to avoid having to build a special
1726 * datatype. Given a reasonable floating-point implementation, there should
1727 * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
1728 * user will have doubtless lost interest anyway...)
1732 check_float8_array(ArrayType *transarray, const char *caller, int n)
1735 * We expect the input to be an N-element float array; verify that. We
1736 * don't need to use deconstruct_array() since the array data is just
1737 * going to look like a C array of N float8 values.
1739 if (ARR_NDIM(transarray) != 1 ||
1740 ARR_DIMS(transarray)[0] != n ||
1741 ARR_HASNULL(transarray) ||
1742 ARR_ELEMTYPE(transarray) != FLOAT8OID)
1743 elog(ERROR, "%s: expected %d-element float8 array", caller, n);
1744 return (float8 *) ARR_DATA_PTR(transarray);
1748 float8_accum(PG_FUNCTION_ARGS)
1750 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1751 float8 newval = PG_GETARG_FLOAT8(1);
1752 float8 *transvalues;
1757 transvalues = check_float8_array(transarray, "float8_accum", 3);
1759 sumX = transvalues[1];
1760 sumX2 = transvalues[2];
1764 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
1765 sumX2 += newval * newval;
1766 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
1769 * If we're invoked as an aggregate, we can cheat and modify our first
1770 * parameter in-place to reduce palloc overhead. Otherwise we construct a
1771 * new array with the updated transition data and return it.
1773 if (AggCheckCallContext(fcinfo, NULL))
1776 transvalues[1] = sumX;
1777 transvalues[2] = sumX2;
1779 PG_RETURN_ARRAYTYPE_P(transarray);
1783 Datum transdatums[3];
1786 transdatums[0] = Float8GetDatumFast(N);
1787 transdatums[1] = Float8GetDatumFast(sumX);
1788 transdatums[2] = Float8GetDatumFast(sumX2);
1790 result = construct_array(transdatums, 3,
1792 sizeof(float8), FLOAT8PASSBYVAL, 'd');
1794 PG_RETURN_ARRAYTYPE_P(result);
1799 float4_accum(PG_FUNCTION_ARGS)
1801 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1803 /* do computations as float8 */
1804 float8 newval = PG_GETARG_FLOAT4(1);
1805 float8 *transvalues;
1810 transvalues = check_float8_array(transarray, "float4_accum", 3);
1812 sumX = transvalues[1];
1813 sumX2 = transvalues[2];
1817 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
1818 sumX2 += newval * newval;
1819 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
1822 * If we're invoked as an aggregate, we can cheat and modify our first
1823 * parameter in-place to reduce palloc overhead. Otherwise we construct a
1824 * new array with the updated transition data and return it.
1826 if (AggCheckCallContext(fcinfo, NULL))
1829 transvalues[1] = sumX;
1830 transvalues[2] = sumX2;
1832 PG_RETURN_ARRAYTYPE_P(transarray);
1836 Datum transdatums[3];
1839 transdatums[0] = Float8GetDatumFast(N);
1840 transdatums[1] = Float8GetDatumFast(sumX);
1841 transdatums[2] = Float8GetDatumFast(sumX2);
1843 result = construct_array(transdatums, 3,
1845 sizeof(float8), FLOAT8PASSBYVAL, 'd');
1847 PG_RETURN_ARRAYTYPE_P(result);
1852 float8_avg(PG_FUNCTION_ARGS)
1854 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1855 float8 *transvalues;
1859 transvalues = check_float8_array(transarray, "float8_avg", 3);
1861 sumX = transvalues[1];
1864 /* SQL92 defines AVG of no values to be NULL */
1868 PG_RETURN_FLOAT8(sumX / N);
1872 float8_var_pop(PG_FUNCTION_ARGS)
1874 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1875 float8 *transvalues;
1881 transvalues = check_float8_array(transarray, "float8_var_pop", 3);
1883 sumX = transvalues[1];
1884 sumX2 = transvalues[2];
1886 /* Population variance is undefined when N is 0, so return NULL */
1890 numerator = N * sumX2 - sumX * sumX;
1891 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
1893 /* Watch out for roundoff error producing a negative numerator */
1894 if (numerator <= 0.0)
1895 PG_RETURN_FLOAT8(0.0);
1897 PG_RETURN_FLOAT8(numerator / (N * N));
1901 float8_var_samp(PG_FUNCTION_ARGS)
1903 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1904 float8 *transvalues;
1910 transvalues = check_float8_array(transarray, "float8_var_samp", 3);
1912 sumX = transvalues[1];
1913 sumX2 = transvalues[2];
1915 /* Sample variance is undefined when N is 0 or 1, so return NULL */
1919 numerator = N * sumX2 - sumX * sumX;
1920 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
1922 /* Watch out for roundoff error producing a negative numerator */
1923 if (numerator <= 0.0)
1924 PG_RETURN_FLOAT8(0.0);
1926 PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
1930 float8_stddev_pop(PG_FUNCTION_ARGS)
1932 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1933 float8 *transvalues;
1939 transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
1941 sumX = transvalues[1];
1942 sumX2 = transvalues[2];
1944 /* Population stddev is undefined when N is 0, so return NULL */
1948 numerator = N * sumX2 - sumX * sumX;
1949 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
1951 /* Watch out for roundoff error producing a negative numerator */
1952 if (numerator <= 0.0)
1953 PG_RETURN_FLOAT8(0.0);
1955 PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
1959 float8_stddev_samp(PG_FUNCTION_ARGS)
1961 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1962 float8 *transvalues;
1968 transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
1970 sumX = transvalues[1];
1971 sumX2 = transvalues[2];
1973 /* Sample stddev is undefined when N is 0 or 1, so return NULL */
1977 numerator = N * sumX2 - sumX * sumX;
1978 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
1980 /* Watch out for roundoff error producing a negative numerator */
1981 if (numerator <= 0.0)
1982 PG_RETURN_FLOAT8(0.0);
1984 PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
1988 * =========================
1989 * SQL2003 BINARY AGGREGATES
1990 * =========================
1992 * The transition datatype for all these aggregates is a 6-element array of
1993 * float8, holding the values N, sum(X), sum(X*X), sum(Y), sum(Y*Y), sum(X*Y)
1994 * in that order. Note that Y is the first argument to the aggregates!
1996 * It might seem attractive to optimize this by having multiple accumulator
1997 * functions that only calculate the sums actually needed. But on most
1998 * modern machines, a couple of extra floating-point multiplies will be
1999 * insignificant compared to the other per-tuple overhead, so I've chosen
2000 * to minimize code space instead.
2004 float8_regr_accum(PG_FUNCTION_ARGS)
2006 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2007 float8 newvalY = PG_GETARG_FLOAT8(1);
2008 float8 newvalX = PG_GETARG_FLOAT8(2);
2009 float8 *transvalues;
2017 transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
2019 sumX = transvalues[1];
2020 sumX2 = transvalues[2];
2021 sumY = transvalues[3];
2022 sumY2 = transvalues[4];
2023 sumXY = transvalues[5];
2027 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
2028 sumX2 += newvalX * newvalX;
2029 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
2031 CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
2032 sumY2 += newvalY * newvalY;
2033 CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
2034 sumXY += newvalX * newvalY;
2035 CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
2036 isinf(newvalY), true);
2039 * If we're invoked as an aggregate, we can cheat and modify our first
2040 * parameter in-place to reduce palloc overhead. Otherwise we construct a
2041 * new array with the updated transition data and return it.
2043 if (AggCheckCallContext(fcinfo, NULL))
2046 transvalues[1] = sumX;
2047 transvalues[2] = sumX2;
2048 transvalues[3] = sumY;
2049 transvalues[4] = sumY2;
2050 transvalues[5] = sumXY;
2052 PG_RETURN_ARRAYTYPE_P(transarray);
2056 Datum transdatums[6];
2059 transdatums[0] = Float8GetDatumFast(N);
2060 transdatums[1] = Float8GetDatumFast(sumX);
2061 transdatums[2] = Float8GetDatumFast(sumX2);
2062 transdatums[3] = Float8GetDatumFast(sumY);
2063 transdatums[4] = Float8GetDatumFast(sumY2);
2064 transdatums[5] = Float8GetDatumFast(sumXY);
2066 result = construct_array(transdatums, 6,
2068 sizeof(float8), FLOAT8PASSBYVAL, 'd');
2070 PG_RETURN_ARRAYTYPE_P(result);
2075 float8_regr_sxx(PG_FUNCTION_ARGS)
2077 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2078 float8 *transvalues;
2084 transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
2086 sumX = transvalues[1];
2087 sumX2 = transvalues[2];
2089 /* if N is 0 we should return NULL */
2093 numerator = N * sumX2 - sumX * sumX;
2094 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
2096 /* Watch out for roundoff error producing a negative numerator */
2097 if (numerator <= 0.0)
2098 PG_RETURN_FLOAT8(0.0);
2100 PG_RETURN_FLOAT8(numerator / N);
2104 float8_regr_syy(PG_FUNCTION_ARGS)
2106 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2107 float8 *transvalues;
2113 transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
2115 sumY = transvalues[3];
2116 sumY2 = transvalues[4];
2118 /* if N is 0 we should return NULL */
2122 numerator = N * sumY2 - sumY * sumY;
2123 CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
2125 /* Watch out for roundoff error producing a negative numerator */
2126 if (numerator <= 0.0)
2127 PG_RETURN_FLOAT8(0.0);
2129 PG_RETURN_FLOAT8(numerator / N);
2133 float8_regr_sxy(PG_FUNCTION_ARGS)
2135 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2136 float8 *transvalues;
2143 transvalues = check_float8_array(transarray, "float8_regr_sxy", 6);
2145 sumX = transvalues[1];
2146 sumY = transvalues[3];
2147 sumXY = transvalues[5];
2149 /* if N is 0 we should return NULL */
2153 numerator = N * sumXY - sumX * sumY;
2154 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2157 /* A negative result is valid here */
2159 PG_RETURN_FLOAT8(numerator / N);
2163 float8_regr_avgx(PG_FUNCTION_ARGS)
2165 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2166 float8 *transvalues;
2170 transvalues = check_float8_array(transarray, "float8_regr_avgx", 6);
2172 sumX = transvalues[1];
2174 /* if N is 0 we should return NULL */
2178 PG_RETURN_FLOAT8(sumX / N);
2182 float8_regr_avgy(PG_FUNCTION_ARGS)
2184 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2185 float8 *transvalues;
2189 transvalues = check_float8_array(transarray, "float8_regr_avgy", 6);
2191 sumY = transvalues[3];
2193 /* if N is 0 we should return NULL */
2197 PG_RETURN_FLOAT8(sumY / N);
2201 float8_covar_pop(PG_FUNCTION_ARGS)
2203 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2204 float8 *transvalues;
2211 transvalues = check_float8_array(transarray, "float8_covar_pop", 6);
2213 sumX = transvalues[1];
2214 sumY = transvalues[3];
2215 sumXY = transvalues[5];
2217 /* if N is 0 we should return NULL */
2221 numerator = N * sumXY - sumX * sumY;
2222 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2225 PG_RETURN_FLOAT8(numerator / (N * N));
2229 float8_covar_samp(PG_FUNCTION_ARGS)
2231 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2232 float8 *transvalues;
2239 transvalues = check_float8_array(transarray, "float8_covar_samp", 6);
2241 sumX = transvalues[1];
2242 sumY = transvalues[3];
2243 sumXY = transvalues[5];
2245 /* if N is <= 1 we should return NULL */
2249 numerator = N * sumXY - sumX * sumY;
2250 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2253 PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
2257 float8_corr(PG_FUNCTION_ARGS)
2259 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2260 float8 *transvalues;
2271 transvalues = check_float8_array(transarray, "float8_corr", 6);
2273 sumX = transvalues[1];
2274 sumX2 = transvalues[2];
2275 sumY = transvalues[3];
2276 sumY2 = transvalues[4];
2277 sumXY = transvalues[5];
2279 /* if N is 0 we should return NULL */
2283 numeratorX = N * sumX2 - sumX * sumX;
2284 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2285 numeratorY = N * sumY2 - sumY * sumY;
2286 CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
2287 numeratorXY = N * sumXY - sumX * sumY;
2288 CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
2290 if (numeratorX <= 0 || numeratorY <= 0)
2293 PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
2297 float8_regr_r2(PG_FUNCTION_ARGS)
2299 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2300 float8 *transvalues;
2311 transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
2313 sumX = transvalues[1];
2314 sumX2 = transvalues[2];
2315 sumY = transvalues[3];
2316 sumY2 = transvalues[4];
2317 sumXY = transvalues[5];
2319 /* if N is 0 we should return NULL */
2323 numeratorX = N * sumX2 - sumX * sumX;
2324 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2325 numeratorY = N * sumY2 - sumY * sumY;
2326 CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
2327 numeratorXY = N * sumXY - sumX * sumY;
2328 CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
2330 if (numeratorX <= 0)
2332 /* per spec, horizontal line produces 1.0 */
2333 if (numeratorY <= 0)
2334 PG_RETURN_FLOAT8(1.0);
2336 PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
2337 (numeratorX * numeratorY));
2341 float8_regr_slope(PG_FUNCTION_ARGS)
2343 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2344 float8 *transvalues;
2353 transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
2355 sumX = transvalues[1];
2356 sumX2 = transvalues[2];
2357 sumY = transvalues[3];
2358 sumXY = transvalues[5];
2360 /* if N is 0 we should return NULL */
2364 numeratorX = N * sumX2 - sumX * sumX;
2365 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2366 numeratorXY = N * sumXY - sumX * sumY;
2367 CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
2369 if (numeratorX <= 0)
2372 PG_RETURN_FLOAT8(numeratorXY / numeratorX);
2376 float8_regr_intercept(PG_FUNCTION_ARGS)
2378 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2379 float8 *transvalues;
2388 transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
2390 sumX = transvalues[1];
2391 sumX2 = transvalues[2];
2392 sumY = transvalues[3];
2393 sumXY = transvalues[5];
2395 /* if N is 0 we should return NULL */
2399 numeratorX = N * sumX2 - sumX * sumX;
2400 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2401 numeratorXXY = sumY * sumX2 - sumX * sumXY;
2402 CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
2403 isinf(sumX) || isinf(sumXY), true);
2404 if (numeratorX <= 0)
2407 PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
2412 * ====================================
2413 * MIXED-PRECISION ARITHMETIC OPERATORS
2414 * ====================================
2418 * float48pl - returns arg1 + arg2
2419 * float48mi - returns arg1 - arg2
2420 * float48mul - returns arg1 * arg2
2421 * float48div - returns arg1 / arg2
2424 float48pl(PG_FUNCTION_ARGS)
2426 float4 arg1 = PG_GETARG_FLOAT4(0);
2427 float8 arg2 = PG_GETARG_FLOAT8(1);
2430 result = arg1 + arg2;
2431 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2432 PG_RETURN_FLOAT8(result);
2436 float48mi(PG_FUNCTION_ARGS)
2438 float4 arg1 = PG_GETARG_FLOAT4(0);
2439 float8 arg2 = PG_GETARG_FLOAT8(1);
2442 result = arg1 - arg2;
2443 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2444 PG_RETURN_FLOAT8(result);
2448 float48mul(PG_FUNCTION_ARGS)
2450 float4 arg1 = PG_GETARG_FLOAT4(0);
2451 float8 arg2 = PG_GETARG_FLOAT8(1);
2454 result = arg1 * arg2;
2455 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
2456 arg1 == 0 || arg2 == 0);
2457 PG_RETURN_FLOAT8(result);
2461 float48div(PG_FUNCTION_ARGS)
2463 float4 arg1 = PG_GETARG_FLOAT4(0);
2464 float8 arg2 = PG_GETARG_FLOAT8(1);
2469 (errcode(ERRCODE_DIVISION_BY_ZERO),
2470 errmsg("division by zero")));
2472 result = arg1 / arg2;
2473 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
2474 PG_RETURN_FLOAT8(result);
2478 * float84pl - returns arg1 + arg2
2479 * float84mi - returns arg1 - arg2
2480 * float84mul - returns arg1 * arg2
2481 * float84div - returns arg1 / arg2
2484 float84pl(PG_FUNCTION_ARGS)
2486 float8 arg1 = PG_GETARG_FLOAT8(0);
2487 float4 arg2 = PG_GETARG_FLOAT4(1);
2490 result = arg1 + arg2;
2492 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2493 PG_RETURN_FLOAT8(result);
2497 float84mi(PG_FUNCTION_ARGS)
2499 float8 arg1 = PG_GETARG_FLOAT8(0);
2500 float4 arg2 = PG_GETARG_FLOAT4(1);
2503 result = arg1 - arg2;
2505 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2506 PG_RETURN_FLOAT8(result);
2510 float84mul(PG_FUNCTION_ARGS)
2512 float8 arg1 = PG_GETARG_FLOAT8(0);
2513 float4 arg2 = PG_GETARG_FLOAT4(1);
2516 result = arg1 * arg2;
2518 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
2519 arg1 == 0 || arg2 == 0);
2520 PG_RETURN_FLOAT8(result);
2524 float84div(PG_FUNCTION_ARGS)
2526 float8 arg1 = PG_GETARG_FLOAT8(0);
2527 float4 arg2 = PG_GETARG_FLOAT4(1);
2532 (errcode(ERRCODE_DIVISION_BY_ZERO),
2533 errmsg("division by zero")));
2535 result = arg1 / arg2;
2537 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
2538 PG_RETURN_FLOAT8(result);
2542 * ====================
2543 * COMPARISON OPERATORS
2544 * ====================
2548 * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
2551 float48eq(PG_FUNCTION_ARGS)
2553 float4 arg1 = PG_GETARG_FLOAT4(0);
2554 float8 arg2 = PG_GETARG_FLOAT8(1);
2556 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
2560 float48ne(PG_FUNCTION_ARGS)
2562 float4 arg1 = PG_GETARG_FLOAT4(0);
2563 float8 arg2 = PG_GETARG_FLOAT8(1);
2565 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
2569 float48lt(PG_FUNCTION_ARGS)
2571 float4 arg1 = PG_GETARG_FLOAT4(0);
2572 float8 arg2 = PG_GETARG_FLOAT8(1);
2574 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
2578 float48le(PG_FUNCTION_ARGS)
2580 float4 arg1 = PG_GETARG_FLOAT4(0);
2581 float8 arg2 = PG_GETARG_FLOAT8(1);
2583 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
2587 float48gt(PG_FUNCTION_ARGS)
2589 float4 arg1 = PG_GETARG_FLOAT4(0);
2590 float8 arg2 = PG_GETARG_FLOAT8(1);
2592 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
2596 float48ge(PG_FUNCTION_ARGS)
2598 float4 arg1 = PG_GETARG_FLOAT4(0);
2599 float8 arg2 = PG_GETARG_FLOAT8(1);
2601 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
2605 * float84{eq,ne,lt,le,gt,ge} - float8/float4 comparison operations
2608 float84eq(PG_FUNCTION_ARGS)
2610 float8 arg1 = PG_GETARG_FLOAT8(0);
2611 float4 arg2 = PG_GETARG_FLOAT4(1);
2613 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
2617 float84ne(PG_FUNCTION_ARGS)
2619 float8 arg1 = PG_GETARG_FLOAT8(0);
2620 float4 arg2 = PG_GETARG_FLOAT4(1);
2622 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
2626 float84lt(PG_FUNCTION_ARGS)
2628 float8 arg1 = PG_GETARG_FLOAT8(0);
2629 float4 arg2 = PG_GETARG_FLOAT4(1);
2631 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
2635 float84le(PG_FUNCTION_ARGS)
2637 float8 arg1 = PG_GETARG_FLOAT8(0);
2638 float4 arg2 = PG_GETARG_FLOAT4(1);
2640 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
2644 float84gt(PG_FUNCTION_ARGS)
2646 float8 arg1 = PG_GETARG_FLOAT8(0);
2647 float4 arg2 = PG_GETARG_FLOAT4(1);
2649 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
2653 float84ge(PG_FUNCTION_ARGS)
2655 float8 arg1 = PG_GETARG_FLOAT8(0);
2656 float4 arg2 = PG_GETARG_FLOAT4(1);
2658 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
2662 * Implements the float8 version of the width_bucket() function
2663 * defined by SQL2003. See also width_bucket_numeric().
2665 * 'bound1' and 'bound2' are the lower and upper bounds of the
2666 * histogram's range, respectively. 'count' is the number of buckets
2667 * in the histogram. width_bucket() returns an integer indicating the
2668 * bucket number that 'operand' belongs to in an equiwidth histogram
2669 * with the specified characteristics. An operand smaller than the
2670 * lower bound is assigned to bucket 0. An operand greater than the
2671 * upper bound is assigned to an additional bucket (with number
2672 * count+1). We don't allow "NaN" for any of the float8 inputs, and we
2673 * don't allow either of the histogram bounds to be +/- infinity.
2676 width_bucket_float8(PG_FUNCTION_ARGS)
2678 float8 operand = PG_GETARG_FLOAT8(0);
2679 float8 bound1 = PG_GETARG_FLOAT8(1);
2680 float8 bound2 = PG_GETARG_FLOAT8(2);
2681 int32 count = PG_GETARG_INT32(3);
2686 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
2687 errmsg("count must be greater than zero")));
2689 if (isnan(operand) || isnan(bound1) || isnan(bound2))
2691 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
2692 errmsg("operand, lower bound and upper bound cannot be NaN")));
2694 /* Note that we allow "operand" to be infinite */
2695 if (isinf(bound1) || isinf(bound2))
2697 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
2698 errmsg("lower and upper bounds must be finite")));
2700 if (bound1 < bound2)
2702 if (operand < bound1)
2704 else if (operand >= bound2)
2707 /* check for overflow */
2710 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
2711 errmsg("integer out of range")));
2714 result = ((float8) count * (operand - bound1) / (bound2 - bound1)) + 1;
2716 else if (bound1 > bound2)
2718 if (operand > bound1)
2720 else if (operand <= bound2)
2723 /* check for overflow */
2726 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
2727 errmsg("integer out of range")));
2730 result = ((float8) count * (bound1 - operand) / (bound1 - bound2)) + 1;
2735 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
2736 errmsg("lower bound cannot equal upper bound")));
2737 result = 0; /* keep the compiler quiet */
2740 PG_RETURN_INT32(result);
2743 /* ========== PRIVATE ROUTINES ========== */
2750 int isneg = (x < 0.0);
2751 double absx = fabs(x);
2752 double tmpres = pow(absx, (double) 1.0 / (double) 3.0);
2755 * The result is somewhat inaccurate --- not really pow()'s fault, as the
2756 * exponent it's handed contains roundoff error. We can improve the
2757 * accuracy by doing one iteration of Newton's formula. Beware of zero
2761 tmpres -= (tmpres - absx / (tmpres * tmpres)) / (double) 3.0;
2763 return isneg ? -tmpres : tmpres;
2766 #endif /* !HAVE_CBRT */