1 /*-------------------------------------------------------------------------
4 * Functions for the built-in floating-point types.
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
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
256 * In some IRIX versions, strtod() recognizes only "inf", so if the input
257 * is "infinity" we have to skip over "inity". Also, it may return
258 * positive infinity for "-inf".
262 if (pg_strncasecmp(num
, "Infinity", 8) == 0)
264 val
= get_float4_infinity();
267 else if (pg_strncasecmp(num
, "-Infinity", 9) == 0)
269 val
= -get_float4_infinity();
272 else if (pg_strncasecmp(num
, "-inf", 4) == 0)
274 val
= -get_float4_infinity();
278 #endif /* HAVE_BUGGY_IRIX_STRTOD */
280 /* skip trailing whitespace */
281 while (*endptr
!= '\0' && isspace((unsigned char) *endptr
))
284 /* if there is any junk left at the end of the string, bail out */
287 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
288 errmsg("invalid input syntax for type real: \"%s\"",
292 * if we get here, we have a legal double, still need to check to see if
293 * it's a legal float4
295 CHECKFLOATVAL((float4
) val
, isinf(val
), val
== 0);
297 PG_RETURN_FLOAT4((float4
) val
);
301 * float4out - converts a float4 number to a string
302 * using a standard output format
305 float4out(PG_FUNCTION_ARGS
)
307 float4 num
= PG_GETARG_FLOAT4(0);
308 char *ascii
= (char *) palloc(MAXFLOATWIDTH
+ 1);
311 PG_RETURN_CSTRING(strcpy(ascii
, "NaN"));
313 switch (is_infinite(num
))
316 strcpy(ascii
, "Infinity");
319 strcpy(ascii
, "-Infinity");
323 int ndig
= FLT_DIG
+ extra_float_digits
;
328 sprintf(ascii
, "%.*g", ndig
, num
);
332 PG_RETURN_CSTRING(ascii
);
336 * float4recv - converts external binary format to float4
339 float4recv(PG_FUNCTION_ARGS
)
341 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
343 PG_RETURN_FLOAT4(pq_getmsgfloat4(buf
));
347 * float4send - converts float4 to binary format
350 float4send(PG_FUNCTION_ARGS
)
352 float4 num
= PG_GETARG_FLOAT4(0);
355 pq_begintypsend(&buf
);
356 pq_sendfloat4(&buf
, num
);
357 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
361 * float8in - converts "num" to float8
363 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
364 * where <sp> is a space, digit is 0-9,
365 * <exp> is "e" or "E" followed by an integer.
368 float8in(PG_FUNCTION_ARGS
)
370 char *num
= PG_GETARG_CSTRING(0);
376 * endptr points to the first character _after_ the sequence we recognized
377 * as a valid floating point number. orig_num points to the original input
383 * Check for an empty-string input to begin with, to avoid the vagaries of
384 * strtod() on different platforms.
388 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
389 errmsg("invalid input syntax for type double precision: \"%s\"",
392 /* skip leading whitespace */
393 while (*num
!= '\0' && isspace((unsigned char) *num
))
397 val
= strtod(num
, &endptr
);
399 /* did we not see anything that looks like a double? */
400 if (endptr
== num
|| errno
!= 0)
403 * C99 requires that strtod() accept NaN and [-]Infinity, but not all
404 * platforms support that yet (and some accept them but set ERANGE
405 * anyway...) Therefore, we check for these inputs ourselves.
407 if (pg_strncasecmp(num
, "NaN", 3) == 0)
409 val
= get_float8_nan();
412 else if (pg_strncasecmp(num
, "Infinity", 8) == 0)
414 val
= get_float8_infinity();
417 else if (pg_strncasecmp(num
, "-Infinity", 9) == 0)
419 val
= -get_float8_infinity();
422 else if (errno
== ERANGE
)
424 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
425 errmsg("\"%s\" is out of range for type double precision",
429 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
430 errmsg("invalid input syntax for type double precision: \"%s\"",
433 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
437 * Many versions of Solaris have a bug wherein strtod sets endptr to
438 * point one byte beyond the end of the string when given "inf" or
441 if (endptr
!= num
&& endptr
[-1] == '\0')
444 #endif /* HAVE_BUGGY_SOLARIS_STRTOD */
446 #ifdef HAVE_BUGGY_IRIX_STRTOD
449 * In some IRIX versions, strtod() recognizes only "inf", so if the input
450 * is "infinity" we have to skip over "inity". Also, it may return
451 * positive infinity for "-inf".
455 if (pg_strncasecmp(num
, "Infinity", 8) == 0)
457 val
= get_float8_infinity();
460 else if (pg_strncasecmp(num
, "-Infinity", 9) == 0)
462 val
= -get_float8_infinity();
465 else if (pg_strncasecmp(num
, "-inf", 4) == 0)
467 val
= -get_float8_infinity();
471 #endif /* HAVE_BUGGY_IRIX_STRTOD */
473 /* skip trailing whitespace */
474 while (*endptr
!= '\0' && isspace((unsigned char) *endptr
))
477 /* if there is any junk left at the end of the string, bail out */
480 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION
),
481 errmsg("invalid input syntax for type double precision: \"%s\"",
484 CHECKFLOATVAL(val
, true, true);
486 PG_RETURN_FLOAT8(val
);
490 * float8out - converts float8 number to a string
491 * using a standard output format
494 float8out(PG_FUNCTION_ARGS
)
496 float8 num
= PG_GETARG_FLOAT8(0);
497 char *ascii
= (char *) palloc(MAXDOUBLEWIDTH
+ 1);
500 PG_RETURN_CSTRING(strcpy(ascii
, "NaN"));
502 switch (is_infinite(num
))
505 strcpy(ascii
, "Infinity");
508 strcpy(ascii
, "-Infinity");
512 int ndig
= DBL_DIG
+ extra_float_digits
;
517 sprintf(ascii
, "%.*g", ndig
, num
);
521 PG_RETURN_CSTRING(ascii
);
525 * float8recv - converts external binary format to float8
528 float8recv(PG_FUNCTION_ARGS
)
530 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
532 PG_RETURN_FLOAT8(pq_getmsgfloat8(buf
));
536 * float8send - converts float8 to binary format
539 float8send(PG_FUNCTION_ARGS
)
541 float8 num
= PG_GETARG_FLOAT8(0);
544 pq_begintypsend(&buf
);
545 pq_sendfloat8(&buf
, num
);
546 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
550 /* ========== PUBLIC ROUTINES ========== */
554 * ======================
555 * FLOAT4 BASE OPERATIONS
556 * ======================
560 * float4abs - returns |arg1| (absolute value)
563 float4abs(PG_FUNCTION_ARGS
)
565 float4 arg1
= PG_GETARG_FLOAT4(0);
567 PG_RETURN_FLOAT4((float4
) fabs(arg1
));
571 * float4um - returns -arg1 (unary minus)
574 float4um(PG_FUNCTION_ARGS
)
576 float4 arg1
= PG_GETARG_FLOAT4(0);
579 result
= ((arg1
!= 0) ? -(arg1
) : arg1
);
581 CHECKFLOATVAL(result
, isinf(arg1
), true);
582 PG_RETURN_FLOAT4(result
);
586 float4up(PG_FUNCTION_ARGS
)
588 float4 arg
= PG_GETARG_FLOAT4(0);
590 PG_RETURN_FLOAT4(arg
);
594 float4larger(PG_FUNCTION_ARGS
)
596 float4 arg1
= PG_GETARG_FLOAT4(0);
597 float4 arg2
= PG_GETARG_FLOAT4(1);
600 if (float4_cmp_internal(arg1
, arg2
) > 0)
604 PG_RETURN_FLOAT4(result
);
608 float4smaller(PG_FUNCTION_ARGS
)
610 float4 arg1
= PG_GETARG_FLOAT4(0);
611 float4 arg2
= PG_GETARG_FLOAT4(1);
614 if (float4_cmp_internal(arg1
, arg2
) < 0)
618 PG_RETURN_FLOAT4(result
);
622 * ======================
623 * FLOAT8 BASE OPERATIONS
624 * ======================
628 * float8abs - returns |arg1| (absolute value)
631 float8abs(PG_FUNCTION_ARGS
)
633 float8 arg1
= PG_GETARG_FLOAT8(0);
635 PG_RETURN_FLOAT8(fabs(arg1
));
640 * float8um - returns -arg1 (unary minus)
643 float8um(PG_FUNCTION_ARGS
)
645 float8 arg1
= PG_GETARG_FLOAT8(0);
648 result
= ((arg1
!= 0) ? -(arg1
) : arg1
);
650 CHECKFLOATVAL(result
, isinf(arg1
), true);
651 PG_RETURN_FLOAT8(result
);
655 float8up(PG_FUNCTION_ARGS
)
657 float8 arg
= PG_GETARG_FLOAT8(0);
659 PG_RETURN_FLOAT8(arg
);
663 float8larger(PG_FUNCTION_ARGS
)
665 float8 arg1
= PG_GETARG_FLOAT8(0);
666 float8 arg2
= PG_GETARG_FLOAT8(1);
669 if (float8_cmp_internal(arg1
, arg2
) > 0)
673 PG_RETURN_FLOAT8(result
);
677 float8smaller(PG_FUNCTION_ARGS
)
679 float8 arg1
= PG_GETARG_FLOAT8(0);
680 float8 arg2
= PG_GETARG_FLOAT8(1);
683 if (float8_cmp_internal(arg1
, arg2
) < 0)
687 PG_RETURN_FLOAT8(result
);
692 * ====================
693 * ARITHMETIC OPERATORS
694 * ====================
698 * float4pl - returns arg1 + arg2
699 * float4mi - returns arg1 - arg2
700 * float4mul - returns arg1 * arg2
701 * float4div - returns arg1 / arg2
704 float4pl(PG_FUNCTION_ARGS
)
706 float8 arg1
= PG_GETARG_FLOAT4(0);
707 float8 arg2
= PG_GETARG_FLOAT4(1);
710 result
= arg1
+ arg2
;
713 * There isn't any way to check for underflow of addition/subtraction
714 * because numbers near the underflow value have been already been to the
715 * point where we can't detect the that the two values were originally
716 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
719 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
720 PG_RETURN_FLOAT4(result
);
724 float4mi(PG_FUNCTION_ARGS
)
726 float4 arg1
= PG_GETARG_FLOAT4(0);
727 float4 arg2
= PG_GETARG_FLOAT4(1);
730 result
= arg1
- arg2
;
731 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
732 PG_RETURN_FLOAT4(result
);
736 float4mul(PG_FUNCTION_ARGS
)
738 float4 arg1
= PG_GETARG_FLOAT4(0);
739 float4 arg2
= PG_GETARG_FLOAT4(1);
742 result
= arg1
* arg2
;
743 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
),
744 arg1
== 0 || arg2
== 0);
745 PG_RETURN_FLOAT4(result
);
749 float4div(PG_FUNCTION_ARGS
)
751 float4 arg1
= PG_GETARG_FLOAT4(0);
752 float4 arg2
= PG_GETARG_FLOAT4(1);
757 (errcode(ERRCODE_DIVISION_BY_ZERO
),
758 errmsg("division by zero")));
760 /* Do division in float8, then check for overflow */
761 result
= arg1
/ arg2
;
763 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), arg1
== 0);
764 PG_RETURN_FLOAT4(result
);
768 * float8pl - returns arg1 + arg2
769 * float8mi - returns arg1 - arg2
770 * float8mul - returns arg1 * arg2
771 * float8div - returns arg1 / arg2
774 float8pl(PG_FUNCTION_ARGS
)
776 float8 arg1
= PG_GETARG_FLOAT8(0);
777 float8 arg2
= PG_GETARG_FLOAT8(1);
780 result
= arg1
+ arg2
;
782 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
783 PG_RETURN_FLOAT8(result
);
787 float8mi(PG_FUNCTION_ARGS
)
789 float8 arg1
= PG_GETARG_FLOAT8(0);
790 float8 arg2
= PG_GETARG_FLOAT8(1);
793 result
= arg1
- arg2
;
795 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
796 PG_RETURN_FLOAT8(result
);
800 float8mul(PG_FUNCTION_ARGS
)
802 float8 arg1
= PG_GETARG_FLOAT8(0);
803 float8 arg2
= PG_GETARG_FLOAT8(1);
806 result
= arg1
* arg2
;
808 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
),
809 arg1
== 0 || arg2
== 0);
810 PG_RETURN_FLOAT8(result
);
814 float8div(PG_FUNCTION_ARGS
)
816 float8 arg1
= PG_GETARG_FLOAT8(0);
817 float8 arg2
= PG_GETARG_FLOAT8(1);
822 (errcode(ERRCODE_DIVISION_BY_ZERO
),
823 errmsg("division by zero")));
825 result
= arg1
/ arg2
;
827 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), arg1
== 0);
828 PG_RETURN_FLOAT8(result
);
833 * ====================
834 * COMPARISON OPERATORS
835 * ====================
839 * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
842 float4_cmp_internal(float4 a
, float4 b
)
845 * We consider all NANs to be equal and larger than any non-NAN. This is
846 * somewhat arbitrary; the important thing is to have a consistent sort
852 return 0; /* NAN = NAN */
854 return 1; /* NAN > non-NAN */
858 return -1; /* non-NAN < NAN */
872 float4eq(PG_FUNCTION_ARGS
)
874 float4 arg1
= PG_GETARG_FLOAT4(0);
875 float4 arg2
= PG_GETARG_FLOAT4(1);
877 PG_RETURN_BOOL(float4_cmp_internal(arg1
, arg2
) == 0);
881 float4ne(PG_FUNCTION_ARGS
)
883 float4 arg1
= PG_GETARG_FLOAT4(0);
884 float4 arg2
= PG_GETARG_FLOAT4(1);
886 PG_RETURN_BOOL(float4_cmp_internal(arg1
, arg2
) != 0);
890 float4lt(PG_FUNCTION_ARGS
)
892 float4 arg1
= PG_GETARG_FLOAT4(0);
893 float4 arg2
= PG_GETARG_FLOAT4(1);
895 PG_RETURN_BOOL(float4_cmp_internal(arg1
, arg2
) < 0);
899 float4le(PG_FUNCTION_ARGS
)
901 float4 arg1
= PG_GETARG_FLOAT4(0);
902 float4 arg2
= PG_GETARG_FLOAT4(1);
904 PG_RETURN_BOOL(float4_cmp_internal(arg1
, arg2
) <= 0);
908 float4gt(PG_FUNCTION_ARGS
)
910 float4 arg1
= PG_GETARG_FLOAT4(0);
911 float4 arg2
= PG_GETARG_FLOAT4(1);
913 PG_RETURN_BOOL(float4_cmp_internal(arg1
, arg2
) > 0);
917 float4ge(PG_FUNCTION_ARGS
)
919 float4 arg1
= PG_GETARG_FLOAT4(0);
920 float4 arg2
= PG_GETARG_FLOAT4(1);
922 PG_RETURN_BOOL(float4_cmp_internal(arg1
, arg2
) >= 0);
926 btfloat4cmp(PG_FUNCTION_ARGS
)
928 float4 arg1
= PG_GETARG_FLOAT4(0);
929 float4 arg2
= PG_GETARG_FLOAT4(1);
931 PG_RETURN_INT32(float4_cmp_internal(arg1
, arg2
));
935 * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
938 float8_cmp_internal(float8 a
, float8 b
)
941 * We consider all NANs to be equal and larger than any non-NAN. This is
942 * somewhat arbitrary; the important thing is to have a consistent sort
948 return 0; /* NAN = NAN */
950 return 1; /* NAN > non-NAN */
954 return -1; /* non-NAN < NAN */
968 float8eq(PG_FUNCTION_ARGS
)
970 float8 arg1
= PG_GETARG_FLOAT8(0);
971 float8 arg2
= PG_GETARG_FLOAT8(1);
973 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) == 0);
977 float8ne(PG_FUNCTION_ARGS
)
979 float8 arg1
= PG_GETARG_FLOAT8(0);
980 float8 arg2
= PG_GETARG_FLOAT8(1);
982 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) != 0);
986 float8lt(PG_FUNCTION_ARGS
)
988 float8 arg1
= PG_GETARG_FLOAT8(0);
989 float8 arg2
= PG_GETARG_FLOAT8(1);
991 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) < 0);
995 float8le(PG_FUNCTION_ARGS
)
997 float8 arg1
= PG_GETARG_FLOAT8(0);
998 float8 arg2
= PG_GETARG_FLOAT8(1);
1000 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) <= 0);
1004 float8gt(PG_FUNCTION_ARGS
)
1006 float8 arg1
= PG_GETARG_FLOAT8(0);
1007 float8 arg2
= PG_GETARG_FLOAT8(1);
1009 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) > 0);
1013 float8ge(PG_FUNCTION_ARGS
)
1015 float8 arg1
= PG_GETARG_FLOAT8(0);
1016 float8 arg2
= PG_GETARG_FLOAT8(1);
1018 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) >= 0);
1022 btfloat8cmp(PG_FUNCTION_ARGS
)
1024 float8 arg1
= PG_GETARG_FLOAT8(0);
1025 float8 arg2
= PG_GETARG_FLOAT8(1);
1027 PG_RETURN_INT32(float8_cmp_internal(arg1
, arg2
));
1031 btfloat48cmp(PG_FUNCTION_ARGS
)
1033 float4 arg1
= PG_GETARG_FLOAT4(0);
1034 float8 arg2
= PG_GETARG_FLOAT8(1);
1036 /* widen float4 to float8 and then compare */
1037 PG_RETURN_INT32(float8_cmp_internal(arg1
, arg2
));
1041 btfloat84cmp(PG_FUNCTION_ARGS
)
1043 float8 arg1
= PG_GETARG_FLOAT8(0);
1044 float4 arg2
= PG_GETARG_FLOAT4(1);
1046 /* widen float4 to float8 and then compare */
1047 PG_RETURN_INT32(float8_cmp_internal(arg1
, arg2
));
1052 * ===================
1053 * CONVERSION ROUTINES
1054 * ===================
1058 * ftod - converts a float4 number to a float8 number
1061 ftod(PG_FUNCTION_ARGS
)
1063 float4 num
= PG_GETARG_FLOAT4(0);
1065 PG_RETURN_FLOAT8((float8
) num
);
1070 * dtof - converts a float8 number to a float4 number
1073 dtof(PG_FUNCTION_ARGS
)
1075 float8 num
= PG_GETARG_FLOAT8(0);
1077 CHECKFLOATVAL((float4
) num
, isinf(num
), num
== 0);
1079 PG_RETURN_FLOAT4((float4
) num
);
1084 * dtoi4 - converts a float8 number to an int4 number
1087 dtoi4(PG_FUNCTION_ARGS
)
1089 float8 num
= PG_GETARG_FLOAT8(0);
1092 /* 'Inf' is handled by INT_MAX */
1093 if (num
< INT_MIN
|| num
> INT_MAX
|| isnan(num
))
1095 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1096 errmsg("integer out of range")));
1098 result
= (int32
) rint(num
);
1099 PG_RETURN_INT32(result
);
1104 * dtoi2 - converts a float8 number to an int2 number
1107 dtoi2(PG_FUNCTION_ARGS
)
1109 float8 num
= PG_GETARG_FLOAT8(0);
1111 if (num
< SHRT_MIN
|| num
> SHRT_MAX
|| isnan(num
))
1113 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1114 errmsg("smallint out of range")));
1116 PG_RETURN_INT16((int16
) rint(num
));
1121 * i4tod - converts an int4 number to a float8 number
1124 i4tod(PG_FUNCTION_ARGS
)
1126 int32 num
= PG_GETARG_INT32(0);
1128 PG_RETURN_FLOAT8((float8
) num
);
1133 * i2tod - converts an int2 number to a float8 number
1136 i2tod(PG_FUNCTION_ARGS
)
1138 int16 num
= PG_GETARG_INT16(0);
1140 PG_RETURN_FLOAT8((float8
) num
);
1145 * ftoi4 - converts a float4 number to an int4 number
1148 ftoi4(PG_FUNCTION_ARGS
)
1150 float4 num
= PG_GETARG_FLOAT4(0);
1152 if (num
< INT_MIN
|| num
> INT_MAX
|| isnan(num
))
1154 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1155 errmsg("integer out of range")));
1157 PG_RETURN_INT32((int32
) rint(num
));
1162 * ftoi2 - converts a float4 number to an int2 number
1165 ftoi2(PG_FUNCTION_ARGS
)
1167 float4 num
= PG_GETARG_FLOAT4(0);
1169 if (num
< SHRT_MIN
|| num
> SHRT_MAX
|| isnan(num
))
1171 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1172 errmsg("smallint out of range")));
1174 PG_RETURN_INT16((int16
) rint(num
));
1179 * i4tof - converts an int4 number to a float4 number
1182 i4tof(PG_FUNCTION_ARGS
)
1184 int32 num
= PG_GETARG_INT32(0);
1186 PG_RETURN_FLOAT4((float4
) num
);
1191 * i2tof - converts an int2 number to a float4 number
1194 i2tof(PG_FUNCTION_ARGS
)
1196 int16 num
= PG_GETARG_INT16(0);
1198 PG_RETURN_FLOAT4((float4
) num
);
1203 * =======================
1204 * RANDOM FLOAT8 OPERATORS
1205 * =======================
1209 * dround - returns ROUND(arg1)
1212 dround(PG_FUNCTION_ARGS
)
1214 float8 arg1
= PG_GETARG_FLOAT8(0);
1216 PG_RETURN_FLOAT8(rint(arg1
));
1220 * dceil - returns the smallest integer greater than or
1221 * equal to the specified float
1224 dceil(PG_FUNCTION_ARGS
)
1226 float8 arg1
= PG_GETARG_FLOAT8(0);
1228 PG_RETURN_FLOAT8(ceil(arg1
));
1232 * dfloor - returns the largest integer lesser than or
1233 * equal to the specified float
1236 dfloor(PG_FUNCTION_ARGS
)
1238 float8 arg1
= PG_GETARG_FLOAT8(0);
1240 PG_RETURN_FLOAT8(floor(arg1
));
1244 * dsign - returns -1 if the argument is less than 0, 0
1245 * if the argument is equal to 0, and 1 if the
1246 * argument is greater than zero.
1249 dsign(PG_FUNCTION_ARGS
)
1251 float8 arg1
= PG_GETARG_FLOAT8(0);
1261 PG_RETURN_FLOAT8(result
);
1265 * dtrunc - returns truncation-towards-zero of arg1,
1266 * arg1 >= 0 ... the greatest integer less
1267 * than or equal to arg1
1268 * arg1 < 0 ... the least integer greater
1269 * than or equal to arg1
1272 dtrunc(PG_FUNCTION_ARGS
)
1274 float8 arg1
= PG_GETARG_FLOAT8(0);
1278 result
= floor(arg1
);
1280 result
= -floor(-arg1
);
1282 PG_RETURN_FLOAT8(result
);
1287 * dsqrt - returns square root of arg1
1290 dsqrt(PG_FUNCTION_ARGS
)
1292 float8 arg1
= PG_GETARG_FLOAT8(0);
1297 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION
),
1298 errmsg("cannot take square root of a negative number")));
1300 result
= sqrt(arg1
);
1302 CHECKFLOATVAL(result
, isinf(arg1
), arg1
== 0);
1303 PG_RETURN_FLOAT8(result
);
1308 * dcbrt - returns cube root of arg1
1311 dcbrt(PG_FUNCTION_ARGS
)
1313 float8 arg1
= PG_GETARG_FLOAT8(0);
1316 result
= cbrt(arg1
);
1317 CHECKFLOATVAL(result
, isinf(arg1
), arg1
== 0);
1318 PG_RETURN_FLOAT8(result
);
1323 * dpow - returns pow(arg1,arg2)
1326 dpow(PG_FUNCTION_ARGS
)
1328 float8 arg1
= PG_GETARG_FLOAT8(0);
1329 float8 arg2
= PG_GETARG_FLOAT8(1);
1333 * The SQL spec requires that we emit a particular SQLSTATE error code for
1334 * certain error conditions. Specifically, we don't return a divide-by-zero
1335 * error code for 0 ^ -1.
1337 if (arg1
== 0 && arg2
< 0)
1339 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION
),
1340 errmsg("zero raised to a negative power is undefined")));
1341 if (arg1
< 0 && floor(arg2
) != arg2
)
1343 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION
),
1344 errmsg("a negative number raised to a non-integer power yields a complex result")));
1347 * pow() sets errno only on some platforms, depending on whether it
1348 * follows _IEEE_, _POSIX_, _XOPEN_, or _SVID_, so we try to avoid using
1349 * errno. However, some platform/CPU combinations return errno == EDOM
1350 * and result == Nan for negative arg1 and very large arg2 (they must be
1351 * using something different from our floor() test to decide it's
1352 * invalid). Other platforms (HPPA) return errno == ERANGE and a large
1353 * (HUGE_VAL) but finite result to signal overflow.
1356 result
= pow(arg1
, arg2
);
1357 if (errno
== EDOM
&& isnan(result
))
1359 if ((fabs(arg1
) > 1 && arg2
>= 0) || (fabs(arg1
) < 1 && arg2
< 0))
1360 /* The sign of Inf is not significant in this case. */
1361 result
= get_float8_infinity();
1362 else if (fabs(arg1
) != 1)
1367 else if (errno
== ERANGE
&& result
!= 0 && !isinf(result
))
1368 result
= get_float8_infinity();
1370 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), arg1
== 0);
1371 PG_RETURN_FLOAT8(result
);
1376 * dexp - returns the exponential function of arg1
1379 dexp(PG_FUNCTION_ARGS
)
1381 float8 arg1
= PG_GETARG_FLOAT8(0);
1386 if (errno
== ERANGE
&& result
!= 0 && !isinf(result
))
1387 result
= get_float8_infinity();
1389 CHECKFLOATVAL(result
, isinf(arg1
), false);
1390 PG_RETURN_FLOAT8(result
);
1395 * dlog1 - returns the natural logarithm of arg1
1398 dlog1(PG_FUNCTION_ARGS
)
1400 float8 arg1
= PG_GETARG_FLOAT8(0);
1404 * Emit particular SQLSTATE error codes for ln(). This is required by the
1409 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG
),
1410 errmsg("cannot take logarithm of zero")));
1413 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG
),
1414 errmsg("cannot take logarithm of a negative number")));
1418 CHECKFLOATVAL(result
, isinf(arg1
), arg1
== 1);
1419 PG_RETURN_FLOAT8(result
);
1424 * dlog10 - returns the base 10 logarithm of arg1
1427 dlog10(PG_FUNCTION_ARGS
)
1429 float8 arg1
= PG_GETARG_FLOAT8(0);
1433 * Emit particular SQLSTATE error codes for log(). The SQL spec doesn't
1434 * define log(), but it does define ln(), so it makes sense to emit the
1435 * same error code for an analogous error condition.
1439 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG
),
1440 errmsg("cannot take logarithm of zero")));
1443 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG
),
1444 errmsg("cannot take logarithm of a negative number")));
1446 result
= log10(arg1
);
1448 CHECKFLOATVAL(result
, isinf(arg1
), arg1
== 1);
1449 PG_RETURN_FLOAT8(result
);
1454 * dacos - returns the arccos of arg1 (radians)
1457 dacos(PG_FUNCTION_ARGS
)
1459 float8 arg1
= PG_GETARG_FLOAT8(0);
1463 * We use errno here because the trigonometric functions are cyclic and
1464 * hard to check for underflow.
1467 result
= acos(arg1
);
1470 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1471 errmsg("input is out of range")));
1473 CHECKFLOATVAL(result
, isinf(arg1
), true);
1474 PG_RETURN_FLOAT8(result
);
1479 * dasin - returns the arcsin of arg1 (radians)
1482 dasin(PG_FUNCTION_ARGS
)
1484 float8 arg1
= PG_GETARG_FLOAT8(0);
1488 result
= asin(arg1
);
1491 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1492 errmsg("input is out of range")));
1494 CHECKFLOATVAL(result
, isinf(arg1
), true);
1495 PG_RETURN_FLOAT8(result
);
1500 * datan - returns the arctan of arg1 (radians)
1503 datan(PG_FUNCTION_ARGS
)
1505 float8 arg1
= PG_GETARG_FLOAT8(0);
1509 result
= atan(arg1
);
1512 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1513 errmsg("input is out of range")));
1515 CHECKFLOATVAL(result
, isinf(arg1
), true);
1516 PG_RETURN_FLOAT8(result
);
1521 * atan2 - returns the arctan2 of arg1 (radians)
1524 datan2(PG_FUNCTION_ARGS
)
1526 float8 arg1
= PG_GETARG_FLOAT8(0);
1527 float8 arg2
= PG_GETARG_FLOAT8(1);
1531 result
= atan2(arg1
, arg2
);
1534 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1535 errmsg("input is out of range")));
1537 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
1538 PG_RETURN_FLOAT8(result
);
1543 * dcos - returns the cosine of arg1 (radians)
1546 dcos(PG_FUNCTION_ARGS
)
1548 float8 arg1
= PG_GETARG_FLOAT8(0);
1555 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1556 errmsg("input is out of range")));
1558 CHECKFLOATVAL(result
, isinf(arg1
), true);
1559 PG_RETURN_FLOAT8(result
);
1564 * dcot - returns the cotangent of arg1 (radians)
1567 dcot(PG_FUNCTION_ARGS
)
1569 float8 arg1
= PG_GETARG_FLOAT8(0);
1576 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1577 errmsg("input is out of range")));
1579 result
= 1.0 / result
;
1580 CHECKFLOATVAL(result
, true /* cotan(pi/2) == inf */ , true);
1581 PG_RETURN_FLOAT8(result
);
1586 * dsin - returns the sine of arg1 (radians)
1589 dsin(PG_FUNCTION_ARGS
)
1591 float8 arg1
= PG_GETARG_FLOAT8(0);
1598 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1599 errmsg("input is out of range")));
1601 CHECKFLOATVAL(result
, isinf(arg1
), true);
1602 PG_RETURN_FLOAT8(result
);
1607 * dtan - returns the tangent of arg1 (radians)
1610 dtan(PG_FUNCTION_ARGS
)
1612 float8 arg1
= PG_GETARG_FLOAT8(0);
1619 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
1620 errmsg("input is out of range")));
1622 CHECKFLOATVAL(result
, true /* tan(pi/2) == Inf */ , true);
1623 PG_RETURN_FLOAT8(result
);
1628 * degrees - returns degrees converted from radians
1631 degrees(PG_FUNCTION_ARGS
)
1633 float8 arg1
= PG_GETARG_FLOAT8(0);
1636 result
= arg1
* (180.0 / M_PI
);
1638 CHECKFLOATVAL(result
, isinf(arg1
), arg1
== 0);
1639 PG_RETURN_FLOAT8(result
);
1644 * dpi - returns the constant PI
1647 dpi(PG_FUNCTION_ARGS
)
1649 PG_RETURN_FLOAT8(M_PI
);
1654 * radians - returns radians converted from degrees
1657 radians(PG_FUNCTION_ARGS
)
1659 float8 arg1
= PG_GETARG_FLOAT8(0);
1662 result
= arg1
* (M_PI
/ 180.0);
1664 CHECKFLOATVAL(result
, isinf(arg1
), arg1
== 0);
1665 PG_RETURN_FLOAT8(result
);
1670 * drandom - returns a random number
1673 drandom(PG_FUNCTION_ARGS
)
1677 /* result [0.0 - 1.0) */
1678 result
= (double) random() / ((double) MAX_RANDOM_VALUE
+ 1);
1680 PG_RETURN_FLOAT8(result
);
1685 * setseed - set seed for the random number generator
1688 setseed(PG_FUNCTION_ARGS
)
1690 float8 seed
= PG_GETARG_FLOAT8(0);
1693 if (seed
< -1 || seed
> 1)
1694 elog(ERROR
, "setseed parameter %f out of range [-1,1]", seed
);
1696 iseed
= (int) (seed
* MAX_RANDOM_VALUE
);
1697 srandom((unsigned int) iseed
);
1705 * =========================
1706 * FLOAT AGGREGATE OPERATORS
1707 * =========================
1709 * float8_accum - accumulate for AVG(), variance aggregates, etc.
1710 * float4_accum - same, but input data is float4
1711 * float8_avg - produce final result for float AVG()
1712 * float8_var_samp - produce final result for float VAR_SAMP()
1713 * float8_var_pop - produce final result for float VAR_POP()
1714 * float8_stddev_samp - produce final result for float STDDEV_SAMP()
1715 * float8_stddev_pop - produce final result for float STDDEV_POP()
1717 * The transition datatype for all these aggregates is a 3-element array
1718 * of float8, holding the values N, sum(X), sum(X*X) in that order.
1720 * Note that we represent N as a float to avoid having to build a special
1721 * datatype. Given a reasonable floating-point implementation, there should
1722 * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
1723 * user will have doubtless lost interest anyway...)
1727 check_float8_array(ArrayType
*transarray
, const char *caller
, int n
)
1730 * We expect the input to be an N-element float array; verify that. We
1731 * don't need to use deconstruct_array() since the array data is just
1732 * going to look like a C array of N float8 values.
1734 if (ARR_NDIM(transarray
) != 1 ||
1735 ARR_DIMS(transarray
)[0] != n
||
1736 ARR_HASNULL(transarray
) ||
1737 ARR_ELEMTYPE(transarray
) != FLOAT8OID
)
1738 elog(ERROR
, "%s: expected %d-element float8 array", caller
, n
);
1739 return (float8
*) ARR_DATA_PTR(transarray
);
1743 float8_accum(PG_FUNCTION_ARGS
)
1745 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1746 float8 newval
= PG_GETARG_FLOAT8(1);
1747 float8
*transvalues
;
1752 transvalues
= check_float8_array(transarray
, "float8_accum", 3);
1754 sumX
= transvalues
[1];
1755 sumX2
= transvalues
[2];
1759 CHECKFLOATVAL(sumX
, isinf(transvalues
[1]) || isinf(newval
), true);
1760 sumX2
+= newval
* newval
;
1761 CHECKFLOATVAL(sumX2
, isinf(transvalues
[2]) || isinf(newval
), true);
1764 * If we're invoked by nodeAgg, we can cheat and modify our first
1765 * parameter in-place to reduce palloc overhead. Otherwise we construct a
1766 * new array with the updated transition data and return it.
1768 if (fcinfo
->context
&& IsA(fcinfo
->context
, AggState
))
1771 transvalues
[1] = sumX
;
1772 transvalues
[2] = sumX2
;
1774 PG_RETURN_ARRAYTYPE_P(transarray
);
1778 Datum transdatums
[3];
1781 transdatums
[0] = Float8GetDatumFast(N
);
1782 transdatums
[1] = Float8GetDatumFast(sumX
);
1783 transdatums
[2] = Float8GetDatumFast(sumX2
);
1785 result
= construct_array(transdatums
, 3,
1787 sizeof(float8
), FLOAT8PASSBYVAL
, 'd');
1789 PG_RETURN_ARRAYTYPE_P(result
);
1794 float4_accum(PG_FUNCTION_ARGS
)
1796 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1798 /* do computations as float8 */
1799 float8 newval
= PG_GETARG_FLOAT4(1);
1800 float8
*transvalues
;
1805 transvalues
= check_float8_array(transarray
, "float4_accum", 3);
1807 sumX
= transvalues
[1];
1808 sumX2
= transvalues
[2];
1812 CHECKFLOATVAL(sumX
, isinf(transvalues
[1]) || isinf(newval
), true);
1813 sumX2
+= newval
* newval
;
1814 CHECKFLOATVAL(sumX2
, isinf(transvalues
[2]) || isinf(newval
), true);
1817 * If we're invoked by nodeAgg, we can cheat and modify our first
1818 * parameter in-place to reduce palloc overhead. Otherwise we construct a
1819 * new array with the updated transition data and return it.
1821 if (fcinfo
->context
&& IsA(fcinfo
->context
, AggState
))
1824 transvalues
[1] = sumX
;
1825 transvalues
[2] = sumX2
;
1827 PG_RETURN_ARRAYTYPE_P(transarray
);
1831 Datum transdatums
[3];
1834 transdatums
[0] = Float8GetDatumFast(N
);
1835 transdatums
[1] = Float8GetDatumFast(sumX
);
1836 transdatums
[2] = Float8GetDatumFast(sumX2
);
1838 result
= construct_array(transdatums
, 3,
1840 sizeof(float8
), FLOAT8PASSBYVAL
, 'd');
1842 PG_RETURN_ARRAYTYPE_P(result
);
1847 float8_avg(PG_FUNCTION_ARGS
)
1849 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1850 float8
*transvalues
;
1854 transvalues
= check_float8_array(transarray
, "float8_avg", 3);
1856 sumX
= transvalues
[1];
1859 /* SQL92 defines AVG of no values to be NULL */
1863 PG_RETURN_FLOAT8(sumX
/ N
);
1867 float8_var_pop(PG_FUNCTION_ARGS
)
1869 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1870 float8
*transvalues
;
1876 transvalues
= check_float8_array(transarray
, "float8_var_pop", 3);
1878 sumX
= transvalues
[1];
1879 sumX2
= transvalues
[2];
1881 /* Population variance is undefined when N is 0, so return NULL */
1885 numerator
= N
* sumX2
- sumX
* sumX
;
1886 CHECKFLOATVAL(numerator
, isinf(sumX2
) || isinf(sumX
), true);
1888 /* Watch out for roundoff error producing a negative numerator */
1889 if (numerator
<= 0.0)
1890 PG_RETURN_FLOAT8(0.0);
1892 PG_RETURN_FLOAT8(numerator
/ (N
* N
));
1896 float8_var_samp(PG_FUNCTION_ARGS
)
1898 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1899 float8
*transvalues
;
1905 transvalues
= check_float8_array(transarray
, "float8_var_samp", 3);
1907 sumX
= transvalues
[1];
1908 sumX2
= transvalues
[2];
1910 /* Sample variance is undefined when N is 0 or 1, so return NULL */
1914 numerator
= N
* sumX2
- sumX
* sumX
;
1915 CHECKFLOATVAL(numerator
, isinf(sumX2
) || isinf(sumX
), true);
1917 /* Watch out for roundoff error producing a negative numerator */
1918 if (numerator
<= 0.0)
1919 PG_RETURN_FLOAT8(0.0);
1921 PG_RETURN_FLOAT8(numerator
/ (N
* (N
- 1.0)));
1925 float8_stddev_pop(PG_FUNCTION_ARGS
)
1927 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1928 float8
*transvalues
;
1934 transvalues
= check_float8_array(transarray
, "float8_stddev_pop", 3);
1936 sumX
= transvalues
[1];
1937 sumX2
= transvalues
[2];
1939 /* Population stddev is undefined when N is 0, so return NULL */
1943 numerator
= N
* sumX2
- sumX
* sumX
;
1944 CHECKFLOATVAL(numerator
, isinf(sumX2
) || isinf(sumX
), true);
1946 /* Watch out for roundoff error producing a negative numerator */
1947 if (numerator
<= 0.0)
1948 PG_RETURN_FLOAT8(0.0);
1950 PG_RETURN_FLOAT8(sqrt(numerator
/ (N
* N
)));
1954 float8_stddev_samp(PG_FUNCTION_ARGS
)
1956 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
1957 float8
*transvalues
;
1963 transvalues
= check_float8_array(transarray
, "float8_stddev_samp", 3);
1965 sumX
= transvalues
[1];
1966 sumX2
= transvalues
[2];
1968 /* Sample stddev is undefined when N is 0 or 1, so return NULL */
1972 numerator
= N
* sumX2
- sumX
* sumX
;
1973 CHECKFLOATVAL(numerator
, isinf(sumX2
) || isinf(sumX
), true);
1975 /* Watch out for roundoff error producing a negative numerator */
1976 if (numerator
<= 0.0)
1977 PG_RETURN_FLOAT8(0.0);
1979 PG_RETURN_FLOAT8(sqrt(numerator
/ (N
* (N
- 1.0))));
1983 * =========================
1984 * SQL2003 BINARY AGGREGATES
1985 * =========================
1987 * The transition datatype for all these aggregates is a 6-element array of
1988 * float8, holding the values N, sum(X), sum(X*X), sum(Y), sum(Y*Y), sum(X*Y)
1989 * in that order. Note that Y is the first argument to the aggregates!
1991 * It might seem attractive to optimize this by having multiple accumulator
1992 * functions that only calculate the sums actually needed. But on most
1993 * modern machines, a couple of extra floating-point multiplies will be
1994 * insignificant compared to the other per-tuple overhead, so I've chosen
1995 * to minimize code space instead.
1999 float8_regr_accum(PG_FUNCTION_ARGS
)
2001 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2002 float8 newvalY
= PG_GETARG_FLOAT8(1);
2003 float8 newvalX
= PG_GETARG_FLOAT8(2);
2004 float8
*transvalues
;
2012 transvalues
= check_float8_array(transarray
, "float8_regr_accum", 6);
2014 sumX
= transvalues
[1];
2015 sumX2
= transvalues
[2];
2016 sumY
= transvalues
[3];
2017 sumY2
= transvalues
[4];
2018 sumXY
= transvalues
[5];
2022 CHECKFLOATVAL(sumX
, isinf(transvalues
[1]) || isinf(newvalX
), true);
2023 sumX2
+= newvalX
* newvalX
;
2024 CHECKFLOATVAL(sumX2
, isinf(transvalues
[2]) || isinf(newvalX
), true);
2026 CHECKFLOATVAL(sumY
, isinf(transvalues
[3]) || isinf(newvalY
), true);
2027 sumY2
+= newvalY
* newvalY
;
2028 CHECKFLOATVAL(sumY2
, isinf(transvalues
[4]) || isinf(newvalY
), true);
2029 sumXY
+= newvalX
* newvalY
;
2030 CHECKFLOATVAL(sumXY
, isinf(transvalues
[5]) || isinf(newvalX
) ||
2031 isinf(newvalY
), true);
2034 * If we're invoked by nodeAgg, we can cheat and modify our first
2035 * parameter in-place to reduce palloc overhead. Otherwise we construct a
2036 * new array with the updated transition data and return it.
2038 if (fcinfo
->context
&& IsA(fcinfo
->context
, AggState
))
2041 transvalues
[1] = sumX
;
2042 transvalues
[2] = sumX2
;
2043 transvalues
[3] = sumY
;
2044 transvalues
[4] = sumY2
;
2045 transvalues
[5] = sumXY
;
2047 PG_RETURN_ARRAYTYPE_P(transarray
);
2051 Datum transdatums
[6];
2054 transdatums
[0] = Float8GetDatumFast(N
);
2055 transdatums
[1] = Float8GetDatumFast(sumX
);
2056 transdatums
[2] = Float8GetDatumFast(sumX2
);
2057 transdatums
[3] = Float8GetDatumFast(sumY
);
2058 transdatums
[4] = Float8GetDatumFast(sumY2
);
2059 transdatums
[5] = Float8GetDatumFast(sumXY
);
2061 result
= construct_array(transdatums
, 6,
2063 sizeof(float8
), FLOAT8PASSBYVAL
, 'd');
2065 PG_RETURN_ARRAYTYPE_P(result
);
2070 float8_regr_sxx(PG_FUNCTION_ARGS
)
2072 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2073 float8
*transvalues
;
2079 transvalues
= check_float8_array(transarray
, "float8_regr_sxx", 6);
2081 sumX
= transvalues
[1];
2082 sumX2
= transvalues
[2];
2084 /* if N is 0 we should return NULL */
2088 numerator
= N
* sumX2
- sumX
* sumX
;
2089 CHECKFLOATVAL(numerator
, isinf(sumX2
) || isinf(sumX
), true);
2091 /* Watch out for roundoff error producing a negative numerator */
2092 if (numerator
<= 0.0)
2093 PG_RETURN_FLOAT8(0.0);
2095 PG_RETURN_FLOAT8(numerator
/ N
);
2099 float8_regr_syy(PG_FUNCTION_ARGS
)
2101 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2102 float8
*transvalues
;
2108 transvalues
= check_float8_array(transarray
, "float8_regr_syy", 6);
2110 sumY
= transvalues
[3];
2111 sumY2
= transvalues
[4];
2113 /* if N is 0 we should return NULL */
2117 numerator
= N
* sumY2
- sumY
* sumY
;
2118 CHECKFLOATVAL(numerator
, isinf(sumY2
) || isinf(sumY
), true);
2120 /* Watch out for roundoff error producing a negative numerator */
2121 if (numerator
<= 0.0)
2122 PG_RETURN_FLOAT8(0.0);
2124 PG_RETURN_FLOAT8(numerator
/ N
);
2128 float8_regr_sxy(PG_FUNCTION_ARGS
)
2130 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2131 float8
*transvalues
;
2138 transvalues
= check_float8_array(transarray
, "float8_regr_sxy", 6);
2140 sumX
= transvalues
[1];
2141 sumY
= transvalues
[3];
2142 sumXY
= transvalues
[5];
2144 /* if N is 0 we should return NULL */
2148 numerator
= N
* sumXY
- sumX
* sumY
;
2149 CHECKFLOATVAL(numerator
, isinf(sumXY
) || isinf(sumX
) ||
2152 /* A negative result is valid here */
2154 PG_RETURN_FLOAT8(numerator
/ N
);
2158 float8_regr_avgx(PG_FUNCTION_ARGS
)
2160 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2161 float8
*transvalues
;
2165 transvalues
= check_float8_array(transarray
, "float8_regr_avgx", 6);
2167 sumX
= transvalues
[1];
2169 /* if N is 0 we should return NULL */
2173 PG_RETURN_FLOAT8(sumX
/ N
);
2177 float8_regr_avgy(PG_FUNCTION_ARGS
)
2179 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2180 float8
*transvalues
;
2184 transvalues
= check_float8_array(transarray
, "float8_regr_avgy", 6);
2186 sumY
= transvalues
[3];
2188 /* if N is 0 we should return NULL */
2192 PG_RETURN_FLOAT8(sumY
/ N
);
2196 float8_covar_pop(PG_FUNCTION_ARGS
)
2198 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2199 float8
*transvalues
;
2206 transvalues
= check_float8_array(transarray
, "float8_covar_pop", 6);
2208 sumX
= transvalues
[1];
2209 sumY
= transvalues
[3];
2210 sumXY
= transvalues
[5];
2212 /* if N is 0 we should return NULL */
2216 numerator
= N
* sumXY
- sumX
* sumY
;
2217 CHECKFLOATVAL(numerator
, isinf(sumXY
) || isinf(sumX
) ||
2220 PG_RETURN_FLOAT8(numerator
/ (N
* N
));
2224 float8_covar_samp(PG_FUNCTION_ARGS
)
2226 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2227 float8
*transvalues
;
2234 transvalues
= check_float8_array(transarray
, "float8_covar_samp", 6);
2236 sumX
= transvalues
[1];
2237 sumY
= transvalues
[3];
2238 sumXY
= transvalues
[5];
2240 /* if N is <= 1 we should return NULL */
2244 numerator
= N
* sumXY
- sumX
* sumY
;
2245 CHECKFLOATVAL(numerator
, isinf(sumXY
) || isinf(sumX
) ||
2248 PG_RETURN_FLOAT8(numerator
/ (N
* (N
- 1.0)));
2252 float8_corr(PG_FUNCTION_ARGS
)
2254 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2255 float8
*transvalues
;
2266 transvalues
= check_float8_array(transarray
, "float8_corr", 6);
2268 sumX
= transvalues
[1];
2269 sumX2
= transvalues
[2];
2270 sumY
= transvalues
[3];
2271 sumY2
= transvalues
[4];
2272 sumXY
= transvalues
[5];
2274 /* if N is 0 we should return NULL */
2278 numeratorX
= N
* sumX2
- sumX
* sumX
;
2279 CHECKFLOATVAL(numeratorX
, isinf(sumX2
) || isinf(sumX
), true);
2280 numeratorY
= N
* sumY2
- sumY
* sumY
;
2281 CHECKFLOATVAL(numeratorY
, isinf(sumY2
) || isinf(sumY
), true);
2282 numeratorXY
= N
* sumXY
- sumX
* sumY
;
2283 CHECKFLOATVAL(numeratorXY
, isinf(sumXY
) || isinf(sumX
) ||
2285 if (numeratorX
<= 0 || numeratorY
<= 0)
2288 PG_RETURN_FLOAT8(numeratorXY
/ sqrt(numeratorX
* numeratorY
));
2292 float8_regr_r2(PG_FUNCTION_ARGS
)
2294 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2295 float8
*transvalues
;
2306 transvalues
= check_float8_array(transarray
, "float8_regr_r2", 6);
2308 sumX
= transvalues
[1];
2309 sumX2
= transvalues
[2];
2310 sumY
= transvalues
[3];
2311 sumY2
= transvalues
[4];
2312 sumXY
= transvalues
[5];
2314 /* if N is 0 we should return NULL */
2318 numeratorX
= N
* sumX2
- sumX
* sumX
;
2319 CHECKFLOATVAL(numeratorX
, isinf(sumX2
) || isinf(sumX
), true);
2320 numeratorY
= N
* sumY2
- sumY
* sumY
;
2321 CHECKFLOATVAL(numeratorY
, isinf(sumY2
) || isinf(sumY
), true);
2322 numeratorXY
= N
* sumXY
- sumX
* sumY
;
2323 CHECKFLOATVAL(numeratorXY
, isinf(sumXY
) || isinf(sumX
) ||
2325 if (numeratorX
<= 0)
2327 /* per spec, horizontal line produces 1.0 */
2328 if (numeratorY
<= 0)
2329 PG_RETURN_FLOAT8(1.0);
2331 PG_RETURN_FLOAT8((numeratorXY
* numeratorXY
) /
2332 (numeratorX
* numeratorY
));
2336 float8_regr_slope(PG_FUNCTION_ARGS
)
2338 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2339 float8
*transvalues
;
2348 transvalues
= check_float8_array(transarray
, "float8_regr_slope", 6);
2350 sumX
= transvalues
[1];
2351 sumX2
= transvalues
[2];
2352 sumY
= transvalues
[3];
2353 sumXY
= transvalues
[5];
2355 /* if N is 0 we should return NULL */
2359 numeratorX
= N
* sumX2
- sumX
* sumX
;
2360 CHECKFLOATVAL(numeratorX
, isinf(sumX2
) || isinf(sumX
), true);
2361 numeratorXY
= N
* sumXY
- sumX
* sumY
;
2362 CHECKFLOATVAL(numeratorXY
, isinf(sumXY
) || isinf(sumX
) ||
2364 if (numeratorX
<= 0)
2367 PG_RETURN_FLOAT8(numeratorXY
/ numeratorX
);
2371 float8_regr_intercept(PG_FUNCTION_ARGS
)
2373 ArrayType
*transarray
= PG_GETARG_ARRAYTYPE_P(0);
2374 float8
*transvalues
;
2383 transvalues
= check_float8_array(transarray
, "float8_regr_intercept", 6);
2385 sumX
= transvalues
[1];
2386 sumX2
= transvalues
[2];
2387 sumY
= transvalues
[3];
2388 sumXY
= transvalues
[5];
2390 /* if N is 0 we should return NULL */
2394 numeratorX
= N
* sumX2
- sumX
* sumX
;
2395 CHECKFLOATVAL(numeratorX
, isinf(sumX2
) || isinf(sumX
), true);
2396 numeratorXXY
= sumY
* sumX2
- sumX
* sumXY
;
2397 CHECKFLOATVAL(numeratorXXY
, isinf(sumY
) || isinf(sumX2
) ||
2398 isinf(sumX
) || isinf(sumXY
), true);
2399 if (numeratorX
<= 0)
2402 PG_RETURN_FLOAT8(numeratorXXY
/ numeratorX
);
2407 * ====================================
2408 * MIXED-PRECISION ARITHMETIC OPERATORS
2409 * ====================================
2413 * float48pl - returns arg1 + arg2
2414 * float48mi - returns arg1 - arg2
2415 * float48mul - returns arg1 * arg2
2416 * float48div - returns arg1 / arg2
2419 float48pl(PG_FUNCTION_ARGS
)
2421 float4 arg1
= PG_GETARG_FLOAT4(0);
2422 float8 arg2
= PG_GETARG_FLOAT8(1);
2425 result
= arg1
+ arg2
;
2426 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
2427 PG_RETURN_FLOAT8(result
);
2431 float48mi(PG_FUNCTION_ARGS
)
2433 float4 arg1
= PG_GETARG_FLOAT4(0);
2434 float8 arg2
= PG_GETARG_FLOAT8(1);
2437 result
= arg1
- arg2
;
2438 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
2439 PG_RETURN_FLOAT8(result
);
2443 float48mul(PG_FUNCTION_ARGS
)
2445 float4 arg1
= PG_GETARG_FLOAT4(0);
2446 float8 arg2
= PG_GETARG_FLOAT8(1);
2449 result
= arg1
* arg2
;
2450 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
),
2451 arg1
== 0 || arg2
== 0);
2452 PG_RETURN_FLOAT8(result
);
2456 float48div(PG_FUNCTION_ARGS
)
2458 float4 arg1
= PG_GETARG_FLOAT4(0);
2459 float8 arg2
= PG_GETARG_FLOAT8(1);
2464 (errcode(ERRCODE_DIVISION_BY_ZERO
),
2465 errmsg("division by zero")));
2467 result
= arg1
/ arg2
;
2468 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), arg1
== 0);
2469 PG_RETURN_FLOAT8(result
);
2473 * float84pl - returns arg1 + arg2
2474 * float84mi - returns arg1 - arg2
2475 * float84mul - returns arg1 * arg2
2476 * float84div - returns arg1 / arg2
2479 float84pl(PG_FUNCTION_ARGS
)
2481 float8 arg1
= PG_GETARG_FLOAT8(0);
2482 float4 arg2
= PG_GETARG_FLOAT4(1);
2485 result
= arg1
+ arg2
;
2487 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
2488 PG_RETURN_FLOAT8(result
);
2492 float84mi(PG_FUNCTION_ARGS
)
2494 float8 arg1
= PG_GETARG_FLOAT8(0);
2495 float4 arg2
= PG_GETARG_FLOAT4(1);
2498 result
= arg1
- arg2
;
2500 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), true);
2501 PG_RETURN_FLOAT8(result
);
2505 float84mul(PG_FUNCTION_ARGS
)
2507 float8 arg1
= PG_GETARG_FLOAT8(0);
2508 float4 arg2
= PG_GETARG_FLOAT4(1);
2511 result
= arg1
* arg2
;
2513 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
),
2514 arg1
== 0 || arg2
== 0);
2515 PG_RETURN_FLOAT8(result
);
2519 float84div(PG_FUNCTION_ARGS
)
2521 float8 arg1
= PG_GETARG_FLOAT8(0);
2522 float4 arg2
= PG_GETARG_FLOAT4(1);
2527 (errcode(ERRCODE_DIVISION_BY_ZERO
),
2528 errmsg("division by zero")));
2530 result
= arg1
/ arg2
;
2532 CHECKFLOATVAL(result
, isinf(arg1
) || isinf(arg2
), arg1
== 0);
2533 PG_RETURN_FLOAT8(result
);
2537 * ====================
2538 * COMPARISON OPERATORS
2539 * ====================
2543 * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
2546 float48eq(PG_FUNCTION_ARGS
)
2548 float4 arg1
= PG_GETARG_FLOAT4(0);
2549 float8 arg2
= PG_GETARG_FLOAT8(1);
2551 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) == 0);
2555 float48ne(PG_FUNCTION_ARGS
)
2557 float4 arg1
= PG_GETARG_FLOAT4(0);
2558 float8 arg2
= PG_GETARG_FLOAT8(1);
2560 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) != 0);
2564 float48lt(PG_FUNCTION_ARGS
)
2566 float4 arg1
= PG_GETARG_FLOAT4(0);
2567 float8 arg2
= PG_GETARG_FLOAT8(1);
2569 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) < 0);
2573 float48le(PG_FUNCTION_ARGS
)
2575 float4 arg1
= PG_GETARG_FLOAT4(0);
2576 float8 arg2
= PG_GETARG_FLOAT8(1);
2578 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) <= 0);
2582 float48gt(PG_FUNCTION_ARGS
)
2584 float4 arg1
= PG_GETARG_FLOAT4(0);
2585 float8 arg2
= PG_GETARG_FLOAT8(1);
2587 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) > 0);
2591 float48ge(PG_FUNCTION_ARGS
)
2593 float4 arg1
= PG_GETARG_FLOAT4(0);
2594 float8 arg2
= PG_GETARG_FLOAT8(1);
2596 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) >= 0);
2600 * float84{eq,ne,lt,le,gt,ge} - float8/float4 comparison operations
2603 float84eq(PG_FUNCTION_ARGS
)
2605 float8 arg1
= PG_GETARG_FLOAT8(0);
2606 float4 arg2
= PG_GETARG_FLOAT4(1);
2608 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) == 0);
2612 float84ne(PG_FUNCTION_ARGS
)
2614 float8 arg1
= PG_GETARG_FLOAT8(0);
2615 float4 arg2
= PG_GETARG_FLOAT4(1);
2617 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) != 0);
2621 float84lt(PG_FUNCTION_ARGS
)
2623 float8 arg1
= PG_GETARG_FLOAT8(0);
2624 float4 arg2
= PG_GETARG_FLOAT4(1);
2626 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) < 0);
2630 float84le(PG_FUNCTION_ARGS
)
2632 float8 arg1
= PG_GETARG_FLOAT8(0);
2633 float4 arg2
= PG_GETARG_FLOAT4(1);
2635 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) <= 0);
2639 float84gt(PG_FUNCTION_ARGS
)
2641 float8 arg1
= PG_GETARG_FLOAT8(0);
2642 float4 arg2
= PG_GETARG_FLOAT4(1);
2644 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) > 0);
2648 float84ge(PG_FUNCTION_ARGS
)
2650 float8 arg1
= PG_GETARG_FLOAT8(0);
2651 float4 arg2
= PG_GETARG_FLOAT4(1);
2653 PG_RETURN_BOOL(float8_cmp_internal(arg1
, arg2
) >= 0);
2657 * Implements the float8 version of the width_bucket() function
2658 * defined by SQL2003. See also width_bucket_numeric().
2660 * 'bound1' and 'bound2' are the lower and upper bounds of the
2661 * histogram's range, respectively. 'count' is the number of buckets
2662 * in the histogram. width_bucket() returns an integer indicating the
2663 * bucket number that 'operand' belongs to in an equiwidth histogram
2664 * with the specified characteristics. An operand smaller than the
2665 * lower bound is assigned to bucket 0. An operand greater than the
2666 * upper bound is assigned to an additional bucket (with number
2667 * count+1). We don't allow "NaN" for any of the float8 inputs, and we
2668 * don't allow either of the histogram bounds to be +/- infinity.
2671 width_bucket_float8(PG_FUNCTION_ARGS
)
2673 float8 operand
= PG_GETARG_FLOAT8(0);
2674 float8 bound1
= PG_GETARG_FLOAT8(1);
2675 float8 bound2
= PG_GETARG_FLOAT8(2);
2676 int32 count
= PG_GETARG_INT32(3);
2681 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION
),
2682 errmsg("count must be greater than zero")));
2684 if (isnan(operand
) || isnan(bound1
) || isnan(bound2
))
2686 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION
),
2687 errmsg("operand, lower bound and upper bound cannot be NaN")));
2689 /* Note that we allow "operand" to be infinite */
2690 if (is_infinite(bound1
) || is_infinite(bound2
))
2692 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION
),
2693 errmsg("lower and upper bounds must be finite")));
2695 if (bound1
< bound2
)
2697 if (operand
< bound1
)
2699 else if (operand
>= bound2
)
2702 /* check for overflow */
2705 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
2706 errmsg("integer out of range")));
2709 result
= ((float8
) count
* (operand
- bound1
) / (bound2
- bound1
)) + 1;
2711 else if (bound1
> bound2
)
2713 if (operand
> bound1
)
2715 else if (operand
<= bound2
)
2718 /* check for overflow */
2721 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE
),
2722 errmsg("integer out of range")));
2725 result
= ((float8
) count
* (bound1
- operand
) / (bound1
- bound2
)) + 1;
2730 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION
),
2731 errmsg("lower bound cannot equal upper bound")));
2732 result
= 0; /* keep the compiler quiet */
2735 PG_RETURN_INT32(result
);
2738 /* ========== PRIVATE ROUTINES ========== */
2745 int isneg
= (x
< 0.0);
2746 double absx
= fabs(x
);
2747 double tmpres
= pow(absx
, (double) 1.0 / (double) 3.0);
2750 * The result is somewhat inaccurate --- not really pow()'s fault, as the
2751 * exponent it's handed contains roundoff error. We can improve the
2752 * accuracy by doing one iteration of Newton's formula. Beware of zero
2756 tmpres
-= (tmpres
- absx
/ (tmpres
* tmpres
)) / (double) 3.0;
2758 return isneg
? -tmpres
: tmpres
;
2761 #endif /* !HAVE_CBRT */