>autoconf check for IEEE 754 floats
Autoconf man says folowing:
>it is safe to assume IEEE-754 in most portable code these days
https://www.gnu.org/software/autoconf/manual/autoconf.html#Floating-Point-Portability

> A union might be more readable
Here is union version of the patch. It's slower 10% than original cube
and dereference version. Have no idea why.
Select performance is improved as in v3.

Also I've investigated a bit why linear package failed. It's usefull
to think in terms of bijections, not in terms of arithmetic functions.

float 1 is 1065353216 hex 3f800000
FLT_MAX / ( 8 >> 3 ) is 2139095039 hex 7f7fffff
FLT_MAX / ( 8 >> 2 ) is 2130706431 hex 7effffff
FLT_MAX / ( 8 >> 1 ) is 2122317823 hex 7e7fffff
FLT_MAX / ( 8 >> 0 ) is 2113929215 hex 7dffffff

This realm borders are completly wrong.
That maens I used 800 thousands values to pack 2billions of values of
realms 1-3, and all other 2.1 bils of values to pack realm 0. Fragile
arithmetics was done wrong.

What I had to use was
Realm 3
INT32_MAX is nan (or something little less than nan)
3*INT32_MAX/4 is 3.689348e+19
Total little less than 512kk different values

Realm 2
3*INT32_MAX/4 is 3.689348e+19
INT32_MAX/2 is 2.000000e+00
Total 512kk different values

Realm 1
INT32_MAX/2 is 2.000000e+00
INT32_MAX/4 is 1.084202e-19
Total 512kk different values

Realm 0
INT32_MAX/4 is 1.084202e-19
0 is 0.000000e+00
Total 512kk different values

Though I hadn't tested it yet. I'm not sure, BTW, hardcoding this
consts is a good idea.

Best regards, Andrey Borodin, Octonica & Ural Federal University.
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c
index 3feddef..ded639b 100644
--- a/contrib/cube/cube.c
+++ b/contrib/cube/cube.c
@@ -91,14 +91,16 @@ PG_FUNCTION_INFO_V1(cube_enlarge);
 /*
 ** For internal use only
 */
-int32          cube_cmp_v0(NDBOX *a, NDBOX *b);
-bool           cube_contains_v0(NDBOX *a, NDBOX *b);
-bool           cube_overlap_v0(NDBOX *a, NDBOX *b);
-NDBOX     *cube_union_v0(NDBOX *a, NDBOX *b);
-void           rt_cube_size(NDBOX *a, double *sz);
-NDBOX     *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
-bool           g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber 
strategy);
-bool           g_cube_internal_consistent(NDBOX *key, NDBOX *query, 
StrategyNumber strategy);
+static int32           cube_cmp_v0(NDBOX *a, NDBOX *b);
+static bool            cube_contains_v0(NDBOX *a, NDBOX *b);
+static bool            cube_overlap_v0(NDBOX *a, NDBOX *b);
+static NDBOX      *cube_union_v0(NDBOX *a, NDBOX *b);
+static float           pack_float(float actualValue, int realm);
+static void            rt_cube_size(NDBOX *a, double *sz);
+static void            rt_cube_edge(NDBOX *a, double *sz);
+static NDBOX      *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep);
+static bool            g_cube_leaf_consistent(NDBOX *key, NDBOX *query, 
StrategyNumber strategy);
+static bool            g_cube_internal_consistent(NDBOX *key, NDBOX *query, 
StrategyNumber strategy);
 
 /*
 ** Auxiliary funxtions
@@ -419,7 +421,32 @@ g_cube_decompress(PG_FUNCTION_ARGS)
        }
        PG_RETURN_POINTER(entry);
 }
+/*
+ * Function to pack floats of different realms
+ * This function serves to pack bit flags inside float type
+ * Resulted value represent can be from four different "realms"
+ * Every value from realm 3 is greater than any value from realms 2,1 and 0.
+ * Every value from realm 2 is less than every value from realm 3 and greater
+ * than any value from realm 1 and 0, and so on. Values from the same realm
+ * loose two bits of precision. This technique is possible due to floating
+ * point numbers specification according to IEEE 754: exponent bits are highest
+ * (excluding sign bits, but here penalty is always positive). If float a is
+ * greater than float b, integer A with same bit representation as a is greater
+ * than integer B with same bits as b.
+ */
+static float
+pack_float(float actualValue, int realm)
+{
+       union
+       {
+               float fp;
+               int32 bits;
+       } buffer;
 
+       buffer.fp = actualValue;
+       buffer.bits = (buffer.bits >> 2) + (INT32_MAX / 4) * realm;
+       return buffer.fp;
+}
 
 /*
 ** The GiST Penalty method for boxes
@@ -428,6 +455,11 @@ g_cube_decompress(PG_FUNCTION_ARGS)
 Datum
 g_cube_penalty(PG_FUNCTION_ARGS)
 {
+       /* REALM 0: No extension is required, volume is zero, return edge       
*/
+       /* REALM 1: No extension is required, return nonzero volume             
        */
+       /* REALM 2: Volume extension is zero, return nonzero edge extension     
*/
+       /* REALM 3: Volume extension is nonzero, return it                      
                */
+
        GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
        GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
        float      *result = (float *) PG_GETARG_POINTER(2);
@@ -441,9 +473,33 @@ g_cube_penalty(PG_FUNCTION_ARGS)
        rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2);
        *result = (float) (tmp1 - tmp2);
 
-       /*
-        * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result);
-        */
+       if( *result == 0 )
+       {
+               double tmp3 = tmp1; /* remember entry volume */
+               rt_cube_edge(ud, &tmp1);
+               rt_cube_edge(DatumGetNDBOX(origentry->key), &tmp2);
+               *result = (float) (tmp1 - tmp2);
+               if( *result == 0 )
+               {
+                       if( tmp3 != 0 )
+                       {
+                               *result = pack_float(tmp3, 1); /* REALM 1 */
+                       }
+                       else
+                       {
+                               *result = pack_float(tmp1, 0); /* REALM 0 */
+                       }
+               }
+               else
+               {
+                       *result = pack_float(*result, 2); /* REALM 2 */
+               }
+       }
+       else
+       {
+               *result = pack_float(*result, 3); /* REALM 3 */
+       }
+
        PG_RETURN_FLOAT8(*result);
 }
 
@@ -626,7 +682,7 @@ g_cube_same(PG_FUNCTION_ARGS)
 /*
 ** SUPPORT ROUTINES
 */
-bool
+static bool
 g_cube_leaf_consistent(NDBOX *key,
                                           NDBOX *query,
                                           StrategyNumber strategy)
@@ -658,7 +714,7 @@ g_cube_leaf_consistent(NDBOX *key,
        return (retval);
 }
 
-bool
+static bool
 g_cube_internal_consistent(NDBOX *key,
                                                   NDBOX *query,
                                                   StrategyNumber strategy)
@@ -688,7 +744,7 @@ g_cube_internal_consistent(NDBOX *key,
        return (retval);
 }
 
-NDBOX *
+static NDBOX *
 g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
 {
        NDBOX      *retval;
@@ -701,7 +757,7 @@ g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep)
 
 
 /* cube_union_v0 */
-NDBOX *
+static NDBOX *
 cube_union_v0(NDBOX *a, NDBOX *b)
 {
        int                     i;
@@ -875,25 +931,40 @@ cube_size(PG_FUNCTION_ARGS)
        PG_RETURN_FLOAT8(result);
 }
 
-void
+static void
 rt_cube_size(NDBOX *a, double *size)
 {
        int                     i;
+       double          result = 0;
 
-       if (a == (NDBOX *) NULL)
-               *size = 0.0;
-       else
+       if (a != (NDBOX *) NULL)
+       {
+               result = 1.0;
+               for (i = 0; i < DIM(a); i++)
+                       result *= UR_COORD(a, i) - LL_COORD(a, i);
+       }
+       *size = Abs(result);
+       return;
+}
+
+static void
+rt_cube_edge(NDBOX *a, double *size)
+{
+       int                     i;
+       double          result = 0;
+
+       if (a != (NDBOX *) NULL)
        {
-               *size = 1.0;
                for (i = 0; i < DIM(a); i++)
-                       *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i));
+                       result += Abs(UR_COORD(a, i) - LL_COORD(a, i));
        }
+       *size = result;
        return;
 }
 
 /* make up a metric in which one box will be 'lower' than the other
    -- this can be useful for sorting and to determine uniqueness */
-int32
+static int32
 cube_cmp_v0(NDBOX *a, NDBOX *b)
 {
        int                     i;
@@ -1080,7 +1151,7 @@ cube_ge(PG_FUNCTION_ARGS)
 
 /* Contains */
 /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */
-bool
+static bool
 cube_contains_v0(NDBOX *a, NDBOX *b)
 {
        int                     i;
@@ -1150,7 +1221,7 @@ cube_contained(PG_FUNCTION_ARGS)
 
 /* Overlap */
 /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */
-bool
+static bool
 cube_overlap_v0(NDBOX *a, NDBOX *b)
 {
        int                     i;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to