Fix oversight in previous error-reporting patch; mustn't pfree path string
[PostgreSQL.git] / src / backend / utils / adt / float.c
blob4d9dc20a281a495bbed01d39393ac726c1a16b6a
1 /*-------------------------------------------------------------------------
3 * float.c
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
10 * IDENTIFICATION
11 * $PostgreSQL$
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include <ctype.h>
18 #include <float.h>
19 #include <math.h>
20 #include <limits.h>
22 #include "catalog/pg_type.h"
23 #include "libpq/pqformat.h"
24 #include "utils/array.h"
25 #include "utils/builtins.h"
28 #ifndef M_PI
29 /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
30 #define M_PI 3.14159265358979323846
31 #endif
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)
40 #endif
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) \
50 do { \
51 if (isinf(val) && !(inf_is_valid)) \
52 ereport(ERROR, \
53 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \
54 errmsg("value out of range: overflow"))); \
56 if ((val) == 0.0 && !(zero_is_valid)) \
57 ereport(ERROR, \
58 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), \
59 errmsg("value out of range: underflow"))); \
60 } while(0)
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);
73 #ifndef HAVE_CBRT
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.
87 double
88 get_float8_infinity(void)
90 #ifdef INFINITY
91 /* C99 standard way */
92 return (double) INFINITY;
93 #else
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
98 * true infinity.
100 return (double) (HUGE_VAL * HUGE_VAL);
101 #endif
104 float
105 get_float4_infinity(void)
107 #ifdef INFINITY
108 /* C99 standard way */
109 return (float) INFINITY;
110 #else
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
115 * true infinity.
117 return (float) (HUGE_VAL * HUGE_VAL);
118 #endif
121 double
122 get_float8_nan(void)
124 #ifdef NAN
125 /* C99 standard way */
126 return (double) NAN;
127 #else
128 /* Assume we can get a NAN via zero divide */
129 return (double) (0.0 / 0.0);
130 #endif
133 float
134 get_float4_nan(void)
136 #ifdef NAN
137 /* C99 standard way */
138 return (float) NAN;
139 #else
140 /* Assume we can get a NAN via zero divide */
141 return (float) (0.0 / 0.0);
142 #endif
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);
158 if (inf == 0)
159 return 0;
160 else if (val > 0)
161 return 1;
162 else
163 return -1;
168 * float4in - converts "num" to float
169 * restricted syntax:
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.
174 Datum
175 float4in(PG_FUNCTION_ARGS)
177 char *num = PG_GETARG_CSTRING(0);
178 char *orig_num;
179 double val;
180 char *endptr;
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
185 * string.
187 orig_num = num;
190 * Check for an empty-string input to begin with, to avoid the vagaries of
191 * strtod() on different platforms.
193 if (*num == '\0')
194 ereport(ERROR,
195 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
196 errmsg("invalid input syntax for type real: \"%s\"",
197 orig_num)));
199 /* skip leading whitespace */
200 while (*num != '\0' && isspace((unsigned char) *num))
201 num++;
203 errno = 0;
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();
217 endptr = num + 3;
219 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
221 val = get_float4_infinity();
222 endptr = num + 8;
224 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
226 val = -get_float4_infinity();
227 endptr = num + 9;
229 else if (errno == ERANGE)
230 ereport(ERROR,
231 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
232 errmsg("\"%s\" is out of range for type real",
233 orig_num)));
234 else
235 ereport(ERROR,
236 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
237 errmsg("invalid input syntax for type real: \"%s\"",
238 orig_num)));
240 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
241 else
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
246 * "infinity".
248 if (endptr != num && endptr[-1] == '\0')
249 endptr--;
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".
260 if (isinf(val))
262 if (pg_strncasecmp(num, "Infinity", 8) == 0)
264 val = get_float4_infinity();
265 endptr = num + 8;
267 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
269 val = -get_float4_infinity();
270 endptr = num + 9;
272 else if (pg_strncasecmp(num, "-inf", 4) == 0)
274 val = -get_float4_infinity();
275 endptr = num + 4;
278 #endif /* HAVE_BUGGY_IRIX_STRTOD */
280 /* skip trailing whitespace */
281 while (*endptr != '\0' && isspace((unsigned char) *endptr))
282 endptr++;
284 /* if there is any junk left at the end of the string, bail out */
285 if (*endptr != '\0')
286 ereport(ERROR,
287 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
288 errmsg("invalid input syntax for type real: \"%s\"",
289 orig_num)));
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
304 Datum
305 float4out(PG_FUNCTION_ARGS)
307 float4 num = PG_GETARG_FLOAT4(0);
308 char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
310 if (isnan(num))
311 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
313 switch (is_infinite(num))
315 case 1:
316 strcpy(ascii, "Infinity");
317 break;
318 case -1:
319 strcpy(ascii, "-Infinity");
320 break;
321 default:
323 int ndig = FLT_DIG + extra_float_digits;
325 if (ndig < 1)
326 ndig = 1;
328 sprintf(ascii, "%.*g", ndig, num);
332 PG_RETURN_CSTRING(ascii);
336 * float4recv - converts external binary format to float4
338 Datum
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
349 Datum
350 float4send(PG_FUNCTION_ARGS)
352 float4 num = PG_GETARG_FLOAT4(0);
353 StringInfoData buf;
355 pq_begintypsend(&buf);
356 pq_sendfloat4(&buf, num);
357 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
361 * float8in - converts "num" to float8
362 * restricted syntax:
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.
367 Datum
368 float8in(PG_FUNCTION_ARGS)
370 char *num = PG_GETARG_CSTRING(0);
371 char *orig_num;
372 double val;
373 char *endptr;
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
378 * string.
380 orig_num = num;
383 * Check for an empty-string input to begin with, to avoid the vagaries of
384 * strtod() on different platforms.
386 if (*num == '\0')
387 ereport(ERROR,
388 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
389 errmsg("invalid input syntax for type double precision: \"%s\"",
390 orig_num)));
392 /* skip leading whitespace */
393 while (*num != '\0' && isspace((unsigned char) *num))
394 num++;
396 errno = 0;
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();
410 endptr = num + 3;
412 else if (pg_strncasecmp(num, "Infinity", 8) == 0)
414 val = get_float8_infinity();
415 endptr = num + 8;
417 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
419 val = -get_float8_infinity();
420 endptr = num + 9;
422 else if (errno == ERANGE)
423 ereport(ERROR,
424 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
425 errmsg("\"%s\" is out of range for type double precision",
426 orig_num)));
427 else
428 ereport(ERROR,
429 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
430 errmsg("invalid input syntax for type double precision: \"%s\"",
431 orig_num)));
433 #ifdef HAVE_BUGGY_SOLARIS_STRTOD
434 else
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
439 * "infinity".
441 if (endptr != num && endptr[-1] == '\0')
442 endptr--;
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".
453 if (isinf(val))
455 if (pg_strncasecmp(num, "Infinity", 8) == 0)
457 val = get_float8_infinity();
458 endptr = num + 8;
460 else if (pg_strncasecmp(num, "-Infinity", 9) == 0)
462 val = -get_float8_infinity();
463 endptr = num + 9;
465 else if (pg_strncasecmp(num, "-inf", 4) == 0)
467 val = -get_float8_infinity();
468 endptr = num + 4;
471 #endif /* HAVE_BUGGY_IRIX_STRTOD */
473 /* skip trailing whitespace */
474 while (*endptr != '\0' && isspace((unsigned char) *endptr))
475 endptr++;
477 /* if there is any junk left at the end of the string, bail out */
478 if (*endptr != '\0')
479 ereport(ERROR,
480 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
481 errmsg("invalid input syntax for type double precision: \"%s\"",
482 orig_num)));
484 CHECKFLOATVAL(val, true, true);
486 PG_RETURN_FLOAT8(val);
490 * float8out - converts float8 number to a string
491 * using a standard output format
493 Datum
494 float8out(PG_FUNCTION_ARGS)
496 float8 num = PG_GETARG_FLOAT8(0);
497 char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
499 if (isnan(num))
500 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
502 switch (is_infinite(num))
504 case 1:
505 strcpy(ascii, "Infinity");
506 break;
507 case -1:
508 strcpy(ascii, "-Infinity");
509 break;
510 default:
512 int ndig = DBL_DIG + extra_float_digits;
514 if (ndig < 1)
515 ndig = 1;
517 sprintf(ascii, "%.*g", ndig, num);
521 PG_RETURN_CSTRING(ascii);
525 * float8recv - converts external binary format to float8
527 Datum
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
538 Datum
539 float8send(PG_FUNCTION_ARGS)
541 float8 num = PG_GETARG_FLOAT8(0);
542 StringInfoData buf;
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)
562 Datum
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)
573 Datum
574 float4um(PG_FUNCTION_ARGS)
576 float4 arg1 = PG_GETARG_FLOAT4(0);
577 float4 result;
579 result = ((arg1 != 0) ? -(arg1) : arg1);
581 CHECKFLOATVAL(result, isinf(arg1), true);
582 PG_RETURN_FLOAT4(result);
585 Datum
586 float4up(PG_FUNCTION_ARGS)
588 float4 arg = PG_GETARG_FLOAT4(0);
590 PG_RETURN_FLOAT4(arg);
593 Datum
594 float4larger(PG_FUNCTION_ARGS)
596 float4 arg1 = PG_GETARG_FLOAT4(0);
597 float4 arg2 = PG_GETARG_FLOAT4(1);
598 float4 result;
600 if (float4_cmp_internal(arg1, arg2) > 0)
601 result = arg1;
602 else
603 result = arg2;
604 PG_RETURN_FLOAT4(result);
607 Datum
608 float4smaller(PG_FUNCTION_ARGS)
610 float4 arg1 = PG_GETARG_FLOAT4(0);
611 float4 arg2 = PG_GETARG_FLOAT4(1);
612 float4 result;
614 if (float4_cmp_internal(arg1, arg2) < 0)
615 result = arg1;
616 else
617 result = arg2;
618 PG_RETURN_FLOAT4(result);
622 * ======================
623 * FLOAT8 BASE OPERATIONS
624 * ======================
628 * float8abs - returns |arg1| (absolute value)
630 Datum
631 float8abs(PG_FUNCTION_ARGS)
633 float8 arg1 = PG_GETARG_FLOAT8(0);
635 PG_RETURN_FLOAT8(fabs(arg1));
640 * float8um - returns -arg1 (unary minus)
642 Datum
643 float8um(PG_FUNCTION_ARGS)
645 float8 arg1 = PG_GETARG_FLOAT8(0);
646 float8 result;
648 result = ((arg1 != 0) ? -(arg1) : arg1);
650 CHECKFLOATVAL(result, isinf(arg1), true);
651 PG_RETURN_FLOAT8(result);
654 Datum
655 float8up(PG_FUNCTION_ARGS)
657 float8 arg = PG_GETARG_FLOAT8(0);
659 PG_RETURN_FLOAT8(arg);
662 Datum
663 float8larger(PG_FUNCTION_ARGS)
665 float8 arg1 = PG_GETARG_FLOAT8(0);
666 float8 arg2 = PG_GETARG_FLOAT8(1);
667 float8 result;
669 if (float8_cmp_internal(arg1, arg2) > 0)
670 result = arg1;
671 else
672 result = arg2;
673 PG_RETURN_FLOAT8(result);
676 Datum
677 float8smaller(PG_FUNCTION_ARGS)
679 float8 arg1 = PG_GETARG_FLOAT8(0);
680 float8 arg2 = PG_GETARG_FLOAT8(1);
681 float8 result;
683 if (float8_cmp_internal(arg1, arg2) < 0)
684 result = arg1;
685 else
686 result = arg2;
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
703 Datum
704 float4pl(PG_FUNCTION_ARGS)
706 float8 arg1 = PG_GETARG_FLOAT4(0);
707 float8 arg2 = PG_GETARG_FLOAT4(1);
708 float4 result;
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 ==
717 * 1.4013e-45.
719 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
720 PG_RETURN_FLOAT4(result);
723 Datum
724 float4mi(PG_FUNCTION_ARGS)
726 float4 arg1 = PG_GETARG_FLOAT4(0);
727 float4 arg2 = PG_GETARG_FLOAT4(1);
728 float4 result;
730 result = arg1 - arg2;
731 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
732 PG_RETURN_FLOAT4(result);
735 Datum
736 float4mul(PG_FUNCTION_ARGS)
738 float4 arg1 = PG_GETARG_FLOAT4(0);
739 float4 arg2 = PG_GETARG_FLOAT4(1);
740 float4 result;
742 result = arg1 * arg2;
743 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
744 arg1 == 0 || arg2 == 0);
745 PG_RETURN_FLOAT4(result);
748 Datum
749 float4div(PG_FUNCTION_ARGS)
751 float4 arg1 = PG_GETARG_FLOAT4(0);
752 float4 arg2 = PG_GETARG_FLOAT4(1);
753 float4 result;
755 if (arg2 == 0.0)
756 ereport(ERROR,
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
773 Datum
774 float8pl(PG_FUNCTION_ARGS)
776 float8 arg1 = PG_GETARG_FLOAT8(0);
777 float8 arg2 = PG_GETARG_FLOAT8(1);
778 float8 result;
780 result = arg1 + arg2;
782 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
783 PG_RETURN_FLOAT8(result);
786 Datum
787 float8mi(PG_FUNCTION_ARGS)
789 float8 arg1 = PG_GETARG_FLOAT8(0);
790 float8 arg2 = PG_GETARG_FLOAT8(1);
791 float8 result;
793 result = arg1 - arg2;
795 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
796 PG_RETURN_FLOAT8(result);
799 Datum
800 float8mul(PG_FUNCTION_ARGS)
802 float8 arg1 = PG_GETARG_FLOAT8(0);
803 float8 arg2 = PG_GETARG_FLOAT8(1);
804 float8 result;
806 result = arg1 * arg2;
808 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
809 arg1 == 0 || arg2 == 0);
810 PG_RETURN_FLOAT8(result);
813 Datum
814 float8div(PG_FUNCTION_ARGS)
816 float8 arg1 = PG_GETARG_FLOAT8(0);
817 float8 arg2 = PG_GETARG_FLOAT8(1);
818 float8 result;
820 if (arg2 == 0.0)
821 ereport(ERROR,
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
841 static int
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
847 * order.
849 if (isnan(a))
851 if (isnan(b))
852 return 0; /* NAN = NAN */
853 else
854 return 1; /* NAN > non-NAN */
856 else if (isnan(b))
858 return -1; /* non-NAN < NAN */
860 else
862 if (a > b)
863 return 1;
864 else if (a < b)
865 return -1;
866 else
867 return 0;
871 Datum
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);
880 Datum
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);
889 Datum
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);
898 Datum
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);
907 Datum
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);
916 Datum
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);
925 Datum
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
937 static int
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
943 * order.
945 if (isnan(a))
947 if (isnan(b))
948 return 0; /* NAN = NAN */
949 else
950 return 1; /* NAN > non-NAN */
952 else if (isnan(b))
954 return -1; /* non-NAN < NAN */
956 else
958 if (a > b)
959 return 1;
960 else if (a < b)
961 return -1;
962 else
963 return 0;
967 Datum
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);
976 Datum
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);
985 Datum
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);
994 Datum
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);
1003 Datum
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);
1012 Datum
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);
1021 Datum
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));
1030 Datum
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));
1040 Datum
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
1060 Datum
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
1072 Datum
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
1086 Datum
1087 dtoi4(PG_FUNCTION_ARGS)
1089 float8 num = PG_GETARG_FLOAT8(0);
1090 int32 result;
1092 /* 'Inf' is handled by INT_MAX */
1093 if (num < INT_MIN || num > INT_MAX || isnan(num))
1094 ereport(ERROR,
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
1106 Datum
1107 dtoi2(PG_FUNCTION_ARGS)
1109 float8 num = PG_GETARG_FLOAT8(0);
1111 if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
1112 ereport(ERROR,
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
1123 Datum
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
1135 Datum
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
1147 Datum
1148 ftoi4(PG_FUNCTION_ARGS)
1150 float4 num = PG_GETARG_FLOAT4(0);
1152 if (num < INT_MIN || num > INT_MAX || isnan(num))
1153 ereport(ERROR,
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
1164 Datum
1165 ftoi2(PG_FUNCTION_ARGS)
1167 float4 num = PG_GETARG_FLOAT4(0);
1169 if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
1170 ereport(ERROR,
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
1181 Datum
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
1193 Datum
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)
1211 Datum
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
1223 Datum
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
1235 Datum
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.
1248 Datum
1249 dsign(PG_FUNCTION_ARGS)
1251 float8 arg1 = PG_GETARG_FLOAT8(0);
1252 float8 result;
1254 if (arg1 > 0)
1255 result = 1.0;
1256 else if (arg1 < 0)
1257 result = -1.0;
1258 else
1259 result = 0.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
1271 Datum
1272 dtrunc(PG_FUNCTION_ARGS)
1274 float8 arg1 = PG_GETARG_FLOAT8(0);
1275 float8 result;
1277 if (arg1 >= 0)
1278 result = floor(arg1);
1279 else
1280 result = -floor(-arg1);
1282 PG_RETURN_FLOAT8(result);
1287 * dsqrt - returns square root of arg1
1289 Datum
1290 dsqrt(PG_FUNCTION_ARGS)
1292 float8 arg1 = PG_GETARG_FLOAT8(0);
1293 float8 result;
1295 if (arg1 < 0)
1296 ereport(ERROR,
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
1310 Datum
1311 dcbrt(PG_FUNCTION_ARGS)
1313 float8 arg1 = PG_GETARG_FLOAT8(0);
1314 float8 result;
1316 result = cbrt(arg1);
1317 CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
1318 PG_RETURN_FLOAT8(result);
1323 * dpow - returns pow(arg1,arg2)
1325 Datum
1326 dpow(PG_FUNCTION_ARGS)
1328 float8 arg1 = PG_GETARG_FLOAT8(0);
1329 float8 arg2 = PG_GETARG_FLOAT8(1);
1330 float8 result;
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)
1338 ereport(ERROR,
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)
1342 ereport(ERROR,
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.
1355 errno = 0;
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)
1363 result = 0;
1364 else
1365 result = 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
1378 Datum
1379 dexp(PG_FUNCTION_ARGS)
1381 float8 arg1 = PG_GETARG_FLOAT8(0);
1382 float8 result;
1384 errno = 0;
1385 result = exp(arg1);
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
1397 Datum
1398 dlog1(PG_FUNCTION_ARGS)
1400 float8 arg1 = PG_GETARG_FLOAT8(0);
1401 float8 result;
1404 * Emit particular SQLSTATE error codes for ln(). This is required by the
1405 * SQL standard.
1407 if (arg1 == 0.0)
1408 ereport(ERROR,
1409 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1410 errmsg("cannot take logarithm of zero")));
1411 if (arg1 < 0)
1412 ereport(ERROR,
1413 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1414 errmsg("cannot take logarithm of a negative number")));
1416 result = log(arg1);
1418 CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
1419 PG_RETURN_FLOAT8(result);
1424 * dlog10 - returns the base 10 logarithm of arg1
1426 Datum
1427 dlog10(PG_FUNCTION_ARGS)
1429 float8 arg1 = PG_GETARG_FLOAT8(0);
1430 float8 result;
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.
1437 if (arg1 == 0.0)
1438 ereport(ERROR,
1439 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
1440 errmsg("cannot take logarithm of zero")));
1441 if (arg1 < 0)
1442 ereport(ERROR,
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)
1456 Datum
1457 dacos(PG_FUNCTION_ARGS)
1459 float8 arg1 = PG_GETARG_FLOAT8(0);
1460 float8 result;
1463 * We use errno here because the trigonometric functions are cyclic and
1464 * hard to check for underflow.
1466 errno = 0;
1467 result = acos(arg1);
1468 if (errno != 0)
1469 ereport(ERROR,
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)
1481 Datum
1482 dasin(PG_FUNCTION_ARGS)
1484 float8 arg1 = PG_GETARG_FLOAT8(0);
1485 float8 result;
1487 errno = 0;
1488 result = asin(arg1);
1489 if (errno != 0)
1490 ereport(ERROR,
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)
1502 Datum
1503 datan(PG_FUNCTION_ARGS)
1505 float8 arg1 = PG_GETARG_FLOAT8(0);
1506 float8 result;
1508 errno = 0;
1509 result = atan(arg1);
1510 if (errno != 0)
1511 ereport(ERROR,
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)
1523 Datum
1524 datan2(PG_FUNCTION_ARGS)
1526 float8 arg1 = PG_GETARG_FLOAT8(0);
1527 float8 arg2 = PG_GETARG_FLOAT8(1);
1528 float8 result;
1530 errno = 0;
1531 result = atan2(arg1, arg2);
1532 if (errno != 0)
1533 ereport(ERROR,
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)
1545 Datum
1546 dcos(PG_FUNCTION_ARGS)
1548 float8 arg1 = PG_GETARG_FLOAT8(0);
1549 float8 result;
1551 errno = 0;
1552 result = cos(arg1);
1553 if (errno != 0)
1554 ereport(ERROR,
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)
1566 Datum
1567 dcot(PG_FUNCTION_ARGS)
1569 float8 arg1 = PG_GETARG_FLOAT8(0);
1570 float8 result;
1572 errno = 0;
1573 result = tan(arg1);
1574 if (errno != 0)
1575 ereport(ERROR,
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)
1588 Datum
1589 dsin(PG_FUNCTION_ARGS)
1591 float8 arg1 = PG_GETARG_FLOAT8(0);
1592 float8 result;
1594 errno = 0;
1595 result = sin(arg1);
1596 if (errno != 0)
1597 ereport(ERROR,
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)
1609 Datum
1610 dtan(PG_FUNCTION_ARGS)
1612 float8 arg1 = PG_GETARG_FLOAT8(0);
1613 float8 result;
1615 errno = 0;
1616 result = tan(arg1);
1617 if (errno != 0)
1618 ereport(ERROR,
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
1630 Datum
1631 degrees(PG_FUNCTION_ARGS)
1633 float8 arg1 = PG_GETARG_FLOAT8(0);
1634 float8 result;
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
1646 Datum
1647 dpi(PG_FUNCTION_ARGS)
1649 PG_RETURN_FLOAT8(M_PI);
1654 * radians - returns radians converted from degrees
1656 Datum
1657 radians(PG_FUNCTION_ARGS)
1659 float8 arg1 = PG_GETARG_FLOAT8(0);
1660 float8 result;
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
1672 Datum
1673 drandom(PG_FUNCTION_ARGS)
1675 float8 result;
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
1687 Datum
1688 setseed(PG_FUNCTION_ARGS)
1690 float8 seed = PG_GETARG_FLOAT8(0);
1691 int iseed;
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);
1699 PG_RETURN_VOID();
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...)
1726 static float8 *
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);
1742 Datum
1743 float8_accum(PG_FUNCTION_ARGS)
1745 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1746 float8 newval = PG_GETARG_FLOAT8(1);
1747 float8 *transvalues;
1748 float8 N,
1749 sumX,
1750 sumX2;
1752 transvalues = check_float8_array(transarray, "float8_accum", 3);
1753 N = transvalues[0];
1754 sumX = transvalues[1];
1755 sumX2 = transvalues[2];
1757 N += 1.0;
1758 sumX += newval;
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))
1770 transvalues[0] = N;
1771 transvalues[1] = sumX;
1772 transvalues[2] = sumX2;
1774 PG_RETURN_ARRAYTYPE_P(transarray);
1776 else
1778 Datum transdatums[3];
1779 ArrayType *result;
1781 transdatums[0] = Float8GetDatumFast(N);
1782 transdatums[1] = Float8GetDatumFast(sumX);
1783 transdatums[2] = Float8GetDatumFast(sumX2);
1785 result = construct_array(transdatums, 3,
1786 FLOAT8OID,
1787 sizeof(float8), FLOAT8PASSBYVAL, 'd');
1789 PG_RETURN_ARRAYTYPE_P(result);
1793 Datum
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;
1801 float8 N,
1802 sumX,
1803 sumX2;
1805 transvalues = check_float8_array(transarray, "float4_accum", 3);
1806 N = transvalues[0];
1807 sumX = transvalues[1];
1808 sumX2 = transvalues[2];
1810 N += 1.0;
1811 sumX += newval;
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))
1823 transvalues[0] = N;
1824 transvalues[1] = sumX;
1825 transvalues[2] = sumX2;
1827 PG_RETURN_ARRAYTYPE_P(transarray);
1829 else
1831 Datum transdatums[3];
1832 ArrayType *result;
1834 transdatums[0] = Float8GetDatumFast(N);
1835 transdatums[1] = Float8GetDatumFast(sumX);
1836 transdatums[2] = Float8GetDatumFast(sumX2);
1838 result = construct_array(transdatums, 3,
1839 FLOAT8OID,
1840 sizeof(float8), FLOAT8PASSBYVAL, 'd');
1842 PG_RETURN_ARRAYTYPE_P(result);
1846 Datum
1847 float8_avg(PG_FUNCTION_ARGS)
1849 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1850 float8 *transvalues;
1851 float8 N,
1852 sumX;
1854 transvalues = check_float8_array(transarray, "float8_avg", 3);
1855 N = transvalues[0];
1856 sumX = transvalues[1];
1857 /* ignore sumX2 */
1859 /* SQL92 defines AVG of no values to be NULL */
1860 if (N == 0.0)
1861 PG_RETURN_NULL();
1863 PG_RETURN_FLOAT8(sumX / N);
1866 Datum
1867 float8_var_pop(PG_FUNCTION_ARGS)
1869 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1870 float8 *transvalues;
1871 float8 N,
1872 sumX,
1873 sumX2,
1874 numerator;
1876 transvalues = check_float8_array(transarray, "float8_var_pop", 3);
1877 N = transvalues[0];
1878 sumX = transvalues[1];
1879 sumX2 = transvalues[2];
1881 /* Population variance is undefined when N is 0, so return NULL */
1882 if (N == 0.0)
1883 PG_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));
1895 Datum
1896 float8_var_samp(PG_FUNCTION_ARGS)
1898 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1899 float8 *transvalues;
1900 float8 N,
1901 sumX,
1902 sumX2,
1903 numerator;
1905 transvalues = check_float8_array(transarray, "float8_var_samp", 3);
1906 N = transvalues[0];
1907 sumX = transvalues[1];
1908 sumX2 = transvalues[2];
1910 /* Sample variance is undefined when N is 0 or 1, so return NULL */
1911 if (N <= 1.0)
1912 PG_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)));
1924 Datum
1925 float8_stddev_pop(PG_FUNCTION_ARGS)
1927 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1928 float8 *transvalues;
1929 float8 N,
1930 sumX,
1931 sumX2,
1932 numerator;
1934 transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
1935 N = transvalues[0];
1936 sumX = transvalues[1];
1937 sumX2 = transvalues[2];
1939 /* Population stddev is undefined when N is 0, so return NULL */
1940 if (N == 0.0)
1941 PG_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)));
1953 Datum
1954 float8_stddev_samp(PG_FUNCTION_ARGS)
1956 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1957 float8 *transvalues;
1958 float8 N,
1959 sumX,
1960 sumX2,
1961 numerator;
1963 transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
1964 N = transvalues[0];
1965 sumX = transvalues[1];
1966 sumX2 = transvalues[2];
1968 /* Sample stddev is undefined when N is 0 or 1, so return NULL */
1969 if (N <= 1.0)
1970 PG_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.
1998 Datum
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;
2005 float8 N,
2006 sumX,
2007 sumX2,
2008 sumY,
2009 sumY2,
2010 sumXY;
2012 transvalues = check_float8_array(transarray, "float8_regr_accum", 6);
2013 N = transvalues[0];
2014 sumX = transvalues[1];
2015 sumX2 = transvalues[2];
2016 sumY = transvalues[3];
2017 sumY2 = transvalues[4];
2018 sumXY = transvalues[5];
2020 N += 1.0;
2021 sumX += newvalX;
2022 CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
2023 sumX2 += newvalX * newvalX;
2024 CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
2025 sumY += newvalY;
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))
2040 transvalues[0] = N;
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);
2049 else
2051 Datum transdatums[6];
2052 ArrayType *result;
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,
2062 FLOAT8OID,
2063 sizeof(float8), FLOAT8PASSBYVAL, 'd');
2065 PG_RETURN_ARRAYTYPE_P(result);
2069 Datum
2070 float8_regr_sxx(PG_FUNCTION_ARGS)
2072 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2073 float8 *transvalues;
2074 float8 N,
2075 sumX,
2076 sumX2,
2077 numerator;
2079 transvalues = check_float8_array(transarray, "float8_regr_sxx", 6);
2080 N = transvalues[0];
2081 sumX = transvalues[1];
2082 sumX2 = transvalues[2];
2084 /* if N is 0 we should return NULL */
2085 if (N < 1.0)
2086 PG_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);
2098 Datum
2099 float8_regr_syy(PG_FUNCTION_ARGS)
2101 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2102 float8 *transvalues;
2103 float8 N,
2104 sumY,
2105 sumY2,
2106 numerator;
2108 transvalues = check_float8_array(transarray, "float8_regr_syy", 6);
2109 N = transvalues[0];
2110 sumY = transvalues[3];
2111 sumY2 = transvalues[4];
2113 /* if N is 0 we should return NULL */
2114 if (N < 1.0)
2115 PG_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);
2127 Datum
2128 float8_regr_sxy(PG_FUNCTION_ARGS)
2130 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2131 float8 *transvalues;
2132 float8 N,
2133 sumX,
2134 sumY,
2135 sumXY,
2136 numerator;
2138 transvalues = check_float8_array(transarray, "float8_regr_sxy", 6);
2139 N = transvalues[0];
2140 sumX = transvalues[1];
2141 sumY = transvalues[3];
2142 sumXY = transvalues[5];
2144 /* if N is 0 we should return NULL */
2145 if (N < 1.0)
2146 PG_RETURN_NULL();
2148 numerator = N * sumXY - sumX * sumY;
2149 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2150 isinf(sumY), true);
2152 /* A negative result is valid here */
2154 PG_RETURN_FLOAT8(numerator / N);
2157 Datum
2158 float8_regr_avgx(PG_FUNCTION_ARGS)
2160 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2161 float8 *transvalues;
2162 float8 N,
2163 sumX;
2165 transvalues = check_float8_array(transarray, "float8_regr_avgx", 6);
2166 N = transvalues[0];
2167 sumX = transvalues[1];
2169 /* if N is 0 we should return NULL */
2170 if (N < 1.0)
2171 PG_RETURN_NULL();
2173 PG_RETURN_FLOAT8(sumX / N);
2176 Datum
2177 float8_regr_avgy(PG_FUNCTION_ARGS)
2179 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2180 float8 *transvalues;
2181 float8 N,
2182 sumY;
2184 transvalues = check_float8_array(transarray, "float8_regr_avgy", 6);
2185 N = transvalues[0];
2186 sumY = transvalues[3];
2188 /* if N is 0 we should return NULL */
2189 if (N < 1.0)
2190 PG_RETURN_NULL();
2192 PG_RETURN_FLOAT8(sumY / N);
2195 Datum
2196 float8_covar_pop(PG_FUNCTION_ARGS)
2198 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2199 float8 *transvalues;
2200 float8 N,
2201 sumX,
2202 sumY,
2203 sumXY,
2204 numerator;
2206 transvalues = check_float8_array(transarray, "float8_covar_pop", 6);
2207 N = transvalues[0];
2208 sumX = transvalues[1];
2209 sumY = transvalues[3];
2210 sumXY = transvalues[5];
2212 /* if N is 0 we should return NULL */
2213 if (N < 1.0)
2214 PG_RETURN_NULL();
2216 numerator = N * sumXY - sumX * sumY;
2217 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2218 isinf(sumY), true);
2220 PG_RETURN_FLOAT8(numerator / (N * N));
2223 Datum
2224 float8_covar_samp(PG_FUNCTION_ARGS)
2226 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2227 float8 *transvalues;
2228 float8 N,
2229 sumX,
2230 sumY,
2231 sumXY,
2232 numerator;
2234 transvalues = check_float8_array(transarray, "float8_covar_samp", 6);
2235 N = transvalues[0];
2236 sumX = transvalues[1];
2237 sumY = transvalues[3];
2238 sumXY = transvalues[5];
2240 /* if N is <= 1 we should return NULL */
2241 if (N < 2.0)
2242 PG_RETURN_NULL();
2244 numerator = N * sumXY - sumX * sumY;
2245 CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
2246 isinf(sumY), true);
2248 PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
2251 Datum
2252 float8_corr(PG_FUNCTION_ARGS)
2254 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2255 float8 *transvalues;
2256 float8 N,
2257 sumX,
2258 sumX2,
2259 sumY,
2260 sumY2,
2261 sumXY,
2262 numeratorX,
2263 numeratorY,
2264 numeratorXY;
2266 transvalues = check_float8_array(transarray, "float8_corr", 6);
2267 N = transvalues[0];
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 */
2275 if (N < 1.0)
2276 PG_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) ||
2284 isinf(sumY), true);
2285 if (numeratorX <= 0 || numeratorY <= 0)
2286 PG_RETURN_NULL();
2288 PG_RETURN_FLOAT8(numeratorXY / sqrt(numeratorX * numeratorY));
2291 Datum
2292 float8_regr_r2(PG_FUNCTION_ARGS)
2294 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2295 float8 *transvalues;
2296 float8 N,
2297 sumX,
2298 sumX2,
2299 sumY,
2300 sumY2,
2301 sumXY,
2302 numeratorX,
2303 numeratorY,
2304 numeratorXY;
2306 transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
2307 N = transvalues[0];
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 */
2315 if (N < 1.0)
2316 PG_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) ||
2324 isinf(sumY), true);
2325 if (numeratorX <= 0)
2326 PG_RETURN_NULL();
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));
2335 Datum
2336 float8_regr_slope(PG_FUNCTION_ARGS)
2338 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2339 float8 *transvalues;
2340 float8 N,
2341 sumX,
2342 sumX2,
2343 sumY,
2344 sumXY,
2345 numeratorX,
2346 numeratorXY;
2348 transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
2349 N = transvalues[0];
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 */
2356 if (N < 1.0)
2357 PG_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) ||
2363 isinf(sumY), true);
2364 if (numeratorX <= 0)
2365 PG_RETURN_NULL();
2367 PG_RETURN_FLOAT8(numeratorXY / numeratorX);
2370 Datum
2371 float8_regr_intercept(PG_FUNCTION_ARGS)
2373 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
2374 float8 *transvalues;
2375 float8 N,
2376 sumX,
2377 sumX2,
2378 sumY,
2379 sumXY,
2380 numeratorX,
2381 numeratorXXY;
2383 transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
2384 N = transvalues[0];
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 */
2391 if (N < 1.0)
2392 PG_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)
2400 PG_RETURN_NULL();
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
2418 Datum
2419 float48pl(PG_FUNCTION_ARGS)
2421 float4 arg1 = PG_GETARG_FLOAT4(0);
2422 float8 arg2 = PG_GETARG_FLOAT8(1);
2423 float8 result;
2425 result = arg1 + arg2;
2426 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2427 PG_RETURN_FLOAT8(result);
2430 Datum
2431 float48mi(PG_FUNCTION_ARGS)
2433 float4 arg1 = PG_GETARG_FLOAT4(0);
2434 float8 arg2 = PG_GETARG_FLOAT8(1);
2435 float8 result;
2437 result = arg1 - arg2;
2438 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2439 PG_RETURN_FLOAT8(result);
2442 Datum
2443 float48mul(PG_FUNCTION_ARGS)
2445 float4 arg1 = PG_GETARG_FLOAT4(0);
2446 float8 arg2 = PG_GETARG_FLOAT8(1);
2447 float8 result;
2449 result = arg1 * arg2;
2450 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
2451 arg1 == 0 || arg2 == 0);
2452 PG_RETURN_FLOAT8(result);
2455 Datum
2456 float48div(PG_FUNCTION_ARGS)
2458 float4 arg1 = PG_GETARG_FLOAT4(0);
2459 float8 arg2 = PG_GETARG_FLOAT8(1);
2460 float8 result;
2462 if (arg2 == 0.0)
2463 ereport(ERROR,
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
2478 Datum
2479 float84pl(PG_FUNCTION_ARGS)
2481 float8 arg1 = PG_GETARG_FLOAT8(0);
2482 float4 arg2 = PG_GETARG_FLOAT4(1);
2483 float8 result;
2485 result = arg1 + arg2;
2487 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2488 PG_RETURN_FLOAT8(result);
2491 Datum
2492 float84mi(PG_FUNCTION_ARGS)
2494 float8 arg1 = PG_GETARG_FLOAT8(0);
2495 float4 arg2 = PG_GETARG_FLOAT4(1);
2496 float8 result;
2498 result = arg1 - arg2;
2500 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
2501 PG_RETURN_FLOAT8(result);
2504 Datum
2505 float84mul(PG_FUNCTION_ARGS)
2507 float8 arg1 = PG_GETARG_FLOAT8(0);
2508 float4 arg2 = PG_GETARG_FLOAT4(1);
2509 float8 result;
2511 result = arg1 * arg2;
2513 CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
2514 arg1 == 0 || arg2 == 0);
2515 PG_RETURN_FLOAT8(result);
2518 Datum
2519 float84div(PG_FUNCTION_ARGS)
2521 float8 arg1 = PG_GETARG_FLOAT8(0);
2522 float4 arg2 = PG_GETARG_FLOAT4(1);
2523 float8 result;
2525 if (arg2 == 0.0)
2526 ereport(ERROR,
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
2545 Datum
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);
2554 Datum
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);
2563 Datum
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);
2572 Datum
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);
2581 Datum
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);
2590 Datum
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
2602 Datum
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);
2611 Datum
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);
2620 Datum
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);
2629 Datum
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);
2638 Datum
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);
2647 Datum
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.
2670 Datum
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);
2677 int32 result;
2679 if (count <= 0.0)
2680 ereport(ERROR,
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))
2685 ereport(ERROR,
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))
2691 ereport(ERROR,
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)
2698 result = 0;
2699 else if (operand >= bound2)
2701 result = count + 1;
2702 /* check for overflow */
2703 if (result < count)
2704 ereport(ERROR,
2705 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
2706 errmsg("integer out of range")));
2708 else
2709 result = ((float8) count * (operand - bound1) / (bound2 - bound1)) + 1;
2711 else if (bound1 > bound2)
2713 if (operand > bound1)
2714 result = 0;
2715 else if (operand <= bound2)
2717 result = count + 1;
2718 /* check for overflow */
2719 if (result < count)
2720 ereport(ERROR,
2721 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
2722 errmsg("integer out of range")));
2724 else
2725 result = ((float8) count * (bound1 - operand) / (bound1 - bound2)) + 1;
2727 else
2729 ereport(ERROR,
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 ========== */
2740 #ifndef HAVE_CBRT
2742 static double
2743 cbrt(double x)
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
2753 * input however.
2755 if (tmpres > 0.0)
2756 tmpres -= (tmpres - absx / (tmpres * tmpres)) / (double) 3.0;
2758 return isneg ? -tmpres : tmpres;
2761 #endif /* !HAVE_CBRT */