]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/float.c
82c257c80157242fb27489db5805751ed3c8c007
[postgresql] / src / backend / utils / adt / float.c
1 /*-------------------------------------------------------------------------
2  *
3  * float.c
4  *        Functions for the built-in floating-point types.
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.93 2003/08/04 02:40:04 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*----------
16  * OLD COMMENTS
17  *              Basic float4 ops:
18  *               float4in, float4out, float4recv, float4send
19  *               float4abs, float4um, float4up
20  *              Basic float8 ops:
21  *               float8in, float8out, float8recv, float8send
22  *               float8abs, float8um, float8up
23  *              Arithmetic operators:
24  *               float4pl, float4mi, float4mul, float4div
25  *               float8pl, float8mi, float8mul, float8div
26  *              Comparison operators:
27  *               float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
28  *               float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
29  *              Conversion routines:
30  *               ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
31  *
32  *              Random float8 ops:
33  *               dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
34  *              Arithmetic operators:
35  *               float48pl, float48mi, float48mul, float48div
36  *               float84pl, float84mi, float84mul, float84div
37  *              Comparison operators:
38  *               float48eq, float48ne, float48lt, float48le, float48gt, float48ge
39  *               float84eq, float84ne, float84lt, float84le, float84gt, float84ge
40  *
41  *              (You can do the arithmetic and comparison stuff using conversion
42  *               routines, but then you pay the overhead of invoking a separate
43  *               conversion function...)
44  *
45  * XXX GLUESOME STUFF. FIX IT! -AY '94
46  *
47  *              Added some additional conversion routines and cleaned up
48  *               a bit of the existing code. Need to change the error checking
49  *               for calls to pow(), exp() since on some machines (my Linux box
50  *               included) these routines do not set errno. - tgl 97/05/10
51  *----------
52  */
53 #include "postgres.h"
54
55 #include <ctype.h>
56 #include <errno.h>
57 #include <float.h>                              /* faked on sunos4 */
58 #include <math.h>
59
60 #include <limits.h>
61 /* for finite() on Solaris */
62 #ifdef HAVE_IEEEFP_H
63 #include <ieeefp.h>
64 #endif
65
66 #include "catalog/pg_type.h"
67 #include "fmgr.h"
68 #include "libpq/pqformat.h"
69 #include "utils/array.h"
70 #include "utils/builtins.h"
71
72
73 #ifndef HAVE_CBRT
74 static double cbrt(double x);
75 #endif   /* HAVE_CBRT */
76
77 #ifndef M_PI
78 /* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
79 #define M_PI 3.14159265358979323846
80 #endif
81
82 #ifndef NAN
83 #define NAN             (0.0/0.0)
84 #endif
85
86 #ifndef SHRT_MAX
87 #define SHRT_MAX 32767
88 #endif
89 #ifndef SHRT_MIN
90 #define SHRT_MIN (-32768)
91 #endif
92
93 /* not sure what the following should be, but better to make it over-sufficient */
94 #define MAXFLOATWIDTH   64
95 #define MAXDOUBLEWIDTH  128
96
97 /* ========== USER I/O ROUTINES ========== */
98
99
100 #define FLOAT4_MAX               FLT_MAX
101 #define FLOAT4_MIN               FLT_MIN
102 #define FLOAT8_MAX               DBL_MAX
103 #define FLOAT8_MIN               DBL_MIN
104
105
106 /* Configurable GUC parameter */
107 int                     extra_float_digits = 0;         /* Added to DBL_DIG or FLT_DIG */
108
109
110 static void CheckFloat4Val(double val);
111 static void CheckFloat8Val(double val);
112 static int      float4_cmp_internal(float4 a, float4 b);
113 static int      float8_cmp_internal(float8 a, float8 b);
114
115
116 /*
117  * check to see if a float4 val is outside of
118  * the FLOAT4_MIN, FLOAT4_MAX bounds.
119  *
120  * raise an ereport warning if it is
121 */
122 static void
123 CheckFloat4Val(double val)
124 {
125         /*
126          * defining unsafe floats's will make float4 and float8 ops faster at
127          * the cost of safety, of course!
128          */
129 #ifdef UNSAFE_FLOATS
130         return;
131 #else
132         if (fabs(val) > FLOAT4_MAX)
133                 ereport(ERROR,
134                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
135                                  errmsg("float4 value out of range: overflow")));
136         if (val != 0.0 && fabs(val) < FLOAT4_MIN)
137                 ereport(ERROR,
138                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
139                                  errmsg("float4 value out of range: underflow")));
140
141         return;
142 #endif   /* UNSAFE_FLOATS */
143 }
144
145 /*
146  * check to see if a float8 val is outside of
147  * the FLOAT8_MIN, FLOAT8_MAX bounds.
148  *
149  * raise an ereport error if it is
150  */
151 static void
152 CheckFloat8Val(double val)
153 {
154         /*
155          * defining unsafe floats's will make float4 and float8 ops faster at
156          * the cost of safety, of course!
157          */
158 #ifdef UNSAFE_FLOATS
159         return;
160 #else
161         if (fabs(val) > FLOAT8_MAX)
162                 ereport(ERROR,
163                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
164                                  errmsg("float8 value out of range: overflow")));
165         if (val != 0.0 && fabs(val) < FLOAT8_MIN)
166                 ereport(ERROR,
167                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
168                                  errmsg("float8 value out of range: underflow")));
169 #endif   /* UNSAFE_FLOATS */
170 }
171
172 /*
173  *              float4in                - converts "num" to float
174  *                                                restricted syntax:
175  *                                                {<sp>} [+|-] {digit} [.{digit}] [<exp>]
176  *                                                where <sp> is a space, digit is 0-9,
177  *                                                <exp> is "e" or "E" followed by an integer.
178  */
179 Datum
180 float4in(PG_FUNCTION_ARGS)
181 {
182         char       *num = PG_GETARG_CSTRING(0);
183         double          val;
184         char       *endptr;
185
186         errno = 0;
187         val = strtod(num, &endptr);
188         if (*endptr != '\0')
189         {
190                 /*
191                  * XXX we should accept "Infinity" and "-Infinity" too, but what
192                  * are the correct values to assign?  HUGE_VAL will provoke an
193                  * error from CheckFloat4Val.
194                  */
195                 if (strcasecmp(num, "NaN") == 0)
196                         val = NAN;
197                 else
198                         ereport(ERROR,
199                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
200                                          errmsg("invalid input syntax for float4: \"%s\"",
201                                                         num)));
202         }
203         else
204         {
205                 if (errno == ERANGE)
206                         ereport(ERROR,
207                                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
208                                          errmsg("\"%s\" is out of range for float4", num)));
209         }
210
211         /*
212          * if we get here, we have a legal double, still need to check to see
213          * if it's a legal float
214          */
215         CheckFloat4Val(val);
216
217         PG_RETURN_FLOAT4((float4) val);
218 }
219
220 /*
221  *              float4out               - converts a float4 number to a string
222  *                                                using a standard output format
223  */
224 Datum
225 float4out(PG_FUNCTION_ARGS)
226 {
227         float4          num = PG_GETARG_FLOAT4(0);
228         char       *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
229         int                     infflag;
230         int                     ndig;
231
232         if (isnan(num))
233                 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
234         infflag = isinf(num);
235         if (infflag > 0)
236                 PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
237         if (infflag < 0)
238                 PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
239
240         ndig = FLT_DIG + extra_float_digits;
241         if (ndig < 1)
242                 ndig = 1;
243
244         sprintf(ascii, "%.*g", ndig, num);
245
246         PG_RETURN_CSTRING(ascii);
247 }
248
249 /*
250  *              float4recv                      - converts external binary format to float4
251  */
252 Datum
253 float4recv(PG_FUNCTION_ARGS)
254 {
255         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
256
257         PG_RETURN_FLOAT4(pq_getmsgfloat4(buf));
258 }
259
260 /*
261  *              float4send                      - converts float4 to binary format
262  */
263 Datum
264 float4send(PG_FUNCTION_ARGS)
265 {
266         float4          num = PG_GETARG_FLOAT4(0);
267         StringInfoData buf;
268
269         pq_begintypsend(&buf);
270         pq_sendfloat4(&buf, num);
271         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
272 }
273
274 /*
275  *              float8in                - converts "num" to float8
276  *                                                restricted syntax:
277  *                                                {<sp>} [+|-] {digit} [.{digit}] [<exp>]
278  *                                                where <sp> is a space, digit is 0-9,
279  *                                                <exp> is "e" or "E" followed by an integer.
280  */
281 Datum
282 float8in(PG_FUNCTION_ARGS)
283 {
284         char       *num = PG_GETARG_CSTRING(0);
285         double          val;
286         char       *endptr;
287
288         errno = 0;
289         val = strtod(num, &endptr);
290         if (*endptr != '\0')
291         {
292                 if (strcasecmp(num, "NaN") == 0)
293                         val = NAN;
294                 else if (strcasecmp(num, "Infinity") == 0)
295                         val = HUGE_VAL;
296                 else if (strcasecmp(num, "-Infinity") == 0)
297                         val = -HUGE_VAL;
298                 else
299                         ereport(ERROR,
300                                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
301                                          errmsg("invalid input syntax for float8: \"%s\"",
302                                                         num)));
303         }
304         else
305         {
306                 if (errno == ERANGE)
307                         ereport(ERROR,
308                                         (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
309                                          errmsg("\"%s\" is out of range for float8", num)));
310         }
311
312         CheckFloat8Val(val);
313
314         PG_RETURN_FLOAT8(val);
315 }
316
317 /*
318  *              float8out               - converts float8 number to a string
319  *                                                using a standard output format
320  */
321 Datum
322 float8out(PG_FUNCTION_ARGS)
323 {
324         float8          num = PG_GETARG_FLOAT8(0);
325         char       *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
326         int                     infflag;
327         int                     ndig;
328
329         if (isnan(num))
330                 PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
331         infflag = isinf(num);
332         if (infflag > 0)
333                 PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
334         if (infflag < 0)
335                 PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
336
337         ndig = DBL_DIG + extra_float_digits;
338         if (ndig < 1)
339                 ndig = 1;
340
341         sprintf(ascii, "%.*g", ndig, num);
342
343         PG_RETURN_CSTRING(ascii);
344 }
345
346 /*
347  *              float8recv                      - converts external binary format to float8
348  */
349 Datum
350 float8recv(PG_FUNCTION_ARGS)
351 {
352         StringInfo      buf = (StringInfo) PG_GETARG_POINTER(0);
353
354         PG_RETURN_FLOAT8(pq_getmsgfloat8(buf));
355 }
356
357 /*
358  *              float8send                      - converts float8 to binary format
359  */
360 Datum
361 float8send(PG_FUNCTION_ARGS)
362 {
363         float8          num = PG_GETARG_FLOAT8(0);
364         StringInfoData buf;
365
366         pq_begintypsend(&buf);
367         pq_sendfloat8(&buf, num);
368         PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
369 }
370
371
372 /* ========== PUBLIC ROUTINES ========== */
373
374
375 /*
376  *              ======================
377  *              FLOAT4 BASE OPERATIONS
378  *              ======================
379  */
380
381 /*
382  *              float4abs               - returns |arg1| (absolute value)
383  */
384 Datum
385 float4abs(PG_FUNCTION_ARGS)
386 {
387         float4          arg1 = PG_GETARG_FLOAT4(0);
388
389         PG_RETURN_FLOAT4((float4) fabs(arg1));
390 }
391
392 /*
393  *              float4um                - returns -arg1 (unary minus)
394  */
395 Datum
396 float4um(PG_FUNCTION_ARGS)
397 {
398         float4          arg1 = PG_GETARG_FLOAT4(0);
399
400         PG_RETURN_FLOAT4((float4) -arg1);
401 }
402
403 Datum
404 float4up(PG_FUNCTION_ARGS)
405 {
406         float4          arg = PG_GETARG_FLOAT4(0);
407
408         PG_RETURN_FLOAT4(arg);
409 }
410
411 Datum
412 float4larger(PG_FUNCTION_ARGS)
413 {
414         float4          arg1 = PG_GETARG_FLOAT4(0);
415         float4          arg2 = PG_GETARG_FLOAT4(1);
416         float4          result;
417
418         if (float4_cmp_internal(arg1, arg2) > 0)
419                 result = arg1;
420         else
421                 result = arg2;
422         PG_RETURN_FLOAT4(result);
423 }
424
425 Datum
426 float4smaller(PG_FUNCTION_ARGS)
427 {
428         float4          arg1 = PG_GETARG_FLOAT4(0);
429         float4          arg2 = PG_GETARG_FLOAT4(1);
430         float4          result;
431
432         if (float4_cmp_internal(arg1, arg2) < 0)
433                 result = arg1;
434         else
435                 result = arg2;
436         PG_RETURN_FLOAT4(result);
437 }
438
439 /*
440  *              ======================
441  *              FLOAT8 BASE OPERATIONS
442  *              ======================
443  */
444
445 /*
446  *              float8abs               - returns |arg1| (absolute value)
447  */
448 Datum
449 float8abs(PG_FUNCTION_ARGS)
450 {
451         float8          arg1 = PG_GETARG_FLOAT8(0);
452         float8          result;
453
454         result = fabs(arg1);
455
456         CheckFloat8Val(result);
457         PG_RETURN_FLOAT8(result);
458 }
459
460
461 /*
462  *              float8um                - returns -arg1 (unary minus)
463  */
464 Datum
465 float8um(PG_FUNCTION_ARGS)
466 {
467         float8          arg1 = PG_GETARG_FLOAT8(0);
468         float8          result;
469
470         result = ((arg1 != 0) ? -(arg1) : arg1);
471
472         CheckFloat8Val(result);
473         PG_RETURN_FLOAT8(result);
474 }
475
476 Datum
477 float8up(PG_FUNCTION_ARGS)
478 {
479         float8          arg = PG_GETARG_FLOAT8(0);
480
481         PG_RETURN_FLOAT8(arg);
482 }
483
484 Datum
485 float8larger(PG_FUNCTION_ARGS)
486 {
487         float8          arg1 = PG_GETARG_FLOAT8(0);
488         float8          arg2 = PG_GETARG_FLOAT8(1);
489         float8          result;
490
491         if (float8_cmp_internal(arg1, arg2) > 0)
492                 result = arg1;
493         else
494                 result = arg2;
495         PG_RETURN_FLOAT8(result);
496 }
497
498 Datum
499 float8smaller(PG_FUNCTION_ARGS)
500 {
501         float8          arg1 = PG_GETARG_FLOAT8(0);
502         float8          arg2 = PG_GETARG_FLOAT8(1);
503         float8          result;
504
505         if (float8_cmp_internal(arg1, arg2) < 0)
506                 result = arg1;
507         else
508                 result = arg2;
509         PG_RETURN_FLOAT8(result);
510 }
511
512
513 /*
514  *              ====================
515  *              ARITHMETIC OPERATORS
516  *              ====================
517  */
518
519 /*
520  *              float4pl                - returns arg1 + arg2
521  *              float4mi                - returns arg1 - arg2
522  *              float4mul               - returns arg1 * arg2
523  *              float4div               - returns arg1 / arg2
524  */
525 Datum
526 float4pl(PG_FUNCTION_ARGS)
527 {
528         float4          arg1 = PG_GETARG_FLOAT4(0);
529         float4          arg2 = PG_GETARG_FLOAT4(1);
530         double          result;
531
532         result = arg1 + arg2;
533         CheckFloat4Val(result);
534         PG_RETURN_FLOAT4((float4) result);
535 }
536
537 Datum
538 float4mi(PG_FUNCTION_ARGS)
539 {
540         float4          arg1 = PG_GETARG_FLOAT4(0);
541         float4          arg2 = PG_GETARG_FLOAT4(1);
542         double          result;
543
544         result = arg1 - arg2;
545         CheckFloat4Val(result);
546         PG_RETURN_FLOAT4((float4) result);
547 }
548
549 Datum
550 float4mul(PG_FUNCTION_ARGS)
551 {
552         float4          arg1 = PG_GETARG_FLOAT4(0);
553         float4          arg2 = PG_GETARG_FLOAT4(1);
554         double          result;
555
556         result = arg1 * arg2;
557         CheckFloat4Val(result);
558         PG_RETURN_FLOAT4((float4) result);
559 }
560
561 Datum
562 float4div(PG_FUNCTION_ARGS)
563 {
564         float4          arg1 = PG_GETARG_FLOAT4(0);
565         float4          arg2 = PG_GETARG_FLOAT4(1);
566         double          result;
567
568         if (arg2 == 0.0)
569                 ereport(ERROR,
570                                 (errcode(ERRCODE_DIVISION_BY_ZERO),
571                                  errmsg("division by zero")));
572
573         /* Do division in float8, then check for overflow */
574         result = (float8) arg1 / (float8) arg2;
575
576         CheckFloat4Val(result);
577         PG_RETURN_FLOAT4((float4) result);
578 }
579
580 /*
581  *              float8pl                - returns arg1 + arg2
582  *              float8mi                - returns arg1 - arg2
583  *              float8mul               - returns arg1 * arg2
584  *              float8div               - returns arg1 / arg2
585  */
586 Datum
587 float8pl(PG_FUNCTION_ARGS)
588 {
589         float8          arg1 = PG_GETARG_FLOAT8(0);
590         float8          arg2 = PG_GETARG_FLOAT8(1);
591         float8          result;
592
593         result = arg1 + arg2;
594
595         CheckFloat8Val(result);
596         PG_RETURN_FLOAT8(result);
597 }
598
599 Datum
600 float8mi(PG_FUNCTION_ARGS)
601 {
602         float8          arg1 = PG_GETARG_FLOAT8(0);
603         float8          arg2 = PG_GETARG_FLOAT8(1);
604         float8          result;
605
606         result = arg1 - arg2;
607
608         CheckFloat8Val(result);
609         PG_RETURN_FLOAT8(result);
610 }
611
612 Datum
613 float8mul(PG_FUNCTION_ARGS)
614 {
615         float8          arg1 = PG_GETARG_FLOAT8(0);
616         float8          arg2 = PG_GETARG_FLOAT8(1);
617         float8          result;
618
619         result = arg1 * arg2;
620
621         CheckFloat8Val(result);
622         PG_RETURN_FLOAT8(result);
623 }
624
625 Datum
626 float8div(PG_FUNCTION_ARGS)
627 {
628         float8          arg1 = PG_GETARG_FLOAT8(0);
629         float8          arg2 = PG_GETARG_FLOAT8(1);
630         float8          result;
631
632         if (arg2 == 0.0)
633                 ereport(ERROR,
634                                 (errcode(ERRCODE_DIVISION_BY_ZERO),
635                                  errmsg("division by zero")));
636
637         result = arg1 / arg2;
638
639         CheckFloat8Val(result);
640         PG_RETURN_FLOAT8(result);
641 }
642
643
644 /*
645  *              ====================
646  *              COMPARISON OPERATORS
647  *              ====================
648  */
649
650 /*
651  *              float4{eq,ne,lt,le,gt,ge}               - float4/float4 comparison operations
652  */
653 static int
654 float4_cmp_internal(float4 a, float4 b)
655 {
656         /*
657          * We consider all NANs to be equal and larger than any non-NAN. This
658          * is somewhat arbitrary; the important thing is to have a consistent
659          * sort order.
660          */
661         if (isnan(a))
662         {
663                 if (isnan(b))
664                         return 0;                       /* NAN = NAN */
665                 else
666                         return 1;                       /* NAN > non-NAN */
667         }
668         else if (isnan(b))
669         {
670                 return -1;                              /* non-NAN < NAN */
671         }
672         else
673         {
674                 if (a > b)
675                         return 1;
676                 else if (a < b)
677                         return -1;
678                 else
679                         return 0;
680         }
681 }
682
683 Datum
684 float4eq(PG_FUNCTION_ARGS)
685 {
686         float4          arg1 = PG_GETARG_FLOAT4(0);
687         float4          arg2 = PG_GETARG_FLOAT4(1);
688
689         PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
690 }
691
692 Datum
693 float4ne(PG_FUNCTION_ARGS)
694 {
695         float4          arg1 = PG_GETARG_FLOAT4(0);
696         float4          arg2 = PG_GETARG_FLOAT4(1);
697
698         PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
699 }
700
701 Datum
702 float4lt(PG_FUNCTION_ARGS)
703 {
704         float4          arg1 = PG_GETARG_FLOAT4(0);
705         float4          arg2 = PG_GETARG_FLOAT4(1);
706
707         PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
708 }
709
710 Datum
711 float4le(PG_FUNCTION_ARGS)
712 {
713         float4          arg1 = PG_GETARG_FLOAT4(0);
714         float4          arg2 = PG_GETARG_FLOAT4(1);
715
716         PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
717 }
718
719 Datum
720 float4gt(PG_FUNCTION_ARGS)
721 {
722         float4          arg1 = PG_GETARG_FLOAT4(0);
723         float4          arg2 = PG_GETARG_FLOAT4(1);
724
725         PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
726 }
727
728 Datum
729 float4ge(PG_FUNCTION_ARGS)
730 {
731         float4          arg1 = PG_GETARG_FLOAT4(0);
732         float4          arg2 = PG_GETARG_FLOAT4(1);
733
734         PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
735 }
736
737 Datum
738 btfloat4cmp(PG_FUNCTION_ARGS)
739 {
740         float4          arg1 = PG_GETARG_FLOAT4(0);
741         float4          arg2 = PG_GETARG_FLOAT4(1);
742
743         PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
744 }
745
746 /*
747  *              float8{eq,ne,lt,le,gt,ge}               - float8/float8 comparison operations
748  */
749 static int
750 float8_cmp_internal(float8 a, float8 b)
751 {
752         /*
753          * We consider all NANs to be equal and larger than any non-NAN. This
754          * is somewhat arbitrary; the important thing is to have a consistent
755          * sort order.
756          */
757         if (isnan(a))
758         {
759                 if (isnan(b))
760                         return 0;                       /* NAN = NAN */
761                 else
762                         return 1;                       /* NAN > non-NAN */
763         }
764         else if (isnan(b))
765         {
766                 return -1;                              /* non-NAN < NAN */
767         }
768         else
769         {
770                 if (a > b)
771                         return 1;
772                 else if (a < b)
773                         return -1;
774                 else
775                         return 0;
776         }
777 }
778
779 Datum
780 float8eq(PG_FUNCTION_ARGS)
781 {
782         float8          arg1 = PG_GETARG_FLOAT8(0);
783         float8          arg2 = PG_GETARG_FLOAT8(1);
784
785         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
786 }
787
788 Datum
789 float8ne(PG_FUNCTION_ARGS)
790 {
791         float8          arg1 = PG_GETARG_FLOAT8(0);
792         float8          arg2 = PG_GETARG_FLOAT8(1);
793
794         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
795 }
796
797 Datum
798 float8lt(PG_FUNCTION_ARGS)
799 {
800         float8          arg1 = PG_GETARG_FLOAT8(0);
801         float8          arg2 = PG_GETARG_FLOAT8(1);
802
803         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
804 }
805
806 Datum
807 float8le(PG_FUNCTION_ARGS)
808 {
809         float8          arg1 = PG_GETARG_FLOAT8(0);
810         float8          arg2 = PG_GETARG_FLOAT8(1);
811
812         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
813 }
814
815 Datum
816 float8gt(PG_FUNCTION_ARGS)
817 {
818         float8          arg1 = PG_GETARG_FLOAT8(0);
819         float8          arg2 = PG_GETARG_FLOAT8(1);
820
821         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
822 }
823
824 Datum
825 float8ge(PG_FUNCTION_ARGS)
826 {
827         float8          arg1 = PG_GETARG_FLOAT8(0);
828         float8          arg2 = PG_GETARG_FLOAT8(1);
829
830         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
831 }
832
833 Datum
834 btfloat8cmp(PG_FUNCTION_ARGS)
835 {
836         float8          arg1 = PG_GETARG_FLOAT8(0);
837         float8          arg2 = PG_GETARG_FLOAT8(1);
838
839         PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
840 }
841
842
843 /*
844  *              ===================
845  *              CONVERSION ROUTINES
846  *              ===================
847  */
848
849 /*
850  *              ftod                    - converts a float4 number to a float8 number
851  */
852 Datum
853 ftod(PG_FUNCTION_ARGS)
854 {
855         float4          num = PG_GETARG_FLOAT4(0);
856
857         PG_RETURN_FLOAT8((float8) num);
858 }
859
860
861 /*
862  *              dtof                    - converts a float8 number to a float4 number
863  */
864 Datum
865 dtof(PG_FUNCTION_ARGS)
866 {
867         float8          num = PG_GETARG_FLOAT8(0);
868
869         CheckFloat4Val(num);
870
871         PG_RETURN_FLOAT4((float4) num);
872 }
873
874
875 /*
876  *              dtoi4                   - converts a float8 number to an int4 number
877  */
878 Datum
879 dtoi4(PG_FUNCTION_ARGS)
880 {
881         float8          num = PG_GETARG_FLOAT8(0);
882         int32           result;
883
884         if ((num < INT_MIN) || (num > INT_MAX))
885                 ereport(ERROR,
886                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
887                                  errmsg("integer out of range")));
888
889         result = (int32) rint(num);
890         PG_RETURN_INT32(result);
891 }
892
893
894 /*
895  *              dtoi2                   - converts a float8 number to an int2 number
896  */
897 Datum
898 dtoi2(PG_FUNCTION_ARGS)
899 {
900         float8          num = PG_GETARG_FLOAT8(0);
901         int16           result;
902
903         if ((num < SHRT_MIN) || (num > SHRT_MAX))
904                 ereport(ERROR,
905                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
906                                  errmsg("integer out of range")));
907
908         result = (int16) rint(num);
909         PG_RETURN_INT16(result);
910 }
911
912
913 /*
914  *              i4tod                   - converts an int4 number to a float8 number
915  */
916 Datum
917 i4tod(PG_FUNCTION_ARGS)
918 {
919         int32           num = PG_GETARG_INT32(0);
920         float8          result;
921
922         result = num;
923         PG_RETURN_FLOAT8(result);
924 }
925
926
927 /*
928  *              i2tod                   - converts an int2 number to a float8 number
929  */
930 Datum
931 i2tod(PG_FUNCTION_ARGS)
932 {
933         int16           num = PG_GETARG_INT16(0);
934         float8          result;
935
936         result = num;
937         PG_RETURN_FLOAT8(result);
938 }
939
940
941 /*
942  *              ftoi4                   - converts a float4 number to an int4 number
943  */
944 Datum
945 ftoi4(PG_FUNCTION_ARGS)
946 {
947         float4          num = PG_GETARG_FLOAT4(0);
948         int32           result;
949
950         if ((num < INT_MIN) || (num > INT_MAX))
951                 ereport(ERROR,
952                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
953                                  errmsg("integer out of range")));
954
955         result = (int32) rint(num);
956         PG_RETURN_INT32(result);
957 }
958
959
960 /*
961  *              ftoi2                   - converts a float4 number to an int2 number
962  */
963 Datum
964 ftoi2(PG_FUNCTION_ARGS)
965 {
966         float4          num = PG_GETARG_FLOAT4(0);
967         int16           result;
968
969         if ((num < SHRT_MIN) || (num > SHRT_MAX))
970                 ereport(ERROR,
971                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
972                                  errmsg("integer out of range")));
973
974         result = (int16) rint(num);
975         PG_RETURN_INT16(result);
976 }
977
978
979 /*
980  *              i4tof                   - converts an int4 number to a float8 number
981  */
982 Datum
983 i4tof(PG_FUNCTION_ARGS)
984 {
985         int32           num = PG_GETARG_INT32(0);
986         float4          result;
987
988         result = num;
989         PG_RETURN_FLOAT4(result);
990 }
991
992
993 /*
994  *              i2tof                   - converts an int2 number to a float4 number
995  */
996 Datum
997 i2tof(PG_FUNCTION_ARGS)
998 {
999         int16           num = PG_GETARG_INT16(0);
1000         float4          result;
1001
1002         result = num;
1003         PG_RETURN_FLOAT4(result);
1004 }
1005
1006
1007 /*
1008  *              float8_text             - converts a float8 number to a text string
1009  */
1010 Datum
1011 float8_text(PG_FUNCTION_ARGS)
1012 {
1013         float8          num = PG_GETARG_FLOAT8(0);
1014         text       *result;
1015         int                     len;
1016         char       *str;
1017
1018         str = DatumGetCString(DirectFunctionCall1(float8out,
1019                                                                                           Float8GetDatum(num)));
1020
1021         len = strlen(str) + VARHDRSZ;
1022
1023         result = (text *) palloc(len);
1024
1025         VARATT_SIZEP(result) = len;
1026         memcpy(VARDATA(result), str, (len - VARHDRSZ));
1027
1028         pfree(str);
1029
1030         PG_RETURN_TEXT_P(result);
1031 }
1032
1033
1034 /*
1035  *              text_float8             - converts a text string to a float8 number
1036  */
1037 Datum
1038 text_float8(PG_FUNCTION_ARGS)
1039 {
1040         text       *string = PG_GETARG_TEXT_P(0);
1041         Datum           result;
1042         int                     len;
1043         char       *str;
1044
1045         len = (VARSIZE(string) - VARHDRSZ);
1046         str = palloc(len + 1);
1047         memcpy(str, VARDATA(string), len);
1048         *(str + len) = '\0';
1049
1050         result = DirectFunctionCall1(float8in, CStringGetDatum(str));
1051
1052         pfree(str);
1053
1054         PG_RETURN_DATUM(result);
1055 }
1056
1057
1058 /*
1059  *              float4_text             - converts a float4 number to a text string
1060  */
1061 Datum
1062 float4_text(PG_FUNCTION_ARGS)
1063 {
1064         float4          num = PG_GETARG_FLOAT4(0);
1065         text       *result;
1066         int                     len;
1067         char       *str;
1068
1069         str = DatumGetCString(DirectFunctionCall1(float4out,
1070                                                                                           Float4GetDatum(num)));
1071
1072         len = strlen(str) + VARHDRSZ;
1073
1074         result = (text *) palloc(len);
1075
1076         VARATT_SIZEP(result) = len;
1077         memcpy(VARDATA(result), str, (len - VARHDRSZ));
1078
1079         pfree(str);
1080
1081         PG_RETURN_TEXT_P(result);
1082 }
1083
1084
1085 /*
1086  *              text_float4             - converts a text string to a float4 number
1087  */
1088 Datum
1089 text_float4(PG_FUNCTION_ARGS)
1090 {
1091         text       *string = PG_GETARG_TEXT_P(0);
1092         Datum           result;
1093         int                     len;
1094         char       *str;
1095
1096         len = (VARSIZE(string) - VARHDRSZ);
1097         str = palloc(len + 1);
1098         memcpy(str, VARDATA(string), len);
1099         *(str + len) = '\0';
1100
1101         result = DirectFunctionCall1(float4in, CStringGetDatum(str));
1102
1103         pfree(str);
1104
1105         PG_RETURN_DATUM(result);
1106 }
1107
1108
1109 /*
1110  *              =======================
1111  *              RANDOM FLOAT8 OPERATORS
1112  *              =======================
1113  */
1114
1115 /*
1116  *              dround                  - returns       ROUND(arg1)
1117  */
1118 Datum
1119 dround(PG_FUNCTION_ARGS)
1120 {
1121         float8          arg1 = PG_GETARG_FLOAT8(0);
1122         float8          result;
1123
1124         result = rint(arg1);
1125
1126         PG_RETURN_FLOAT8(result);
1127 }
1128
1129 /*
1130  *              dceil                   - returns the smallest integer greater than or
1131  *                                                equal to the specified float
1132  */
1133 Datum
1134 dceil(PG_FUNCTION_ARGS)
1135 {
1136         float8          arg1 = PG_GETARG_FLOAT8(0);
1137
1138         PG_RETURN_FLOAT8(ceil(arg1));
1139 }
1140
1141 /*
1142  *              dfloor                  - returns the largest integer lesser than or
1143  *                                                equal to the specified float
1144  */
1145 Datum
1146 dfloor(PG_FUNCTION_ARGS)
1147 {
1148         float8          arg1 = PG_GETARG_FLOAT8(0);
1149
1150         PG_RETURN_FLOAT8(floor(arg1));
1151 }
1152
1153 /*
1154  *              dsign                   - returns -1 if the argument is less than 0, 0
1155  *                                                if the argument is equal to 0, and 1 if the
1156  *                                                argument is greater than zero.
1157  */
1158 Datum
1159 dsign(PG_FUNCTION_ARGS)
1160 {
1161         float8          arg1 = PG_GETARG_FLOAT8(0);
1162         float8          result;
1163
1164         if (arg1 > 0)
1165                 result = 1.0;
1166         else if (arg1 < 0)
1167                 result = -1.0;
1168         else
1169                 result = 0.0;
1170
1171         PG_RETURN_FLOAT8(result);
1172 }
1173
1174 /*
1175  *              dtrunc                  - returns truncation-towards-zero of arg1,
1176  *                                                arg1 >= 0 ... the greatest integer less
1177  *                                                                              than or equal to arg1
1178  *                                                arg1 < 0      ... the least integer greater
1179  *                                                                              than or equal to arg1
1180  */
1181 Datum
1182 dtrunc(PG_FUNCTION_ARGS)
1183 {
1184         float8          arg1 = PG_GETARG_FLOAT8(0);
1185         float8          result;
1186
1187         if (arg1 >= 0)
1188                 result = floor(arg1);
1189         else
1190                 result = -floor(-arg1);
1191
1192         PG_RETURN_FLOAT8(result);
1193 }
1194
1195
1196 /*
1197  *              dsqrt                   - returns square root of arg1
1198  */
1199 Datum
1200 dsqrt(PG_FUNCTION_ARGS)
1201 {
1202         float8          arg1 = PG_GETARG_FLOAT8(0);
1203         float8          result;
1204
1205         if (arg1 < 0)
1206                 ereport(ERROR,
1207                                 (errcode(ERRCODE_FLOATING_POINT_EXCEPTION),
1208                                  errmsg("cannot take square root of a negative number")));
1209
1210         result = sqrt(arg1);
1211
1212         CheckFloat8Val(result);
1213         PG_RETURN_FLOAT8(result);
1214 }
1215
1216
1217 /*
1218  *              dcbrt                   - returns cube root of arg1
1219  */
1220 Datum
1221 dcbrt(PG_FUNCTION_ARGS)
1222 {
1223         float8          arg1 = PG_GETARG_FLOAT8(0);
1224         float8          result;
1225
1226         result = cbrt(arg1);
1227         PG_RETURN_FLOAT8(result);
1228 }
1229
1230
1231 /*
1232  *              dpow                    - returns pow(arg1,arg2)
1233  */
1234 Datum
1235 dpow(PG_FUNCTION_ARGS)
1236 {
1237         float8          arg1 = PG_GETARG_FLOAT8(0);
1238         float8          arg2 = PG_GETARG_FLOAT8(1);
1239         float8          result;
1240
1241         /*
1242          * We must check both for errno getting set and for a NaN result, in
1243          * order to deal with the vagaries of different platforms...
1244          */
1245         errno = 0;
1246         result = pow(arg1, arg2);
1247         if (errno != 0
1248 #ifdef HAVE_FINITE
1249                 || !finite(result)
1250 #endif
1251                 )
1252                 ereport(ERROR,
1253                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1254                                  errmsg("result is out of range")));
1255
1256         CheckFloat8Val(result);
1257         PG_RETURN_FLOAT8(result);
1258 }
1259
1260
1261 /*
1262  *              dexp                    - returns the exponential function of arg1
1263  */
1264 Datum
1265 dexp(PG_FUNCTION_ARGS)
1266 {
1267         float8          arg1 = PG_GETARG_FLOAT8(0);
1268         float8          result;
1269
1270         /*
1271          * We must check both for errno getting set and for a NaN result, in
1272          * order to deal with the vagaries of different platforms. Also, a
1273          * zero result implies unreported underflow.
1274          */
1275         errno = 0;
1276         result = exp(arg1);
1277         if (errno != 0 || result == 0.0
1278 #ifdef HAVE_FINITE
1279                 || !finite(result)
1280 #endif
1281                 )
1282                 ereport(ERROR,
1283                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1284                                  errmsg("result is out of range")));
1285
1286         CheckFloat8Val(result);
1287         PG_RETURN_FLOAT8(result);
1288 }
1289
1290
1291 /*
1292  *              dlog1                   - returns the natural logarithm of arg1
1293  *                                                ("dlog" is already a logging routine...)
1294  */
1295 Datum
1296 dlog1(PG_FUNCTION_ARGS)
1297 {
1298         float8          arg1 = PG_GETARG_FLOAT8(0);
1299         float8          result;
1300
1301         if (arg1 == 0.0)
1302                 ereport(ERROR,
1303                                 (errcode(ERRCODE_FLOATING_POINT_EXCEPTION),
1304                                  errmsg("cannot take log of zero")));
1305
1306         if (arg1 < 0)
1307                 ereport(ERROR,
1308                                 (errcode(ERRCODE_FLOATING_POINT_EXCEPTION),
1309                                  errmsg("cannot take log of a negative number")));
1310
1311         result = log(arg1);
1312
1313         CheckFloat8Val(result);
1314         PG_RETURN_FLOAT8(result);
1315 }
1316
1317
1318 /*
1319  *              dlog10                  - returns the base 10 logarithm of arg1
1320  */
1321 Datum
1322 dlog10(PG_FUNCTION_ARGS)
1323 {
1324         float8          arg1 = PG_GETARG_FLOAT8(0);
1325         float8          result;
1326
1327         if (arg1 == 0.0)
1328                 ereport(ERROR,
1329                                 (errcode(ERRCODE_FLOATING_POINT_EXCEPTION),
1330                                  errmsg("cannot take log of zero")));
1331
1332         if (arg1 < 0)
1333                 ereport(ERROR,
1334                                 (errcode(ERRCODE_FLOATING_POINT_EXCEPTION),
1335                                  errmsg("cannot take log of a negative number")));
1336
1337         result = log10(arg1);
1338
1339         CheckFloat8Val(result);
1340         PG_RETURN_FLOAT8(result);
1341 }
1342
1343
1344 /*
1345  *              dacos                   - returns the arccos of arg1 (radians)
1346  */
1347 Datum
1348 dacos(PG_FUNCTION_ARGS)
1349 {
1350         float8          arg1 = PG_GETARG_FLOAT8(0);
1351         float8          result;
1352
1353         errno = 0;
1354         result = acos(arg1);
1355         if (errno != 0
1356 #ifdef HAVE_FINITE
1357                 || !finite(result)
1358 #endif
1359                 )
1360                 ereport(ERROR,
1361                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1362                                  errmsg("input is out of range")));
1363
1364         CheckFloat8Val(result);
1365         PG_RETURN_FLOAT8(result);
1366 }
1367
1368
1369 /*
1370  *              dasin                   - returns the arcsin of arg1 (radians)
1371  */
1372 Datum
1373 dasin(PG_FUNCTION_ARGS)
1374 {
1375         float8          arg1 = PG_GETARG_FLOAT8(0);
1376         float8          result;
1377
1378         errno = 0;
1379         result = asin(arg1);
1380         if (errno != 0
1381 #ifdef HAVE_FINITE
1382                 || !finite(result)
1383 #endif
1384                 )
1385                 ereport(ERROR,
1386                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1387                                  errmsg("input is out of range")));
1388
1389         CheckFloat8Val(result);
1390         PG_RETURN_FLOAT8(result);
1391 }
1392
1393
1394 /*
1395  *              datan                   - returns the arctan of arg1 (radians)
1396  */
1397 Datum
1398 datan(PG_FUNCTION_ARGS)
1399 {
1400         float8          arg1 = PG_GETARG_FLOAT8(0);
1401         float8          result;
1402
1403         errno = 0;
1404         result = atan(arg1);
1405         if (errno != 0
1406 #ifdef HAVE_FINITE
1407                 || !finite(result)
1408 #endif
1409                 )
1410                 ereport(ERROR,
1411                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1412                                  errmsg("input is out of range")));
1413
1414         CheckFloat8Val(result);
1415         PG_RETURN_FLOAT8(result);
1416 }
1417
1418
1419 /*
1420  *              atan2                   - returns the arctan2 of arg1 (radians)
1421  */
1422 Datum
1423 datan2(PG_FUNCTION_ARGS)
1424 {
1425         float8          arg1 = PG_GETARG_FLOAT8(0);
1426         float8          arg2 = PG_GETARG_FLOAT8(1);
1427         float8          result;
1428
1429         errno = 0;
1430         result = atan2(arg1, arg2);
1431         if (errno != 0
1432 #ifdef HAVE_FINITE
1433                 || !finite(result)
1434 #endif
1435                 )
1436                 ereport(ERROR,
1437                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1438                                  errmsg("input is out of range")));
1439
1440         CheckFloat8Val(result);
1441         PG_RETURN_FLOAT8(result);
1442 }
1443
1444
1445 /*
1446  *              dcos                    - returns the cosine of arg1 (radians)
1447  */
1448 Datum
1449 dcos(PG_FUNCTION_ARGS)
1450 {
1451         float8          arg1 = PG_GETARG_FLOAT8(0);
1452         float8          result;
1453
1454         errno = 0;
1455         result = cos(arg1);
1456         if (errno != 0
1457 #ifdef HAVE_FINITE
1458                 || !finite(result)
1459 #endif
1460                 )
1461                 ereport(ERROR,
1462                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1463                                  errmsg("input is out of range")));
1464
1465         CheckFloat8Val(result);
1466         PG_RETURN_FLOAT8(result);
1467 }
1468
1469
1470 /*
1471  *              dcot                    - returns the cotangent of arg1 (radians)
1472  */
1473 Datum
1474 dcot(PG_FUNCTION_ARGS)
1475 {
1476         float8          arg1 = PG_GETARG_FLOAT8(0);
1477         float8          result;
1478
1479         errno = 0;
1480         result = tan(arg1);
1481         if (errno != 0 || result == 0.0
1482 #ifdef HAVE_FINITE
1483                 || !finite(result)
1484 #endif
1485                 )
1486                 ereport(ERROR,
1487                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1488                                  errmsg("input is out of range")));
1489
1490         result = 1.0 / result;
1491         CheckFloat8Val(result);
1492         PG_RETURN_FLOAT8(result);
1493 }
1494
1495
1496 /*
1497  *              dsin                    - returns the sine of arg1 (radians)
1498  */
1499 Datum
1500 dsin(PG_FUNCTION_ARGS)
1501 {
1502         float8          arg1 = PG_GETARG_FLOAT8(0);
1503         float8          result;
1504
1505         errno = 0;
1506         result = sin(arg1);
1507         if (errno != 0
1508 #ifdef HAVE_FINITE
1509                 || !finite(result)
1510 #endif
1511                 )
1512                 ereport(ERROR,
1513                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1514                                  errmsg("input is out of range")));
1515
1516         CheckFloat8Val(result);
1517         PG_RETURN_FLOAT8(result);
1518 }
1519
1520
1521 /*
1522  *              dtan                    - returns the tangent of arg1 (radians)
1523  */
1524 Datum
1525 dtan(PG_FUNCTION_ARGS)
1526 {
1527         float8          arg1 = PG_GETARG_FLOAT8(0);
1528         float8          result;
1529
1530         errno = 0;
1531         result = tan(arg1);
1532         if (errno != 0
1533 #ifdef HAVE_FINITE
1534                 || !finite(result)
1535 #endif
1536                 )
1537                 ereport(ERROR,
1538                                 (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1539                                  errmsg("input is out of range")));
1540
1541         CheckFloat8Val(result);
1542         PG_RETURN_FLOAT8(result);
1543 }
1544
1545
1546 /*
1547  *              degrees         - returns degrees converted from radians
1548  */
1549 Datum
1550 degrees(PG_FUNCTION_ARGS)
1551 {
1552         float8          arg1 = PG_GETARG_FLOAT8(0);
1553         float8          result;
1554
1555         result = arg1 * (180.0 / M_PI);
1556
1557         CheckFloat8Val(result);
1558         PG_RETURN_FLOAT8(result);
1559 }
1560
1561
1562 /*
1563  *              dpi                             - returns the constant PI
1564  */
1565 Datum
1566 dpi(PG_FUNCTION_ARGS)
1567 {
1568         PG_RETURN_FLOAT8(M_PI);
1569 }
1570
1571
1572 /*
1573  *              radians         - returns radians converted from degrees
1574  */
1575 Datum
1576 radians(PG_FUNCTION_ARGS)
1577 {
1578         float8          arg1 = PG_GETARG_FLOAT8(0);
1579         float8          result;
1580
1581         result = arg1 * (M_PI / 180.0);
1582
1583         CheckFloat8Val(result);
1584         PG_RETURN_FLOAT8(result);
1585 }
1586
1587
1588 /*
1589  *              drandom         - returns a random number
1590  */
1591 Datum
1592 drandom(PG_FUNCTION_ARGS)
1593 {
1594         float8          result;
1595
1596         /* result 0.0-1.0 */
1597         result = ((double) random()) / ((double) MAX_RANDOM_VALUE);
1598
1599         PG_RETURN_FLOAT8(result);
1600 }
1601
1602
1603 /*
1604  *              setseed         - set seed for the random number generator
1605  */
1606 Datum
1607 setseed(PG_FUNCTION_ARGS)
1608 {
1609         float8          seed = PG_GETARG_FLOAT8(0);
1610         int                     iseed = (int) (seed * MAX_RANDOM_VALUE);
1611
1612         srandom((unsigned int) iseed);
1613
1614         PG_RETURN_INT32(iseed);
1615 }
1616
1617
1618
1619 /*
1620  *              =========================
1621  *              FLOAT AGGREGATE OPERATORS
1622  *              =========================
1623  *
1624  *              float8_accum    - accumulate for AVG(), STDDEV(), etc
1625  *              float4_accum    - same, but input data is float4
1626  *              float8_avg              - produce final result for float AVG()
1627  *              float8_variance - produce final result for float VARIANCE()
1628  *              float8_stddev   - produce final result for float STDDEV()
1629  *
1630  * The transition datatype for all these aggregates is a 3-element array
1631  * of float8, holding the values N, sum(X), sum(X*X) in that order.
1632  *
1633  * Note that we represent N as a float to avoid having to build a special
1634  * datatype.  Given a reasonable floating-point implementation, there should
1635  * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
1636  * user will have doubtless lost interest anyway...)
1637  */
1638
1639 static float8 *
1640 check_float8_array(ArrayType *transarray, const char *caller)
1641 {
1642         /*
1643          * We expect the input to be a 3-element float array; verify that. We
1644          * don't need to use deconstruct_array() since the array data is just
1645          * going to look like a C array of 3 float8 values.
1646          */
1647         if (ARR_NDIM(transarray) != 1 ||
1648                 ARR_DIMS(transarray)[0] != 3 ||
1649                 ARR_ELEMTYPE(transarray) != FLOAT8OID)
1650                 elog(ERROR, "%s: expected 3-element float8 array", caller);
1651         return (float8 *) ARR_DATA_PTR(transarray);
1652 }
1653
1654 Datum
1655 float8_accum(PG_FUNCTION_ARGS)
1656 {
1657         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1658         float8          newval = PG_GETARG_FLOAT8(1);
1659         float8     *transvalues;
1660         float8          N,
1661                                 sumX,
1662                                 sumX2;
1663         Datum           transdatums[3];
1664         ArrayType  *result;
1665
1666         transvalues = check_float8_array(transarray, "float8_accum");
1667         N = transvalues[0];
1668         sumX = transvalues[1];
1669         sumX2 = transvalues[2];
1670
1671         N += 1.0;
1672         sumX += newval;
1673         sumX2 += newval * newval;
1674
1675         transdatums[0] = Float8GetDatumFast(N);
1676         transdatums[1] = Float8GetDatumFast(sumX);
1677         transdatums[2] = Float8GetDatumFast(sumX2);
1678
1679         result = construct_array(transdatums, 3,
1680                                                          FLOAT8OID,
1681                                                  sizeof(float8), false /* float8 byval */ , 'd');
1682
1683         PG_RETURN_ARRAYTYPE_P(result);
1684 }
1685
1686 Datum
1687 float4_accum(PG_FUNCTION_ARGS)
1688 {
1689         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1690         float4          newval4 = PG_GETARG_FLOAT4(1);
1691         float8     *transvalues;
1692         float8          N,
1693                                 sumX,
1694                                 sumX2,
1695                                 newval;
1696         Datum           transdatums[3];
1697         ArrayType  *result;
1698
1699         transvalues = check_float8_array(transarray, "float4_accum");
1700         N = transvalues[0];
1701         sumX = transvalues[1];
1702         sumX2 = transvalues[2];
1703
1704         /* Do arithmetic in float8 for best accuracy */
1705         newval = newval4;
1706
1707         N += 1.0;
1708         sumX += newval;
1709         sumX2 += newval * newval;
1710
1711         transdatums[0] = Float8GetDatumFast(N);
1712         transdatums[1] = Float8GetDatumFast(sumX);
1713         transdatums[2] = Float8GetDatumFast(sumX2);
1714
1715         result = construct_array(transdatums, 3,
1716                                                          FLOAT8OID,
1717                                                  sizeof(float8), false /* float8 byval */ , 'd');
1718
1719         PG_RETURN_ARRAYTYPE_P(result);
1720 }
1721
1722 Datum
1723 float8_avg(PG_FUNCTION_ARGS)
1724 {
1725         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1726         float8     *transvalues;
1727         float8          N,
1728                                 sumX;
1729
1730         transvalues = check_float8_array(transarray, "float8_avg");
1731         N = transvalues[0];
1732         sumX = transvalues[1];
1733         /* ignore sumX2 */
1734
1735         /* SQL92 defines AVG of no values to be NULL */
1736         if (N == 0.0)
1737                 PG_RETURN_NULL();
1738
1739         PG_RETURN_FLOAT8(sumX / N);
1740 }
1741
1742 Datum
1743 float8_variance(PG_FUNCTION_ARGS)
1744 {
1745         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1746         float8     *transvalues;
1747         float8          N,
1748                                 sumX,
1749                                 sumX2,
1750                                 numerator;
1751
1752         transvalues = check_float8_array(transarray, "float8_variance");
1753         N = transvalues[0];
1754         sumX = transvalues[1];
1755         sumX2 = transvalues[2];
1756
1757         /* Sample variance is undefined when N is 0 or 1, so return NULL */
1758         if (N <= 1.0)
1759                 PG_RETURN_NULL();
1760
1761         numerator = N * sumX2 - sumX * sumX;
1762
1763         /* Watch out for roundoff error producing a negative numerator */
1764         if (numerator <= 0.0)
1765                 PG_RETURN_FLOAT8(0.0);
1766
1767         PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
1768 }
1769
1770 Datum
1771 float8_stddev(PG_FUNCTION_ARGS)
1772 {
1773         ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
1774         float8     *transvalues;
1775         float8          N,
1776                                 sumX,
1777                                 sumX2,
1778                                 numerator;
1779
1780         transvalues = check_float8_array(transarray, "float8_stddev");
1781         N = transvalues[0];
1782         sumX = transvalues[1];
1783         sumX2 = transvalues[2];
1784
1785         /* Sample stddev is undefined when N is 0 or 1, so return NULL */
1786         if (N <= 1.0)
1787                 PG_RETURN_NULL();
1788
1789         numerator = N * sumX2 - sumX * sumX;
1790
1791         /* Watch out for roundoff error producing a negative numerator */
1792         if (numerator <= 0.0)
1793                 PG_RETURN_FLOAT8(0.0);
1794
1795         PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
1796 }
1797
1798
1799 /*
1800  *              ====================================
1801  *              MIXED-PRECISION ARITHMETIC OPERATORS
1802  *              ====================================
1803  */
1804
1805 /*
1806  *              float48pl               - returns arg1 + arg2
1807  *              float48mi               - returns arg1 - arg2
1808  *              float48mul              - returns arg1 * arg2
1809  *              float48div              - returns arg1 / arg2
1810  */
1811 Datum
1812 float48pl(PG_FUNCTION_ARGS)
1813 {
1814         float4          arg1 = PG_GETARG_FLOAT4(0);
1815         float8          arg2 = PG_GETARG_FLOAT8(1);
1816         float8          result;
1817
1818         result = arg1 + arg2;
1819         CheckFloat8Val(result);
1820         PG_RETURN_FLOAT8(result);
1821 }
1822
1823 Datum
1824 float48mi(PG_FUNCTION_ARGS)
1825 {
1826         float4          arg1 = PG_GETARG_FLOAT4(0);
1827         float8          arg2 = PG_GETARG_FLOAT8(1);
1828         float8          result;
1829
1830         result = arg1 - arg2;
1831         CheckFloat8Val(result);
1832         PG_RETURN_FLOAT8(result);
1833 }
1834
1835 Datum
1836 float48mul(PG_FUNCTION_ARGS)
1837 {
1838         float4          arg1 = PG_GETARG_FLOAT4(0);
1839         float8          arg2 = PG_GETARG_FLOAT8(1);
1840         float8          result;
1841
1842         result = arg1 * arg2;
1843         CheckFloat8Val(result);
1844         PG_RETURN_FLOAT8(result);
1845 }
1846
1847 Datum
1848 float48div(PG_FUNCTION_ARGS)
1849 {
1850         float4          arg1 = PG_GETARG_FLOAT4(0);
1851         float8          arg2 = PG_GETARG_FLOAT8(1);
1852         float8          result;
1853
1854         if (arg2 == 0.0)
1855                 ereport(ERROR,
1856                                 (errcode(ERRCODE_DIVISION_BY_ZERO),
1857                                  errmsg("division by zero")));
1858
1859         result = arg1 / arg2;
1860         CheckFloat8Val(result);
1861         PG_RETURN_FLOAT8(result);
1862 }
1863
1864 /*
1865  *              float84pl               - returns arg1 + arg2
1866  *              float84mi               - returns arg1 - arg2
1867  *              float84mul              - returns arg1 * arg2
1868  *              float84div              - returns arg1 / arg2
1869  */
1870 Datum
1871 float84pl(PG_FUNCTION_ARGS)
1872 {
1873         float8          arg1 = PG_GETARG_FLOAT8(0);
1874         float4          arg2 = PG_GETARG_FLOAT4(1);
1875         float8          result;
1876
1877         result = arg1 + arg2;
1878
1879         CheckFloat8Val(result);
1880         PG_RETURN_FLOAT8(result);
1881 }
1882
1883 Datum
1884 float84mi(PG_FUNCTION_ARGS)
1885 {
1886         float8          arg1 = PG_GETARG_FLOAT8(0);
1887         float4          arg2 = PG_GETARG_FLOAT4(1);
1888         float8          result;
1889
1890         result = arg1 - arg2;
1891
1892         CheckFloat8Val(result);
1893         PG_RETURN_FLOAT8(result);
1894 }
1895
1896 Datum
1897 float84mul(PG_FUNCTION_ARGS)
1898 {
1899         float8          arg1 = PG_GETARG_FLOAT8(0);
1900         float4          arg2 = PG_GETARG_FLOAT4(1);
1901         float8          result;
1902
1903         result = arg1 * arg2;
1904
1905         CheckFloat8Val(result);
1906         PG_RETURN_FLOAT8(result);
1907 }
1908
1909 Datum
1910 float84div(PG_FUNCTION_ARGS)
1911 {
1912         float8          arg1 = PG_GETARG_FLOAT8(0);
1913         float4          arg2 = PG_GETARG_FLOAT4(1);
1914         float8          result;
1915
1916         if (arg2 == 0.0)
1917                 ereport(ERROR,
1918                                 (errcode(ERRCODE_DIVISION_BY_ZERO),
1919                                  errmsg("division by zero")));
1920
1921         result = arg1 / arg2;
1922
1923         CheckFloat8Val(result);
1924         PG_RETURN_FLOAT8(result);
1925 }
1926
1927 /*
1928  *              ====================
1929  *              COMPARISON OPERATORS
1930  *              ====================
1931  */
1932
1933 /*
1934  *              float48{eq,ne,lt,le,gt,ge}              - float4/float8 comparison operations
1935  */
1936 Datum
1937 float48eq(PG_FUNCTION_ARGS)
1938 {
1939         float4          arg1 = PG_GETARG_FLOAT4(0);
1940         float8          arg2 = PG_GETARG_FLOAT8(1);
1941
1942         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
1943 }
1944
1945 Datum
1946 float48ne(PG_FUNCTION_ARGS)
1947 {
1948         float4          arg1 = PG_GETARG_FLOAT4(0);
1949         float8          arg2 = PG_GETARG_FLOAT8(1);
1950
1951         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
1952 }
1953
1954 Datum
1955 float48lt(PG_FUNCTION_ARGS)
1956 {
1957         float4          arg1 = PG_GETARG_FLOAT4(0);
1958         float8          arg2 = PG_GETARG_FLOAT8(1);
1959
1960         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
1961 }
1962
1963 Datum
1964 float48le(PG_FUNCTION_ARGS)
1965 {
1966         float4          arg1 = PG_GETARG_FLOAT4(0);
1967         float8          arg2 = PG_GETARG_FLOAT8(1);
1968
1969         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1970 }
1971
1972 Datum
1973 float48gt(PG_FUNCTION_ARGS)
1974 {
1975         float4          arg1 = PG_GETARG_FLOAT4(0);
1976         float8          arg2 = PG_GETARG_FLOAT8(1);
1977
1978         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1979 }
1980
1981 Datum
1982 float48ge(PG_FUNCTION_ARGS)
1983 {
1984         float4          arg1 = PG_GETARG_FLOAT4(0);
1985         float8          arg2 = PG_GETARG_FLOAT8(1);
1986
1987         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1988 }
1989
1990 /*
1991  *              float84{eq,ne,lt,le,gt,ge}              - float8/float4 comparison operations
1992  */
1993 Datum
1994 float84eq(PG_FUNCTION_ARGS)
1995 {
1996         float8          arg1 = PG_GETARG_FLOAT8(0);
1997         float4          arg2 = PG_GETARG_FLOAT4(1);
1998
1999         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
2000 }
2001
2002 Datum
2003 float84ne(PG_FUNCTION_ARGS)
2004 {
2005         float8          arg1 = PG_GETARG_FLOAT8(0);
2006         float4          arg2 = PG_GETARG_FLOAT4(1);
2007
2008         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
2009 }
2010
2011 Datum
2012 float84lt(PG_FUNCTION_ARGS)
2013 {
2014         float8          arg1 = PG_GETARG_FLOAT8(0);
2015         float4          arg2 = PG_GETARG_FLOAT4(1);
2016
2017         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
2018 }
2019
2020 Datum
2021 float84le(PG_FUNCTION_ARGS)
2022 {
2023         float8          arg1 = PG_GETARG_FLOAT8(0);
2024         float4          arg2 = PG_GETARG_FLOAT4(1);
2025
2026         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
2027 }
2028
2029 Datum
2030 float84gt(PG_FUNCTION_ARGS)
2031 {
2032         float8          arg1 = PG_GETARG_FLOAT8(0);
2033         float4          arg2 = PG_GETARG_FLOAT4(1);
2034
2035         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
2036 }
2037
2038 Datum
2039 float84ge(PG_FUNCTION_ARGS)
2040 {
2041         float8          arg1 = PG_GETARG_FLOAT8(0);
2042         float4          arg2 = PG_GETARG_FLOAT4(1);
2043
2044         PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
2045 }
2046
2047 /* ========== PRIVATE ROUTINES ========== */
2048
2049 #ifndef HAVE_CBRT
2050 static double
2051 cbrt(double x)
2052 {
2053         int                     isneg = (x < 0.0);
2054         double          tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
2055
2056         return isneg ? -tmpres : tmpres;
2057 }
2058
2059 #endif   /* !HAVE_CBRT */