1 /*-------------------------------------------------------------------------
4 * Functions for the built-in floating-point types.
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.81 2002/09/04 20:31:27 momjian Exp $
13 *-------------------------------------------------------------------------
18 * float4in, float4out, float4abs, float4um, float4up
20 * float8in, float8out, float8abs, float8um, float8up
21 * Arithmetic operators:
22 * float4pl, float4mi, float4mul, float4div
23 * float8pl, float8mi, float8mul, float8div
24 * Comparison operators:
25 * float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
26 * float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
27 * Conversion routines:
28 * ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
31 * dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
32 * Arithmetic operators:
33 * float48pl, float48mi, float48mul, float48div
34 * float84pl, float84mi, float84mul, float84div
35 * Comparison operators:
36 * float48eq, float48ne, float48lt, float48le, float48gt, float48ge
37 * float84eq, float84ne, float84lt, float84le, float84gt, float84ge
39 * (You can do the arithmetic and comparison stuff using conversion
40 * routines, but then you pay the overhead of invoking a separate
41 * conversion function...)
43 * XXX GLUESOME STUFF. FIX IT! -AY '94
45 * Added some additional conversion routines and cleaned up
46 * a bit of the existing code. Need to change the error checking
47 * for calls to pow(), exp() since on some machines (my Linux box
48 * included) these routines do not set errno. - tgl 97/05/10
55 #include <float.h> /* faked on sunos4 */
59 /* for finite() on Solaris */
64 #include "catalog/pg_type.h"
66 #include "utils/array.h"
67 #include "utils/builtins.h"
70 #if !(NeXT && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_2)
71 /* NS3.3 has conflicting declarations of these in <math.h> */
74 extern double atof(const char *p);
79 static double cbrt(double x);
82 #if !defined(nextstep)
83 extern double cbrt(double x);
85 #endif /* HAVE_CBRT */
89 static double rint(double x);
92 extern double rint(double x);
93 #endif /* HAVE_RINT */
94 #endif /* NeXT check */
97 static void CheckFloat4Val(double val);
98 static void CheckFloat8Val(double val);
101 /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
102 #define M_PI 3.14159265358979323846
106 #define NAN (0.0/0.0)
110 #define SHRT_MAX 32767
113 #define SHRT_MIN (-32768)
116 #define FORMAT 'g' /* use "g" output format as standard
118 /* not sure what the following should be, but better to make it over-sufficient */
119 #define MAXFLOATWIDTH 64
120 #define MAXDOUBLEWIDTH 128
122 /* ========== USER I/O ROUTINES ========== */
125 #define FLOAT4_MAX FLT_MAX
126 #define FLOAT4_MIN FLT_MIN
127 #define FLOAT8_MAX DBL_MAX
128 #define FLOAT8_MIN DBL_MIN
132 check to see if a float4 val is outside of
133 the FLOAT4_MIN, FLOAT4_MAX bounds.
135 raise an elog warning if it is
138 CheckFloat4Val(double val)
141 * defining unsafe floats's will make float4 and float8 ops faster at
142 * the cost of safety, of course!
147 if (fabs(val) > FLOAT4_MAX)
148 elog(ERROR, "Bad float4 input format -- overflow");
149 if (val != 0.0 && fabs(val) < FLOAT4_MIN)
150 elog(ERROR, "Bad float4 input format -- underflow");
152 #endif /* UNSAFE_FLOATS */
156 check to see if a float8 val is outside of
157 the FLOAT8_MIN, FLOAT8_MAX bounds.
159 raise an elog warning if it is
162 CheckFloat8Val(double val)
165 * defining unsafe floats's will make float4 and float8 ops faster at
166 * the cost of safety, of course!
171 if (fabs(val) > FLOAT8_MAX)
172 elog(ERROR, "Bad float8 input format -- overflow");
173 if (val != 0.0 && fabs(val) < FLOAT8_MIN)
174 elog(ERROR, "Bad float8 input format -- underflow");
176 #endif /* UNSAFE_FLOATS */
180 * float4in - converts "num" to float
182 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
183 * where <sp> is a space, digit is 0-9,
184 * <exp> is "e" or "E" followed by an integer.
187 float4in(PG_FUNCTION_ARGS)
189 char *num = PG_GETARG_CSTRING(0);
194 val = strtod(num, &endptr);
198 * XXX we should accept "Infinity" and "-Infinity" too, but what
199 * are the correct values to assign? HUGE_VAL will provoke an
200 * error from CheckFloat4Val.
202 if (strcasecmp(num, "NaN") == 0)
205 elog(ERROR, "Bad float4 input format '%s'", num);
210 elog(ERROR, "Input '%s' is out of range for float4", num);
214 * if we get here, we have a legal double, still need to check to see
215 * if it's a legal float
219 PG_RETURN_FLOAT4((float4) val);
223 * float4out - converts a float4 number to a string
224 * using a standard output format
227 float4out(PG_FUNCTION_ARGS)
229 float4 num = PG_GETARG_FLOAT4(0);
230 char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
234 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
235 infflag = isinf(num);
237 PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
239 PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
241 sprintf(ascii, "%.*g", FLT_DIG, num);
242 PG_RETURN_CSTRING(ascii);
246 * float8in - converts "num" to float8
248 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
249 * where <sp> is a space, digit is 0-9,
250 * <exp> is "e" or "E" followed by an integer.
253 float8in(PG_FUNCTION_ARGS)
255 char *num = PG_GETARG_CSTRING(0);
260 val = strtod(num, &endptr);
263 if (strcasecmp(num, "NaN") == 0)
265 else if (strcasecmp(num, "Infinity") == 0)
267 else if (strcasecmp(num, "-Infinity") == 0)
270 elog(ERROR, "Bad float8 input format '%s'", num);
275 elog(ERROR, "Input '%s' is out of range for float8", num);
280 PG_RETURN_FLOAT8(val);
285 * float8out - converts float8 number to a string
286 * using a standard output format
289 float8out(PG_FUNCTION_ARGS)
291 float8 num = PG_GETARG_FLOAT8(0);
292 char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
296 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
297 infflag = isinf(num);
299 PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
301 PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
303 sprintf(ascii, "%.*g", DBL_DIG, num);
304 PG_RETURN_CSTRING(ascii);
307 /* ========== PUBLIC ROUTINES ========== */
311 * ======================
312 * FLOAT4 BASE OPERATIONS
313 * ======================
317 * float4abs - returns |arg1| (absolute value)
320 float4abs(PG_FUNCTION_ARGS)
322 float4 arg1 = PG_GETARG_FLOAT4(0);
324 PG_RETURN_FLOAT4((float4) fabs(arg1));
328 * float4um - returns -arg1 (unary minus)
331 float4um(PG_FUNCTION_ARGS)
333 float4 arg1 = PG_GETARG_FLOAT4(0);
335 PG_RETURN_FLOAT4((float4) -arg1);
339 float4up(PG_FUNCTION_ARGS)
341 float4 arg = PG_GETARG_FLOAT4(0);
343 PG_RETURN_FLOAT4(arg);
347 float4larger(PG_FUNCTION_ARGS)
349 float4 arg1 = PG_GETARG_FLOAT4(0);
350 float4 arg2 = PG_GETARG_FLOAT4(1);
353 result = ((arg1 > arg2) ? arg1 : arg2);
354 PG_RETURN_FLOAT4(result);
358 float4smaller(PG_FUNCTION_ARGS)
360 float4 arg1 = PG_GETARG_FLOAT4(0);
361 float4 arg2 = PG_GETARG_FLOAT4(1);
364 result = ((arg1 < arg2) ? arg1 : arg2);
365 PG_RETURN_FLOAT4(result);
369 * ======================
370 * FLOAT8 BASE OPERATIONS
371 * ======================
375 * float8abs - returns |arg1| (absolute value)
378 float8abs(PG_FUNCTION_ARGS)
380 float8 arg1 = PG_GETARG_FLOAT8(0);
385 CheckFloat8Val(result);
386 PG_RETURN_FLOAT8(result);
391 * float8um - returns -arg1 (unary minus)
394 float8um(PG_FUNCTION_ARGS)
396 float8 arg1 = PG_GETARG_FLOAT8(0);
399 result = ((arg1 != 0) ? -(arg1) : arg1);
401 CheckFloat8Val(result);
402 PG_RETURN_FLOAT8(result);
406 float8up(PG_FUNCTION_ARGS)
408 float8 arg = PG_GETARG_FLOAT8(0);
410 PG_RETURN_FLOAT8(arg);
414 float8larger(PG_FUNCTION_ARGS)
416 float8 arg1 = PG_GETARG_FLOAT8(0);
417 float8 arg2 = PG_GETARG_FLOAT8(1);
420 result = ((arg1 > arg2) ? arg1 : arg2);
422 PG_RETURN_FLOAT8(result);
426 float8smaller(PG_FUNCTION_ARGS)
428 float8 arg1 = PG_GETARG_FLOAT8(0);
429 float8 arg2 = PG_GETARG_FLOAT8(1);
432 result = ((arg1 < arg2) ? arg1 : arg2);
434 PG_RETURN_FLOAT8(result);
439 * ====================
440 * ARITHMETIC OPERATORS
441 * ====================
445 * float4pl - returns arg1 + arg2
446 * float4mi - returns arg1 - arg2
447 * float4mul - returns arg1 * arg2
448 * float4div - returns arg1 / arg2
451 float4pl(PG_FUNCTION_ARGS)
453 float4 arg1 = PG_GETARG_FLOAT4(0);
454 float4 arg2 = PG_GETARG_FLOAT4(1);
457 result = arg1 + arg2;
458 CheckFloat4Val(result);
459 PG_RETURN_FLOAT4((float4) result);
463 float4mi(PG_FUNCTION_ARGS)
465 float4 arg1 = PG_GETARG_FLOAT4(0);
466 float4 arg2 = PG_GETARG_FLOAT4(1);
469 result = arg1 - arg2;
470 CheckFloat4Val(result);
471 PG_RETURN_FLOAT4((float4) result);
475 float4mul(PG_FUNCTION_ARGS)
477 float4 arg1 = PG_GETARG_FLOAT4(0);
478 float4 arg2 = PG_GETARG_FLOAT4(1);
481 result = arg1 * arg2;
482 CheckFloat4Val(result);
483 PG_RETURN_FLOAT4((float4) result);
487 float4div(PG_FUNCTION_ARGS)
489 float4 arg1 = PG_GETARG_FLOAT4(0);
490 float4 arg2 = PG_GETARG_FLOAT4(1);
494 elog(ERROR, "float4div: divide by zero error");
496 /* Do division in float8, then check for overflow */
497 result = (float8) arg1 / (float8) arg2;
499 CheckFloat4Val(result);
500 PG_RETURN_FLOAT4((float4) result);
504 * float8pl - returns arg1 + arg2
505 * float8mi - returns arg1 - arg2
506 * float8mul - returns arg1 * arg2
507 * float8div - returns arg1 / arg2
510 float8pl(PG_FUNCTION_ARGS)
512 float8 arg1 = PG_GETARG_FLOAT8(0);
513 float8 arg2 = PG_GETARG_FLOAT8(1);
516 result = arg1 + arg2;
518 CheckFloat8Val(result);
519 PG_RETURN_FLOAT8(result);
523 float8mi(PG_FUNCTION_ARGS)
525 float8 arg1 = PG_GETARG_FLOAT8(0);
526 float8 arg2 = PG_GETARG_FLOAT8(1);
529 result = arg1 - arg2;
531 CheckFloat8Val(result);
532 PG_RETURN_FLOAT8(result);
536 float8mul(PG_FUNCTION_ARGS)
538 float8 arg1 = PG_GETARG_FLOAT8(0);
539 float8 arg2 = PG_GETARG_FLOAT8(1);
542 result = arg1 * arg2;
544 CheckFloat8Val(result);
545 PG_RETURN_FLOAT8(result);
549 float8div(PG_FUNCTION_ARGS)
551 float8 arg1 = PG_GETARG_FLOAT8(0);
552 float8 arg2 = PG_GETARG_FLOAT8(1);
556 elog(ERROR, "float8div: divide by zero error");
558 result = arg1 / arg2;
560 CheckFloat8Val(result);
561 PG_RETURN_FLOAT8(result);
566 * ====================
567 * COMPARISON OPERATORS
568 * ====================
572 * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
575 float4_cmp_internal(float4 a, float4 b)
578 * We consider all NANs to be equal and larger than any non-NAN. This
579 * is somewhat arbitrary; the important thing is to have a consistent
585 return 0; /* NAN = NAN */
587 return 1; /* NAN > non-NAN */
591 return -1; /* non-NAN < NAN */
605 float4eq(PG_FUNCTION_ARGS)
607 float4 arg1 = PG_GETARG_FLOAT4(0);
608 float4 arg2 = PG_GETARG_FLOAT4(1);
610 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
614 float4ne(PG_FUNCTION_ARGS)
616 float4 arg1 = PG_GETARG_FLOAT4(0);
617 float4 arg2 = PG_GETARG_FLOAT4(1);
619 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
623 float4lt(PG_FUNCTION_ARGS)
625 float4 arg1 = PG_GETARG_FLOAT4(0);
626 float4 arg2 = PG_GETARG_FLOAT4(1);
628 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
632 float4le(PG_FUNCTION_ARGS)
634 float4 arg1 = PG_GETARG_FLOAT4(0);
635 float4 arg2 = PG_GETARG_FLOAT4(1);
637 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
641 float4gt(PG_FUNCTION_ARGS)
643 float4 arg1 = PG_GETARG_FLOAT4(0);
644 float4 arg2 = PG_GETARG_FLOAT4(1);
646 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
650 float4ge(PG_FUNCTION_ARGS)
652 float4 arg1 = PG_GETARG_FLOAT4(0);
653 float4 arg2 = PG_GETARG_FLOAT4(1);
655 PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
659 btfloat4cmp(PG_FUNCTION_ARGS)
661 float4 arg1 = PG_GETARG_FLOAT4(0);
662 float4 arg2 = PG_GETARG_FLOAT4(1);
664 PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
668 * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
671 float8_cmp_internal(float8 a, float8 b)
674 * We consider all NANs to be equal and larger than any non-NAN. This
675 * is somewhat arbitrary; the important thing is to have a consistent
681 return 0; /* NAN = NAN */
683 return 1; /* NAN > non-NAN */
687 return -1; /* non-NAN < NAN */
701 float8eq(PG_FUNCTION_ARGS)
703 float8 arg1 = PG_GETARG_FLOAT8(0);
704 float8 arg2 = PG_GETARG_FLOAT8(1);
706 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
710 float8ne(PG_FUNCTION_ARGS)
712 float8 arg1 = PG_GETARG_FLOAT8(0);
713 float8 arg2 = PG_GETARG_FLOAT8(1);
715 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
719 float8lt(PG_FUNCTION_ARGS)
721 float8 arg1 = PG_GETARG_FLOAT8(0);
722 float8 arg2 = PG_GETARG_FLOAT8(1);
724 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
728 float8le(PG_FUNCTION_ARGS)
730 float8 arg1 = PG_GETARG_FLOAT8(0);
731 float8 arg2 = PG_GETARG_FLOAT8(1);
733 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
737 float8gt(PG_FUNCTION_ARGS)
739 float8 arg1 = PG_GETARG_FLOAT8(0);
740 float8 arg2 = PG_GETARG_FLOAT8(1);
742 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
746 float8ge(PG_FUNCTION_ARGS)
748 float8 arg1 = PG_GETARG_FLOAT8(0);
749 float8 arg2 = PG_GETARG_FLOAT8(1);
751 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
755 btfloat8cmp(PG_FUNCTION_ARGS)
757 float8 arg1 = PG_GETARG_FLOAT8(0);
758 float8 arg2 = PG_GETARG_FLOAT8(1);
760 PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
765 * ===================
766 * CONVERSION ROUTINES
767 * ===================
771 * ftod - converts a float4 number to a float8 number
774 ftod(PG_FUNCTION_ARGS)
776 float4 num = PG_GETARG_FLOAT4(0);
778 PG_RETURN_FLOAT8((float8) num);
783 * dtof - converts a float8 number to a float4 number
786 dtof(PG_FUNCTION_ARGS)
788 float8 num = PG_GETARG_FLOAT8(0);
792 PG_RETURN_FLOAT4((float4) num);
797 * dtoi4 - converts a float8 number to an int4 number
800 dtoi4(PG_FUNCTION_ARGS)
802 float8 num = PG_GETARG_FLOAT8(0);
805 if ((num < INT_MIN) || (num > INT_MAX))
806 elog(ERROR, "dtoi4: integer out of range");
808 result = (int32) rint(num);
809 PG_RETURN_INT32(result);
814 * dtoi2 - converts a float8 number to an int2 number
817 dtoi2(PG_FUNCTION_ARGS)
819 float8 num = PG_GETARG_FLOAT8(0);
822 if ((num < SHRT_MIN) || (num > SHRT_MAX))
823 elog(ERROR, "dtoi2: integer out of range");
825 result = (int16) rint(num);
826 PG_RETURN_INT16(result);
831 * i4tod - converts an int4 number to a float8 number
834 i4tod(PG_FUNCTION_ARGS)
836 int32 num = PG_GETARG_INT32(0);
840 PG_RETURN_FLOAT8(result);
845 * i2tod - converts an int2 number to a float8 number
848 i2tod(PG_FUNCTION_ARGS)
850 int16 num = PG_GETARG_INT16(0);
854 PG_RETURN_FLOAT8(result);
859 * ftoi4 - converts a float4 number to an int4 number
862 ftoi4(PG_FUNCTION_ARGS)
864 float4 num = PG_GETARG_FLOAT4(0);
867 if ((num < INT_MIN) || (num > INT_MAX))
868 elog(ERROR, "ftoi4: integer out of range");
870 result = (int32) rint(num);
871 PG_RETURN_INT32(result);
876 * ftoi2 - converts a float4 number to an int2 number
879 ftoi2(PG_FUNCTION_ARGS)
881 float4 num = PG_GETARG_FLOAT4(0);
884 if ((num < SHRT_MIN) || (num > SHRT_MAX))
885 elog(ERROR, "ftoi2: integer out of range");
887 result = (int16) rint(num);
888 PG_RETURN_INT16(result);
893 * i4tof - converts an int4 number to a float8 number
896 i4tof(PG_FUNCTION_ARGS)
898 int32 num = PG_GETARG_INT32(0);
902 PG_RETURN_FLOAT4(result);
907 * i2tof - converts an int2 number to a float4 number
910 i2tof(PG_FUNCTION_ARGS)
912 int16 num = PG_GETARG_INT16(0);
916 PG_RETURN_FLOAT4(result);
921 * float8_text - converts a float8 number to a text string
924 float8_text(PG_FUNCTION_ARGS)
926 float8 num = PG_GETARG_FLOAT8(0);
931 str = DatumGetCString(DirectFunctionCall1(float8out,
932 Float8GetDatum(num)));
934 len = strlen(str) + VARHDRSZ;
936 result = (text *) palloc(len);
938 VARATT_SIZEP(result) = len;
939 memcpy(VARDATA(result), str, (len - VARHDRSZ));
943 PG_RETURN_TEXT_P(result);
948 * text_float8 - converts a text string to a float8 number
951 text_float8(PG_FUNCTION_ARGS)
953 text *string = PG_GETARG_TEXT_P(0);
958 len = (VARSIZE(string) - VARHDRSZ);
959 str = palloc(len + 1);
960 memcpy(str, VARDATA(string), len);
963 result = DirectFunctionCall1(float8in, CStringGetDatum(str));
967 PG_RETURN_DATUM(result);
972 * float4_text - converts a float4 number to a text string
975 float4_text(PG_FUNCTION_ARGS)
977 float4 num = PG_GETARG_FLOAT4(0);
982 str = DatumGetCString(DirectFunctionCall1(float4out,
983 Float4GetDatum(num)));
985 len = strlen(str) + VARHDRSZ;
987 result = (text *) palloc(len);
989 VARATT_SIZEP(result) = len;
990 memcpy(VARDATA(result), str, (len - VARHDRSZ));
994 PG_RETURN_TEXT_P(result);
999 * text_float4 - converts a text string to a float4 number
1002 text_float4(PG_FUNCTION_ARGS)
1004 text *string = PG_GETARG_TEXT_P(0);
1009 len = (VARSIZE(string) - VARHDRSZ);
1010 str = palloc(len + 1);
1011 memcpy(str, VARDATA(string), len);
1012 *(str + len) = '\0';
1014 result = DirectFunctionCall1(float4in, CStringGetDatum(str));
1018 PG_RETURN_DATUM(result);
1023 * =======================
1024 * RANDOM FLOAT8 OPERATORS
1025 * =======================
1029 * dround - returns ROUND(arg1)
1032 dround(PG_FUNCTION_ARGS)
1034 float8 arg1 = PG_GETARG_FLOAT8(0);
1037 result = rint(arg1);
1039 PG_RETURN_FLOAT8(result);
1044 * dtrunc - returns truncation-towards-zero of arg1,
1045 * arg1 >= 0 ... the greatest integer less
1046 * than or equal to arg1
1047 * arg1 < 0 ... the least integer greater
1048 * than or equal to arg1
1051 dtrunc(PG_FUNCTION_ARGS)
1053 float8 arg1 = PG_GETARG_FLOAT8(0);
1057 result = floor(arg1);
1059 result = -floor(-arg1);
1061 PG_RETURN_FLOAT8(result);
1066 * dsqrt - returns square root of arg1
1069 dsqrt(PG_FUNCTION_ARGS)
1071 float8 arg1 = PG_GETARG_FLOAT8(0);
1075 elog(ERROR, "can't take sqrt of a negative number");
1077 result = sqrt(arg1);
1079 CheckFloat8Val(result);
1080 PG_RETURN_FLOAT8(result);
1085 * dcbrt - returns cube root of arg1
1088 dcbrt(PG_FUNCTION_ARGS)
1090 float8 arg1 = PG_GETARG_FLOAT8(0);
1093 result = cbrt(arg1);
1094 PG_RETURN_FLOAT8(result);
1099 * dpow - returns pow(arg1,arg2)
1102 dpow(PG_FUNCTION_ARGS)
1104 float8 arg1 = PG_GETARG_FLOAT8(0);
1105 float8 arg2 = PG_GETARG_FLOAT8(1);
1109 * We must check both for errno getting set and for a NaN result, in
1110 * order to deal with the vagaries of different platforms...
1113 result = pow(arg1, arg2);
1119 elog(ERROR, "pow() result is out of range");
1121 CheckFloat8Val(result);
1122 PG_RETURN_FLOAT8(result);
1127 * dexp - returns the exponential function of arg1
1130 dexp(PG_FUNCTION_ARGS)
1132 float8 arg1 = PG_GETARG_FLOAT8(0);
1136 * We must check both for errno getting set and for a NaN result, in
1137 * order to deal with the vagaries of different platforms. Also, a
1138 * zero result implies unreported underflow.
1142 if (errno != 0 || result == 0.0
1147 elog(ERROR, "exp() result is out of range");
1149 CheckFloat8Val(result);
1150 PG_RETURN_FLOAT8(result);
1155 * dlog1 - returns the natural logarithm of arg1
1156 * ("dlog" is already a logging routine...)
1159 dlog1(PG_FUNCTION_ARGS)
1161 float8 arg1 = PG_GETARG_FLOAT8(0);
1165 elog(ERROR, "can't take log of zero");
1167 elog(ERROR, "can't take log of a negative number");
1171 CheckFloat8Val(result);
1172 PG_RETURN_FLOAT8(result);
1177 * dlog10 - returns the base 10 logarithm of arg1
1180 dlog10(PG_FUNCTION_ARGS)
1182 float8 arg1 = PG_GETARG_FLOAT8(0);
1186 elog(ERROR, "can't take log of zero");
1188 elog(ERROR, "can't take log of a negative number");
1190 result = log10(arg1);
1192 CheckFloat8Val(result);
1193 PG_RETURN_FLOAT8(result);
1198 * dacos - returns the arccos of arg1 (radians)
1201 dacos(PG_FUNCTION_ARGS)
1203 float8 arg1 = PG_GETARG_FLOAT8(0);
1207 result = acos(arg1);
1213 elog(ERROR, "acos(%f) input is out of range", arg1);
1215 CheckFloat8Val(result);
1216 PG_RETURN_FLOAT8(result);
1221 * dasin - returns the arcsin of arg1 (radians)
1224 dasin(PG_FUNCTION_ARGS)
1226 float8 arg1 = PG_GETARG_FLOAT8(0);
1230 result = asin(arg1);
1236 elog(ERROR, "asin(%f) input is out of range", arg1);
1238 CheckFloat8Val(result);
1239 PG_RETURN_FLOAT8(result);
1244 * datan - returns the arctan of arg1 (radians)
1247 datan(PG_FUNCTION_ARGS)
1249 float8 arg1 = PG_GETARG_FLOAT8(0);
1253 result = atan(arg1);
1259 elog(ERROR, "atan(%f) input is out of range", arg1);
1261 CheckFloat8Val(result);
1262 PG_RETURN_FLOAT8(result);
1267 * atan2 - returns the arctan2 of arg1 (radians)
1270 datan2(PG_FUNCTION_ARGS)
1272 float8 arg1 = PG_GETARG_FLOAT8(0);
1273 float8 arg2 = PG_GETARG_FLOAT8(1);
1277 result = atan2(arg1, arg2);
1283 elog(ERROR, "atan2(%f,%f) input is out of range", arg1, arg2);
1285 CheckFloat8Val(result);
1286 PG_RETURN_FLOAT8(result);
1291 * dcos - returns the cosine of arg1 (radians)
1294 dcos(PG_FUNCTION_ARGS)
1296 float8 arg1 = PG_GETARG_FLOAT8(0);
1306 elog(ERROR, "cos(%f) input is out of range", arg1);
1308 CheckFloat8Val(result);
1309 PG_RETURN_FLOAT8(result);
1314 * dcot - returns the cotangent of arg1 (radians)
1317 dcot(PG_FUNCTION_ARGS)
1319 float8 arg1 = PG_GETARG_FLOAT8(0);
1324 if (errno != 0 || result == 0.0
1329 elog(ERROR, "cot(%f) input is out of range", arg1);
1331 result = 1.0 / result;
1332 CheckFloat8Val(result);
1333 PG_RETURN_FLOAT8(result);
1338 * dsin - returns the sine of arg1 (radians)
1341 dsin(PG_FUNCTION_ARGS)
1343 float8 arg1 = PG_GETARG_FLOAT8(0);
1353 elog(ERROR, "sin(%f) input is out of range", arg1);
1355 CheckFloat8Val(result);
1356 PG_RETURN_FLOAT8(result);
1361 * dtan - returns the tangent of arg1 (radians)
1364 dtan(PG_FUNCTION_ARGS)
1366 float8 arg1 = PG_GETARG_FLOAT8(0);
1376 elog(ERROR, "tan(%f) input is out of range", arg1);
1378 CheckFloat8Val(result);
1379 PG_RETURN_FLOAT8(result);
1384 * degrees - returns degrees converted from radians
1387 degrees(PG_FUNCTION_ARGS)
1389 float8 arg1 = PG_GETARG_FLOAT8(0);
1392 result = arg1 * (180.0 / M_PI);
1394 CheckFloat8Val(result);
1395 PG_RETURN_FLOAT8(result);
1400 * dpi - returns the constant PI
1403 dpi(PG_FUNCTION_ARGS)
1405 PG_RETURN_FLOAT8(M_PI);
1410 * radians - returns radians converted from degrees
1413 radians(PG_FUNCTION_ARGS)
1415 float8 arg1 = PG_GETARG_FLOAT8(0);
1418 result = arg1 * (M_PI / 180.0);
1420 CheckFloat8Val(result);
1421 PG_RETURN_FLOAT8(result);
1426 * drandom - returns a random number
1429 drandom(PG_FUNCTION_ARGS)
1433 /* result 0.0-1.0 */
1434 result = ((double) random()) / ((double) MAX_RANDOM_VALUE);
1436 PG_RETURN_FLOAT8(result);
1441 * setseed - set seed for the random number generator
1444 setseed(PG_FUNCTION_ARGS)
1446 float8 seed = PG_GETARG_FLOAT8(0);
1447 int iseed = (int) (seed * MAX_RANDOM_VALUE);
1449 srandom((unsigned int) iseed);
1451 PG_RETURN_INT32(iseed);
1457 * =========================
1458 * FLOAT AGGREGATE OPERATORS
1459 * =========================
1461 * float8_accum - accumulate for AVG(), STDDEV(), etc
1462 * float4_accum - same, but input data is float4
1463 * float8_avg - produce final result for float AVG()
1464 * float8_variance - produce final result for float VARIANCE()
1465 * float8_stddev - produce final result for float STDDEV()
1467 * The transition datatype for all these aggregates is a 3-element array
1468 * of float8, holding the values N, sum(X), sum(X*X) in that order.
1470 * Note that we represent N as a float to avoid having to build a special
1471 * datatype. Given a reasonable floating-point implementation, there should
1472 * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
1473 * user will have doubtless lost interest anyway...)
1477 check_float8_array(ArrayType *transarray, const char *caller)
1480 * We expect the input to be a 3-element float array; verify that. We
1481 * don't need to use deconstruct_array() since the array data is just
1482 * going to look like a C array of 3 float8 values.
1484 if (ARR_NDIM(transarray) != 1 ||
1485 ARR_DIMS(transarray)[0] != 3 ||
1486 ARR_ELEMTYPE(transarray) != FLOAT8OID)
1487 elog(ERROR, "%s: expected 3-element float8 array", caller);
1488 return (float8 *) ARR_DATA_PTR(transarray);
1492 float8_accum(PG_FUNCTION_ARGS)
1494 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1495 float8 newval = PG_GETARG_FLOAT8(1);
1496 float8 *transvalues;
1500 Datum transdatums[3];
1503 transvalues = check_float8_array(transarray, "float8_accum");
1505 sumX = transvalues[1];
1506 sumX2 = transvalues[2];
1510 sumX2 += newval * newval;
1512 transdatums[0] = Float8GetDatumFast(N);
1513 transdatums[1] = Float8GetDatumFast(sumX);
1514 transdatums[2] = Float8GetDatumFast(sumX2);
1516 result = construct_array(transdatums, 3,
1518 sizeof(float8), false /* float8 byval */ , 'd');
1520 PG_RETURN_ARRAYTYPE_P(result);
1524 float4_accum(PG_FUNCTION_ARGS)
1526 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1527 float4 newval4 = PG_GETARG_FLOAT4(1);
1528 float8 *transvalues;
1533 Datum transdatums[3];
1536 transvalues = check_float8_array(transarray, "float4_accum");
1538 sumX = transvalues[1];
1539 sumX2 = transvalues[2];
1541 /* Do arithmetic in float8 for best accuracy */
1546 sumX2 += newval * newval;
1548 transdatums[0] = Float8GetDatumFast(N);
1549 transdatums[1] = Float8GetDatumFast(sumX);
1550 transdatums[2] = Float8GetDatumFast(sumX2);
1552 result = construct_array(transdatums, 3,
1554 sizeof(float8), false /* float8 byval */ , 'd');
1556 PG_RETURN_ARRAYTYPE_P(result);
1560 float8_avg(PG_FUNCTION_ARGS)
1562 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1563 float8 *transvalues;
1567 transvalues = check_float8_array(transarray, "float8_avg");
1569 sumX = transvalues[1];
1572 /* SQL92 defines AVG of no values to be NULL */
1576 PG_RETURN_FLOAT8(sumX / N);
1580 float8_variance(PG_FUNCTION_ARGS)
1582 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1583 float8 *transvalues;
1589 transvalues = check_float8_array(transarray, "float8_variance");
1591 sumX = transvalues[1];
1592 sumX2 = transvalues[2];
1594 /* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
1599 PG_RETURN_FLOAT8(0.0);
1601 numerator = N * sumX2 - sumX * sumX;
1603 /* Watch out for roundoff error producing a negative numerator */
1604 if (numerator <= 0.0)
1605 PG_RETURN_FLOAT8(0.0);
1607 PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
1611 float8_stddev(PG_FUNCTION_ARGS)
1613 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1614 float8 *transvalues;
1620 transvalues = check_float8_array(transarray, "float8_stddev");
1622 sumX = transvalues[1];
1623 sumX2 = transvalues[2];
1625 /* We define STDDEV of no values to be NULL, of 1 value to be 0 */
1630 PG_RETURN_FLOAT8(0.0);
1632 numerator = N * sumX2 - sumX * sumX;
1634 /* Watch out for roundoff error producing a negative numerator */
1635 if (numerator <= 0.0)
1636 PG_RETURN_FLOAT8(0.0);
1638 PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
1643 * ====================================
1644 * MIXED-PRECISION ARITHMETIC OPERATORS
1645 * ====================================
1649 * float48pl - returns arg1 + arg2
1650 * float48mi - returns arg1 - arg2
1651 * float48mul - returns arg1 * arg2
1652 * float48div - returns arg1 / arg2
1655 float48pl(PG_FUNCTION_ARGS)
1657 float4 arg1 = PG_GETARG_FLOAT4(0);
1658 float8 arg2 = PG_GETARG_FLOAT8(1);
1661 result = arg1 + arg2;
1662 CheckFloat8Val(result);
1663 PG_RETURN_FLOAT8(result);
1667 float48mi(PG_FUNCTION_ARGS)
1669 float4 arg1 = PG_GETARG_FLOAT4(0);
1670 float8 arg2 = PG_GETARG_FLOAT8(1);
1673 result = arg1 - arg2;
1674 CheckFloat8Val(result);
1675 PG_RETURN_FLOAT8(result);
1679 float48mul(PG_FUNCTION_ARGS)
1681 float4 arg1 = PG_GETARG_FLOAT4(0);
1682 float8 arg2 = PG_GETARG_FLOAT8(1);
1685 result = arg1 * arg2;
1686 CheckFloat8Val(result);
1687 PG_RETURN_FLOAT8(result);
1691 float48div(PG_FUNCTION_ARGS)
1693 float4 arg1 = PG_GETARG_FLOAT4(0);
1694 float8 arg2 = PG_GETARG_FLOAT8(1);
1698 elog(ERROR, "float48div: divide by zero");
1700 result = arg1 / arg2;
1701 CheckFloat8Val(result);
1702 PG_RETURN_FLOAT8(result);
1706 * float84pl - returns arg1 + arg2
1707 * float84mi - returns arg1 - arg2
1708 * float84mul - returns arg1 * arg2
1709 * float84div - returns arg1 / arg2
1712 float84pl(PG_FUNCTION_ARGS)
1714 float8 arg1 = PG_GETARG_FLOAT8(0);
1715 float4 arg2 = PG_GETARG_FLOAT4(1);
1718 result = arg1 + arg2;
1720 CheckFloat8Val(result);
1721 PG_RETURN_FLOAT8(result);
1725 float84mi(PG_FUNCTION_ARGS)
1727 float8 arg1 = PG_GETARG_FLOAT8(0);
1728 float4 arg2 = PG_GETARG_FLOAT4(1);
1731 result = arg1 - arg2;
1733 CheckFloat8Val(result);
1734 PG_RETURN_FLOAT8(result);
1738 float84mul(PG_FUNCTION_ARGS)
1740 float8 arg1 = PG_GETARG_FLOAT8(0);
1741 float4 arg2 = PG_GETARG_FLOAT4(1);
1744 result = arg1 * arg2;
1746 CheckFloat8Val(result);
1747 PG_RETURN_FLOAT8(result);
1751 float84div(PG_FUNCTION_ARGS)
1753 float8 arg1 = PG_GETARG_FLOAT8(0);
1754 float4 arg2 = PG_GETARG_FLOAT4(1);
1758 elog(ERROR, "float84div: divide by zero");
1760 result = arg1 / arg2;
1762 CheckFloat8Val(result);
1763 PG_RETURN_FLOAT8(result);
1767 * ====================
1768 * COMPARISON OPERATORS
1769 * ====================
1773 * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
1776 float48eq(PG_FUNCTION_ARGS)
1778 float4 arg1 = PG_GETARG_FLOAT4(0);
1779 float8 arg2 = PG_GETARG_FLOAT8(1);
1781 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
1785 float48ne(PG_FUNCTION_ARGS)
1787 float4 arg1 = PG_GETARG_FLOAT4(0);
1788 float8 arg2 = PG_GETARG_FLOAT8(1);
1790 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
1794 float48lt(PG_FUNCTION_ARGS)
1796 float4 arg1 = PG_GETARG_FLOAT4(0);
1797 float8 arg2 = PG_GETARG_FLOAT8(1);
1799 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
1803 float48le(PG_FUNCTION_ARGS)
1805 float4 arg1 = PG_GETARG_FLOAT4(0);
1806 float8 arg2 = PG_GETARG_FLOAT8(1);
1808 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1812 float48gt(PG_FUNCTION_ARGS)
1814 float4 arg1 = PG_GETARG_FLOAT4(0);
1815 float8 arg2 = PG_GETARG_FLOAT8(1);
1817 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1821 float48ge(PG_FUNCTION_ARGS)
1823 float4 arg1 = PG_GETARG_FLOAT4(0);
1824 float8 arg2 = PG_GETARG_FLOAT8(1);
1826 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1830 * float84{eq,ne,lt,le,gt,ge} - float8/float4 comparison operations
1833 float84eq(PG_FUNCTION_ARGS)
1835 float8 arg1 = PG_GETARG_FLOAT8(0);
1836 float4 arg2 = PG_GETARG_FLOAT4(1);
1838 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
1842 float84ne(PG_FUNCTION_ARGS)
1844 float8 arg1 = PG_GETARG_FLOAT8(0);
1845 float4 arg2 = PG_GETARG_FLOAT4(1);
1847 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
1851 float84lt(PG_FUNCTION_ARGS)
1853 float8 arg1 = PG_GETARG_FLOAT8(0);
1854 float4 arg2 = PG_GETARG_FLOAT4(1);
1856 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
1860 float84le(PG_FUNCTION_ARGS)
1862 float8 arg1 = PG_GETARG_FLOAT8(0);
1863 float4 arg2 = PG_GETARG_FLOAT4(1);
1865 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1869 float84gt(PG_FUNCTION_ARGS)
1871 float8 arg1 = PG_GETARG_FLOAT8(0);
1872 float4 arg2 = PG_GETARG_FLOAT4(1);
1874 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1878 float84ge(PG_FUNCTION_ARGS)
1880 float8 arg1 = PG_GETARG_FLOAT8(0);
1881 float4 arg2 = PG_GETARG_FLOAT4(1);
1883 PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1886 /* ========== PRIVATE ROUTINES ========== */
1888 /* From "fdlibm" @ netlib.att.com */
1892 /* @(#)s_rint.c 5.1 93/09/24 */
1894 * ====================================================
1895 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
1897 * Developed at SunPro, a Sun Microsystems, Inc. business.
1898 * Permission to use, copy, modify, and distribute this
1899 * software is freely granted, provided that this notice
1901 * ====================================================
1906 * Return x rounded to integral value according to the prevailing
1909 * Using floating addition.
1911 * Inexact flag raised if x not equal to rint(x).
1914 static const double one = 1.0,
1916 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
1917 -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
1932 n0 = (*((int *) &one) >> 29) ^ 1;
1933 i0 = *(n0 + (int *) &x);
1934 sx = (i0 >> 31) & 1;
1935 i1 = *(1 - n0 + (int *) &x);
1936 j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
1941 if (((i0 & 0x7fffffff) | i1) == 0)
1943 i1 |= (i0 & 0x0fffff);
1945 i0 |= ((i1 | -i1) >> 12) & 0x80000;
1946 *(n0 + (int *) &x) = i0;
1949 i0 = *(n0 + (int *) &t);
1950 *(n0 + (int *) &t) = (i0 & 0x7fffffff) | (sx << 31);
1955 i = (0x000fffff) >> j0;
1956 if (((i0 & i) | i1) == 0)
1957 return x; /* x is integral */
1959 if (((i0 & i) | i1) != 0)
1964 i0 = (i0 & (~i)) | ((0x20000) >> j0);
1971 return x + x; /* inf or NaN */
1973 return x; /* x is integral */
1977 i = ((unsigned) (0xffffffff)) >> (j0 - 20);
1979 return x; /* x is integral */
1982 i1 = (i1 & (~i)) | ((0x40000000) >> (j0 - 20));
1984 *(n0 + (int *) &x) = i0;
1985 *(1 - n0 + (int *) &x) = i1;
1987 return w - TWO52[sx];
1989 #endif /* !HAVE_RINT */
1996 int isneg = (x < 0.0);
1997 double tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
1999 return isneg ? -tmpres : tmpres;
2002 #endif /* !HAVE_CBRT */