From a4f68bd1a925f001030097a8daebcbef68415a20 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Sat, 28 May 2016 18:16:05 +0200
Subject: [PATCH 1/2] float-header-v01

---
 src/backend/access/gist/gistget.c             |   2 +-
 src/backend/access/gist/gistproc.c            |  56 ++---
 src/backend/access/gist/gistutil.c            |   2 +-
 src/backend/utils/adt/float.c                 | 313 +++++++-------------------
 src/backend/utils/adt/formatting.c            |   8 +-
 src/backend/utils/adt/geo_ops.c               |   6 +-
 src/backend/utils/adt/geo_spgist.c            |   2 +-
 src/backend/utils/adt/numeric.c               |   1 +
 src/backend/utils/adt/rangetypes_gist.c       |   2 +-
 src/backend/utils/adt/rangetypes_selfuncs.c   |   2 +-
 src/backend/utils/adt/rangetypes_typanalyze.c |   2 +-
 src/backend/utils/adt/timestamp.c             |   1 +
 src/backend/utils/misc/guc.c                  |   1 +
 src/include/utils/builtins.h                  |  13 --
 src/include/utils/float.h                     | 130 +++++++++++
 15 files changed, 246 insertions(+), 295 deletions(-)
 create mode 100644 src/include/utils/float.h

diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index 5ba7d0a..eda48ef 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -13,21 +13,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist_private.h"
 #include "access/relscan.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "lib/pairingheap.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/rel.h"
 
 /*
  * gistkillitems() -- set LP_DEAD state for items an indexscan caller has
  * told us were killed.
  *
  * We re-read page here, so it's important to check page LSN. If the page
  * has been modified since the last read (as determined by LSN), we cannot
  * flag any entries because it is possible that the old entry was vacuumed
diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index d47211a..c7ac033 100644
--- a/src/backend/access/gist/gistproc.c
+++ b/src/backend/access/gist/gistproc.c
@@ -15,73 +15,65 @@
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <math.h>
 
 #include "access/gist.h"
 #include "access/stratnum.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 
 static bool gist_box_leaf_consistent(BOX *key, BOX *query,
 						 StrategyNumber strategy);
 static bool rtree_internal_consistent(BOX *key, BOX *query,
 						  StrategyNumber strategy);
 
 /* Minimum accepted ratio of split */
 #define LIMIT_RATIO 0.3
 
-/* Convenience macros for NaN-aware comparisons */
-#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
-#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
-#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
-#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
-#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
-#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
-#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))
-
 
 /**************************************************
  * Box ops
  **************************************************/
 
 /*
  * Calculates union of two boxes, a and b. The result is stored in *n.
  */
 static void
 rt_box_union(BOX *n, const BOX *a, const BOX *b)
 {
-	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
-	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
-	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
-	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
+	n->high.x = FLOAT_MAX(a->high.x, b->high.x);
+	n->high.y = FLOAT_MAX(a->high.y, b->high.y);
+	n->low.x = FLOAT_MIN(a->low.x, b->low.x);
+	n->low.y = FLOAT_MIN(a->low.y, b->low.y);
 }
 
 /*
  * Size of a BOX for penalty-calculation purposes.
  * The result can be +Infinity, but not NaN.
  */
 static double
 size_box(const BOX *box)
 {
 	/*
 	 * Check for zero-width cases.  Note that we define the size of a zero-
 	 * by-infinity box as zero.  It's important to special-case this somehow,
 	 * as naively multiplying infinity by zero will produce NaN.
 	 *
 	 * The less-than cases should not happen, but if they do, say "zero".
 	 */
-	if (FLOAT8_LE(box->high.x, box->low.x) ||
-		FLOAT8_LE(box->high.y, box->low.y))
+	if (FLOAT_LE(box->high.x, box->low.x) ||
+		FLOAT_LE(box->high.y, box->low.y))
 		return 0.0;
 
 	/*
 	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
 	 * and a non-NaN is infinite.  Note the previous check eliminated the
 	 * possibility that the low fields are NaNs.
 	 */
 	if (isnan(box->high.x) || isnan(box->high.y))
 		return get_float8_infinity();
 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
@@ -136,27 +128,27 @@ gist_box_consistent(PG_FUNCTION_ARGS)
 												 query,
 												 strategy));
 }
 
 /*
  * Increase BOX b to include addon.
  */
 static void
 adjustBox(BOX *b, const BOX *addon)
 {
-	if (FLOAT8_LT(b->high.x, addon->high.x))
+	if (FLOAT_LT(b->high.x, addon->high.x))
 		b->high.x = addon->high.x;
-	if (FLOAT8_GT(b->low.x, addon->low.x))
+	if (FLOAT_GT(b->low.x, addon->low.x))
 		b->low.x = addon->low.x;
-	if (FLOAT8_LT(b->high.y, addon->high.y))
+	if (FLOAT_LT(b->high.y, addon->high.y))
 		b->high.y = addon->high.y;
-	if (FLOAT8_GT(b->low.y, addon->low.y))
+	if (FLOAT_GT(b->low.y, addon->low.y))
 		b->low.y = addon->low.y;
 }
 
 /*
  * The GiST Union method for boxes
  *
  * returns the minimal bounding box that encloses all the entries in entryvec
  */
 Datum
 gist_box_union(PG_FUNCTION_ARGS)
@@ -636,36 +628,36 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		i1 = 0;
 		i2 = 0;
 		rightLower = intervalsLower[i1].lower;
 		leftUpper = intervalsUpper[i2].lower;
 		while (true)
 		{
 			/*
 			 * Find next lower bound of right group.
 			 */
 			while (i1 < nentries &&
-				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
+				   FLOAT_EQ(rightLower, intervalsLower[i1].lower))
 			{
-				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
+				if (FLOAT_LT(leftUpper, intervalsLower[i1].upper))
 					leftUpper = intervalsLower[i1].upper;
 				i1++;
 			}
 			if (i1 >= nentries)
 				break;
 			rightLower = intervalsLower[i1].lower;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * left group.
 			 */
 			while (i2 < nentries &&
-				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
+				   FLOAT_LE(intervalsUpper[i2].upper, leftUpper))
 				i2++;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
 		}
 
 		/*
 		 * Iterate over upper bound of left group finding greatest possible
@@ -673,35 +665,35 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		 */
 		i1 = nentries - 1;
 		i2 = nentries - 1;
 		rightLower = intervalsLower[i1].upper;
 		leftUpper = intervalsUpper[i2].upper;
 		while (true)
 		{
 			/*
 			 * Find next upper bound of left group.
 			 */
-			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
+			while (i2 >= 0 && FLOAT_EQ(leftUpper, intervalsUpper[i2].upper))
 			{
-				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
+				if (FLOAT_GT(rightLower, intervalsUpper[i2].lower))
 					rightLower = intervalsUpper[i2].lower;
 				i2--;
 			}
 			if (i2 < 0)
 				break;
 			leftUpper = intervalsUpper[i2].upper;
 
 			/*
 			 * Find count of intervals which anyway should be placed to the
 			 * right group.
 			 */
-			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
+			while (i1 >= 0 && FLOAT_GE(intervalsLower[i1].lower, rightLower))
 				i1--;
 
 			/*
 			 * Consider found split.
 			 */
 			g_box_consider_split(&context, dim,
 								 rightLower, i1 + 1, leftUpper, i2 + 1);
 		}
 	}
 
@@ -775,42 +767,42 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
 		{
 			lower = box->low.x;
 			upper = box->high.x;
 		}
 		else
 		{
 			lower = box->low.y;
 			upper = box->high.y;
 		}
 
-		if (FLOAT8_LE(upper, context.leftUpper))
+		if (FLOAT_LE(upper, context.leftUpper))
 		{
 			/* Fits to the left group */
-			if (FLOAT8_GE(lower, context.rightLower))
+			if (FLOAT_GE(lower, context.rightLower))
 			{
 				/* Fits also to the right group, so "common entry" */
 				commonEntries[commonEntriesCount++].index = i;
 			}
 			else
 			{
 				/* Doesn't fit to the right group, so join to the left group */
 				PLACE_LEFT(box, i);
 			}
 		}
 		else
 		{
 			/*
 			 * Each entry should fit on either left or right group. Since this
 			 * entry didn't fit on the left group, it better fit in the right
 			 * group.
 			 */
-			Assert(FLOAT8_GE(lower, context.rightLower));
+			Assert(FLOAT_GE(lower, context.rightLower));
 
 			/* Doesn't fit to the left group, so join to the right group */
 			PLACE_RIGHT(box, i);
 		}
 	}
 
 	/*
 	 * Distribute "common entries", if any.
 	 */
 	if (commonEntriesCount > 0)
@@ -880,24 +872,24 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
  * equivalent to box_same().
  */
 Datum
 gist_box_same(PG_FUNCTION_ARGS)
 {
 	BOX		   *b1 = PG_GETARG_BOX_P(0);
 	BOX		   *b2 = PG_GETARG_BOX_P(1);
 	bool	   *result = (bool *) PG_GETARG_POINTER(2);
 
 	if (b1 && b2)
-		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
-				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
-				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
-				   FLOAT8_EQ(b1->high.y, b2->high.y));
+		*result = (FLOAT_EQ(b1->low.x, b2->low.x) &&
+				   FLOAT_EQ(b1->low.y, b2->low.y) &&
+				   FLOAT_EQ(b1->high.x, b2->high.x) &&
+				   FLOAT_EQ(b1->high.y, b2->high.y));
 	else
 		*result = (b1 == NULL && b2 == NULL);
 	PG_RETURN_POINTER(result);
 }
 
 /*
  * Leaf-level consistency for boxes: just apply the query operator
  */
 static bool
 gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index fac166d..88f26d0 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -12,21 +12,21 @@
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <math.h>
 
 #include "access/gist_private.h"
 #include "access/reloptions.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 
 
 /*
  * Write itup vector to page, has no control of free space.
  */
 void
 gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
 {
 	OffsetNumber l = InvalidOffsetNumber;
 	int			i;
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 8aa17e1..5b69221 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -16,61 +16,24 @@
 
 #include <ctype.h>
 #include <float.h>
 #include <math.h>
 #include <limits.h>
 
 #include "catalog/pg_type.h"
 #include "libpq/pqformat.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/sortsupport.h"
 
 
-#ifndef M_PI
-/* from my RH5.2 gcc math.h file - thomas 2000-04-03 */
-#define M_PI 3.14159265358979323846
-#endif
-
-/* Radians per degree, a.k.a. PI / 180 */
-#define RADIANS_PER_DEGREE 0.0174532925199432957692
-
-/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
- */
-#if defined(WIN32) && !defined(NAN)
-static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
-
-#define NAN (*(const double *) nan)
-#endif
-
-/* not sure what the following should be, but better to make it over-sufficient */
-#define MAXFLOATWIDTH	64
-#define MAXDOUBLEWIDTH	128
-
-/*
- * check to see if a float4/8 val has underflowed or overflowed
- */
-#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
-do {															\
-	if (isinf(val) && !(inf_is_valid))							\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		  errmsg("value out of range: overflow")));				\
-																\
-	if ((val) == 0.0 && !(zero_is_valid))						\
-		ereport(ERROR,											\
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
-		 errmsg("value out of range: underflow")));				\
-} while(0)
-
-
 /* Configurable GUC parameter */
 int			extra_float_digits = 0;		/* Added to DBL_DIG or FLT_DIG */
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
 static float8 sin_30 = 0;
 static float8 one_minus_cos_60 = 0;
 static float8 asin_0_5 = 0;
 static float8 acos_0_5 = 0;
 static float8 atan_1_0 = 0;
@@ -689,35 +652,35 @@ float4up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT4(arg);
 }
 
 Datum
 float4larger(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) > 0)
+	if (FLOAT_GT(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4smaller(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (float4_cmp_internal(arg1, arg2) < 0)
+	if (FLOAT_LT(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		======================
  *		FLOAT8 BASE OPERATIONS
  *		======================
@@ -756,35 +719,35 @@ float8up(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(arg);
 }
 
 Datum
 float8larger(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) > 0)
+	if (FLOAT_GT(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8smaller(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (float8_cmp_internal(arg1, arg2) < 0)
+	if (FLOAT_LT(arg1, arg2))
 		result = arg1;
 	else
 		result = arg2;
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		ARITHMETIC OPERATORS
@@ -797,232 +760,188 @@ float8smaller(PG_FUNCTION_ARGS)
  *		float4mul		- returns arg1 * arg2
  *		float4div		- returns arg1 / arg2
  */
 Datum
 float4pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	result = arg1 + arg2;
+	FLOAT_PL(result, arg1, arg2);
 
-	/*
-	 * There isn't any way to check for underflow of addition/subtraction
-	 * because numbers near the underflow value have already been rounded to
-	 * the point where we can't detect that the two values were originally
-	 * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
-	 * 1.4013e-45.
-	 */
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
+	FLOAT_MI(result, arg1, arg2);
+
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
+	FLOAT_MUL(result, arg1, arg2);
+
 	PG_RETURN_FLOAT4(result);
 }
 
 Datum
 float4div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float4		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	FLOAT_DIV(result, arg1, arg2);
 
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT4(result);
 }
 
 /*
  *		float8pl		- returns arg1 + arg2
  *		float8mi		- returns arg1 - arg2
  *		float8mul		- returns arg1 * arg2
  *		float8div		- returns arg1 / arg2
  */
 Datum
 float8pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	result = arg1 + arg2;
+	FLOAT_PL(result, arg1, arg2);
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	result = arg1 - arg2;
+	FLOAT_MI(result, arg1, arg2);
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	result = arg1 * arg2;
+	FLOAT_MUL(result, arg1, arg2);
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float8div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	FLOAT_DIV(result, arg1, arg2);
 
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
  */
 int
 float4_cmp_internal(float4 a, float4 b)
 {
-	/*
-	 * 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.
-	 */
-	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 */
-	}
+	if (FLOAT_GT(a, b))
+		return 1;
+	else if (FLOAT_LT(a, b))
+		return -1;
 	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+		return 0;
 }
 
 Datum
 float4eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(FLOAT_EQ(arg1, arg2));
 }
 
 Datum
 float4ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(FLOAT_NE(arg1, arg2));
 }
 
 Datum
 float4lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(FLOAT_LT(arg1, arg2));
 }
 
 Datum
 float4le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(FLOAT_LE(arg1, arg2));
 }
 
 Datum
 float4gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(FLOAT_GT(arg1, arg2));
 }
 
 Datum
 float4ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(FLOAT_GE(arg1, arg2));
 }
 
 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));
 }
@@ -1044,99 +963,80 @@ btfloat4sortsupport(PG_FUNCTION_ARGS)
 	ssup->comparator = btfloat4fastcmp;
 	PG_RETURN_VOID();
 }
 
 /*
  *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
  */
 int
 float8_cmp_internal(float8 a, float8 b)
 {
-	/*
-	 * 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.
-	 */
-	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 */
-	}
+	if (FLOAT_GT(a, b))
+		return 1;
+	else if (FLOAT_LT(a, b))
+		return -1;
 	else
-	{
-		if (a > b)
-			return 1;
-		else if (a < b)
-			return -1;
-		else
-			return 0;
-	}
+		return 0;
 }
 
 Datum
 float8eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(FLOAT_EQ(arg1, arg2));
 }
 
 Datum
 float8ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(FLOAT_NE(arg1, arg2));
 }
 
 Datum
 float8lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(FLOAT_LT(arg1, arg2));
 }
 
 Datum
 float8le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(FLOAT_LE(arg1, arg2));
 }
 
 Datum
 float8gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(FLOAT_GT(arg1, arg2));
 }
 
 Datum
 float8ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(FLOAT_GE(arg1, arg2));
 }
 
 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));
 }
@@ -2369,23 +2269,22 @@ dtand(PG_FUNCTION_ARGS)
 
 /*
  *		degrees		- returns degrees converted from radians
  */
 Datum
 degrees(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
-	result = arg1 / RADIANS_PER_DEGREE;
+	FLOAT_DIV(result, arg1, RADIANS_PER_DEGREE);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		dpi				- returns the constant PI
  */
 Datum
 dpi(PG_FUNCTION_ARGS)
 {
@@ -2395,23 +2294,22 @@ dpi(PG_FUNCTION_ARGS)
 
 /*
  *		radians		- returns radians converted from degrees
  */
 Datum
 radians(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float8		result;
 
-	result = arg1 * RADIANS_PER_DEGREE;
+	FLOAT_MUL(result, arg1, RADIANS_PER_DEGREE);
 
-	CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 
 /*
  *		drandom		- returns a random number
  */
 Datum
 drandom(PG_FUNCTION_ARGS)
 {
@@ -2498,61 +2396,49 @@ float8_combine(PG_FUNCTION_ARGS)
 	float8	   *transvalues1;
 	float8	   *transvalues2;
 	float8		N,
 				sumX,
 				sumX2;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_combine", 3);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-
 	transvalues2 = check_float8_array(transarray2, "float8_combine", 3);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
+	N = transvalues1[0] + transvalues2[0];
+	FLOAT_PL(sumX, transvalues1[1], transvalues2[1]);
+	FLOAT_PL(sumX2, transvalues1[2], transvalues2[2]);
 
 	transvalues1[0] = N;
 	transvalues1[1] = sumX;
 	transvalues1[2] = sumX2;
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
 
 Datum
 float8_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 	float8		newval = PG_GETARG_FLOAT8(1);
 	float8	   *transvalues;
 	float8		N,
+				newval2,
 				sumX,
 				sumX2;
 
 	transvalues = check_float8_array(transarray, "float8_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
+	N = transvalues[0] + 1.0;
+	FLOAT_PL(sumX, transvalues[1], newval);
+	FLOAT_MUL(newval2, newval, newval);
+	FLOAT_PL(sumX2, transvalues[2], newval2);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2579,33 +2465,29 @@ float8_accum(PG_FUNCTION_ARGS)
 
 Datum
 float4_accum(PG_FUNCTION_ARGS)
 {
 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
 
 	/* do computations as float8 */
 	float8		newval = PG_GETARG_FLOAT4(1);
 	float8	   *transvalues;
 	float8		N,
+				newval2,
 				sumX,
 				sumX2;
 
 	transvalues = check_float8_array(transarray, "float4_accum", 3);
-	N = transvalues[0];
-	sumX = transvalues[1];
-	sumX2 = transvalues[2];
-
-	N += 1.0;
-	sumX += newval;
-	CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newval), true);
-	sumX2 += newval * newval;
-	CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newval), true);
+	N = transvalues[0] + 1.0;
+	FLOAT_PL(sumX, transvalues[1], newval);
+	FLOAT_MUL(newval2, newval, newval);
+	FLOAT_PL(sumX2, transvalues[2], newval2);
 
 	/*
 	 * If we're invoked as an aggregate, we can cheat and modify our first
 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
 	 * new array with the updated transition data and return it.
 	 */
 	if (AggCheckCallContext(fcinfo, NULL))
 	{
 		transvalues[0] = N;
 		transvalues[1] = sumX;
@@ -2872,45 +2754,28 @@ float8_regr_combine(PG_FUNCTION_ARGS)
 				sumX,
 				sumX2,
 				sumY,
 				sumY2,
 				sumXY;
 
 	if (!AggCheckCallContext(fcinfo, NULL))
 		elog(ERROR, "aggregate function called in non-aggregate context");
 
 	transvalues1 = check_float8_array(transarray1, "float8_regr_combine", 6);
-	N = transvalues1[0];
-	sumX = transvalues1[1];
-	sumX2 = transvalues1[2];
-	sumY = transvalues1[3];
-	sumY2 = transvalues1[4];
-	sumXY = transvalues1[5];
-
 	transvalues2 = check_float8_array(transarray2, "float8_regr_combine", 6);
 
-	N += transvalues2[0];
-	sumX += transvalues2[1];
-	CHECKFLOATVAL(sumX, isinf(transvalues1[1]) || isinf(transvalues2[1]),
-				  true);
-	sumX2 += transvalues2[2];
-	CHECKFLOATVAL(sumX2, isinf(transvalues1[2]) || isinf(transvalues2[2]),
-				  true);
-	sumY += transvalues2[3];
-	CHECKFLOATVAL(sumY, isinf(transvalues1[3]) || isinf(transvalues2[3]),
-				  true);
-	sumY2 += transvalues2[4];
-	CHECKFLOATVAL(sumY2, isinf(transvalues1[4]) || isinf(transvalues2[4]),
-				  true);
-	sumXY += transvalues2[5];
-	CHECKFLOATVAL(sumXY, isinf(transvalues1[5]) || isinf(transvalues2[5]),
-				  true);
+	N = transvalues1[0] + transvalues2[0];
+	FLOAT_PL(sumX, transvalues1[1], transvalues2[1]);
+	FLOAT_PL(sumX2, transvalues1[2], transvalues2[2]);
+	FLOAT_PL(sumY, transvalues1[3], transvalues2[3]);
+	FLOAT_PL(sumY2, transvalues1[4], transvalues2[4]);
+	FLOAT_PL(sumXY, transvalues1[5], transvalues2[5]);
 
 	transvalues1[0] = N;
 	transvalues1[1] = sumX;
 	transvalues1[2] = sumX2;
 	transvalues1[3] = sumY;
 	transvalues1[4] = sumY2;
 	transvalues1[5] = sumXY;
 
 	PG_RETURN_ARRAYTYPE_P(transarray1);
 }
@@ -3265,249 +3130,233 @@ float8_regr_intercept(PG_FUNCTION_ARGS)
  *		float48mul		- returns arg1 * arg2
  *		float48div		- returns arg1 / arg2
  */
 Datum
 float48pl(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	result = arg1 + arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
+	FLOAT_PL(result, arg1, arg2);
+
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float48mi(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	result = arg1 - arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
+	FLOAT_MI(result, arg1, arg2);
+
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float48mul(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	result = arg1 * arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
+	FLOAT_MUL(result, arg1, arg2);
+
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float48div(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	FLOAT_DIV(result, arg1, arg2);
 
-	result = arg1 / arg2;
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  *		float84pl		- returns arg1 + arg2
  *		float84mi		- returns arg1 - arg2
  *		float84mul		- returns arg1 * arg2
  *		float84div		- returns arg1 / arg2
  */
 Datum
 float84pl(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float8		result;
 
-	result = arg1 + arg2;
+	FLOAT_PL(result, arg1, arg2);
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float84mi(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float8		result;
 
-	result = arg1 - arg2;
+	FLOAT_MI(result, arg1, arg2);
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float84mul(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float8		result;
 
-	result = arg1 * arg2;
+	FLOAT_MUL(result, arg1, arg2);
 
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
-				  arg1 == 0 || arg2 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 Datum
 float84div(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 	float8		result;
 
-	if (arg2 == 0.0)
-		ereport(ERROR,
-				(errcode(ERRCODE_DIVISION_BY_ZERO),
-				 errmsg("division by zero")));
+	FLOAT_DIV(result, arg1, arg2);
 
-	result = arg1 / arg2;
-
-	CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
 	PG_RETURN_FLOAT8(result);
 }
 
 /*
  *		====================
  *		COMPARISON OPERATORS
  *		====================
  */
 
 /*
  *		float48{eq,ne,lt,le,gt,ge}		- float4/float8 comparison operations
  */
 Datum
 float48eq(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(FLOAT_EQ(arg1, arg2));
 }
 
 Datum
 float48ne(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(FLOAT_NE(arg1, arg2));
 }
 
 Datum
 float48lt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(FLOAT_LT(arg1, arg2));
 }
 
 Datum
 float48le(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(FLOAT_LE(arg1, arg2));
 }
 
 Datum
 float48gt(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(FLOAT_GT(arg1, arg2));
 }
 
 Datum
 float48ge(PG_FUNCTION_ARGS)
 {
 	float4		arg1 = PG_GETARG_FLOAT4(0);
 	float8		arg2 = PG_GETARG_FLOAT8(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(FLOAT_GE(arg1, arg2));
 }
 
 /*
  *		float84{eq,ne,lt,le,gt,ge}		- float8/float4 comparison operations
  */
 Datum
 float84eq(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+	PG_RETURN_BOOL(FLOAT_EQ(arg1, arg2));
 }
 
 Datum
 float84ne(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+	PG_RETURN_BOOL(FLOAT_NE(arg1, arg2));
 }
 
 Datum
 float84lt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+	PG_RETURN_BOOL(FLOAT_LT(arg1, arg2));
 }
 
 Datum
 float84le(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+	PG_RETURN_BOOL(FLOAT_LE(arg1, arg2));
 }
 
 Datum
 float84gt(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+	PG_RETURN_BOOL(FLOAT_GT(arg1, arg2));
 }
 
 Datum
 float84ge(PG_FUNCTION_ARGS)
 {
 	float8		arg1 = PG_GETARG_FLOAT8(0);
 	float4		arg2 = PG_GETARG_FLOAT4(1);
 
-	PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+	PG_RETURN_BOOL(FLOAT_GE(arg1, arg2));
 }
 
 /*
  * Implements the float8 version of the width_bucket() function
  * defined by SQL2003. See also width_bucket_numeric().
  *
  * 'bound1' and 'bound2' are the lower and upper bounds of the
  * histogram's range, respectively. 'count' is the number of buckets
  * in the histogram. width_bucket() returns an integer indicating the
  * bucket number that 'operand' belongs to in an equiwidth histogram
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index ae93fe0..fde2749 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -80,20 +80,21 @@
 #endif
 #ifdef HAVE_WCTYPE_H
 #include <wctype.h>
 #endif
 
 #include "catalog/pg_collation.h"
 #include "mb/pg_wchar.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 #include "utils/formatting.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/pg_locale.h"
 
 /* ----------
  * Routines type
  * ----------
  */
 #define DCH_TYPE		1		/* DATE-TIME version	*/
@@ -106,27 +107,20 @@
 #define KeyWord_INDEX_SIZE		('~' - ' ')
 #define KeyWord_INDEX_FILTER(_c)	((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
 /* ----------
  * Maximal length of one node
  * ----------
  */
 #define DCH_MAX_ITEM_SIZ	   12		/* max localized day name		*/
 #define NUM_MAX_ITEM_SIZ		8		/* roman number (RN has 15 chars)	*/
 
-/* ----------
- * More is in float.c
- * ----------
- */
-#define MAXFLOATWIDTH	60
-#define MAXDOUBLEWIDTH	500
-
 
 /* ----------
  * Format parser structs
  * ----------
  */
 typedef struct
 {
 	char	   *name;			/* suffix string		*/
 	int			len,			/* suffix length		*/
 				id,				/* used in node->suffix */
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index 0dff40d..efc81ab 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -14,27 +14,23 @@
  */
 #include "postgres.h"
 
 #include <math.h>
 #include <limits.h>
 #include <float.h>
 #include <ctype.h>
 
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
 
 /*
  * Internal routines
  */
 
 enum path_delim
 {
 	PATH_NONE, PATH_OPEN, PATH_CLOSED
 };
 
diff --git a/src/backend/utils/adt/geo_spgist.c b/src/backend/utils/adt/geo_spgist.c
index 0190156..565a034 100644
--- a/src/backend/utils/adt/geo_spgist.c
+++ b/src/backend/utils/adt/geo_spgist.c
@@ -69,21 +69,21 @@
  *			src/backend/utils/adt/geo_spgist.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
 #include "access/spgist.h"
 #include "access/stratnum.h"
 #include "catalog/pg_type.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/geo_decls.h"
 
 /*
  * Comparator for qsort
  *
  * We don't need to use the floating point macros in here, because this
  * is going only going to be used in a place to effect the performance
  * of the index, not the correctness.
  */
 static int
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 2fbdfe0..6442374 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,20 +28,21 @@
 
 #include "access/hash.h"
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/guc.h"
 #include "utils/int8.h"
 #include "utils/numeric.h"
 #include "utils/sortsupport.h"
 
 /* ----------
  * Uncomment the following to enable compilation of dump_numeric()
  * and dump_var() and to get a dump of any result produced by make_result().
  * ----------
 #define NUMERIC_DEBUG
diff --git a/src/backend/utils/adt/rangetypes_gist.c b/src/backend/utils/adt/rangetypes_gist.c
index 01cd234..71dc12e 100644
--- a/src/backend/utils/adt/rangetypes_gist.c
+++ b/src/backend/utils/adt/rangetypes_gist.c
@@ -9,21 +9,21 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_gist.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/gist.h"
 #include "access/stratnum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/datum.h"
 #include "utils/rangetypes.h"
 
 
 /*
  * Range class properties used to segregate different classes of ranges in
  * GiST.  Each unique combination of properties is a class.  CLS_EMPTY cannot
  * be combined with anything else.
  */
 #define CLS_NORMAL			0	/* Ordinary finite range (no bits set) */
diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c
index 8595d41..2e79ec7 100644
--- a/src/backend/utils/adt/rangetypes_selfuncs.c
+++ b/src/backend/utils/adt/rangetypes_selfuncs.c
@@ -13,21 +13,21 @@
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_selfuncs.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/htup_details.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 #include "utils/selfuncs.h"
 #include "utils/typcache.h"
 
 static double calc_rangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
 			  RangeType *constval, Oid operator);
 static double default_range_selectivity(Oid operator);
 static double calc_hist_selectivity(TypeCacheEntry *typcache,
 					  VariableStatData *vardata, RangeType *constval,
diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c
index fcb71d3..eca3807 100644
--- a/src/backend/utils/adt/rangetypes_typanalyze.c
+++ b/src/backend/utils/adt/rangetypes_typanalyze.c
@@ -19,21 +19,21 @@
  *
  * IDENTIFICATION
  *	  src/backend/utils/adt/rangetypes_typanalyze.c
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
 #include "commands/vacuum.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
 #include "utils/lsyscache.h"
 #include "utils/rangetypes.h"
 
 static int	float8_qsort_cmp(const void *a1, const void *a2);
 static int	range_bound_qsort_cmp(const void *a1, const void *a2, void *arg);
 static void compute_range_stats(VacAttrStats *stats,
 		   AnalyzeAttrFetchFunc fetchfunc, int samplerows, double totalrows);
 
 /*
  * range_typanalyze -- typanalyze function for range columns
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index d7ee865..062e041 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -26,20 +26,21 @@
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "parser/scansup.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/datetime.h"
+#include "utils/float.h"
 
 /*
  * gcc's -ffast-math switch breaks routines that expect exact results from
  * expressions like timeval / SECS_PER_HOUR, where timeval is double.
  */
 #ifdef __FAST_MATH__
 #error -ffast-math is known to break this code
 #endif
 
 #define SAMESIGN(a,b)	(((a) < 0) == ((b) < 0))
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6ac5184..46bbf3b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -67,20 +67,21 @@
 #include "storage/standby.h"
 #include "storage/fd.h"
 #include "storage/pg_shmem.h"
 #include "storage/proc.h"
 #include "storage/predicate.h"
 #include "tcop/tcopprot.h"
 #include "tsearch/ts_cache.h"
 #include "utils/builtins.h"
 #include "utils/bytea.h"
 #include "utils/guc_tables.h"
+#include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
 #include "utils/rls.h"
 #include "utils/snapmgr.h"
 #include "utils/tzparser.h"
 #include "utils/xml.h"
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 8cebc86..159fc09 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -329,33 +329,20 @@ extern Datum bttextsortsupport(PG_FUNCTION_ARGS);
  */
 extern Datum btint2sortsupport(PG_FUNCTION_ARGS);
 extern Datum btint4sortsupport(PG_FUNCTION_ARGS);
 extern Datum btint8sortsupport(PG_FUNCTION_ARGS);
 extern Datum btfloat4sortsupport(PG_FUNCTION_ARGS);
 extern Datum btfloat8sortsupport(PG_FUNCTION_ARGS);
 extern Datum btoidsortsupport(PG_FUNCTION_ARGS);
 extern Datum btnamesortsupport(PG_FUNCTION_ARGS);
 
 /* float.c */
-extern PGDLLIMPORT int extra_float_digits;
-
-extern double get_float8_infinity(void);
-extern float get_float4_infinity(void);
-extern double get_float8_nan(void);
-extern float get_float4_nan(void);
-extern int	is_infinite(double val);
-extern double float8in_internal(char *num, char **endptr_p,
-				  const char *type_name, const char *orig_string);
-extern char *float8out_internal(double num);
-extern int	float4_cmp_internal(float4 a, float4 b);
-extern int	float8_cmp_internal(float8 a, float8 b);
-
 extern Datum float4in(PG_FUNCTION_ARGS);
 extern Datum float4out(PG_FUNCTION_ARGS);
 extern Datum float4recv(PG_FUNCTION_ARGS);
 extern Datum float4send(PG_FUNCTION_ARGS);
 extern Datum float8in(PG_FUNCTION_ARGS);
 extern Datum float8out(PG_FUNCTION_ARGS);
 extern Datum float8recv(PG_FUNCTION_ARGS);
 extern Datum float8send(PG_FUNCTION_ARGS);
 extern Datum float4abs(PG_FUNCTION_ARGS);
 extern Datum float4um(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
new file mode 100644
index 0000000..4eacd56
--- /dev/null
+++ b/src/include/utils/float.h
@@ -0,0 +1,130 @@
+/*-------------------------------------------------------------------------
+ *
+ * float.h
+ *	  Definitions for the built-in floating-point types
+ *
+ * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/include/utils/float.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FLOAT_H
+#define FLOAT_H
+
+#ifndef M_PI
+/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
+#define M_PI 3.14159265358979323846
+#endif
+
+/* Radians per degree, a.k.a. PI / 180 */
+#define RADIANS_PER_DEGREE 0.0174532925199432957692
+
+/* Visual C++ etc lacks NAN, and won't accept 0.0/0.0.  NAN definition from
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrfNotNumberNANItems.asp
+ */
+#if defined(WIN32) && !defined(NAN)
+static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
+
+#define NAN (*(const double *) nan)
+#endif
+
+/*
+ * We are not sure what the following should be, but better to make it
+ * over-sufficient.
+ */
+#define MAXFLOATWIDTH	64
+#define MAXDOUBLEWIDTH	128
+
+/*
+ * Check to see if a float4/8 val has underflowed or overflowed
+ */
+#define CHECKFLOATVAL(val, inf_is_valid, zero_is_valid)			\
+do {															\
+	if (isinf(val) && !(inf_is_valid))							\
+		ereport(ERROR,											\
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
+		  errmsg("value out of range: overflow")));				\
+																\
+	if ((val) == 0.0 && !(zero_is_valid))						\
+		ereport(ERROR,											\
+				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),	\
+		 errmsg("value out of range: underflow")));				\
+} while(0)
+
+/*
+ * Convenience macros for operations with checking
+ *
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have already been rounded to
+ * the point where we can't detect that the two values were originally
+ * different, e.g. on x86, '1e-45'::float4 == '2e-45'::float4 ==
+ * 1.4013e-45.
+ */
+#define FLOAT_PL(result, val1, val2)							\
+do {															\
+	result = (val1) + (val2);									\
+	CHECKFLOATVAL(result, isinf(val1) || isinf(val2), true);	\
+} while(0)
+
+#define FLOAT_MI(result, val1, val2)							\
+do {															\
+	result = (val1) - (val2);									\
+	CHECKFLOATVAL(result, isinf(val1) || isinf(val2), true);	\
+} while(0)
+
+#define FLOAT_MUL(result, val1, val2)							\
+do {															\
+	result = (val1) * (val2);									\
+	CHECKFLOATVAL(result, isinf(val1) || isinf(val2),			\
+				  (val1) == 0.0 || (val2) == 0.0);				\
+} while(0)
+
+#define FLOAT_DIV(result, val1, val2)							\
+do {															\
+	if (val2 == 0.0)											\
+		ereport(ERROR,											\
+				(errcode(ERRCODE_DIVISION_BY_ZERO),				\
+				 errmsg("division by zero")));					\
+																\
+	result = (val1) / (val2);									\
+	CHECKFLOATVAL(result, isinf(val1) || isinf(val2),			\
+				  (val1) == 0.0);								\
+} while(0)
+
+/*
+ * Convenience macros for NaN-aware comparisons
+ *
+ * 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.
+ */
+#define FLOAT_EQ(a, b)	(isnan(a) ? isnan(b) : !isnan(b) && (a) == (b))
+#define FLOAT_NE(a, b)	(isnan(a) ? !isnan(b) : isnan(b) || (a) != (b))
+#define FLOAT_LT(a, b)	(!isnan(a) && (isnan(b) || (a) < (b)))
+#define FLOAT_LE(a, b)	(isnan(b) || (!isnan(a) && (a) <= (b)))
+#define FLOAT_GT(a, b)	(!isnan(b) && (isnan(a) || (a) > (b)))
+#define FLOAT_GE(a, b)	(isnan(a) || (!isnan(b) && (a) >= (b)))
+#define FLOAT_MAX(a, b)	(FLOAT_GT(a, b) ? (a) : (b))
+#define FLOAT_MIN(a, b)	(FLOAT_LT(a, b) ? (a) : (b))
+
+extern PGDLLIMPORT int extra_float_digits;
+
+/*
+ * Utility functions in float.c
+ */
+extern float get_float4_infinity(void);
+extern double get_float8_infinity(void);
+extern float get_float4_nan(void);
+extern double get_float8_nan(void);
+extern int  is_infinite(double val);
+extern double float8in_internal(char *num, char **endptr_p,
+							const char *type_name, const char *orig_string);
+extern char *float8out_internal(double num);
+extern int	float4_cmp_internal(float4 a, float4 b);
+extern int	float8_cmp_internal(float8 a, float8 b);
+
+#endif   /* FLOAT_H */
-- 
2.7.4 (Apple Git-66)

