1 /*-------------------------------------------------------------------------
4 * Functions for the built-in floating-point types.
6 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.68 2000/08/07 00:51:14 tgl Exp $
13 *-------------------------------------------------------------------------
18 * float4in, float4out, float4abs, float4um
20 * float8in, float8out, float8abs, float8um
21 * Arithmetic operators:
22 * float4pl, float4mi, float4mul, float4div
23 * float8pl, float8mi, float8mul, float8div
24 * Comparison operators:
25 * float4eq, float4ne, float4lt, float4le, float4gt, float4ge
26 * float8eq, float8ne, float8lt, float8le, float8gt, float8ge
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 converting...)
42 * XXX GLUESOME STUFF. FIX IT! -AY '94
44 * Added some additional conversion routines and cleaned up
45 * a bit of the existing code. Need to change the error checking
46 * for calls to pow(), exp() since on some machines (my Linux box
47 * included) these routines do not set errno. - tgl 97/05/10
51 #include <float.h> /* faked on sunos4 */
57 /* for finite() on Solaris */
63 #include "utils/array.h"
64 #include "utils/builtins.h"
67 #if !(NeXT && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_2)
68 /* NS3.3 has conflicting declarations of these in <math.h> */
71 extern double atof(const char *p);
76 static double cbrt(double x);
79 #if !defined(nextstep)
80 extern double cbrt(double x);
82 #endif /* HAVE_CBRT */
86 static double rint(double x);
89 extern double rint(double x);
90 #endif /* HAVE_RINT */
92 #endif /* NeXT check */
95 static void CheckFloat4Val(double val);
96 static void CheckFloat8Val(double val);
99 /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
100 #define M_PI 3.14159265358979323846
104 #define NAN (0.0/0.0)
108 #define SHRT_MAX 32767
111 #define SHRT_MIN (-32768)
114 #define FORMAT 'g' /* use "g" output format as standard
116 /* not sure what the following should be, but better to make it over-sufficient */
117 #define MAXFLOATWIDTH 64
118 #define MAXDOUBLEWIDTH 128
120 /* ========== USER I/O ROUTINES ========== */
123 #define FLOAT4_MAX FLT_MAX
124 #define FLOAT4_MIN FLT_MIN
125 #define FLOAT8_MAX DBL_MAX
126 #define FLOAT8_MIN DBL_MIN
130 check to see if a float4 val is outside of
131 the FLOAT4_MIN, FLOAT4_MAX bounds.
133 raise an elog warning if it is
136 CheckFloat4Val(double val)
140 * defining unsafe floats's will make float4 and float8 ops faster at
141 * the cost of safety, of course!
146 if (fabs(val) > FLOAT4_MAX)
147 elog(ERROR, "Bad float4 input format -- overflow");
148 if (val != 0.0 && fabs(val) < FLOAT4_MIN)
149 elog(ERROR, "Bad float4 input format -- underflow");
151 #endif /* UNSAFE_FLOATS */
155 check to see if a float8 val is outside of
156 the FLOAT8_MIN, FLOAT8_MAX bounds.
158 raise an elog warning if it is
161 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);
197 /* Should we accept "NaN" or "Infinity" for float4? */
198 elog(ERROR, "Bad float4 input format '%s'", num);
203 elog(ERROR, "Input '%s' is out of range for float4", num);
207 * if we get here, we have a legal double, still need to check to see
208 * if it's a legal float
212 PG_RETURN_FLOAT4((float4) val);
216 * float4out - converts a float4 number to a string
217 * using a standard output format
220 float4out(PG_FUNCTION_ARGS)
222 float4 num = PG_GETARG_FLOAT4(0);
223 char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
225 sprintf(ascii, "%.*g", FLT_DIG, num);
226 PG_RETURN_CSTRING(ascii);
230 * float8in - converts "num" to float8
232 * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
233 * where <sp> is a space, digit is 0-9,
234 * <exp> is "e" or "E" followed by an integer.
237 float8in(PG_FUNCTION_ARGS)
239 char *num = PG_GETARG_CSTRING(0);
244 val = strtod(num, &endptr);
247 if (strcasecmp(num, "NaN") == 0)
249 else if (strcasecmp(num, "Infinity") == 0)
252 elog(ERROR, "Bad float8 input format '%s'", num);
257 elog(ERROR, "Input '%s' is out of range for float8", num);
262 PG_RETURN_FLOAT8(val);
267 * float8out - converts float8 number to a string
268 * using a standard output format
271 float8out(PG_FUNCTION_ARGS)
273 float8 num = PG_GETARG_FLOAT8(0);
274 char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
277 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
279 PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
281 sprintf(ascii, "%.*g", DBL_DIG, num);
282 PG_RETURN_CSTRING(ascii);
285 /* ========== PUBLIC ROUTINES ========== */
289 * ======================
290 * FLOAT4 BASE OPERATIONS
291 * ======================
295 * float4abs - returns |arg1| (absolute value)
298 float4abs(PG_FUNCTION_ARGS)
300 float4 arg1 = PG_GETARG_FLOAT4(0);
302 PG_RETURN_FLOAT4((float4) fabs(arg1));
306 * float4um - returns -arg1 (unary minus)
309 float4um(PG_FUNCTION_ARGS)
311 float4 arg1 = PG_GETARG_FLOAT4(0);
313 PG_RETURN_FLOAT4((float4) -arg1);
317 float4larger(PG_FUNCTION_ARGS)
319 float4 arg1 = PG_GETARG_FLOAT4(0);
320 float4 arg2 = PG_GETARG_FLOAT4(1);
323 result = ((arg1 > arg2) ? arg1 : arg2);
324 PG_RETURN_FLOAT4(result);
328 float4smaller(PG_FUNCTION_ARGS)
330 float4 arg1 = PG_GETARG_FLOAT4(0);
331 float4 arg2 = PG_GETARG_FLOAT4(1);
334 result = ((arg1 < arg2) ? arg1 : arg2);
335 PG_RETURN_FLOAT4(result);
339 * ======================
340 * FLOAT8 BASE OPERATIONS
341 * ======================
345 * float8abs - returns |arg1| (absolute value)
348 float8abs(PG_FUNCTION_ARGS)
350 float8 arg1 = PG_GETARG_FLOAT8(0);
355 CheckFloat8Val(result);
356 PG_RETURN_FLOAT8(result);
361 * float8um - returns -arg1 (unary minus)
364 float8um(PG_FUNCTION_ARGS)
366 float8 arg1 = PG_GETARG_FLOAT8(0);
369 result = ((arg1 != 0) ? -(arg1) : arg1);
371 CheckFloat8Val(result);
372 PG_RETURN_FLOAT8(result);
376 float8larger(PG_FUNCTION_ARGS)
378 float8 arg1 = PG_GETARG_FLOAT8(0);
379 float8 arg2 = PG_GETARG_FLOAT8(1);
382 result = ((arg1 > arg2) ? arg1 : arg2);
384 PG_RETURN_FLOAT8(result);
388 float8smaller(PG_FUNCTION_ARGS)
390 float8 arg1 = PG_GETARG_FLOAT8(0);
391 float8 arg2 = PG_GETARG_FLOAT8(1);
394 result = ((arg1 < arg2) ? arg1 : arg2);
396 PG_RETURN_FLOAT8(result);
401 * ====================
402 * ARITHMETIC OPERATORS
403 * ====================
407 * float4pl - returns arg1 + arg2
408 * float4mi - returns arg1 - arg2
409 * float4mul - returns arg1 * arg2
410 * float4div - returns arg1 / arg2
413 float4pl(PG_FUNCTION_ARGS)
415 float4 arg1 = PG_GETARG_FLOAT4(0);
416 float4 arg2 = PG_GETARG_FLOAT4(1);
419 result = arg1 + arg2;
420 CheckFloat4Val(result);
421 PG_RETURN_FLOAT4((float4) result);
425 float4mi(PG_FUNCTION_ARGS)
427 float4 arg1 = PG_GETARG_FLOAT4(0);
428 float4 arg2 = PG_GETARG_FLOAT4(1);
431 result = arg1 - arg2;
432 CheckFloat4Val(result);
433 PG_RETURN_FLOAT4((float4) result);
437 float4mul(PG_FUNCTION_ARGS)
439 float4 arg1 = PG_GETARG_FLOAT4(0);
440 float4 arg2 = PG_GETARG_FLOAT4(1);
443 result = arg1 * arg2;
444 CheckFloat4Val(result);
445 PG_RETURN_FLOAT4((float4) result);
449 float4div(PG_FUNCTION_ARGS)
451 float4 arg1 = PG_GETARG_FLOAT4(0);
452 float4 arg2 = PG_GETARG_FLOAT4(1);
456 elog(ERROR, "float4div: divide by zero error");
458 /* Do division in float8, then check for overflow */
459 result = (float8) arg1 / (float8) arg2;
461 CheckFloat4Val(result);
462 PG_RETURN_FLOAT4((float4) result);
466 * float8pl - returns arg1 + arg2
467 * float8mi - returns arg1 - arg2
468 * float8mul - returns arg1 * arg2
469 * float8div - returns arg1 / arg2
472 float8pl(PG_FUNCTION_ARGS)
474 float8 arg1 = PG_GETARG_FLOAT8(0);
475 float8 arg2 = PG_GETARG_FLOAT8(1);
478 result = arg1 + arg2;
480 CheckFloat8Val(result);
481 PG_RETURN_FLOAT8(result);
485 float8mi(PG_FUNCTION_ARGS)
487 float8 arg1 = PG_GETARG_FLOAT8(0);
488 float8 arg2 = PG_GETARG_FLOAT8(1);
491 result = arg1 - arg2;
493 CheckFloat8Val(result);
494 PG_RETURN_FLOAT8(result);
498 float8mul(PG_FUNCTION_ARGS)
500 float8 arg1 = PG_GETARG_FLOAT8(0);
501 float8 arg2 = PG_GETARG_FLOAT8(1);
504 result = arg1 * arg2;
506 CheckFloat8Val(result);
507 PG_RETURN_FLOAT8(result);
511 float8div(PG_FUNCTION_ARGS)
513 float8 arg1 = PG_GETARG_FLOAT8(0);
514 float8 arg2 = PG_GETARG_FLOAT8(1);
518 elog(ERROR, "float8div: divide by zero error");
520 result = arg1 / arg2;
522 CheckFloat8Val(result);
523 PG_RETURN_FLOAT8(result);
528 * ====================
529 * COMPARISON OPERATORS
530 * ====================
534 * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
537 float4eq(PG_FUNCTION_ARGS)
539 float4 arg1 = PG_GETARG_FLOAT4(0);
540 float4 arg2 = PG_GETARG_FLOAT4(1);
542 PG_RETURN_BOOL(arg1 == arg2);
546 float4ne(PG_FUNCTION_ARGS)
548 float4 arg1 = PG_GETARG_FLOAT4(0);
549 float4 arg2 = PG_GETARG_FLOAT4(1);
551 PG_RETURN_BOOL(arg1 != arg2);
555 float4lt(PG_FUNCTION_ARGS)
557 float4 arg1 = PG_GETARG_FLOAT4(0);
558 float4 arg2 = PG_GETARG_FLOAT4(1);
560 PG_RETURN_BOOL(arg1 < arg2);
564 float4le(PG_FUNCTION_ARGS)
566 float4 arg1 = PG_GETARG_FLOAT4(0);
567 float4 arg2 = PG_GETARG_FLOAT4(1);
569 PG_RETURN_BOOL(arg1 <= arg2);
573 float4gt(PG_FUNCTION_ARGS)
575 float4 arg1 = PG_GETARG_FLOAT4(0);
576 float4 arg2 = PG_GETARG_FLOAT4(1);
578 PG_RETURN_BOOL(arg1 > arg2);
582 float4ge(PG_FUNCTION_ARGS)
584 float4 arg1 = PG_GETARG_FLOAT4(0);
585 float4 arg2 = PG_GETARG_FLOAT4(1);
587 PG_RETURN_BOOL(arg1 >= arg2);
591 * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
594 float8eq(PG_FUNCTION_ARGS)
596 float8 arg1 = PG_GETARG_FLOAT8(0);
597 float8 arg2 = PG_GETARG_FLOAT8(1);
599 PG_RETURN_BOOL(arg1 == arg2);
603 float8ne(PG_FUNCTION_ARGS)
605 float8 arg1 = PG_GETARG_FLOAT8(0);
606 float8 arg2 = PG_GETARG_FLOAT8(1);
608 PG_RETURN_BOOL(arg1 != arg2);
612 float8lt(PG_FUNCTION_ARGS)
614 float8 arg1 = PG_GETARG_FLOAT8(0);
615 float8 arg2 = PG_GETARG_FLOAT8(1);
617 PG_RETURN_BOOL(arg1 < arg2);
621 float8le(PG_FUNCTION_ARGS)
623 float8 arg1 = PG_GETARG_FLOAT8(0);
624 float8 arg2 = PG_GETARG_FLOAT8(1);
626 PG_RETURN_BOOL(arg1 <= arg2);
630 float8gt(PG_FUNCTION_ARGS)
632 float8 arg1 = PG_GETARG_FLOAT8(0);
633 float8 arg2 = PG_GETARG_FLOAT8(1);
635 PG_RETURN_BOOL(arg1 > arg2);
639 float8ge(PG_FUNCTION_ARGS)
641 float8 arg1 = PG_GETARG_FLOAT8(0);
642 float8 arg2 = PG_GETARG_FLOAT8(1);
644 PG_RETURN_BOOL(arg1 >= arg2);
649 * ===================
650 * CONVERSION ROUTINES
651 * ===================
655 * ftod - converts a float4 number to a float8 number
658 ftod(PG_FUNCTION_ARGS)
660 float4 num = PG_GETARG_FLOAT4(0);
662 PG_RETURN_FLOAT8((float8) num);
667 * dtof - converts a float8 number to a float4 number
670 dtof(PG_FUNCTION_ARGS)
672 float8 num = PG_GETARG_FLOAT8(0);
676 PG_RETURN_FLOAT4((float4) num);
681 * dtoi4 - converts a float8 number to an int4 number
684 dtoi4(PG_FUNCTION_ARGS)
686 float8 num = PG_GETARG_FLOAT8(0);
689 if ((num < INT_MIN) || (num > INT_MAX))
690 elog(ERROR, "dtoi4: integer out of range");
692 result = (int32) rint(num);
693 PG_RETURN_INT32(result);
698 * dtoi2 - converts a float8 number to an int2 number
701 dtoi2(PG_FUNCTION_ARGS)
703 float8 num = PG_GETARG_FLOAT8(0);
706 if ((num < SHRT_MIN) || (num > SHRT_MAX))
707 elog(ERROR, "dtoi2: integer out of range");
709 result = (int16) rint(num);
710 PG_RETURN_INT16(result);
715 * i4tod - converts an int4 number to a float8 number
718 i4tod(PG_FUNCTION_ARGS)
720 int32 num = PG_GETARG_INT32(0);
724 PG_RETURN_FLOAT8(result);
729 * i2tod - converts an int2 number to a float8 number
732 i2tod(PG_FUNCTION_ARGS)
734 int16 num = PG_GETARG_INT16(0);
738 PG_RETURN_FLOAT8(result);
743 * ftoi4 - converts a float4 number to an int4 number
746 ftoi4(PG_FUNCTION_ARGS)
748 float4 num = PG_GETARG_FLOAT4(0);
751 if ((num < INT_MIN) || (num > INT_MAX))
752 elog(ERROR, "ftoi4: integer out of range");
754 result = (int32) rint(num);
755 PG_RETURN_INT32(result);
760 * ftoi2 - converts a float4 number to an int2 number
763 ftoi2(PG_FUNCTION_ARGS)
765 float4 num = PG_GETARG_FLOAT4(0);
768 if ((num < SHRT_MIN) || (num > SHRT_MAX))
769 elog(ERROR, "ftoi2: integer out of range");
771 result = (int16) rint(num);
772 PG_RETURN_INT16(result);
777 * i4tof - converts an int4 number to a float8 number
780 i4tof(PG_FUNCTION_ARGS)
782 int32 num = PG_GETARG_INT32(0);
786 PG_RETURN_FLOAT4(result);
791 * i2tof - converts an int2 number to a float4 number
794 i2tof(PG_FUNCTION_ARGS)
796 int16 num = PG_GETARG_INT16(0);
800 PG_RETURN_FLOAT4(result);
805 * float8_text - converts a float8 number to a text string
808 float8_text(PG_FUNCTION_ARGS)
810 float8 num = PG_GETARG_FLOAT8(0);
815 str = DatumGetCString(DirectFunctionCall1(float8out,
816 Float8GetDatum(num)));
818 len = strlen(str) + VARHDRSZ;
820 result = (text *) palloc(len);
822 VARATT_SIZEP(result) = len;
823 memcpy(VARDATA(result), str, (len - VARHDRSZ));
827 PG_RETURN_TEXT_P(result);
832 * text_float8 - converts a text string to a float8 number
835 text_float8(PG_FUNCTION_ARGS)
837 text *string = PG_GETARG_TEXT_P(0);
842 len = (VARSIZE(string) - VARHDRSZ);
843 str = palloc(len + 1);
844 memcpy(str, VARDATA(string), len);
847 result = DirectFunctionCall1(float8in, CStringGetDatum(str));
851 PG_RETURN_DATUM(result);
856 * float4_text - converts a float4 number to a text string
859 float4_text(PG_FUNCTION_ARGS)
861 float4 num = PG_GETARG_FLOAT4(0);
866 str = DatumGetCString(DirectFunctionCall1(float4out,
867 Float4GetDatum(num)));
869 len = strlen(str) + VARHDRSZ;
871 result = (text *) palloc(len);
873 VARATT_SIZEP(result) = len;
874 memcpy(VARDATA(result), str, (len - VARHDRSZ));
878 PG_RETURN_TEXT_P(result);
883 * text_float4 - converts a text string to a float4 number
886 text_float4(PG_FUNCTION_ARGS)
888 text *string = PG_GETARG_TEXT_P(0);
893 len = (VARSIZE(string) - VARHDRSZ);
894 str = palloc(len + 1);
895 memcpy(str, VARDATA(string), len);
898 result = DirectFunctionCall1(float4in, CStringGetDatum(str));
902 PG_RETURN_DATUM(result);
907 * =======================
908 * RANDOM FLOAT8 OPERATORS
909 * =======================
913 * dround - returns ROUND(arg1)
916 dround(PG_FUNCTION_ARGS)
918 float8 arg1 = PG_GETARG_FLOAT8(0);
923 PG_RETURN_FLOAT8(result);
928 * dtrunc - returns truncation-towards-zero of arg1,
929 * arg1 >= 0 ... the greatest integer less
930 * than or equal to arg1
931 * arg1 < 0 ... the least integer greater
932 * than or equal to arg1
935 dtrunc(PG_FUNCTION_ARGS)
937 float8 arg1 = PG_GETARG_FLOAT8(0);
941 result = floor(arg1);
943 result = -floor(-arg1);
945 PG_RETURN_FLOAT8(result);
950 * dsqrt - returns square root of arg1
953 dsqrt(PG_FUNCTION_ARGS)
955 float8 arg1 = PG_GETARG_FLOAT8(0);
959 elog(ERROR, "can't take sqrt of a negative number");
963 CheckFloat8Val(result);
964 PG_RETURN_FLOAT8(result);
969 * dcbrt - returns cube root of arg1
972 dcbrt(PG_FUNCTION_ARGS)
974 float8 arg1 = PG_GETARG_FLOAT8(0);
978 PG_RETURN_FLOAT8(result);
983 * dpow - returns pow(arg1,arg2)
986 dpow(PG_FUNCTION_ARGS)
988 float8 arg1 = PG_GETARG_FLOAT8(0);
989 float8 arg2 = PG_GETARG_FLOAT8(1);
993 * We must check both for errno getting set and for a NaN result, in
994 * order to deal with the vagaries of different platforms...
997 result = pow(arg1, arg2);
1003 elog(ERROR, "pow() result is out of range");
1005 CheckFloat8Val(result);
1006 PG_RETURN_FLOAT8(result);
1011 * dexp - returns the exponential function of arg1
1014 dexp(PG_FUNCTION_ARGS)
1016 float8 arg1 = PG_GETARG_FLOAT8(0);
1020 * We must check both for errno getting set and for a NaN result, in
1021 * order to deal with the vagaries of different platforms. Also, a
1022 * zero result implies unreported underflow.
1026 if (errno != 0 || result == 0.0
1031 elog(ERROR, "exp() result is out of range");
1033 CheckFloat8Val(result);
1034 PG_RETURN_FLOAT8(result);
1039 * dlog1 - returns the natural logarithm of arg1
1040 * ("dlog" is already a logging routine...)
1043 dlog1(PG_FUNCTION_ARGS)
1045 float8 arg1 = PG_GETARG_FLOAT8(0);
1049 elog(ERROR, "can't take log of zero");
1051 elog(ERROR, "can't take log of a negative number");
1055 CheckFloat8Val(result);
1056 PG_RETURN_FLOAT8(result);
1061 * dlog10 - returns the base 10 logarithm of arg1
1064 dlog10(PG_FUNCTION_ARGS)
1066 float8 arg1 = PG_GETARG_FLOAT8(0);
1070 elog(ERROR, "can't take log of zero");
1072 elog(ERROR, "can't take log of a negative number");
1074 result = log10(arg1);
1076 CheckFloat8Val(result);
1077 PG_RETURN_FLOAT8(result);
1082 * dacos - returns the arccos of arg1 (radians)
1085 dacos(PG_FUNCTION_ARGS)
1087 float8 arg1 = PG_GETARG_FLOAT8(0);
1091 result = acos(arg1);
1097 elog(ERROR, "acos(%f) input is out of range", arg1);
1099 CheckFloat8Val(result);
1100 PG_RETURN_FLOAT8(result);
1105 * dasin - returns the arcsin of arg1 (radians)
1108 dasin(PG_FUNCTION_ARGS)
1110 float8 arg1 = PG_GETARG_FLOAT8(0);
1114 result = asin(arg1);
1120 elog(ERROR, "asin(%f) input is out of range", arg1);
1122 CheckFloat8Val(result);
1123 PG_RETURN_FLOAT8(result);
1128 * datan - returns the arctan of arg1 (radians)
1131 datan(PG_FUNCTION_ARGS)
1133 float8 arg1 = PG_GETARG_FLOAT8(0);
1137 result = atan(arg1);
1143 elog(ERROR, "atan(%f) input is out of range", arg1);
1145 CheckFloat8Val(result);
1146 PG_RETURN_FLOAT8(result);
1151 * atan2 - returns the arctan2 of arg1 (radians)
1154 datan2(PG_FUNCTION_ARGS)
1156 float8 arg1 = PG_GETARG_FLOAT8(0);
1157 float8 arg2 = PG_GETARG_FLOAT8(1);
1161 result = atan2(arg1, arg2);
1167 elog(ERROR, "atan2(%f,%f) input is out of range", arg1, arg2);
1169 CheckFloat8Val(result);
1170 PG_RETURN_FLOAT8(result);
1175 * dcos - returns the cosine of arg1 (radians)
1178 dcos(PG_FUNCTION_ARGS)
1180 float8 arg1 = PG_GETARG_FLOAT8(0);
1190 elog(ERROR, "cos(%f) input is out of range", arg1);
1192 CheckFloat8Val(result);
1193 PG_RETURN_FLOAT8(result);
1198 * dcot - returns the cotangent of arg1 (radians)
1201 dcot(PG_FUNCTION_ARGS)
1203 float8 arg1 = PG_GETARG_FLOAT8(0);
1208 if (errno != 0 || result == 0.0
1213 elog(ERROR, "cot(%f) input is out of range", arg1);
1215 result = 1.0 / result;
1216 CheckFloat8Val(result);
1217 PG_RETURN_FLOAT8(result);
1222 * dsin - returns the sine of arg1 (radians)
1225 dsin(PG_FUNCTION_ARGS)
1227 float8 arg1 = PG_GETARG_FLOAT8(0);
1237 elog(ERROR, "sin(%f) input is out of range", arg1);
1239 CheckFloat8Val(result);
1240 PG_RETURN_FLOAT8(result);
1245 * dtan - returns the tangent of arg1 (radians)
1248 dtan(PG_FUNCTION_ARGS)
1250 float8 arg1 = PG_GETARG_FLOAT8(0);
1260 elog(ERROR, "tan(%f) input is out of range", arg1);
1262 CheckFloat8Val(result);
1263 PG_RETURN_FLOAT8(result);
1268 * degrees - returns degrees converted from radians
1271 degrees(PG_FUNCTION_ARGS)
1273 float8 arg1 = PG_GETARG_FLOAT8(0);
1276 result = arg1 * (180.0 / M_PI);
1278 CheckFloat8Val(result);
1279 PG_RETURN_FLOAT8(result);
1284 * dpi - returns the constant PI
1287 dpi(PG_FUNCTION_ARGS)
1289 PG_RETURN_FLOAT8(M_PI);
1294 * radians - returns radians converted from degrees
1297 radians(PG_FUNCTION_ARGS)
1299 float8 arg1 = PG_GETARG_FLOAT8(0);
1302 result = arg1 * (M_PI / 180.0);
1304 CheckFloat8Val(result);
1305 PG_RETURN_FLOAT8(result);
1310 * drandom - returns a random number
1313 drandom(PG_FUNCTION_ARGS)
1317 /* result 0.0-1.0 */
1318 result = ((double) random()) / ((double) MAX_RANDOM_VALUE);
1320 PG_RETURN_FLOAT8(result);
1325 * setseed - set seed for the random number generator
1328 setseed(PG_FUNCTION_ARGS)
1330 float8 seed = PG_GETARG_FLOAT8(0);
1331 int iseed = (int) (seed * MAX_RANDOM_VALUE);
1333 srandom((unsigned int) iseed);
1335 PG_RETURN_INT32(iseed);
1341 * =========================
1342 * FLOAT AGGREGATE OPERATORS
1343 * =========================
1345 * float8_accum - accumulate for AVG(), STDDEV(), etc
1346 * float4_accum - same, but input data is float4
1347 * float8_avg - produce final result for float AVG()
1348 * float8_variance - produce final result for float VARIANCE()
1349 * float8_stddev - produce final result for float STDDEV()
1351 * The transition datatype for all these aggregates is a 3-element array
1352 * of float8, holding the values N, sum(X), sum(X*X) in that order.
1354 * Note that we represent N as a float to avoid having to build a special
1355 * datatype. Given a reasonable floating-point implementation, there should
1356 * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
1357 * user will have doubtless lost interest anyway...)
1361 check_float8_array(ArrayType *transarray, const char *caller)
1364 * We expect the input to be a 3-element float array; verify that.
1365 * We don't need to use deconstruct_array() since the array data
1366 * is just going to look like a C array of 3 float8 values.
1368 if (ARR_SIZE(transarray) != (ARR_OVERHEAD(1) + 3 * sizeof(float8)) ||
1369 ARR_NDIM(transarray) != 1 ||
1370 ARR_DIMS(transarray)[0] != 3)
1371 elog(ERROR, "%s: expected 3-element float8 array", caller);
1372 return (float8 *) ARR_DATA_PTR(transarray);
1376 float8_accum(PG_FUNCTION_ARGS)
1378 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1379 float8 newval = PG_GETARG_FLOAT8(1);
1380 float8 *transvalues;
1384 Datum transdatums[3];
1387 transvalues = check_float8_array(transarray, "float8_accum");
1389 sumX = transvalues[1];
1390 sumX2 = transvalues[2];
1394 sumX2 += newval * newval;
1396 transdatums[0] = Float8GetDatumFast(N);
1397 transdatums[1] = Float8GetDatumFast(sumX);
1398 transdatums[2] = Float8GetDatumFast(sumX2);
1400 result = construct_array(transdatums, 3,
1401 false /* float8 byval */, sizeof(float8), 'd');
1403 PG_RETURN_ARRAYTYPE_P(result);
1407 float4_accum(PG_FUNCTION_ARGS)
1409 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1410 float4 newval4 = PG_GETARG_FLOAT4(1);
1411 float8 *transvalues;
1416 Datum transdatums[3];
1419 transvalues = check_float8_array(transarray, "float4_accum");
1421 sumX = transvalues[1];
1422 sumX2 = transvalues[2];
1424 /* Do arithmetic in float8 for best accuracy */
1429 sumX2 += newval * newval;
1431 transdatums[0] = Float8GetDatumFast(N);
1432 transdatums[1] = Float8GetDatumFast(sumX);
1433 transdatums[2] = Float8GetDatumFast(sumX2);
1435 result = construct_array(transdatums, 3,
1436 false /* float8 byval */, sizeof(float8), 'd');
1438 PG_RETURN_ARRAYTYPE_P(result);
1442 float8_avg(PG_FUNCTION_ARGS)
1444 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1445 float8 *transvalues;
1449 transvalues = check_float8_array(transarray, "float8_avg");
1451 sumX = transvalues[1];
1454 /* SQL92 defines AVG of no values to be NULL */
1458 PG_RETURN_FLOAT8(sumX / N);
1462 float8_variance(PG_FUNCTION_ARGS)
1464 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1465 float8 *transvalues;
1470 transvalues = check_float8_array(transarray, "float8_variance");
1472 sumX = transvalues[1];
1473 sumX2 = transvalues[2];
1475 /* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
1480 PG_RETURN_FLOAT8(0.0);
1482 PG_RETURN_FLOAT8((N * sumX2 - sumX * sumX) / (N * (N - 1.0)));
1486 float8_stddev(PG_FUNCTION_ARGS)
1488 ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
1489 float8 *transvalues;
1494 transvalues = check_float8_array(transarray, "float8_stddev");
1496 sumX = transvalues[1];
1497 sumX2 = transvalues[2];
1499 /* We define STDDEV of no values to be NULL, of 1 value to be 0 */
1504 PG_RETURN_FLOAT8(0.0);
1506 PG_RETURN_FLOAT8(sqrt((N * sumX2 - sumX * sumX) / (N * (N - 1.0))));
1511 * ====================================
1512 * MIXED-PRECISION ARITHMETIC OPERATORS
1513 * ====================================
1517 * float48pl - returns arg1 + arg2
1518 * float48mi - returns arg1 - arg2
1519 * float48mul - returns arg1 * arg2
1520 * float48div - returns arg1 / arg2
1523 float48pl(PG_FUNCTION_ARGS)
1525 float4 arg1 = PG_GETARG_FLOAT4(0);
1526 float8 arg2 = PG_GETARG_FLOAT8(1);
1529 result = arg1 + arg2;
1530 CheckFloat8Val(result);
1531 PG_RETURN_FLOAT8(result);
1535 float48mi(PG_FUNCTION_ARGS)
1537 float4 arg1 = PG_GETARG_FLOAT4(0);
1538 float8 arg2 = PG_GETARG_FLOAT8(1);
1541 result = arg1 - arg2;
1542 CheckFloat8Val(result);
1543 PG_RETURN_FLOAT8(result);
1547 float48mul(PG_FUNCTION_ARGS)
1549 float4 arg1 = PG_GETARG_FLOAT4(0);
1550 float8 arg2 = PG_GETARG_FLOAT8(1);
1553 result = arg1 * arg2;
1554 CheckFloat8Val(result);
1555 PG_RETURN_FLOAT8(result);
1559 float48div(PG_FUNCTION_ARGS)
1561 float4 arg1 = PG_GETARG_FLOAT4(0);
1562 float8 arg2 = PG_GETARG_FLOAT8(1);
1566 elog(ERROR, "float48div: divide by zero");
1568 result = arg1 / arg2;
1569 CheckFloat8Val(result);
1570 PG_RETURN_FLOAT8(result);
1574 * float84pl - returns arg1 + arg2
1575 * float84mi - returns arg1 - arg2
1576 * float84mul - returns arg1 * arg2
1577 * float84div - returns arg1 / arg2
1580 float84pl(PG_FUNCTION_ARGS)
1582 float8 arg1 = PG_GETARG_FLOAT8(0);
1583 float4 arg2 = PG_GETARG_FLOAT4(1);
1586 result = arg1 + arg2;
1588 CheckFloat8Val(result);
1589 PG_RETURN_FLOAT8(result);
1593 float84mi(PG_FUNCTION_ARGS)
1595 float8 arg1 = PG_GETARG_FLOAT8(0);
1596 float4 arg2 = PG_GETARG_FLOAT4(1);
1599 result = arg1 - arg2;
1601 CheckFloat8Val(result);
1602 PG_RETURN_FLOAT8(result);
1606 float84mul(PG_FUNCTION_ARGS)
1608 float8 arg1 = PG_GETARG_FLOAT8(0);
1609 float4 arg2 = PG_GETARG_FLOAT4(1);
1612 result = arg1 * arg2;
1614 CheckFloat8Val(result);
1615 PG_RETURN_FLOAT8(result);
1619 float84div(PG_FUNCTION_ARGS)
1621 float8 arg1 = PG_GETARG_FLOAT8(0);
1622 float4 arg2 = PG_GETARG_FLOAT4(1);
1626 elog(ERROR, "float84div: divide by zero");
1628 result = arg1 / arg2;
1630 CheckFloat8Val(result);
1631 PG_RETURN_FLOAT8(result);
1635 * ====================
1636 * COMPARISON OPERATORS
1637 * ====================
1641 * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
1644 float48eq(PG_FUNCTION_ARGS)
1646 float4 arg1 = PG_GETARG_FLOAT4(0);
1647 float8 arg2 = PG_GETARG_FLOAT8(1);
1649 PG_RETURN_BOOL(arg1 == arg2);
1653 float48ne(PG_FUNCTION_ARGS)
1655 float4 arg1 = PG_GETARG_FLOAT4(0);
1656 float8 arg2 = PG_GETARG_FLOAT8(1);
1658 PG_RETURN_BOOL(arg1 != arg2);
1662 float48lt(PG_FUNCTION_ARGS)
1664 float4 arg1 = PG_GETARG_FLOAT4(0);
1665 float8 arg2 = PG_GETARG_FLOAT8(1);
1667 PG_RETURN_BOOL(arg1 < arg2);
1671 float48le(PG_FUNCTION_ARGS)
1673 float4 arg1 = PG_GETARG_FLOAT4(0);
1674 float8 arg2 = PG_GETARG_FLOAT8(1);
1676 PG_RETURN_BOOL(arg1 <= arg2);
1680 float48gt(PG_FUNCTION_ARGS)
1682 float4 arg1 = PG_GETARG_FLOAT4(0);
1683 float8 arg2 = PG_GETARG_FLOAT8(1);
1685 PG_RETURN_BOOL(arg1 > arg2);
1689 float48ge(PG_FUNCTION_ARGS)
1691 float4 arg1 = PG_GETARG_FLOAT4(0);
1692 float8 arg2 = PG_GETARG_FLOAT8(1);
1694 PG_RETURN_BOOL(arg1 >= arg2);
1698 * float84{eq,ne,lt,le,gt,ge} - float8/float4 comparison operations
1701 float84eq(PG_FUNCTION_ARGS)
1703 float8 arg1 = PG_GETARG_FLOAT8(0);
1704 float4 arg2 = PG_GETARG_FLOAT4(1);
1706 PG_RETURN_BOOL(arg1 == arg2);
1710 float84ne(PG_FUNCTION_ARGS)
1712 float8 arg1 = PG_GETARG_FLOAT8(0);
1713 float4 arg2 = PG_GETARG_FLOAT4(1);
1715 PG_RETURN_BOOL(arg1 != arg2);
1719 float84lt(PG_FUNCTION_ARGS)
1721 float8 arg1 = PG_GETARG_FLOAT8(0);
1722 float4 arg2 = PG_GETARG_FLOAT4(1);
1724 PG_RETURN_BOOL(arg1 < arg2);
1728 float84le(PG_FUNCTION_ARGS)
1730 float8 arg1 = PG_GETARG_FLOAT8(0);
1731 float4 arg2 = PG_GETARG_FLOAT4(1);
1733 PG_RETURN_BOOL(arg1 <= arg2);
1737 float84gt(PG_FUNCTION_ARGS)
1739 float8 arg1 = PG_GETARG_FLOAT8(0);
1740 float4 arg2 = PG_GETARG_FLOAT4(1);
1742 PG_RETURN_BOOL(arg1 > arg2);
1746 float84ge(PG_FUNCTION_ARGS)
1748 float8 arg1 = PG_GETARG_FLOAT8(0);
1749 float4 arg2 = PG_GETARG_FLOAT4(1);
1751 PG_RETURN_BOOL(arg1 >= arg2);
1754 /* ========== PRIVATE ROUTINES ========== */
1756 /* From "fdlibm" @ netlib.att.com */
1760 /* @(#)s_rint.c 5.1 93/09/24 */
1762 * ====================================================
1763 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
1765 * Developed at SunPro, a Sun Microsystems, Inc. business.
1766 * Permission to use, copy, modify, and distribute this
1767 * software is freely granted, provided that this notice
1769 * ====================================================
1774 * Return x rounded to integral value according to the prevailing
1777 * Using floating addition.
1779 * Inexact flag raised if x not equal to rint(x).
1782 static const double one = 1.0,
1784 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
1785 -4.50359962737049600000e+15,/* 0xC3300000, 0x00000000 */
1800 n0 = (*((int *) &one) >> 29) ^ 1;
1801 i0 = *(n0 + (int *) &x);
1802 sx = (i0 >> 31) & 1;
1803 i1 = *(1 - n0 + (int *) &x);
1804 j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
1809 if (((i0 & 0x7fffffff) | i1) == 0)
1811 i1 |= (i0 & 0x0fffff);
1813 i0 |= ((i1 | -i1) >> 12) & 0x80000;
1814 *(n0 + (int *) &x) = i0;
1817 i0 = *(n0 + (int *) &t);
1818 *(n0 + (int *) &t) = (i0 & 0x7fffffff) | (sx << 31);
1823 i = (0x000fffff) >> j0;
1824 if (((i0 & i) | i1) == 0)
1825 return x; /* x is integral */
1827 if (((i0 & i) | i1) != 0)
1832 i0 = (i0 & (~i)) | ((0x20000) >> j0);
1839 return x + x; /* inf or NaN */
1841 return x; /* x is integral */
1845 i = ((unsigned) (0xffffffff)) >> (j0 - 20);
1847 return x; /* x is integral */
1850 i1 = (i1 & (~i)) | ((0x40000000) >> (j0 - 20));
1852 *(n0 + (int *) &x) = i0;
1853 *(1 - n0 + (int *) &x) = i1;
1855 return w - TWO52[sx];
1858 #endif /* !HAVE_RINT */
1865 int isneg = (x < 0.0);
1866 double tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
1868 return isneg ? -tmpres : tmpres;
1871 #endif /* !HAVE_CBRT */