diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c
index e8213e2..d47211a 100644
*** a/src/backend/access/gist/gistproc.c
--- b/src/backend/access/gist/gistproc.c
***************
*** 17,36 ****
   */
  #include "postgres.h"
  
  #include "access/gist.h"
  #include "access/stratnum.h"
  #include "utils/geo_decls.h"
  
  
  static bool gist_box_leaf_consistent(BOX *key, BOX *query,
  						 StrategyNumber strategy);
- static double size_box(BOX *box);
  static bool rtree_internal_consistent(BOX *key, BOX *query,
  						  StrategyNumber strategy);
  
  /* Minimum accepted ratio of split */
  #define LIMIT_RATIO 0.3
  
  
  /**************************************************
   * Box ops
--- 17,47 ----
   */
  #include "postgres.h"
  
+ #include <math.h>
+ 
  #include "access/gist.h"
  #include "access/stratnum.h"
+ #include "utils/builtins.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
*************** static bool rtree_internal_consistent(BO
*** 40,51 ****
   * Calculates union of two boxes, a and b. The result is stored in *n.
   */
  static void
! rt_box_union(BOX *n, BOX *a, BOX *b)
  {
! 	n->high.x = Max(a->high.x, b->high.x);
! 	n->high.y = Max(a->high.y, b->high.y);
! 	n->low.x = Min(a->low.x, b->low.x);
! 	n->low.y = Min(a->low.y, b->low.y);
  }
  
  /*
--- 51,103 ----
   * 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);
! }
! 
! /*
!  * 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))
! 		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);
! }
! 
! /*
!  * Return amount by which the union of the two boxes is larger than
!  * the original BOX's area.  The result can be +Infinity, but not NaN.
!  */
! static double
! box_penalty(const BOX *original, const BOX *new)
! {
! 	BOX			unionbox;
! 
! 	rt_box_union(&unionbox, original, new);
! 	return size_box(&unionbox) - size_box(original);
  }
  
  /*
*************** gist_box_consistent(PG_FUNCTION_ARGS)
*** 85,100 ****
  												 strategy));
  }
  
  static void
! adjustBox(BOX *b, BOX *addon)
  {
! 	if (b->high.x < addon->high.x)
  		b->high.x = addon->high.x;
! 	if (b->low.x > addon->low.x)
  		b->low.x = addon->low.x;
! 	if (b->high.y < addon->high.y)
  		b->high.y = addon->high.y;
! 	if (b->low.y > addon->low.y)
  		b->low.y = addon->low.y;
  }
  
--- 137,155 ----
  												 strategy));
  }
  
+ /*
+  * Increase BOX b to include addon.
+  */
  static void
! adjustBox(BOX *b, const BOX *addon)
  {
! 	if (FLOAT8_LT(b->high.x, addon->high.x))
  		b->high.x = addon->high.x;
! 	if (FLOAT8_GT(b->low.x, addon->low.x))
  		b->low.x = addon->low.x;
! 	if (FLOAT8_LT(b->high.y, addon->high.y))
  		b->high.y = addon->high.y;
! 	if (FLOAT8_GT(b->low.y, addon->low.y))
  		b->low.y = addon->low.y;
  }
  
*************** gist_box_penalty(PG_FUNCTION_ARGS)
*** 174,183 ****
  	float	   *result = (float *) PG_GETARG_POINTER(2);
  	BOX		   *origbox = DatumGetBoxP(origentry->key);
  	BOX		   *newbox = DatumGetBoxP(newentry->key);
- 	BOX			unionbox;
  
! 	rt_box_union(&unionbox, origbox, newbox);
! 	*result = (float) (size_box(&unionbox) - size_box(origbox));
  	PG_RETURN_POINTER(result);
  }
  
--- 229,236 ----
  	float	   *result = (float *) PG_GETARG_POINTER(2);
  	BOX		   *origbox = DatumGetBoxP(origentry->key);
  	BOX		   *newbox = DatumGetBoxP(newentry->key);
  
! 	*result = (float) box_penalty(origbox, newbox);
  	PG_RETURN_POINTER(result);
  }
  
*************** interval_cmp_lower(const void *i1, const
*** 290,301 ****
  	double		lower1 = ((const SplitInterval *) i1)->lower,
  				lower2 = ((const SplitInterval *) i2)->lower;
  
! 	if (lower1 < lower2)
! 		return -1;
! 	else if (lower1 > lower2)
! 		return 1;
! 	else
! 		return 0;
  }
  
  /*
--- 343,349 ----
  	double		lower1 = ((const SplitInterval *) i1)->lower,
  				lower2 = ((const SplitInterval *) i2)->lower;
  
! 	return float8_cmp_internal(lower1, lower2);
  }
  
  /*
*************** interval_cmp_upper(const void *i1, const
*** 307,322 ****
  	double		upper1 = ((const SplitInterval *) i1)->upper,
  				upper2 = ((const SplitInterval *) i2)->upper;
  
! 	if (upper1 < upper2)
! 		return -1;
! 	else if (upper1 > upper2)
! 		return 1;
! 	else
! 		return 0;
  }
  
  /*
!  * Replace negative value with zero.
   */
  static inline float
  non_negative(float val)
--- 355,365 ----
  	double		upper1 = ((const SplitInterval *) i1)->upper,
  				upper2 = ((const SplitInterval *) i2)->upper;
  
! 	return float8_cmp_internal(upper1, upper2);
  }
  
  /*
!  * Replace negative (or NaN) value with zero.
   */
  static inline float
  non_negative(float val)
*************** g_box_consider_split(ConsiderSplitContex
*** 436,459 ****
  }
  
  /*
-  * Return increase of original BOX area by new BOX area insertion.
-  */
- static double
- box_penalty(BOX *original, BOX *new)
- {
- 	double		union_width,
- 				union_height;
- 
- 	union_width = Max(original->high.x, new->high.x) -
- 		Min(original->low.x, new->low.x);
- 	union_height = Max(original->high.y, new->high.y) -
- 		Min(original->low.y, new->low.y);
- 	return union_width * union_height - (original->high.x - original->low.x) *
- 		(original->high.y - original->low.y);
- }
- 
- /*
   * Compare common entries by their deltas.
   */
  static int
  common_entry_cmp(const void *i1, const void *i2)
--- 479,486 ----
  }
  
  /*
   * Compare common entries by their deltas.
+  * (We assume the deltas can't be NaN.)
   */
  static int
  common_entry_cmp(const void *i1, const void *i2)
*************** gist_box_picksplit(PG_FUNCTION_ARGS)
*** 615,623 ****
  			/*
  			 * Find next lower bound of right group.
  			 */
! 			while (i1 < nentries && rightLower == intervalsLower[i1].lower)
  			{
! 				leftUpper = Max(leftUpper, intervalsLower[i1].upper);
  				i1++;
  			}
  			if (i1 >= nentries)
--- 642,652 ----
  			/*
  			 * Find next lower bound of right group.
  			 */
! 			while (i1 < nentries &&
! 				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
  			{
! 				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
! 					leftUpper = intervalsLower[i1].upper;
  				i1++;
  			}
  			if (i1 >= nentries)
*************** gist_box_picksplit(PG_FUNCTION_ARGS)
*** 628,634 ****
  			 * Find count of intervals which anyway should be placed to the
  			 * left group.
  			 */
! 			while (i2 < nentries && intervalsUpper[i2].upper <= leftUpper)
  				i2++;
  
  			/*
--- 657,664 ----
  			 * Find count of intervals which anyway should be placed to the
  			 * left group.
  			 */
! 			while (i2 < nentries &&
! 				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
  				i2++;
  
  			/*
*************** gist_box_picksplit(PG_FUNCTION_ARGS)
*** 650,658 ****
  			/*
  			 * Find next upper bound of left group.
  			 */
! 			while (i2 >= 0 && leftUpper == intervalsUpper[i2].upper)
  			{
! 				rightLower = Min(rightLower, intervalsUpper[i2].lower);
  				i2--;
  			}
  			if (i2 < 0)
--- 680,689 ----
  			/*
  			 * Find next upper bound of left group.
  			 */
! 			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
  			{
! 				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
! 					rightLower = intervalsUpper[i2].lower;
  				i2--;
  			}
  			if (i2 < 0)
*************** gist_box_picksplit(PG_FUNCTION_ARGS)
*** 663,669 ****
  			 * Find count of intervals which anyway should be placed to the
  			 * right group.
  			 */
! 			while (i1 >= 0 && intervalsLower[i1].lower >= rightLower)
  				i1--;
  
  			/*
--- 694,700 ----
  			 * Find count of intervals which anyway should be placed to the
  			 * right group.
  			 */
! 			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
  				i1--;
  
  			/*
*************** gist_box_picksplit(PG_FUNCTION_ARGS)
*** 751,760 ****
  			upper = box->high.y;
  		}
  
! 		if (upper <= context.leftUpper)
  		{
  			/* Fits to the left group */
! 			if (lower >= context.rightLower)
  			{
  				/* Fits also to the right group, so "common entry" */
  				commonEntries[commonEntriesCount++].index = i;
--- 782,791 ----
  			upper = box->high.y;
  		}
  
! 		if (FLOAT8_LE(upper, context.leftUpper))
  		{
  			/* Fits to the left group */
! 			if (FLOAT8_GE(lower, context.rightLower))
  			{
  				/* Fits also to the right group, so "common entry" */
  				commonEntries[commonEntriesCount++].index = i;
*************** gist_box_picksplit(PG_FUNCTION_ARGS)
*** 772,778 ****
  			 * entry didn't fit on the left group, it better fit in the right
  			 * group.
  			 */
! 			Assert(lower >= context.rightLower);
  
  			/* Doesn't fit to the left group, so join to the right group */
  			PLACE_RIGHT(box, i);
--- 803,809 ----
  			 * entry didn't fit on the left group, it better fit in the right
  			 * group.
  			 */
! 			Assert(FLOAT8_GE(lower, context.rightLower));
  
  			/* Doesn't fit to the left group, so join to the right group */
  			PLACE_RIGHT(box, i);
*************** gist_box_same(PG_FUNCTION_ARGS)
*** 856,863 ****
  	bool	   *result = (bool *) PG_GETARG_POINTER(2);
  
  	if (b1 && b2)
! 		*result = (b1->low.x == b2->low.x && b1->low.y == b2->low.y &&
! 				   b1->high.x == b2->high.x && b1->high.y == b2->high.y);
  	else
  		*result = (b1 == NULL && b2 == NULL);
  	PG_RETURN_POINTER(result);
--- 887,896 ----
  	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));
  	else
  		*result = (b1 == NULL && b2 == NULL);
  	PG_RETURN_POINTER(result);
*************** gist_box_leaf_consistent(BOX *key, BOX *
*** 943,956 ****
  	return retval;
  }
  
- static double
- size_box(BOX *box)
- {
- 	if (box->high.x <= box->low.x || box->high.y <= box->low.y)
- 		return 0.0;
- 	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
- }
- 
  /*****************************************
   * Common rtree functions (for boxes, polygons, and circles)
   *****************************************/
--- 976,981 ----
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index cdc5d52..8aa17e1 100644
*** a/src/backend/utils/adt/float.c
--- b/src/backend/utils/adt/float.c
*************** float8		degree_c_one_half = 0.5;
*** 90,97 ****
  float8		degree_c_one = 1.0;
  
  /* Local function prototypes */
- static int	float4_cmp_internal(float4 a, float4 b);
- static int	float8_cmp_internal(float8 a, float8 b);
  static double sind_q1(double x);
  static double cosd_q1(double x);
  static void init_degree_constants(void);
--- 90,95 ----
*************** float8div(PG_FUNCTION_ARGS)
*** 936,942 ****
  /*
   *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
   */
! static int
  float4_cmp_internal(float4 a, float4 b)
  {
  	/*
--- 934,940 ----
  /*
   *		float4{eq,ne,lt,le,gt,ge}		- float4/float4 comparison operations
   */
! int
  float4_cmp_internal(float4 a, float4 b)
  {
  	/*
*************** btfloat4sortsupport(PG_FUNCTION_ARGS)
*** 1050,1056 ****
  /*
   *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
   */
! static int
  float8_cmp_internal(float8 a, float8 b)
  {
  	/*
--- 1048,1054 ----
  /*
   *		float8{eq,ne,lt,le,gt,ge}		- float8/float8 comparison operations
   */
! int
  float8_cmp_internal(float8 a, float8 b)
  {
  	/*
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 01976a1..8cebc86 100644
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern int	is_infinite(double val);
*** 346,351 ****
--- 346,353 ----
  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);
