1 /*-------------------------------------------------------------------------
4 * Functions for the built-in floating-point types.
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.141 2007/01/05 03:19:26 momjian Exp $
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);
74 static double cbrt(double x);
75 #endif /* HAVE_CBRT */
79 * Routines to provide reasonably platform-independent handling of
80 * infinity and NaN. We assume that isinf() and isnan() are available
81 * and work per spec. (On some platforms, we have to supply our own;
82 * see src/port.) However, generating an Infinity or NaN in the first
83 * place is less well standardized; pre-C99 systems tend not to have C99's
84 * INFINITY and NAN macros. We centralize our workarounds for this here.
88 get_float8_infinity(void)
91 /* C99 standard way */
92 return (double) INFINITY;
96 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
97 * largest normal double. We assume forcing an overflow will get us a
100 return (double) (HUGE_VAL * HUGE_VAL);
105 get_float4_infinity(void)
108 /* C99 standard way */
109 return (float) INFINITY;
113 * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
114 * largest normal double. We assume forcing an overflow will get us a
117 return (float) (HUGE_VAL * HUGE_VAL);
125 /* C99 standard way */
128 /* Assume we can get a NAN via zero divide */
129 return (double) (0.0 / 0.0);
137 /* C99 standard way */
140 /* Assume we can get a NAN via zero divide */
141 return (float) (0.0 / 0.0);
147 * Returns -1 if 'val' represents negative infinity, 1 if 'val'
148 * represents (positive) infinity, and 0 otherwise. On some platforms,
149 * this is equivalent to the isinf() macro, but not everywhere: C99
150 * does not specify that isinf() needs to distinguish between positive
151 * and negative infinity.
154 is_infinite(double val)
156 int inf = isinf(val);
168 * float4in - converts "num" to float
170 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
171 * where <sp> is a space, digit is 0-9,
172 * <exp> is "e" or "E" followed by an integer.
175 float4in(PG_FUNCTION_ARGS)
177 char *num = PG_GETARG_CSTRING(0);
183 * endptr points to the first character _after_ the sequence we recognized
184 * as a valid floating point number. orig_num points to the original input
190 * Check for an empty-string input to begin with, to avoid the vagaries of
191 * strtod() on different platforms.
195 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
196 errmsg("invalid input syntax for type real: \"%s\"",
199 /* skip leading whitespace */
200 while (*num != '\0' && isspace((unsigned char) *num))
204 val = strtod(num, &endptr);
206 /* did we not see anything that looks like a double? */
207 if (endptr == num || errno != 0)
210 * C99 requires that strtod() accept NaN and [-]Infinity, but not all
211 * platforms support that yet (and some accept them but set ERANGE
212 * anyway...) Therefore, we check for these inputs ourselves.
214 if (pg_strncasecmp(num, "NaN", 3) == 0)
216 val = get_float4_nan();
219 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
221 val = get_float4_infinity();
224 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
226 val = -get_float4_infinity();
229 else if (errno == ERANGE)
231 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
232 errmsg("\"%s\" is out of range for type real",
236 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
237 errmsg("invalid input syntax for type real: \"%s\"",
240 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
244 * Many versions of Solaris have a bug wherein strtod sets endptr to
245 * point one byte beyond the end of the string when given "inf" or
248 if (endptr != num && endptr[-1] == '\0')
251 #endif /* HAVE_BUGGY_SOLARIS_STRTOD */
253 #ifdef HAVE_BUGGY_IRIX_STRTOD
255 * In some IRIX versions, strtod() recognizes only "inf", so if the
256 * input is "infinity" we have to skip over "inity". Also, it may
257 * return positive infinity for "-inf".
261 if (pg_strncasecmp(num, "Infinity", 8) == 0)
263 val = get_float4_infinity();
266 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
268 val = -get_float4_infinity();
271 else if (pg_strncasecmp(num, "-inf", 4) == 0)
273 val = -get_float4_infinity();
277 #endif /* HAVE_BUGGY_IRIX_STRTOD */
279 /* skip trailing whitespace */
280 while (*endptr != '\0' && isspace((unsigned char) *endptr))
283 /* if there is any junk left at the end of the string, bail out */
286 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
287 errmsg("invalid input syntax for type real: \"%s\"",
291 * if we get here, we have a legal double, still need to check to see if
292 * it's a legal float4
294 CHECKFLOATVAL((float4) val, isinf(val), val == 0);
296 PG_RETURN_FLOAT4((float4) val);
300 * float4out - converts a float4 number to a string
301 * using a standard output format
304 float4out(PG_FUNCTION_ARGS)
306 float4 num = PG_GETARG_FLOAT4(0);
307 char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
310 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
312 switch (is_infinite(num))
315 strcpy(ascii, "Infinity");
318 strcpy(ascii, "-Infinity");
322 int ndig = FLT_DIG + extra_float_digits;
327 sprintf(ascii, "%.*g", ndig, num);
331 PG_RETURN_CSTRING(ascii);
335 * float4recv - converts external binary format to float4
338 float4recv(PG_FUNCTION_ARGS)
340 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
342 PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));
346 * float4send - converts float4 to binary format
349 float4send(PG_FUNCTION_ARGS)
351 float4 num = PG_GETARG_FLOAT4(0);
354 pq_begintypsend(&buf);
355 pq_sendfloat4(&buf, num);
356 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
360 * float8in - converts "num" to float8
362 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
363 * where <sp> is a space, digit is 0-9,
364 * <exp> is "e" or "E" followed by an integer.
367 float8in(PG_FUNCTION_ARGS)
369 char *num = PG_GETARG_CSTRING(0);
375 * endptr points to the first character _after_ the sequence we recognized
376 * as a valid floating point number. orig_num points to the original input
382 * Check for an empty-string input to begin with, to avoid the vagaries of
383 * strtod() on different platforms.
387 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
388 errmsg("invalid input syntax for type double precision: \"%s\"",
391 /* skip leading whitespace */
392 while (*num != '\0' && isspace((unsigned char) *num))
396 val = strtod(num, &endptr);
398 /* did we not see anything that looks like a double? */
399 if (endptr == num || errno != 0)
402 * C99 requires that strtod() accept NaN and [-]Infinity, but not all
403 * platforms support that yet (and some accept them but set ERANGE
404 * anyway...) Therefore, we check for these inputs ourselves.
406 if (pg_strncasecmp(num, "NaN", 3) == 0)
408 val = get_float8_nan();
411 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
413 val = get_float8_infinity();
416 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
418 val = -get_float8_infinity();
421 else if (errno == ERANGE)
423 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
424 errmsg("\"%s\" is out of range for type double precision",
428 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
429 errmsg("invalid input syntax for type double precision: \"%s\"",
432 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
436 * Many versions of Solaris have a bug wherein strtod sets endptr to
437 * point one byte beyond the end of the string when given "inf" or
440 if (endptr != num && endptr[-1] == '\0')
443 #endif /* HAVE_BUGGY_SOLARIS_STRTOD */
445 #ifdef HAVE_BUGGY_IRIX_STRTOD
447 * In some IRIX versions, strtod() recognizes only "inf", so if the
448 * input is "infinity" we have to skip over "inity". Also, it may
449 * return positive infinity for "-inf".
453 if (pg_strncasecmp(num, "Infinity", 8) == 0)
455 val = get_float8_infinity();
458 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
460 val = -get_float8_infinity();
463 else if (pg_strncasecmp(num, "-inf", 4) == 0)
465 val = -get_float8_infinity();
469 #endif /* HAVE_BUGGY_IRIX_STRTOD */
471 /* skip trailing whitespace */
472 while (*endptr != '\0' && isspace((unsigned char) *endptr))
475 /* if there is any junk left at the end of the string, bail out */
478 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
479 errmsg("invalid input syntax for type double precision: \"%s\"",
482 CHECKFLOATVAL(val, true, true);
484 PG_RETURN_FLOAT8(val);
488 * float8out - converts float8 number to a string
489 * using a standard output format
492 float8out(PG_FUNCTION_ARGS)
494 float8 num = PG_GETARG_FLOAT8(0);
495 char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
498 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
500 switch (is_infinite(num))
503 strcpy(ascii, "Infinity");
506 strcpy(ascii, "-Infinity");
510 int ndig = DBL_DIG + extra_float_digits;
515 sprintf(ascii, "%.*g", ndig, num);
519 PG_RETURN_CSTRING(ascii);
523 * float8recv - converts external binary format to float8
526 float8recv(PG_FUNCTION_ARGS)
528 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
530 PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));
534 * float8send - converts float8 to binary format
537 float8send(PG_FUNCTION_ARGS)
539 float8 num = PG_GETARG_FLOAT8(0);
542 pq_begintypsend(&buf);
543 pq_sendfloat8(&buf, num);
544 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
548 /* ========== PUBLIC ROUTINES ========== */
552 * ======================
553 * FLOAT4 BASE OPERATIONS
554 * ======================
558 * float4abs - returns |arg1| (absolute value)
561 float4abs(PG_FUNCTION_ARGS)
563 float4 arg1 = PG_GETARG_FLOAT4(0);
565 PG_RETURN_FLOAT4((float4) fabs(arg1));
569 * float4um - returns -arg1 (unary minus)
572 float4um(PG_FUNCTION_ARGS)
574 float4 arg1 = PG_GETARG_FLOAT4(0);
577 result = ((arg1 != 0) ? -(arg1) : arg1);
579 CHECKFLOATVAL(result, isinf(arg1), true);
580 PG_RETURN_FLOAT4(result);
584 float4up(PG_FUNCTION_ARGS)
586 float4 arg = PG_GETARG_FLOAT4(0);
588 PG_RETURN_FLOAT4(arg);
592 float4larger(PG_FUNCTION_ARGS)
594 float4 arg1 = PG_GETARG_FLOAT4(0);
595 float4 arg2 = PG_GETARG_FLOAT4(1);
598 if (float4_cmp_internal(arg1, arg2) > 0)
602 PG_RETURN_FLOAT4(result);
606 float4smaller(PG_FUNCTION_ARGS)
608 float4 arg1 = PG_GETARG_FLOAT4(0);
609 float4 arg2 = PG_GETARG_FLOAT4(1);
612 if (float4_cmp_internal(arg1, arg2) < 0)
616 PG_RETURN_FLOAT4(result);
620 * ======================
621 * FLOAT8 BASE OPERATIONS
622 * ======================
626 * float8abs - returns |arg1| (absolute value)
629 float8abs(PG_FUNCTION_ARGS)
631 float8 arg1 = PG_GETARG_FLOAT8(0);
633 PG_RETURN_FLOAT8(fabs(arg1));
638 * float8um - returns -arg1 (unary minus)
641 float8um(PG_FUNCTION_ARGS)
643 float8 arg1 = PG_GETARG_FLOAT8(0);
646 result = ((arg1 != 0) ? -(arg1) : arg1);
648 CHECKFLOATVAL(result, isinf(arg1), true);
649 PG_RETURN_FLOAT8(result);
653 float8up(PG_FUNCTION_ARGS)
655 float8 arg = PG_GETARG_FLOAT8(0);
657 PG_RETURN_FLOAT8(arg);
661 float8larger(PG_FUNCTION_ARGS)
663 float8 arg1 = PG_GETARG_FLOAT8(0);
664 float8 arg2 = PG_GETARG_FLOAT8(1);
667 if (float8_cmp_internal(arg1, arg2) > 0)
671 PG_RETURN_FLOAT8(result);
675 float8smaller(PG_FUNCTION_ARGS)
677 float8 arg1 = PG_GETARG_FLOAT8(0);
678 float8 arg2 = PG_GETARG_FLOAT8(1);
681 if (float8_cmp_internal(arg1, arg2) < 0)
685 PG_RETURN_FLOAT8(result);
690 * ====================
691 * ARITHMETIC OPERATORS
692 * ====================
696 * float4pl - returns arg1 + arg2
697 * float4mi - returns arg1 - arg2
698 * float4mul - returns arg1 * arg2
699 * float4div - returns arg1 / arg2
702 float4pl(PG_FUNCTION_ARGS)
704 float8 arg1 = PG_GETARG_FLOAT4(0);
705 float8 arg2 = PG_GETARG_FLOAT4(1);
708 result = arg1 + arg2;
710 * There isn't any way to check for underflow of addition/subtraction
711 * because numbers near the underflow value have been already been
712 * to the point where we can't detect the that the two values
713 * were originally different, e.g. on x86, '1e-45'::float4 ==
714 * '2e-45'::float4 == 1.4013e-45.
716 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
717 PG_RETURN_FLOAT4(result);
721 float4mi(PG_FUNCTION_ARGS)
723 float4 arg1 = PG_GETARG_FLOAT4(0);
724 float4 arg2 = PG_GETARG_FLOAT4(1);
727 result = arg1 - arg2;
728 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
729 PG_RETURN_FLOAT4(result);
733 float4mul(PG_FUNCTION_ARGS)
735 float4 arg1 = PG_GETARG_FLOAT4(0);
736 float4 arg2 = PG_GETARG_FLOAT4(1);
739 result = arg1 * arg2;
740 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
741 arg1 == 0 || arg2 == 0);
742 PG_RETURN_FLOAT4(result);
746 float4div(PG_FUNCTION_ARGS)
748 float4 arg1 = PG_GETARG_FLOAT4(0);
749 float4 arg2 = PG_GETARG_FLOAT4(1);
754 (errcode(ERRCODE_DIVISION_BY_ZERO),
755 errmsg("division by zero")));
757 /* Do division in float8, then check for overflow */
758 result = arg1 / arg2;
760 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
761 PG_RETURN_FLOAT4(result);
765 * float8pl - returns arg1 + arg2
766 * float8mi - returns arg1 - arg2
767 * float8mul - returns arg1 * arg2
768 * float8div - returns arg1 / arg2
771 float8pl(PG_FUNCTION_ARGS)
773 float8 arg1 = PG_GETARG_FLOAT8(0);
774 float8 arg2 = PG_GETARG_FLOAT8(1);
777 result = arg1 + arg2;
779 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
780 PG_RETURN_FLOAT8(result);
784 float8mi(PG_FUNCTION_ARGS)
786 float8 arg1 = PG_GETARG_FLOAT8(0);
787 float8 arg2 = PG_GETARG_FLOAT8(1);
790 result = arg1 - arg2;
792 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
793 PG_RETURN_FLOAT8(result);
797 float8mul(PG_FUNCTION_ARGS)
799 float8 arg1 = PG_GETARG_FLOAT8(0);
800 float8 arg2 = PG_GETARG_FLOAT8(1);
803 result = arg1 * arg2;
805 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
806 arg1 == 0 || arg2 == 0);
807 PG_RETURN_FLOAT8(result);
811 float8div(PG_FUNCTION_ARGS)
813 float8 arg1 = PG_GETARG_FLOAT8(0);
814 float8 arg2 = PG_GETARG_FLOAT8(1);
819 (errcode(ERRCODE_DIVISION_BY_ZERO),
820 errmsg("division by zero")));
822 result = arg1 / arg2;
824 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
825 PG_RETURN_FLOAT8(result);
830 * ====================
831 * COMPARISON OPERATORS
832 * ====================
836 * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
839 float4_cmp_internal(float4 a, float4 b)
842 * We consider all NANs to be equal and larger than any non-NAN. This is
843 * somewhat arbitrary; the important thing is to have a consistent sort
849 return 0; /* NAN = NAN */
851 return 1; /* NAN > non-NAN */
855 return -1; /* non-NAN < NAN */
869 float4eq(PG_FUNCTION_ARGS)
871 float4 arg1 = PG_GETARG_FLOAT4(0);
872 float4 arg2 = PG_GETARG_FLOAT4(1);
874 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
878 float4ne(PG_FUNCTION_ARGS)
880 float4 arg1 = PG_GETARG_FLOAT4(0);
881 float4 arg2 = PG_GETARG_FLOAT4(1);
883 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
887 float4lt(PG_FUNCTION_ARGS)
889 float4 arg1 = PG_GETARG_FLOAT4(0);
890 float4 arg2 = PG_GETARG_FLOAT4(1);
892 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
896 float4le(PG_FUNCTION_ARGS)
898 float4 arg1 = PG_GETARG_FLOAT4(0);
899 float4 arg2 = PG_GETARG_FLOAT4(1);
901 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
905 float4gt(PG_FUNCTION_ARGS)
907 float4 arg1 = PG_GETARG_FLOAT4(0);
908 float4 arg2 = PG_GETARG_FLOAT4(1);
910 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
914 float4ge(PG_FUNCTION_ARGS)
916 float4 arg1 = PG_GETARG_FLOAT4(0);
917 float4 arg2 = PG_GETARG_FLOAT4(1);
919 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
923 btfloat4cmp(PG_FUNCTION_ARGS)
925 float4 arg1 = PG_GETARG_FLOAT4(0);
926 float4 arg2 = PG_GETARG_FLOAT4(1);
928 PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
932 * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
935 float8_cmp_internal(float8 a, float8 b)
938 * We consider all NANs to be equal and larger than any non-NAN. This is
939 * somewhat arbitrary; the important thing is to have a consistent sort
945 return 0; /* NAN = NAN */
947 return 1; /* NAN > non-NAN */
951 return -1; /* non-NAN < NAN */
965 float8eq(PG_FUNCTION_ARGS)
967 float8 arg1 = PG_GETARG_FLOAT8(0);
968 float8 arg2 = PG_GETARG_FLOAT8(1);
970 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
974 float8ne(PG_FUNCTION_ARGS)
976 float8 arg1 = PG_GETARG_FLOAT8(0);
977 float8 arg2 = PG_GETARG_FLOAT8(1);
979 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
983 float8lt(PG_FUNCTION_ARGS)
985 float8 arg1 = PG_GETARG_FLOAT8(0);
986 float8 arg2 = PG_GETARG_FLOAT8(1);
988 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
992 float8le(PG_FUNCTION_ARGS)
994 float8 arg1 = PG_GETARG_FLOAT8(0);
995 float8 arg2 = PG_GETARG_FLOAT8(1);
997 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1001 float8gt(PG_FUNCTION_ARGS)
1003 float8 arg1 = PG_GETARG_FLOAT8(0);
1004 float8 arg2 = PG_GETARG_FLOAT8(1);
1006 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1010 float8ge(PG_FUNCTION_ARGS)
1012 float8 arg1 = PG_GETARG_FLOAT8(0);
1013 float8 arg2 = PG_GETARG_FLOAT8(1);
1015 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1019 btfloat8cmp(PG_FUNCTION_ARGS)
1021 float8 arg1 = PG_GETARG_FLOAT8(0);
1022 float8 arg2 = PG_GETARG_FLOAT8(1);
1024 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
1028 btfloat48cmp(PG_FUNCTION_ARGS)
1030 float4 arg1 = PG_GETARG_FLOAT4(0);
1031 float8 arg2 = PG_GETARG_FLOAT8(1);
1033 /* widen float4 to float8 and then compare */
1034 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
1038 btfloat84cmp(PG_FUNCTION_ARGS)
1040 float8 arg1 = PG_GETARG_FLOAT8(0);
1041 float4 arg2 = PG_GETARG_FLOAT4(1);
1043 /* widen float4 to float8 and then compare */
1044 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
1049 * ===================
1050 * CONVERSION ROUTINES
1051 * ===================
1055 * ftod - converts a float4 number to a float8 number
1058 ftod(PG_FUNCTION_ARGS)
1060 float4 num = PG_GETARG_FLOAT4(0);
1062 PG_RETURN_FLOAT8((float8) num);
1067 * dtof - converts a float8 number to a float4 number
1070 dtof(PG_FUNCTION_ARGS)
1072 float8 num = PG_GETARG_FLOAT8(0);
1074 CHECKFLOATVAL((float4) num, isinf(num), num == 0);
1076 PG_RETURN_FLOAT4((float4) num);
1081 * dtoi4 - converts a float8 number to an int4 number
1084 dtoi4(PG_FUNCTION_ARGS)
1086 float8 num = PG_GETARG_FLOAT8(0);
1089 /* 'Inf' is handled by INT_MAX */
1090 if (num < INT_MIN || num > INT_MAX || isnan(num))
1092 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1093 errmsg("integer out of range")));
1095 result = (int32) rint(num);
1096 PG_RETURN_INT32(result);
1101 * dtoi2 - converts a float8 number to an int2 number
1104 dtoi2(PG_FUNCTION_ARGS)
1106 float8 num = PG_GETARG_FLOAT8(0);
1108 if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
1110 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1111 errmsg("smallint out of range")));
1113 PG_RETURN_INT16((int16) rint(num));
1118 * i4tod - converts an int4 number to a float8 number
1121 i4tod(PG_FUNCTION_ARGS)
1123 int32 num = PG_GETARG_INT32(0);
1125 PG_RETURN_FLOAT8((float8) num);
1130 * i2tod - converts an int2 number to a float8 number
1133 i2tod(PG_FUNCTION_ARGS)
1135 int16 num = PG_GETARG_INT16(0);
1137 PG_RETURN_FLOAT8((float8) num);
1142 * ftoi4 - converts a float4 number to an int4 number
1145 ftoi4(PG_FUNCTION_ARGS)
1147 float4 num = PG_GETARG_FLOAT4(0);
1149 if (num < INT_MIN || num > INT_MAX || isnan(num))
1151 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1152 errmsg("integer out of range")));
1154 PG_RETURN_INT32((int32) rint(num));
1159 * ftoi2 - converts a float4 number to an int2 number
1162 ftoi2(PG_FUNCTION_ARGS)
1164 float4 num = PG_GETARG_FLOAT4(0);
1166 if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
1168 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1169 errmsg("smallint out of range")));
1171 PG_RETURN_INT16((int16) rint(num));
1176 * i4tof - converts an int4 number to a float4 number
1179 i4tof(PG_FUNCTION_ARGS)
1181 int32 num = PG_GETARG_INT32(0);
1183 PG_RETURN_FLOAT4((float4) num);
1188 * i2tof - converts an int2 number to a float4 number
1191 i2tof(PG_FUNCTION_ARGS)
1193 int16 num = PG_GETARG_INT16(0);
1195 PG_RETURN_FLOAT4((float4) num);
1200 * float8_text - converts a float8 number to a text string
1203 float8_text(PG_FUNCTION_ARGS)
1205 float8 num = PG_GETARG_FLOAT8(0);
1210 str = DatumGetCString(DirectFunctionCall1(float8out,
1211 Float8GetDatum(num)));
1213 len = strlen(str) + VARHDRSZ;
1215 result = (text *) palloc(len);
1217 VARATT_SIZEP(result) = len;
1218 memcpy(VARDATA(result), str, (len - VARHDRSZ));
1222 PG_RETURN_TEXT_P(result);
1227 * text_float8 - converts a text string to a float8 number
1230 text_float8(PG_FUNCTION_ARGS)
1232 text *string = PG_GETARG_TEXT_P(0);
1237 len = (VARSIZE(string) - VARHDRSZ);
1238 str = palloc(len + 1);
1239 memcpy(str, VARDATA(string), len);
1240 *(str + len) = '\0';
1242 result = DirectFunctionCall1(float8in, CStringGetDatum(str));
1246 PG_RETURN_DATUM(result);
1251 * float4_text - converts a float4 number to a text string
1254 float4_text(PG_FUNCTION_ARGS)
1256 float4 num = PG_GETARG_FLOAT4(0);
1261 str = DatumGetCString(DirectFunctionCall1(float4out,
1262 Float4GetDatum(num)));
1264 len = strlen(str) + VARHDRSZ;
1266 result = (text *) palloc(len);
1268 VARATT_SIZEP(result) = len;
1269 memcpy(VARDATA(result), str, (len - VARHDRSZ));
1273 PG_RETURN_TEXT_P(result);
1278 * text_float4 - converts a text string to a float4 number
1281 text_float4(PG_FUNCTION_ARGS)
1283 text *string = PG_GETARG_TEXT_P(0);
1288 len = (VARSIZE(string) - VARHDRSZ);
1289 str = palloc(len + 1);
1290 memcpy(str, VARDATA(string), len);
1291 *(str + len) = '\0';
1293 result = DirectFunctionCall1(float4in, CStringGetDatum(str));
1297 PG_RETURN_DATUM(result);
1302 * =======================
1303 * RANDOM FLOAT8 OPERATORS
1304 * =======================
1308 * dround - returns ROUND(arg1)
1311 dround(PG_FUNCTION_ARGS)
1313 float8 arg1 = PG_GETARG_FLOAT8(0);
1315 PG_RETURN_FLOAT8(rint(arg1));
1319 * dceil - returns the smallest integer greater than or
1320 * equal to the specified float
1323 dceil(PG_FUNCTION_ARGS)
1325 float8 arg1 = PG_GETARG_FLOAT8(0);
1327 PG_RETURN_FLOAT8(ceil(arg1));
1331 * dfloor - returns the largest integer lesser than or
1332 * equal to the specified float
1335 dfloor(PG_FUNCTION_ARGS)
1337 float8 arg1 = PG_GETARG_FLOAT8(0);
1339 PG_RETURN_FLOAT8(floor(arg1));
1343 * dsign - returns -1 if the argument is less than 0, 0
1344 * if the argument is equal to 0, and 1 if the
1345 * argument is greater than zero.
1348 dsign(PG_FUNCTION_ARGS)
1350 float8 arg1 = PG_GETARG_FLOAT8(0);
1360 PG_RETURN_FLOAT8(result);
1364 * dtrunc - returns truncation-towards-zero of arg1,
1365 * arg1 >= 0 ... the greatest integer less
1366 * than or equal to arg1
1367 * arg1 < 0 ... the least integer greater
1368 * than or equal to arg1
1371 dtrunc(PG_FUNCTION_ARGS)
1373 float8 arg1 = PG_GETARG_FLOAT8(0);
1377 result = floor(arg1);
1379 result = -floor(-arg1);
1381 PG_RETURN_FLOAT8(result);
1386 * dsqrt - returns square root of arg1
1389 dsqrt(PG_FUNCTION_ARGS)
1391 float8 arg1 = PG_GETARG_FLOAT8(0);
1396 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
1397 errmsg("cannot take square root of a negative number")));
1399 result = sqrt(arg1);
1401 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1402 PG_RETURN_FLOAT8(result);
1407 * dcbrt - returns cube root of arg1
1410 dcbrt(PG_FUNCTION_ARGS)
1412 float8 arg1 = PG_GETARG_FLOAT8(0);
1415 result = cbrt(arg1);
1416 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1417 PG_RETURN_FLOAT8(result);
1422 * dpow - returns pow(arg1,arg2)
1425 dpow(PG_FUNCTION_ARGS)
1427 float8 arg1 = PG_GETARG_FLOAT8(0);
1428 float8 arg2 = PG_GETARG_FLOAT8(1);
1432 * The SQL spec requires that we emit a particular SQLSTATE error code for
1433 * certain error conditions.
1435 if ((arg1 == 0 && arg2 < 0) ||
1436 (arg1 < 0 && floor(arg2) != arg2))
1438 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
1439 errmsg("invalid argument for power function")));
1442 * pow() sets errno only on some platforms, depending on whether it
1443 * follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid
1444 * using errno. However, some platform/CPU combinations return
1445 * errno == EDOM and result == Nan, so we have to check for that and
1446 * set result properly. For example, Linux on 32-bit x86 hardware
1447 * returns EDOM/Nan for (-1) ^ 1e19, but (-1) ^ 1e18 returns
1448 * 1 -- basically a negative base raised to a very high power causes
1452 result = pow(arg1, arg2);
1453 if (errno == EDOM && isnan(result))
1455 if ((fabs(arg1) > 1 && arg2 >= 0) || (fabs(arg1) < 1 && arg2 < 0))
1456 /* The sign if Inf is not significant in this case. */
1457 result = get_float8_infinity();
1458 else if (fabs(arg1) != 1)
1464 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
1465 PG_RETURN_FLOAT8(result);
1470 * dexp - returns the exponential function of arg1
1473 dexp(PG_FUNCTION_ARGS)
1475 float8 arg1 = PG_GETARG_FLOAT8(0);
1480 CHECKFLOATVAL(result, isinf(arg1), false);
1481 PG_RETURN_FLOAT8(result);
1486 * dlog1 - returns the natural logarithm of arg1
1489 dlog1(PG_FUNCTION_ARGS)
1491 float8 arg1 = PG_GETARG_FLOAT8(0);
1495 * Emit particular SQLSTATE error codes for ln(). This is required by the
1500 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1501 errmsg("cannot take logarithm of zero")));
1504 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1505 errmsg("cannot take logarithm of a negative number")));
1509 CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
1510 PG_RETURN_FLOAT8(result);
1515 * dlog10 - returns the base 10 logarithm of arg1
1518 dlog10(PG_FUNCTION_ARGS)
1520 float8 arg1 = PG_GETARG_FLOAT8(0);
1524 * Emit particular SQLSTATE error codes for log(). The SQL spec doesn't
1525 * define log(), but it does define ln(), so it makes sense to emit the
1526 * same error code for an analogous error condition.
1530 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1531 errmsg("cannot take logarithm of zero")));
1534 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1535 errmsg("cannot take logarithm of a negative number")));
1537 result = log10(arg1);
1539 CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
1540 PG_RETURN_FLOAT8(result);
1545 * dacos - returns the arccos of arg1 (radians)
1548 dacos(PG_FUNCTION_ARGS)
1550 float8 arg1 = PG_GETARG_FLOAT8(0);
1554 * We use errno here because the trigonometric functions are cyclic
1555 * and hard to check for underflow.
1558 result = acos(arg1);
1561 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1562 errmsg("input is out of range")));
1564 CHECKFLOATVAL(result, isinf(arg1), true);
1565 PG_RETURN_FLOAT8(result);
1570 * dasin - returns the arcsin of arg1 (radians)
1573 dasin(PG_FUNCTION_ARGS)
1575 float8 arg1 = PG_GETARG_FLOAT8(0);
1579 result = asin(arg1);
1582 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1583 errmsg("input is out of range")));
1585 CHECKFLOATVAL(result, isinf(arg1), true);
1586 PG_RETURN_FLOAT8(result);
1591 * datan - returns the arctan of arg1 (radians)
1594 datan(PG_FUNCTION_ARGS)
1596 float8 arg1 = PG_GETARG_FLOAT8(0);
1600 result = atan(arg1);
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 * atan2 - returns the arctan2 of arg1 (radians)
1615 datan2(PG_FUNCTION_ARGS)
1617 float8 arg1 = PG_GETARG_FLOAT8(0);
1618 float8 arg2 = PG_GETARG_FLOAT8(1);
1622 result = atan2(arg1, arg2);
1625 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1626 errmsg("input is out of range")));
1628 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
1629 PG_RETURN_FLOAT8(result);
1634 * dcos - returns the cosine of arg1 (radians)
1637 dcos(PG_FUNCTION_ARGS)
1639 float8 arg1 = PG_GETARG_FLOAT8(0);
1646 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1647 errmsg("input is out of range")));
1649 CHECKFLOATVAL(result, isinf(arg1), true);
1650 PG_RETURN_FLOAT8(result);
1655 * dcot - returns the cotangent of arg1 (radians)
1658 dcot(PG_FUNCTION_ARGS)
1660 float8 arg1 = PG_GETARG_FLOAT8(0);
1667 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1668 errmsg("input is out of range")));
1670 result = 1.0 / result;
1671 CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */, true);
1672 PG_RETURN_FLOAT8(result);
1677 * dsin - returns the sine of arg1 (radians)
1680 dsin(PG_FUNCTION_ARGS)
1682 float8 arg1 = PG_GETARG_FLOAT8(0);
1689 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1690 errmsg("input is out of range")));
1692 CHECKFLOATVAL(result, isinf(arg1), true);
1693 PG_RETURN_FLOAT8(result);
1698 * dtan - returns the tangent of arg1 (radians)
1701 dtan(PG_FUNCTION_ARGS)
1703 float8 arg1 = PG_GETARG_FLOAT8(0);
1710 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1711 errmsg("input is out of range")));
1713 CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */, true);
1714 PG_RETURN_FLOAT8(result);
1719 * degrees - returns degrees converted from radians
1722 degrees(PG_FUNCTION_ARGS)
1724 float8 arg1 = PG_GETARG_FLOAT8(0);
1727 result = arg1 * (180.0 / M_PI);
1729 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1730 PG_RETURN_FLOAT8(result);
1735 * dpi - returns the constant PI
1738 dpi(PG_FUNCTION_ARGS)
1740 PG_RETURN_FLOAT8(M_PI);
1745 * radians - returns radians converted from degrees
1748 radians(PG_FUNCTION_ARGS)
1750 float8 arg1 = PG_GETARG_FLOAT8(0);
1753 result = arg1 * (M_PI / 180.0);
1755 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1756 PG_RETURN_FLOAT8(result);
1761 * drandom - returns a random number
1764 drandom(PG_FUNCTION_ARGS)
1768 /* result [0.0 - 1.0) */
1769 result = (double) random() / ((double) MAX_RANDOM_VALUE + 1);
1771 PG_RETURN_FLOAT8(result);
1776 * setseed - set seed for the random number generator
1779 setseed(PG_FUNCTION_ARGS)
1781 float8 seed = PG_GETARG_FLOAT8(0);
1782 int iseed = (int) (seed * MAX_RANDOM_VALUE);
1784 srandom((unsigned int) iseed);
1786 PG_RETURN_INT32(iseed);
1792 * =========================
1793 * FLOAT AGGREGATE OPERATORS
1794 * =========================
1796 * float8_accum - accumulate for AVG(), variance aggregates, etc.
1797 * float4_accum - same, but input data is float4
1798 * float8_avg - produce final result for float AVG()
1799 * float8_var_samp - produce final result for float VAR_SAMP()
1800 * float8_var_pop - produce final result for float VAR_POP()
1801 * float8_stddev_samp - produce final result for float STDDEV_SAMP()
1802 * float8_stddev_pop - produce final result for float STDDEV_POP()
1804 * The transition datatype for all these aggregates is a 3-element array
1805 * of float8, holding the values N, sum(X), sum(X*X) in that order.
1807 * Note that we represent N as a float to avoid having to build a special
1808 * datatype. Given a reasonable floating-point implementation, there should
1809 * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
1810 * user will have doubtless lost interest anyway...)
1814 check_float8_array(ArrayType *transarray, const char *caller, int n)
1817 * We expect the input to be an N-element float array; verify that. We
1818 * don't need to use deconstruct_array() since the array data is just
1819 * going to look like a C array of N float8 values.
1821 if (ARR_NDIM(transarray) != 1 ||
1822 ARR_DIMS(transarray)[0] != n ||
1823 ARR_HASNULL(transarray) ||
1824 ARR_ELEMTYPE(transarray) != FLOAT8OID)
1825 elog(ERROR, "%s: expected %d-element float8 array", caller, n);
1826 return (float8 *) ARR_DATA_PTR(transarray);
1830 float8_accum(PG_FUNCTION_ARGS)
1832 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1833 float8 newval = PG_GETARG_FLOAT8(1);
1834 float8 *transvalues;
1839 transvalues = check_float8_array(transarray, "float8_accum", 3);
1841 sumX = transvalues[1];
1842 sumX2 = transvalues[2];
1846 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
1847 sumX2 += newval * newval;
1848 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
1851 * If we're invoked by nodeAgg, we can cheat and modify our first
1852 * parameter in-place to reduce palloc overhead. Otherwise we construct a
1853 * new array with the updated transition data and return it.
1855 if (fcinfo->context && IsA(fcinfo->context, AggState))
1858 transvalues[1] = sumX;
1859 transvalues[2] = sumX2;
1861 PG_RETURN_ARRAYTYPE_P(transarray);
1865 Datum transdatums[3];
1868 transdatums[0] = Float8GetDatumFast(N);
1869 transdatums[1] = Float8GetDatumFast(sumX);
1870 transdatums[2] = Float8GetDatumFast(sumX2);
1872 result = construct_array(transdatums, 3,
1874 sizeof(float8), false /* float8 byval */ , 'd');
1876 PG_RETURN_ARRAYTYPE_P(result);
1881 float4_accum(PG_FUNCTION_ARGS)
1883 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1884 /* do computations as float8 */
1885 float8 newval = PG_GETARG_FLOAT4(1);
1886 float8 *transvalues;
1891 transvalues = check_float8_array(transarray, "float4_accum", 3);
1893 sumX = transvalues[1];
1894 sumX2 = transvalues[2];
1898 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
1899 sumX2 += newval * newval;
1900 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
1903 * If we're invoked by nodeAgg, we can cheat and modify our first
1904 * parameter in-place to reduce palloc overhead. Otherwise we construct a
1905 * new array with the updated transition data and return it.
1907 if (fcinfo->context && IsA(fcinfo->context, AggState))
1910 transvalues[1] = sumX;
1911 transvalues[2] = sumX2;
1913 PG_RETURN_ARRAYTYPE_P(transarray);
1917 Datum transdatums[3];
1920 transdatums[0] = Float8GetDatumFast(N);
1921 transdatums[1] = Float8GetDatumFast(sumX);
1922 transdatums[2] = Float8GetDatumFast(sumX2);
1924 result = construct_array(transdatums, 3,
1926 sizeof(float8), false /* float8 byval */ , 'd');
1928 PG_RETURN_ARRAYTYPE_P(result);
1933 float8_avg(PG_FUNCTION_ARGS)
1935 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1936 float8 *transvalues;
1940 transvalues = check_float8_array(transarray, "float8_avg", 3);
1942 sumX = transvalues[1];
1945 /* SQL92 defines AVG of no values to be NULL */
1949 PG_RETURN_FLOAT8(sumX / N);
1953 float8_var_pop(PG_FUNCTION_ARGS)
1955 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1956 float8 *transvalues;
1962 transvalues = check_float8_array(transarray, "float8_var_pop", 3);
1964 sumX = transvalues[1];
1965 sumX2 = transvalues[2];
1967 /* Population variance is undefined when N is 0, so return NULL */
1971 numerator = N * sumX2 - sumX * sumX;
1972 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
1974 /* Watch out for roundoff error producing a negative numerator */
1975 if (numerator <= 0.0)
1976 PG_RETURN_FLOAT8(0.0);
1978 PG_RETURN_FLOAT8(numerator / (N * N));
1982 float8_var_samp(PG_FUNCTION_ARGS)
1984 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1985 float8 *transvalues;
1991 transvalues = check_float8_array(transarray, "float8_var_samp", 3);
1993 sumX = transvalues[1];
1994 sumX2 = transvalues[2];
1996 /* Sample variance is undefined when N is 0 or 1, so return NULL */
2000 numerator = N * sumX2 - sumX * sumX;
2001 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
2003 /* Watch out for roundoff error producing a negative numerator */
2004 if (numerator <= 0.0)
2005 PG_RETURN_FLOAT8(0.0);
2007 PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
2011 float8_stddev_pop(PG_FUNCTION_ARGS)
2013 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2014 float8 *transvalues;
2020 transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
2022 sumX = transvalues[1];
2023 sumX2 = transvalues[2];
2025 /* Population stddev is undefined when N is 0, so return NULL */
2029 numerator = N * sumX2 - sumX * sumX;
2030 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
2032 /* Watch out for roundoff error producing a negative numerator */
2033 if (numerator <= 0.0)
2034 PG_RETURN_FLOAT8(0.0);
2036 PG_RETURN_FLOAT8(sqrt(numerator / (N * N)));
2040 float8_stddev_samp(PG_FUNCTION_ARGS)
2042 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2043 float8 *transvalues;
2049 transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
2051 sumX = transvalues[1];
2052 sumX2 = transvalues[2];
2054 /* Sample stddev is undefined when N is 0 or 1, so return NULL */
2058 numerator = N * sumX2 - sumX * sumX;
2059 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
2061 /* Watch out for roundoff error producing a negative numerator */
2062 if (numerator <= 0.0)
2063 PG_RETURN_FLOAT8(0.0);
2065 PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
2069 * =========================
2070 * SQL2003 BINARY AGGREGATES
2071 * =========================
2073 * The transition datatype for all these aggregates is a 6-element array of
2074 * float8, holding the values N, sum(X), sum(X*X), sum(Y), sum(Y*Y), sum(X*Y)
2075 * in that order. Note that Y is the first argument to the aggregates!
2077 * It might seem attractive to optimize this by having multiple accumulator
2078 * functions that only calculate the sums actually needed. But on most
2079 * modern machines, a couple of extra floating-point multiplies will be
2080 * insignificant compared to the other per-tuple overhead, so I've chosen
2081 * to minimize code space instead.
2085 float8_regr_accum(PG_FUNCTION_ARGS)
2087 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2088 float8 newvalY = PG_GETARG_FLOAT8(1);
2089 float8 newvalX = PG_GETARG_FLOAT8(2);
2090 float8 *transvalues;
2098 transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
2100 sumX = transvalues[1];
2101 sumX2 = transvalues[2];
2102 sumY = transvalues[3];
2103 sumY2 = transvalues[4];
2104 sumXY = transvalues[5];
2108 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
2109 sumX2 += newvalX * newvalX;
2110 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
2112 CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
2113 sumY2 += newvalY * newvalY;
2114 CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
2115 sumXY += newvalX * newvalY;
2116 CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
2117 isinf(newvalY), true);
2120 * If we're invoked by nodeAgg, we can cheat and modify our first
2121 * parameter in-place to reduce palloc overhead. Otherwise we construct a
2122 * new array with the updated transition data and return it.
2124 if (fcinfo->context && IsA(fcinfo->context, AggState))
2127 transvalues[1] = sumX;
2128 transvalues[2] = sumX2;
2129 transvalues[3] = sumY;
2130 transvalues[4] = sumY2;
2131 transvalues[5] = sumXY;
2133 PG_RETURN_ARRAYTYPE_P(transarray);
2137 Datum transdatums[6];
2140 transdatums[0] = Float8GetDatumFast(N);
2141 transdatums[1] = Float8GetDatumFast(sumX);
2142 transdatums[2] = Float8GetDatumFast(sumX2);
2143 transdatums[3] = Float8GetDatumFast(sumY);
2144 transdatums[4] = Float8GetDatumFast(sumY2);
2145 transdatums[5] = Float8GetDatumFast(sumXY);
2147 result = construct_array(transdatums, 6,
2150 false /* float8 byval */ , 'd');
2152 PG_RETURN_ARRAYTYPE_P(result);
2157 float8_regr_sxx(PG_FUNCTION_ARGS)
2159 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2160 float8 *transvalues;
2166 transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
2168 sumX = transvalues[1];
2169 sumX2 = transvalues[2];
2171 /* if N is 0 we should return NULL */
2175 numerator = N * sumX2 - sumX * sumX;
2176 CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
2178 /* Watch out for roundoff error producing a negative numerator */
2179 if (numerator <= 0.0)
2180 PG_RETURN_FLOAT8(0.0);
2182 PG_RETURN_FLOAT8(numerator / N);
2186 float8_regr_syy(PG_FUNCTION_ARGS)
2188 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2189 float8 *transvalues;
2195 transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
2197 sumY = transvalues[3];
2198 sumY2 = transvalues[4];
2200 /* if N is 0 we should return NULL */
2204 numerator = N * sumY2 - sumY * sumY;
2205 CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
2207 /* Watch out for roundoff error producing a negative numerator */
2208 if (numerator <= 0.0)
2209 PG_RETURN_FLOAT8(0.0);
2211 PG_RETURN_FLOAT8(numerator / N);
2215 float8_regr_sxy(PG_FUNCTION_ARGS)
2217 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2218 float8 *transvalues;
2225 transvalues = check_float8_array(transarray, "float8_regr_sxy", 6);
2227 sumX = transvalues[1];
2228 sumY = transvalues[3];
2229 sumXY = transvalues[5];
2231 /* if N is 0 we should return NULL */
2235 numerator = N * sumXY - sumX * sumY;
2236 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2239 /* A negative result is valid here */
2241 PG_RETURN_FLOAT8(numerator / N);
2245 float8_regr_avgx(PG_FUNCTION_ARGS)
2247 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2248 float8 *transvalues;
2252 transvalues = check_float8_array(transarray, "float8_regr_avgx", 6);
2254 sumX = transvalues[1];
2256 /* if N is 0 we should return NULL */
2260 PG_RETURN_FLOAT8(sumX / N);
2264 float8_regr_avgy(PG_FUNCTION_ARGS)
2266 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2267 float8 *transvalues;
2271 transvalues = check_float8_array(transarray, "float8_regr_avgy", 6);
2273 sumY = transvalues[3];
2275 /* if N is 0 we should return NULL */
2279 PG_RETURN_FLOAT8(sumY / N);
2283 float8_covar_pop(PG_FUNCTION_ARGS)
2285 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2286 float8 *transvalues;
2293 transvalues = check_float8_array(transarray, "float8_covar_pop", 6);
2295 sumX = transvalues[1];
2296 sumY = transvalues[3];
2297 sumXY = transvalues[5];
2299 /* if N is 0 we should return NULL */
2303 numerator = N * sumXY - sumX * sumY;
2304 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2307 PG_RETURN_FLOAT8(numerator / (N * N));
2311 float8_covar_samp(PG_FUNCTION_ARGS)
2313 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2314 float8 *transvalues;
2321 transvalues = check_float8_array(transarray, "float8_covar_samp", 6);
2323 sumX = transvalues[1];
2324 sumY = transvalues[3];
2325 sumXY = transvalues[5];
2327 /* if N is <= 1 we should return NULL */
2331 numerator = N * sumXY - sumX * sumY;
2332 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2335 PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
2339 float8_corr(PG_FUNCTION_ARGS)
2341 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2342 float8 *transvalues;
2353 transvalues = check_float8_array(transarray, "float8_corr", 6);
2355 sumX = transvalues[1];
2356 sumX2 = transvalues[2];
2357 sumY = transvalues[3];
2358 sumY2 = transvalues[4];
2359 sumXY = transvalues[5];
2361 /* if N is 0 we should return NULL */
2365 numeratorX = N * sumX2 - sumX * sumX;
2366 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2367 numeratorY = N * sumY2 - sumY * sumY;
2368 CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
2369 numeratorXY = N * sumXY - sumX * sumY;
2370 CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
2372 if (numeratorX <= 0 || numeratorY <= 0)
2375 PG_RETURN_FLOAT8(sqrt((numeratorXY * numeratorXY) /
2376 (numeratorX * numeratorY)));
2380 float8_regr_r2(PG_FUNCTION_ARGS)
2382 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2383 float8 *transvalues;
2394 transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
2396 sumX = transvalues[1];
2397 sumX2 = transvalues[2];
2398 sumY = transvalues[3];
2399 sumY2 = transvalues[4];
2400 sumXY = transvalues[5];
2402 /* if N is 0 we should return NULL */
2406 numeratorX = N * sumX2 - sumX * sumX;
2407 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2408 numeratorY = N * sumY2 - sumY * sumY;
2409 CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
2410 numeratorXY = N * sumXY - sumX * sumY;
2411 CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
2413 if (numeratorX <= 0)
2415 /* per spec, horizontal line produces 1.0 */
2416 if (numeratorY <= 0)
2417 PG_RETURN_FLOAT8(1.0);
2419 PG_RETURN_FLOAT8((numeratorXY * numeratorXY) /
2420 (numeratorX * numeratorY));
2424 float8_regr_slope(PG_FUNCTION_ARGS)
2426 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2427 float8 *transvalues;
2436 transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
2438 sumX = transvalues[1];
2439 sumX2 = transvalues[2];
2440 sumY = transvalues[3];
2441 sumXY = transvalues[5];
2443 /* if N is 0 we should return NULL */
2447 numeratorX = N * sumX2 - sumX * sumX;
2448 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2449 numeratorXY = N * sumXY - sumX * sumY;
2450 CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
2452 if (numeratorX <= 0)
2455 PG_RETURN_FLOAT8(numeratorXY / numeratorX);
2459 float8_regr_intercept(PG_FUNCTION_ARGS)
2461 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2462 float8 *transvalues;
2471 transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
2473 sumX = transvalues[1];
2474 sumX2 = transvalues[2];
2475 sumY = transvalues[3];
2476 sumXY = transvalues[5];
2478 /* if N is 0 we should return NULL */
2482 numeratorX = N * sumX2 - sumX * sumX;
2483 CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
2484 numeratorXXY = sumY * sumX2 - sumX * sumXY;
2485 CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
2486 isinf(sumX) || isinf(sumXY), true);
2487 if (numeratorX <= 0)
2490 PG_RETURN_FLOAT8(numeratorXXY / numeratorX);
2495 * ====================================
2496 * MIXED-PRECISION ARITHMETIC OPERATORS
2497 * ====================================
2501 * float48pl - returns arg1 + arg2
2502 * float48mi - returns arg1 - arg2
2503 * float48mul - returns arg1 * arg2
2504 * float48div - returns arg1 / arg2
2507 float48pl(PG_FUNCTION_ARGS)
2509 float4 arg1 = PG_GETARG_FLOAT4(0);
2510 float8 arg2 = PG_GETARG_FLOAT8(1);
2513 result = arg1 + arg2;
2514 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2515 PG_RETURN_FLOAT8(result);
2519 float48mi(PG_FUNCTION_ARGS)
2521 float4 arg1 = PG_GETARG_FLOAT4(0);
2522 float8 arg2 = PG_GETARG_FLOAT8(1);
2525 result = arg1 - arg2;
2526 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2527 PG_RETURN_FLOAT8(result);
2531 float48mul(PG_FUNCTION_ARGS)
2533 float4 arg1 = PG_GETARG_FLOAT4(0);
2534 float8 arg2 = PG_GETARG_FLOAT8(1);
2537 result = arg1 * arg2;
2538 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
2539 arg1 == 0 || arg2 == 0);
2540 PG_RETURN_FLOAT8(result);
2544 float48div(PG_FUNCTION_ARGS)
2546 float4 arg1 = PG_GETARG_FLOAT4(0);
2547 float8 arg2 = PG_GETARG_FLOAT8(1);
2552 (errcode(ERRCODE_DIVISION_BY_ZERO),
2553 errmsg("division by zero")));
2555 result = arg1 / arg2;
2556 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
2557 PG_RETURN_FLOAT8(result);
2561 * float84pl - returns arg1 + arg2
2562 * float84mi - returns arg1 - arg2
2563 * float84mul - returns arg1 * arg2
2564 * float84div - returns arg1 / arg2
2567 float84pl(PG_FUNCTION_ARGS)
2569 float8 arg1 = PG_GETARG_FLOAT8(0);
2570 float4 arg2 = PG_GETARG_FLOAT4(1);
2573 result = arg1 + arg2;
2575 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2576 PG_RETURN_FLOAT8(result);
2580 float84mi(PG_FUNCTION_ARGS)
2582 float8 arg1 = PG_GETARG_FLOAT8(0);
2583 float4 arg2 = PG_GETARG_FLOAT4(1);
2586 result = arg1 - arg2;
2588 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2589 PG_RETURN_FLOAT8(result);
2593 float84mul(PG_FUNCTION_ARGS)
2595 float8 arg1 = PG_GETARG_FLOAT8(0);
2596 float4 arg2 = PG_GETARG_FLOAT4(1);
2599 result = arg1 * arg2;
2601 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
2602 arg1 == 0 || arg2 == 0);
2603 PG_RETURN_FLOAT8(result);
2607 float84div(PG_FUNCTION_ARGS)
2609 float8 arg1 = PG_GETARG_FLOAT8(0);
2610 float4 arg2 = PG_GETARG_FLOAT4(1);
2615 (errcode(ERRCODE_DIVISION_BY_ZERO),
2616 errmsg("division by zero")));
2618 result = arg1 / arg2;
2620 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
2621 PG_RETURN_FLOAT8(result);
2625 * ====================
2626 * COMPARISON OPERATORS
2627 * ====================
2631 * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
2634 float48eq(PG_FUNCTION_ARGS)
2636 float4 arg1 = PG_GETARG_FLOAT4(0);
2637 float8 arg2 = PG_GETARG_FLOAT8(1);
2639 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
2643 float48ne(PG_FUNCTION_ARGS)
2645 float4 arg1 = PG_GETARG_FLOAT4(0);
2646 float8 arg2 = PG_GETARG_FLOAT8(1);
2648 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
2652 float48lt(PG_FUNCTION_ARGS)
2654 float4 arg1 = PG_GETARG_FLOAT4(0);
2655 float8 arg2 = PG_GETARG_FLOAT8(1);
2657 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
2661 float48le(PG_FUNCTION_ARGS)
2663 float4 arg1 = PG_GETARG_FLOAT4(0);
2664 float8 arg2 = PG_GETARG_FLOAT8(1);
2666 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
2670 float48gt(PG_FUNCTION_ARGS)
2672 float4 arg1 = PG_GETARG_FLOAT4(0);
2673 float8 arg2 = PG_GETARG_FLOAT8(1);
2675 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
2679 float48ge(PG_FUNCTION_ARGS)
2681 float4 arg1 = PG_GETARG_FLOAT4(0);
2682 float8 arg2 = PG_GETARG_FLOAT8(1);
2684 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
2688 * float84{eq,ne,lt,le,gt,ge} - float8/float4 comparison operations
2691 float84eq(PG_FUNCTION_ARGS)
2693 float8 arg1 = PG_GETARG_FLOAT8(0);
2694 float4 arg2 = PG_GETARG_FLOAT4(1);
2696 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
2700 float84ne(PG_FUNCTION_ARGS)
2702 float8 arg1 = PG_GETARG_FLOAT8(0);
2703 float4 arg2 = PG_GETARG_FLOAT4(1);
2705 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
2709 float84lt(PG_FUNCTION_ARGS)
2711 float8 arg1 = PG_GETARG_FLOAT8(0);
2712 float4 arg2 = PG_GETARG_FLOAT4(1);
2714 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
2718 float84le(PG_FUNCTION_ARGS)
2720 float8 arg1 = PG_GETARG_FLOAT8(0);
2721 float4 arg2 = PG_GETARG_FLOAT4(1);
2723 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
2727 float84gt(PG_FUNCTION_ARGS)
2729 float8 arg1 = PG_GETARG_FLOAT8(0);
2730 float4 arg2 = PG_GETARG_FLOAT4(1);
2732 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
2736 float84ge(PG_FUNCTION_ARGS)
2738 float8 arg1 = PG_GETARG_FLOAT8(0);
2739 float4 arg2 = PG_GETARG_FLOAT4(1);
2741 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
2744 /* ========== PRIVATE ROUTINES ========== */
2751 int isneg = (x < 0.0);
2752 double absx = fabs(x);
2753 double tmpres = pow(absx, (double) 1.0 / (double) 3.0);
2756 * The result is somewhat inaccurate --- not really pow()'s fault, as the
2757 * exponent it's handed contains roundoff error. We can improve the
2758 * accuracy by doing one iteration of Newton's formula. Beware of zero
2762 tmpres -= (tmpres - absx / (tmpres * tmpres)) / (double) 3.0;
2764 return isneg ? -tmpres : tmpres;
2767 #endif /* !HAVE_CBRT */