~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/float.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

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