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