float.c 36.9 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * float.c
4
 *	  Functions for the built-in floating-point types.
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
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.78 2001/12/11 02:02:12 tgl Exp $
12 13 14
 *
 *-------------------------------------------------------------------------
 */
15
/*----------
16
 * OLD COMMENTS
17
 *		Basic float4 ops:
18
 *		 float4in, float4out, float4abs, float4um, float4up
19
 *		Basic float8 ops:
20
 *		 float8in, float8out, float8abs, float8um, float8up
21 22 23 24
 *		Arithmetic operators:
 *		 float4pl, float4mi, float4mul, float4div
 *		 float8pl, float8mi, float8mul, float8div
 *		Comparison operators:
25 26
 *		 float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
 *		 float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
27 28
 *		Conversion routines:
 *		 ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
29
 *
30 31 32 33 34 35 36 37
 *		Random float8 ops:
 *		 dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
 *		Arithmetic operators:
 *		 float48pl, float48mi, float48mul, float48div
 *		 float84pl, float84mi, float84mul, float84div
 *		Comparison operators:
 *		 float48eq, float48ne, float48lt, float48le, float48gt, float48ge
 *		 float84eq, float84ne, float84lt, float84le, float84gt, float84ge
38
 *
39
 *		(You can do the arithmetic and comparison stuff using conversion
40 41
 *		 routines, but then you pay the overhead of invoking a separate
 *		 conversion function...)
42 43
 *
 * XXX GLUESOME STUFF. FIX IT! -AY '94
44
 *
45 46 47 48
 *		Added some additional conversion routines and cleaned up
 *		 a bit of the existing code. Need to change the error checking
 *		 for calls to pow(), exp() since on some machines (my Linux box
 *		 included) these routines do not set errno. - tgl 97/05/10
49
 *----------
50
 */
51 52
#include "postgres.h"

53 54
#include <ctype.h>
#include <errno.h>
55
#include <float.h>				/* faked on sunos4 */
56 57
#include <math.h>

58
#include <limits.h>
59 60
/* for finite() on Solaris */
#ifdef HAVE_IEEEFP_H
61
#include <ieeefp.h>
62 63
#endif

64
#include "fmgr.h"
65
#include "utils/array.h"
Bruce Momjian's avatar
Bruce Momjian committed
66
#include "utils/builtins.h"
67 68 69


#if !(NeXT && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_2)
70
 /* NS3.3 has conflicting declarations of these in <math.h> */
71 72

#ifndef atof
73
extern double atof(const char *p);
74 75
#endif

76
#ifndef HAVE_CBRT
77
#define cbrt my_cbrt
78
static double cbrt(double x);
79 80 81

#else
#if !defined(nextstep)
82
extern double cbrt(double x);
83
#endif
84
#endif   /* HAVE_CBRT */
85 86

#ifndef HAVE_RINT
87
#define rint my_rint
88
static double rint(double x);
89 90

#else
91
extern double rint(double x);
92 93
#endif   /* HAVE_RINT */
#endif   /* NeXT check */
94

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

static void CheckFloat4Val(double val);
static void CheckFloat8Val(double val);

#ifndef M_PI
/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
#define M_PI 3.14159265358979323846
#endif

#ifndef NAN
#define NAN		(0.0/0.0)
#endif

#ifndef SHRT_MAX
#define SHRT_MAX 32767
#endif
#ifndef SHRT_MIN
#define SHRT_MIN (-32768)
#endif

#define FORMAT			'g'		/* use "g" output format as standard
								 * format */
/* not sure what the following should be, but better to make it over-sufficient */
#define MAXFLOATWIDTH	64
#define MAXDOUBLEWIDTH	128

121
/* ========== USER I/O ROUTINES ========== */
122 123 124 125 126 127 128


#define FLOAT4_MAX		 FLT_MAX
#define FLOAT4_MIN		 FLT_MIN
#define FLOAT8_MAX		 DBL_MAX
#define FLOAT8_MIN		 DBL_MIN

129

130 131 132
/*
   check to see if a float4 val is outside of
   the FLOAT4_MIN, FLOAT4_MAX bounds.
133

134 135
   raise an elog warning if it is
*/
136 137
static void
CheckFloat4Val(double val)
138
{
139 140 141 142
	/*
	 * defining unsafe floats's will make float4 and float8 ops faster at
	 * the cost of safety, of course!
	 */
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 156
}

/*
   check to see if a float8 val is outside of
   the FLOAT8_MIN, FLOAT8_MAX bounds.
157

158 159
   raise an elog warning if it is
*/
160
static void
161
CheckFloat8Val(double val)
162
{
163 164 165 166
	/*
	 * defining unsafe floats's will make float4 and float8 ops faster at
	 * the cost of safety, of course!
	 */
167
#ifdef UNSAFE_FLOATS
168
	return;
169
#else
170
	if (fabs(val) > FLOAT8_MAX)
171
		elog(ERROR, "Bad float8 input format -- overflow");
172
	if (val != 0.0 && fabs(val) < FLOAT8_MIN)
173
		elog(ERROR, "Bad float8 input format -- underflow");
174
	return;
175
#endif   /* UNSAFE_FLOATS */
176 177 178
}

/*
179 180 181 182 183
 *		float4in		- converts "num" to float
 *						  restricted syntax:
 *						  {<sp>} [+|-] {digit} [.{digit}] [<exp>]
 *						  where <sp> is a space, digit is 0-9,
 *						  <exp> is "e" or "E" followed by an integer.
184
 */
185 186
Datum
float4in(PG_FUNCTION_ARGS)
187
{
188
	char	   *num = PG_GETARG_CSTRING(0);
189 190
	double		val;
	char	   *endptr;
191 192 193

	errno = 0;
	val = strtod(num, &endptr);
194 195
	if (*endptr != '\0')
	{
196 197 198 199 200 201 202 203 204
		/*
		 * XXX we should accept "Infinity" and "-Infinity" too, but what
		 * are the correct values to assign?  HUGE_VAL will provoke an
		 * error from CheckFloat4Val.
		 */
		if (strcasecmp(num, "NaN") == 0)
			val = NAN;
		else
			elog(ERROR, "Bad float4 input format '%s'", num);
205 206 207 208 209 210
	}
	else
	{
		if (errno == ERANGE)
			elog(ERROR, "Input '%s' is out of range for float4", num);
	}
211 212 213 214 215 216 217

	/*
	 * if we get here, we have a legal double, still need to check to see
	 * if it's a legal float
	 */
	CheckFloat4Val(val);

218
	PG_RETURN_FLOAT4((float4) val);
219 220 221
}

/*
222 223
 *		float4out		- converts a float4 number to a string
 *						  using a standard output format
224
 */
225 226
Datum
float4out(PG_FUNCTION_ARGS)
227
{
228
	float4		num = PG_GETARG_FLOAT4(0);
229
	char	   *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
230
	int			infflag;
231

232 233
	if (isnan(num))
		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
234 235
	infflag = isinf(num);
	if (infflag > 0)
236
		PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
237 238
	if (infflag < 0)
		PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
239

240 241
	sprintf(ascii, "%.*g", FLT_DIG, num);
	PG_RETURN_CSTRING(ascii);
242 243 244
}

/*
245 246 247 248 249
 *		float8in		- converts "num" to float8
 *						  restricted syntax:
 *						  {<sp>} [+|-] {digit} [.{digit}] [<exp>]
 *						  where <sp> is a space, digit is 0-9,
 *						  <exp> is "e" or "E" followed by an integer.
250
 */
251 252
Datum
float8in(PG_FUNCTION_ARGS)
253
{
254
	char	   *num = PG_GETARG_CSTRING(0);
255 256
	double		val;
	char	   *endptr;
257 258 259

	errno = 0;
	val = strtod(num, &endptr);
260 261 262 263 264 265
	if (*endptr != '\0')
	{
		if (strcasecmp(num, "NaN") == 0)
			val = NAN;
		else if (strcasecmp(num, "Infinity") == 0)
			val = HUGE_VAL;
266 267
		else if (strcasecmp(num, "-Infinity") == 0)
			val = -HUGE_VAL;
268 269 270
		else
			elog(ERROR, "Bad float8 input format '%s'", num);
	}
271 272 273 274 275
	else
	{
		if (errno == ERANGE)
			elog(ERROR, "Input '%s' is out of range for float8", num);
	}
276 277

	CheckFloat8Val(val);
278

279
	PG_RETURN_FLOAT8(val);
280 281 282 283
}


/*
284 285
 *		float8out		- converts float8 number to a string
 *						  using a standard output format
286
 */
287 288
Datum
float8out(PG_FUNCTION_ARGS)
289
{
290
	float8		num = PG_GETARG_FLOAT8(0);
291
	char	   *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
292
	int			infflag;
293

294 295
	if (isnan(num))
		PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
296 297
	infflag = isinf(num);
	if (infflag > 0)
298
		PG_RETURN_CSTRING(strcpy(ascii, "Infinity"));
299 300
	if (infflag < 0)
		PG_RETURN_CSTRING(strcpy(ascii, "-Infinity"));
301

302 303
	sprintf(ascii, "%.*g", DBL_DIG, num);
	PG_RETURN_CSTRING(ascii);
304 305 306 307 308 309
}

/* ========== PUBLIC ROUTINES ========== */


/*
310 311 312
 *		======================
 *		FLOAT4 BASE OPERATIONS
 *		======================
313 314 315
 */

/*
316
 *		float4abs		- returns |arg1| (absolute value)
317
 */
318 319
Datum
float4abs(PG_FUNCTION_ARGS)
320
{
321
	float4		arg1 = PG_GETARG_FLOAT4(0);
322

323
	PG_RETURN_FLOAT4((float4) fabs(arg1));
324 325 326
}

/*
327
 *		float4um		- returns -arg1 (unary minus)
328
 */
329 330
Datum
float4um(PG_FUNCTION_ARGS)
331
{
332
	float4		arg1 = PG_GETARG_FLOAT4(0);
333

334
	PG_RETURN_FLOAT4((float4) -arg1);
335 336
}

337 338 339 340
Datum
float4up(PG_FUNCTION_ARGS)
{
	float4		arg = PG_GETARG_FLOAT4(0);
341

342 343 344
	PG_RETURN_FLOAT4(arg);
}

345 346
Datum
float4larger(PG_FUNCTION_ARGS)
347
{
348 349 350
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	float4		result;
351

352 353
	result = ((arg1 > arg2) ? arg1 : arg2);
	PG_RETURN_FLOAT4(result);
354 355
}

356 357
Datum
float4smaller(PG_FUNCTION_ARGS)
358
{
359 360 361
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	float4		result;
362

363 364
	result = ((arg1 < arg2) ? arg1 : arg2);
	PG_RETURN_FLOAT4(result);
365 366 367
}

/*
368 369 370
 *		======================
 *		FLOAT8 BASE OPERATIONS
 *		======================
371 372 373
 */

/*
374
 *		float8abs		- returns |arg1| (absolute value)
375
 */
376 377
Datum
float8abs(PG_FUNCTION_ARGS)
378
{
379 380
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
381

382
	result = fabs(arg1);
383

384 385
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
386 387 388 389
}


/*
390
 *		float8um		- returns -arg1 (unary minus)
391
 */
392 393
Datum
float8um(PG_FUNCTION_ARGS)
394
{
395 396
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
397

398
	result = ((arg1 != 0) ? -(arg1) : arg1);
399

400 401
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
402 403
}

404 405 406 407
Datum
float8up(PG_FUNCTION_ARGS)
{
	float8		arg = PG_GETARG_FLOAT8(0);
408

409 410 411
	PG_RETURN_FLOAT8(arg);
}

412 413
Datum
float8larger(PG_FUNCTION_ARGS)
414
{
415 416 417
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
418

419
	result = ((arg1 > arg2) ? arg1 : arg2);
420

421
	PG_RETURN_FLOAT8(result);
422 423
}

424 425
Datum
float8smaller(PG_FUNCTION_ARGS)
426
{
427 428 429
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
430

431
	result = ((arg1 < arg2) ? arg1 : arg2);
432

433
	PG_RETURN_FLOAT8(result);
434 435 436 437
}


/*
438 439 440
 *		====================
 *		ARITHMETIC OPERATORS
 *		====================
441 442 443
 */

/*
444 445 446 447
 *		float4pl		- returns arg1 + arg2
 *		float4mi		- returns arg1 - arg2
 *		float4mul		- returns arg1 * arg2
 *		float4div		- returns arg1 / arg2
448
 */
449 450
Datum
float4pl(PG_FUNCTION_ARGS)
451
{
452 453 454
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	double		result;
455

456 457 458
	result = arg1 + arg2;
	CheckFloat4Val(result);
	PG_RETURN_FLOAT4((float4) result);
459 460
}

461 462
Datum
float4mi(PG_FUNCTION_ARGS)
463
{
464 465 466
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	double		result;
467

468 469 470
	result = arg1 - arg2;
	CheckFloat4Val(result);
	PG_RETURN_FLOAT4((float4) result);
471 472
}

473 474
Datum
float4mul(PG_FUNCTION_ARGS)
475
{
476 477 478
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	double		result;
479

480 481 482
	result = arg1 * arg2;
	CheckFloat4Val(result);
	PG_RETURN_FLOAT4((float4) result);
483 484
}

485 486
Datum
float4div(PG_FUNCTION_ARGS)
487
{
488 489 490
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	double		result;
491

492
	if (arg2 == 0.0)
493
		elog(ERROR, "float4div: divide by zero error");
494

495 496
	/* Do division in float8, then check for overflow */
	result = (float8) arg1 / (float8) arg2;
497

498 499
	CheckFloat4Val(result);
	PG_RETURN_FLOAT4((float4) result);
500 501 502
}

/*
503 504 505 506
 *		float8pl		- returns arg1 + arg2
 *		float8mi		- returns arg1 - arg2
 *		float8mul		- returns arg1 * arg2
 *		float8div		- returns arg1 / arg2
507
 */
508 509
Datum
float8pl(PG_FUNCTION_ARGS)
510
{
511 512 513
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
514

515
	result = arg1 + arg2;
516

517 518
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
519 520
}

521 522
Datum
float8mi(PG_FUNCTION_ARGS)
523
{
524 525 526
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
527

528
	result = arg1 - arg2;
529

530 531
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
532 533
}

534 535
Datum
float8mul(PG_FUNCTION_ARGS)
536
{
537 538 539
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
540

541
	result = arg1 * arg2;
542

543 544
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
545 546
}

547 548
Datum
float8div(PG_FUNCTION_ARGS)
549
{
550 551 552
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
553

554
	if (arg2 == 0.0)
555
		elog(ERROR, "float8div: divide by zero error");
556

557 558 559 560
	result = arg1 / arg2;

	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
561 562
}

563 564

/*
565 566 567
 *		====================
 *		COMPARISON OPERATORS
 *		====================
568 569 570
 */

/*
571
 *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
572
 */
573 574 575 576
static int
float4_cmp_internal(float4 a, float4 b)
{
	/*
577 578 579
	 * We consider all NANs to be equal and larger than any non-NAN. This
	 * is somewhat arbitrary; the important thing is to have a consistent
	 * sort order.
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
	 */
	if (isnan(a))
	{
		if (isnan(b))
			return 0;			/* NAN = NAN */
		else
			return 1;			/* NAN > non-NAN */
	}
	else if (isnan(b))
	{
		return -1;				/* non-NAN < NAN */
	}
	else
	{
		if (a > b)
			return 1;
596
		else if (a < b)
597
			return -1;
598 599
		else
			return 0;
600 601 602
	}
}

603 604
Datum
float4eq(PG_FUNCTION_ARGS)
605
{
606 607
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
608

609
	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
610 611
}

612 613
Datum
float4ne(PG_FUNCTION_ARGS)
614
{
615 616
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
617

618
	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
619 620
}

621 622
Datum
float4lt(PG_FUNCTION_ARGS)
623
{
624 625
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
626

627
	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
628 629
}

630 631
Datum
float4le(PG_FUNCTION_ARGS)
632
{
633 634
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
635

636
	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
637 638
}

639 640
Datum
float4gt(PG_FUNCTION_ARGS)
641
{
642 643
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
644

645
	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
646 647
}

648 649
Datum
float4ge(PG_FUNCTION_ARGS)
650
{
651 652
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
653

654 655 656 657 658 659 660 661 662 663
	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
}

Datum
btfloat4cmp(PG_FUNCTION_ARGS)
{
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);

	PG_RETURN_INT32(float4_cmp_internal(arg1, arg2));
664 665 666
}

/*
667
 *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
668
 */
669 670 671 672
static int
float8_cmp_internal(float8 a, float8 b)
{
	/*
673 674 675
	 * We consider all NANs to be equal and larger than any non-NAN. This
	 * is somewhat arbitrary; the important thing is to have a consistent
	 * sort order.
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
	 */
	if (isnan(a))
	{
		if (isnan(b))
			return 0;			/* NAN = NAN */
		else
			return 1;			/* NAN > non-NAN */
	}
	else if (isnan(b))
	{
		return -1;				/* non-NAN < NAN */
	}
	else
	{
		if (a > b)
			return 1;
692
		else if (a < b)
693
			return -1;
694 695
		else
			return 0;
696 697 698
	}
}

699 700
Datum
float8eq(PG_FUNCTION_ARGS)
701
{
702 703
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
704

705
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
706 707
}

708 709
Datum
float8ne(PG_FUNCTION_ARGS)
710
{
711 712
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
713

714
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
715 716
}

717 718
Datum
float8lt(PG_FUNCTION_ARGS)
719
{
720 721
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
722

723
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
724 725
}

726 727
Datum
float8le(PG_FUNCTION_ARGS)
728
{
729 730
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
731

732
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
733 734
}

735 736
Datum
float8gt(PG_FUNCTION_ARGS)
737
{
738 739
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
740

741
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
742 743
}

744 745
Datum
float8ge(PG_FUNCTION_ARGS)
746
{
747 748
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
749

750 751 752 753 754 755 756 757 758 759
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
}

Datum
btfloat8cmp(PG_FUNCTION_ARGS)
{
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);

	PG_RETURN_INT32(float8_cmp_internal(arg1, arg2));
760 761 762 763
}


/*
764 765 766
 *		===================
 *		CONVERSION ROUTINES
 *		===================
767 768 769
 */

/*
770
 *		ftod			- converts a float4 number to a float8 number
771
 */
772 773
Datum
ftod(PG_FUNCTION_ARGS)
774
{
775
	float4		num = PG_GETARG_FLOAT4(0);
776

777
	PG_RETURN_FLOAT8((float8) num);
778 779 780 781
}


/*
782
 *		dtof			- converts a float8 number to a float4 number
783
 */
784 785
Datum
dtof(PG_FUNCTION_ARGS)
786
{
787
	float8		num = PG_GETARG_FLOAT8(0);
788

789
	CheckFloat4Val(num);
790

791
	PG_RETURN_FLOAT4((float4) num);
792 793 794 795
}


/*
796
 *		dtoi4			- converts a float8 number to an int4 number
797
 */
798 799
Datum
dtoi4(PG_FUNCTION_ARGS)
800
{
801
	float8		num = PG_GETARG_FLOAT8(0);
802
	int32		result;
803

804
	if ((num < INT_MIN) || (num > INT_MAX))
805
		elog(ERROR, "dtoi4: integer out of range");
806

807 808
	result = (int32) rint(num);
	PG_RETURN_INT32(result);
809 810 811 812
}


/*
813
 *		dtoi2			- converts a float8 number to an int2 number
814
 */
815 816
Datum
dtoi2(PG_FUNCTION_ARGS)
817
{
818
	float8		num = PG_GETARG_FLOAT8(0);
819
	int16		result;
820

821
	if ((num < SHRT_MIN) || (num > SHRT_MAX))
822
		elog(ERROR, "dtoi2: integer out of range");
823

824 825
	result = (int16) rint(num);
	PG_RETURN_INT16(result);
826 827 828 829
}


/*
830
 *		i4tod			- converts an int4 number to a float8 number
831
 */
832 833
Datum
i4tod(PG_FUNCTION_ARGS)
834
{
835 836
	int32		num = PG_GETARG_INT32(0);
	float8		result;
837

838 839
	result = num;
	PG_RETURN_FLOAT8(result);
840 841 842 843
}


/*
844
 *		i2tod			- converts an int2 number to a float8 number
845
 */
846 847
Datum
i2tod(PG_FUNCTION_ARGS)
848
{
849 850
	int16		num = PG_GETARG_INT16(0);
	float8		result;
851

852 853
	result = num;
	PG_RETURN_FLOAT8(result);
854 855 856 857
}


/*
858
 *		ftoi4			- converts a float4 number to an int4 number
859
 */
860 861
Datum
ftoi4(PG_FUNCTION_ARGS)
862
{
863
	float4		num = PG_GETARG_FLOAT4(0);
864
	int32		result;
865

866
	if ((num < INT_MIN) || (num > INT_MAX))
867
		elog(ERROR, "ftoi4: integer out of range");
868

869 870
	result = (int32) rint(num);
	PG_RETURN_INT32(result);
871 872 873 874
}


/*
875
 *		ftoi2			- converts a float4 number to an int2 number
876
 */
877 878
Datum
ftoi2(PG_FUNCTION_ARGS)
879
{
880
	float4		num = PG_GETARG_FLOAT4(0);
881
	int16		result;
882

883
	if ((num < SHRT_MIN) || (num > SHRT_MAX))
884
		elog(ERROR, "ftoi2: integer out of range");
885

886 887
	result = (int16) rint(num);
	PG_RETURN_INT16(result);
888 889 890 891
}


/*
892
 *		i4tof			- converts an int4 number to a float8 number
893
 */
894 895
Datum
i4tof(PG_FUNCTION_ARGS)
896
{
897 898
	int32		num = PG_GETARG_INT32(0);
	float4		result;
899

900 901
	result = num;
	PG_RETURN_FLOAT4(result);
902 903 904 905
}


/*
906
 *		i2tof			- converts an int2 number to a float4 number
907
 */
908 909
Datum
i2tof(PG_FUNCTION_ARGS)
910
{
911 912
	int16		num = PG_GETARG_INT16(0);
	float4		result;
913

914 915
	result = num;
	PG_RETURN_FLOAT4(result);
916 917 918
}


919 920 921
/*
 *		float8_text		- converts a float8 number to a text string
 */
922 923
Datum
float8_text(PG_FUNCTION_ARGS)
924
{
925
	float8		num = PG_GETARG_FLOAT8(0);
Bruce Momjian's avatar
Bruce Momjian committed
926 927 928
	text	   *result;
	int			len;
	char	   *str;
929

930 931 932
	str = DatumGetCString(DirectFunctionCall1(float8out,
											  Float8GetDatum(num)));

933
	len = strlen(str) + VARHDRSZ;
934

935
	result = (text *) palloc(len);
936

Jan Wieck's avatar
TOAST  
Jan Wieck committed
937
	VARATT_SIZEP(result) = len;
938
	memcpy(VARDATA(result), str, (len - VARHDRSZ));
939 940

	pfree(str);
941 942 943

	PG_RETURN_TEXT_P(result);
}
944 945 946 947 948


/*
 *		text_float8		- converts a text string to a float8 number
 */
949 950
Datum
text_float8(PG_FUNCTION_ARGS)
951
{
952
	text	   *string = PG_GETARG_TEXT_P(0);
953
	Datum		result;
Bruce Momjian's avatar
Bruce Momjian committed
954 955
	int			len;
	char	   *str;
956 957 958

	len = (VARSIZE(string) - VARHDRSZ);
	str = palloc(len + 1);
959
	memcpy(str, VARDATA(string), len);
960 961
	*(str + len) = '\0';

962
	result = DirectFunctionCall1(float8in, CStringGetDatum(str));
963

964 965
	pfree(str);

966
	PG_RETURN_DATUM(result);
967
}
968 969 970 971 972


/*
 *		float4_text		- converts a float4 number to a text string
 */
973 974
Datum
float4_text(PG_FUNCTION_ARGS)
975
{
976
	float4		num = PG_GETARG_FLOAT4(0);
Bruce Momjian's avatar
Bruce Momjian committed
977 978 979
	text	   *result;
	int			len;
	char	   *str;
980

981 982 983
	str = DatumGetCString(DirectFunctionCall1(float4out,
											  Float4GetDatum(num)));

984
	len = strlen(str) + VARHDRSZ;
985

986
	result = (text *) palloc(len);
987

Jan Wieck's avatar
TOAST  
Jan Wieck committed
988
	VARATT_SIZEP(result) = len;
989
	memcpy(VARDATA(result), str, (len - VARHDRSZ));
990 991

	pfree(str);
992 993 994

	PG_RETURN_TEXT_P(result);
}
995 996 997 998 999


/*
 *		text_float4		- converts a text string to a float4 number
 */
1000 1001
Datum
text_float4(PG_FUNCTION_ARGS)
1002
{
1003
	text	   *string = PG_GETARG_TEXT_P(0);
1004
	Datum		result;
Bruce Momjian's avatar
Bruce Momjian committed
1005 1006
	int			len;
	char	   *str;
1007 1008 1009

	len = (VARSIZE(string) - VARHDRSZ);
	str = palloc(len + 1);
1010
	memcpy(str, VARDATA(string), len);
1011 1012
	*(str + len) = '\0';

1013
	result = DirectFunctionCall1(float4in, CStringGetDatum(str));
1014

1015 1016
	pfree(str);

1017
	PG_RETURN_DATUM(result);
1018
}
1019 1020


1021
/*
1022 1023 1024
 *		=======================
 *		RANDOM FLOAT8 OPERATORS
 *		=======================
1025 1026 1027
 */

/*
1028
 *		dround			- returns	ROUND(arg1)
1029
 */
1030 1031
Datum
dround(PG_FUNCTION_ARGS)
1032
{
1033 1034
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1035

1036
	result = rint(arg1);
1037

1038
	PG_RETURN_FLOAT8(result);
1039 1040 1041 1042
}


/*
1043 1044
 *		dtrunc			- returns truncation-towards-zero of arg1,
 *						  arg1 >= 0 ... the greatest integer less
1045
 *										than or equal to arg1
1046
 *						  arg1 < 0	... the least integer greater
1047
 *										than or equal to arg1
1048
 */
1049 1050
Datum
dtrunc(PG_FUNCTION_ARGS)
1051
{
1052 1053
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1054

1055 1056
	if (arg1 >= 0)
		result = floor(arg1);
1057
	else
1058 1059 1060
		result = -floor(-arg1);

	PG_RETURN_FLOAT8(result);
1061 1062 1063 1064
}


/*
1065
 *		dsqrt			- returns square root of arg1
1066
 */
1067 1068
Datum
dsqrt(PG_FUNCTION_ARGS)
1069
{
1070 1071
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1072

1073 1074
	if (arg1 < 0)
		elog(ERROR, "can't take sqrt of a negative number");
1075

1076
	result = sqrt(arg1);
1077

1078 1079
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1080 1081 1082 1083
}


/*
1084
 *		dcbrt			- returns cube root of arg1
1085
 */
1086 1087
Datum
dcbrt(PG_FUNCTION_ARGS)
1088
{
1089 1090
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1091

1092 1093
	result = cbrt(arg1);
	PG_RETURN_FLOAT8(result);
1094 1095 1096 1097
}


/*
1098
 *		dpow			- returns pow(arg1,arg2)
1099
 */
1100 1101
Datum
dpow(PG_FUNCTION_ARGS)
1102
{
1103 1104 1105
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
1106

1107 1108 1109
	/*
	 * We must check both for errno getting set and for a NaN result, in
	 * order to deal with the vagaries of different platforms...
1110
	 */
1111
	errno = 0;
1112
	result = pow(arg1, arg2);
1113 1114
	if (errno != 0
#ifdef HAVE_FINITE
1115
		|| !finite(result)
1116
#endif
1117
		)
1118
		elog(ERROR, "pow() result is out of range");
1119

1120 1121
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1122 1123 1124 1125
}


/*
1126
 *		dexp			- returns the exponential function of arg1
1127
 */
1128 1129
Datum
dexp(PG_FUNCTION_ARGS)
1130
{
1131 1132
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1133

1134 1135 1136 1137
	/*
	 * We must check both for errno getting set and for a NaN result, in
	 * order to deal with the vagaries of different platforms. Also, a
	 * zero result implies unreported underflow.
1138
	 */
1139
	errno = 0;
1140 1141
	result = exp(arg1);
	if (errno != 0 || result == 0.0
1142
#ifdef HAVE_FINITE
1143
		|| !finite(result)
1144
#endif
1145
		)
1146
		elog(ERROR, "exp() result is out of range");
1147

1148 1149
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1150 1151 1152 1153
}


/*
1154
 *		dlog1			- returns the natural logarithm of arg1
1155
 *						  ("dlog" is already a logging routine...)
1156
 */
1157 1158
Datum
dlog1(PG_FUNCTION_ARGS)
1159
{
1160 1161
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1162

1163
	if (arg1 == 0.0)
1164
		elog(ERROR, "can't take log of zero");
1165
	if (arg1 < 0)
1166
		elog(ERROR, "can't take log of a negative number");
1167

1168 1169 1170 1171 1172
	result = log(arg1);

	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1173

1174

1175
/*
1176
 *		dlog10			- returns the base 10 logarithm of arg1
1177
 */
1178 1179
Datum
dlog10(PG_FUNCTION_ARGS)
1180
{
1181 1182
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1183

1184
	if (arg1 == 0.0)
1185
		elog(ERROR, "can't take log of zero");
1186
	if (arg1 < 0)
1187 1188
		elog(ERROR, "can't take log of a negative number");

1189 1190 1191 1192 1193
	result = log10(arg1);

	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1194

1195

1196
/*
1197
 *		dacos			- returns the arccos of arg1 (radians)
1198
 */
1199 1200
Datum
dacos(PG_FUNCTION_ARGS)
1201
{
1202 1203
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1204 1205

	errno = 0;
1206
	result = acos(arg1);
1207 1208
	if (errno != 0
#ifdef HAVE_FINITE
1209
		|| !finite(result)
1210 1211
#endif
		)
1212
		elog(ERROR, "acos(%f) input is out of range", arg1);
1213

1214 1215 1216
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1217 1218 1219


/*
1220
 *		dasin			- returns the arcsin of arg1 (radians)
1221
 */
1222 1223
Datum
dasin(PG_FUNCTION_ARGS)
1224
{
1225 1226
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1227 1228

	errno = 0;
1229
	result = asin(arg1);
1230 1231
	if (errno != 0
#ifdef HAVE_FINITE
1232
		|| !finite(result)
1233 1234
#endif
		)
1235
		elog(ERROR, "asin(%f) input is out of range", arg1);
1236

1237 1238 1239
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1240 1241 1242


/*
1243
 *		datan			- returns the arctan of arg1 (radians)
1244
 */
1245 1246
Datum
datan(PG_FUNCTION_ARGS)
1247
{
1248 1249
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1250 1251

	errno = 0;
1252
	result = atan(arg1);
1253 1254
	if (errno != 0
#ifdef HAVE_FINITE
1255
		|| !finite(result)
1256 1257
#endif
		)
1258
		elog(ERROR, "atan(%f) input is out of range", arg1);
1259

1260 1261 1262
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1263 1264 1265


/*
1266
 *		atan2			- returns the arctan2 of arg1 (radians)
1267
 */
1268 1269
Datum
datan2(PG_FUNCTION_ARGS)
1270
{
1271 1272 1273
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
1274 1275

	errno = 0;
1276
	result = atan2(arg1, arg2);
1277 1278
	if (errno != 0
#ifdef HAVE_FINITE
1279
		|| !finite(result)
1280 1281
#endif
		)
1282
		elog(ERROR, "atan2(%f,%f) input is out of range", arg1, arg2);
1283

1284 1285 1286
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1287 1288 1289


/*
1290
 *		dcos			- returns the cosine of arg1 (radians)
1291
 */
1292 1293
Datum
dcos(PG_FUNCTION_ARGS)
1294
{
1295 1296
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1297 1298

	errno = 0;
1299
	result = cos(arg1);
1300 1301
	if (errno != 0
#ifdef HAVE_FINITE
1302
		|| !finite(result)
1303 1304
#endif
		)
1305
		elog(ERROR, "cos(%f) input is out of range", arg1);
1306

1307 1308 1309
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1310 1311 1312


/*
1313
 *		dcot			- returns the cotangent of arg1 (radians)
1314
 */
1315 1316
Datum
dcot(PG_FUNCTION_ARGS)
1317
{
1318 1319
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1320 1321

	errno = 0;
1322 1323
	result = tan(arg1);
	if (errno != 0 || result == 0.0
1324
#ifdef HAVE_FINITE
1325
		|| !finite(result)
1326 1327
#endif
		)
1328
		elog(ERROR, "cot(%f) input is out of range", arg1);
1329

1330 1331 1332 1333
	result = 1.0 / result;
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1334 1335 1336


/*
1337
 *		dsin			- returns the sine of arg1 (radians)
1338
 */
1339 1340
Datum
dsin(PG_FUNCTION_ARGS)
1341
{
1342 1343
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1344 1345

	errno = 0;
1346
	result = sin(arg1);
1347 1348
	if (errno != 0
#ifdef HAVE_FINITE
1349
		|| !finite(result)
1350 1351
#endif
		)
1352
		elog(ERROR, "sin(%f) input is out of range", arg1);
1353

1354 1355 1356
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1357 1358 1359


/*
1360
 *		dtan			- returns the tangent of arg1 (radians)
1361
 */
1362 1363
Datum
dtan(PG_FUNCTION_ARGS)
1364
{
1365 1366
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1367 1368

	errno = 0;
1369
	result = tan(arg1);
1370 1371
	if (errno != 0
#ifdef HAVE_FINITE
1372
		|| !finite(result)
1373 1374
#endif
		)
1375
		elog(ERROR, "tan(%f) input is out of range", arg1);
1376

1377 1378 1379
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1380 1381 1382


/*
1383
 *		degrees		- returns degrees converted from radians
1384
 */
1385 1386
Datum
degrees(PG_FUNCTION_ARGS)
1387
{
1388 1389
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1390

1391
	result = arg1 * (180.0 / M_PI);
1392

1393 1394 1395
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1396 1397 1398


/*
1399
 *		dpi				- returns the constant PI
1400
 */
1401 1402
Datum
dpi(PG_FUNCTION_ARGS)
1403
{
1404 1405
	PG_RETURN_FLOAT8(M_PI);
}
1406 1407 1408


/*
1409
 *		radians		- returns radians converted from degrees
1410
 */
1411 1412
Datum
radians(PG_FUNCTION_ARGS)
1413
{
1414 1415
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float8		result;
1416

1417
	result = arg1 * (M_PI / 180.0);
1418

1419 1420 1421
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
}
1422 1423 1424


/*
1425
 *		drandom		- returns a random number
1426
 */
1427 1428
Datum
drandom(PG_FUNCTION_ARGS)
1429
{
1430
	float8		result;
1431 1432

	/* result 0.0-1.0 */
1433
	result = ((double) random()) / ((double) MAX_RANDOM_VALUE);
1434

1435 1436
	PG_RETURN_FLOAT8(result);
}
1437 1438 1439 1440 1441


/*
 *		setseed		- set seed for the random number generator
 */
1442 1443
Datum
setseed(PG_FUNCTION_ARGS)
1444
{
1445
	float8		seed = PG_GETARG_FLOAT8(0);
1446
	int			iseed = (int) (seed * MAX_RANDOM_VALUE);
1447

1448
	srandom((unsigned int) iseed);
1449

1450 1451
	PG_RETURN_INT32(iseed);
}
1452 1453


1454

1455
/*
1456 1457 1458 1459 1460 1461 1462
 *		=========================
 *		FLOAT AGGREGATE OPERATORS
 *		=========================
 *
 *		float8_accum	- accumulate for AVG(), STDDEV(), etc
 *		float4_accum	- same, but input data is float4
 *		float8_avg		- produce final result for float AVG()
1463
 *		float8_variance - produce final result for float VARIANCE()
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
 *		float8_stddev	- produce final result for float STDDEV()
 *
 * The transition datatype for all these aggregates is a 3-element array
 * of float8, holding the values N, sum(X), sum(X*X) in that order.
 *
 * Note that we represent N as a float to avoid having to build a special
 * datatype.  Given a reasonable floating-point implementation, there should
 * be no accuracy loss unless N exceeds 2 ^ 52 or so (by which time the
 * user will have doubtless lost interest anyway...)
 */

static float8 *
check_float8_array(ArrayType *transarray, const char *caller)
{
	/*
1479 1480 1481
	 * We expect the input to be a 3-element float array; verify that. We
	 * don't need to use deconstruct_array() since the array data is just
	 * going to look like a C array of 3 float8 values.
1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
	 */
	if (ARR_SIZE(transarray) != (ARR_OVERHEAD(1) + 3 * sizeof(float8)) ||
		ARR_NDIM(transarray) != 1 ||
		ARR_DIMS(transarray)[0] != 3)
		elog(ERROR, "%s: expected 3-element float8 array", caller);
	return (float8 *) ARR_DATA_PTR(transarray);
}

Datum
float8_accum(PG_FUNCTION_ARGS)
{
	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
	float8		newval = PG_GETARG_FLOAT8(1);
	float8	   *transvalues;
	float8		N,
				sumX,
				sumX2;
	Datum		transdatums[3];
	ArrayType  *result;

	transvalues = check_float8_array(transarray, "float8_accum");
	N = transvalues[0];
	sumX = transvalues[1];
	sumX2 = transvalues[2];

	N += 1.0;
	sumX += newval;
	sumX2 += newval * newval;

	transdatums[0] = Float8GetDatumFast(N);
	transdatums[1] = Float8GetDatumFast(sumX);
	transdatums[2] = Float8GetDatumFast(sumX2);

	result = construct_array(transdatums, 3,
1516
						 false /* float8 byval */ , sizeof(float8), 'd');
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550

	PG_RETURN_ARRAYTYPE_P(result);
}

Datum
float4_accum(PG_FUNCTION_ARGS)
{
	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
	float4		newval4 = PG_GETARG_FLOAT4(1);
	float8	   *transvalues;
	float8		N,
				sumX,
				sumX2,
				newval;
	Datum		transdatums[3];
	ArrayType  *result;

	transvalues = check_float8_array(transarray, "float4_accum");
	N = transvalues[0];
	sumX = transvalues[1];
	sumX2 = transvalues[2];

	/* Do arithmetic in float8 for best accuracy */
	newval = newval4;

	N += 1.0;
	sumX += newval;
	sumX2 += newval * newval;

	transdatums[0] = Float8GetDatumFast(N);
	transdatums[1] = Float8GetDatumFast(sumX);
	transdatums[2] = Float8GetDatumFast(sumX2);

	result = construct_array(transdatums, 3,
1551
						 false /* float8 byval */ , sizeof(float8), 'd');
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582

	PG_RETURN_ARRAYTYPE_P(result);
}

Datum
float8_avg(PG_FUNCTION_ARGS)
{
	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
	float8	   *transvalues;
	float8		N,
				sumX;

	transvalues = check_float8_array(transarray, "float8_avg");
	N = transvalues[0];
	sumX = transvalues[1];
	/* ignore sumX2 */

	/* SQL92 defines AVG of no values to be NULL */
	if (N == 0.0)
		PG_RETURN_NULL();

	PG_RETURN_FLOAT8(sumX / N);
}

Datum
float8_variance(PG_FUNCTION_ARGS)
{
	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
	float8	   *transvalues;
	float8		N,
				sumX,
1583 1584
				sumX2,
				numerator;
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597

	transvalues = check_float8_array(transarray, "float8_variance");
	N = transvalues[0];
	sumX = transvalues[1];
	sumX2 = transvalues[2];

	/* We define VARIANCE of no values to be NULL, of 1 value to be 0 */
	if (N == 0.0)
		PG_RETURN_NULL();

	if (N <= 1.0)
		PG_RETURN_FLOAT8(0.0);

1598 1599 1600 1601 1602 1603 1604
	numerator = N * sumX2 - sumX * sumX;

	/* Watch out for roundoff error producing a negative numerator */
	if (numerator <= 0.0)
		PG_RETURN_FLOAT8(0.0);

	PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
1605 1606 1607 1608 1609 1610 1611 1612 1613
}

Datum
float8_stddev(PG_FUNCTION_ARGS)
{
	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
	float8	   *transvalues;
	float8		N,
				sumX,
1614 1615
				sumX2,
				numerator;
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628

	transvalues = check_float8_array(transarray, "float8_stddev");
	N = transvalues[0];
	sumX = transvalues[1];
	sumX2 = transvalues[2];

	/* We define STDDEV of no values to be NULL, of 1 value to be 0 */
	if (N == 0.0)
		PG_RETURN_NULL();

	if (N <= 1.0)
		PG_RETURN_FLOAT8(0.0);

1629 1630 1631 1632 1633 1634 1635
	numerator = N * sumX2 - sumX * sumX;

	/* Watch out for roundoff error producing a negative numerator */
	if (numerator <= 0.0)
		PG_RETURN_FLOAT8(0.0);

	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
1636 1637 1638 1639 1640 1641 1642
}


/*
 *		====================================
 *		MIXED-PRECISION ARITHMETIC OPERATORS
 *		====================================
1643 1644 1645
 */

/*
1646 1647 1648 1649
 *		float48pl		- returns arg1 + arg2
 *		float48mi		- returns arg1 - arg2
 *		float48mul		- returns arg1 * arg2
 *		float48div		- returns arg1 / arg2
1650
 */
1651 1652
Datum
float48pl(PG_FUNCTION_ARGS)
1653
{
1654 1655 1656
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
1657

1658 1659 1660
	result = arg1 + arg2;
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1661 1662
}

1663 1664
Datum
float48mi(PG_FUNCTION_ARGS)
1665
{
1666 1667 1668
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
1669

1670 1671 1672
	result = arg1 - arg2;
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1673 1674
}

1675 1676
Datum
float48mul(PG_FUNCTION_ARGS)
1677
{
1678 1679 1680
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
1681

1682 1683 1684
	result = arg1 * arg2;
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1685 1686
}

1687 1688
Datum
float48div(PG_FUNCTION_ARGS)
1689
{
1690 1691 1692
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
	float8		result;
1693

1694
	if (arg2 == 0.0)
1695
		elog(ERROR, "float48div: divide by zero");
1696

1697 1698 1699
	result = arg1 / arg2;
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1700 1701 1702
}

/*
1703 1704 1705 1706
 *		float84pl		- returns arg1 + arg2
 *		float84mi		- returns arg1 - arg2
 *		float84mul		- returns arg1 * arg2
 *		float84div		- returns arg1 / arg2
1707
 */
1708 1709
Datum
float84pl(PG_FUNCTION_ARGS)
1710
{
1711 1712 1713
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	float8		result;
1714

1715
	result = arg1 + arg2;
1716

1717 1718
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1719 1720
}

1721 1722
Datum
float84mi(PG_FUNCTION_ARGS)
1723
{
1724 1725 1726
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	float8		result;
1727

1728
	result = arg1 - arg2;
1729

1730 1731
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1732 1733
}

1734 1735
Datum
float84mul(PG_FUNCTION_ARGS)
1736
{
1737 1738 1739
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	float8		result;
1740

1741
	result = arg1 * arg2;
1742

1743 1744
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1745 1746
}

1747 1748
Datum
float84div(PG_FUNCTION_ARGS)
1749
{
1750 1751 1752
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
	float8		result;
1753

1754 1755
	if (arg2 == 0.0)
		elog(ERROR, "float84div: divide by zero");
1756

1757
	result = arg1 / arg2;
1758

1759 1760
	CheckFloat8Val(result);
	PG_RETURN_FLOAT8(result);
1761 1762 1763
}

/*
1764 1765 1766
 *		====================
 *		COMPARISON OPERATORS
 *		====================
1767 1768 1769
 */

/*
1770
 *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
1771
 */
1772 1773
Datum
float48eq(PG_FUNCTION_ARGS)
1774
{
1775 1776
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
1777

1778
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
1779 1780
}

1781 1782
Datum
float48ne(PG_FUNCTION_ARGS)
1783
{
1784 1785
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
1786

1787
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
1788 1789
}

1790 1791
Datum
float48lt(PG_FUNCTION_ARGS)
1792
{
1793 1794
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
1795

1796
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
1797 1798
}

1799 1800
Datum
float48le(PG_FUNCTION_ARGS)
1801
{
1802 1803
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
1804

1805
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1806 1807
}

1808 1809
Datum
float48gt(PG_FUNCTION_ARGS)
1810
{
1811 1812
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
1813

1814
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1815 1816
}

1817 1818
Datum
float48ge(PG_FUNCTION_ARGS)
1819
{
1820 1821
	float4		arg1 = PG_GETARG_FLOAT4(0);
	float8		arg2 = PG_GETARG_FLOAT8(1);
1822

1823
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1824 1825 1826
}

/*
1827
 *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
1828
 */
1829 1830
Datum
float84eq(PG_FUNCTION_ARGS)
1831
{
1832 1833
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
1834

1835
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
1836 1837
}

1838 1839
Datum
float84ne(PG_FUNCTION_ARGS)
1840
{
1841 1842
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
1843

1844
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
1845 1846
}

1847 1848
Datum
float84lt(PG_FUNCTION_ARGS)
1849
{
1850 1851
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
1852

1853
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
1854 1855
}

1856 1857
Datum
float84le(PG_FUNCTION_ARGS)
1858
{
1859 1860
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
1861

1862
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
1863 1864
}

1865 1866
Datum
float84gt(PG_FUNCTION_ARGS)
1867
{
1868 1869
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
1870

1871
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
1872 1873
}

1874 1875
Datum
float84ge(PG_FUNCTION_ARGS)
1876
{
1877 1878
	float8		arg1 = PG_GETARG_FLOAT8(0);
	float4		arg2 = PG_GETARG_FLOAT4(1);
1879

1880
	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
1881 1882 1883 1884 1885 1886
}

/* ========== PRIVATE ROUTINES ========== */

/* From "fdlibm" @ netlib.att.com */

1887
#ifndef HAVE_RINT
1888 1889 1890 1891 1892 1893 1894 1895

/* @(#)s_rint.c 5.1 93/09/24 */
/*
 * ====================================================
 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
 *
 * Developed at SunPro, a Sun Microsystems, Inc. business.
 * Permission to use, copy, modify, and distribute this
1896
 * software is freely granted, provided that this notice
1897 1898 1899 1900 1901 1902 1903 1904 1905
 * is preserved.
 * ====================================================
 */

/*
 * rint(x)
 * Return x rounded to integral value according to the prevailing
 * rounding mode.
 * Method:
1906
 *		Using floating addition.
1907
 * Exception:
1908
 *		Inexact flag raised if x not equal to rint(x).
1909 1910
 */

1911
static const double one = 1.0,
1912
			TWO52[2] = {
1913
	4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
1914
	-4.50359962737049600000e+15,	/* 0xC3300000, 0x00000000 */
1915
};
1916

1917 1918
static double
rint(double x)
1919
{
1920 1921 1922 1923 1924 1925 1926 1927
	int			i0,
				n0,
				j0,
				sx;
	unsigned	i,
				i1;
	double		w,
				t;
1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979

	n0 = (*((int *) &one) >> 29) ^ 1;
	i0 = *(n0 + (int *) &x);
	sx = (i0 >> 31) & 1;
	i1 = *(1 - n0 + (int *) &x);
	j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
	if (j0 < 20)
	{
		if (j0 < 0)
		{
			if (((i0 & 0x7fffffff) | i1) == 0)
				return x;
			i1 |= (i0 & 0x0fffff);
			i0 &= 0xfffe0000;
			i0 |= ((i1 | -i1) >> 12) & 0x80000;
			*(n0 + (int *) &x) = i0;
			w = TWO52[sx] + x;
			t = w - TWO52[sx];
			i0 = *(n0 + (int *) &t);
			*(n0 + (int *) &t) = (i0 & 0x7fffffff) | (sx << 31);
			return t;
		}
		else
		{
			i = (0x000fffff) >> j0;
			if (((i0 & i) | i1) == 0)
				return x;		/* x is integral */
			i >>= 1;
			if (((i0 & i) | i1) != 0)
			{
				if (j0 == 19)
					i1 = 0x40000000;
				else
					i0 = (i0 & (~i)) | ((0x20000) >> j0);
			}
		}
	}
	else if (j0 > 51)
	{
		if (j0 == 0x400)
			return x + x;		/* inf or NaN */
		else
			return x;			/* x is integral */
	}
	else
	{
		i = ((unsigned) (0xffffffff)) >> (j0 - 20);
		if ((i1 & i) == 0)
			return x;			/* x is integral */
		i >>= 1;
		if ((i1 & i) != 0)
			i1 = (i1 & (~i)) | ((0x40000000) >> (j0 - 20));
1980
	}
1981 1982 1983 1984 1985
	*(n0 + (int *) &x) = i0;
	*(1 - n0 + (int *) &x) = i1;
	w = TWO52[sx] + x;
	return w - TWO52[sx];
}
1986
#endif   /* !HAVE_RINT */
1987

1988
#ifndef HAVE_CBRT
1989

1990 1991
static double
cbrt(double x)
1992
{
1993 1994
	int			isneg = (x < 0.0);
	double		tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
1995

1996
	return isneg ? -tmpres : tmpres;
1997
}
1998

1999
#endif   /* !HAVE_CBRT */