From 352234925472956e4fdc7f63732dbc0b6b151da6 Mon Sep 17 00:00:00 2001 From: Emre Hasegeli Date: Sat, 28 May 2016 18:16:05 +0200 Subject: [PATCH 1/2] float-header-v02 --- contrib/btree_gin/btree_gin.c | 1 + contrib/btree_gist/btree_ts.c | 2 +- contrib/cube/cube.c | 2 +- contrib/postgres_fdw/postgres_fdw.c | 1 + 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 | 315 +++++++------------------- 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 +++++++++++ 19 files changed, 250 insertions(+), 299 deletions(-) create mode 100644 src/include/utils/float.h diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c index 030b610..560ce85 100644 --- a/contrib/btree_gin/btree_gin.c +++ b/contrib/btree_gin/btree_gin.c @@ -3,20 +3,21 @@ */ #include "postgres.h" #include #include "access/stratnum.h" #include "utils/builtins.h" #include "utils/bytea.h" #include "utils/cash.h" #include "utils/date.h" +#include "utils/float.h" #include "utils/inet.h" #include "utils/numeric.h" #include "utils/timestamp.h" #include "utils/varbit.h" PG_MODULE_MAGIC; typedef struct QueryInfo { StrategyNumber strategy; diff --git a/contrib/btree_gist/btree_ts.c b/contrib/btree_gist/btree_ts.c index ab22b27..5fb0a9f 100644 --- a/contrib/btree_gist/btree_ts.c +++ b/contrib/btree_gist/btree_ts.c @@ -1,19 +1,19 @@ /* * contrib/btree_gist/btree_ts.c */ #include "postgres.h" #include "btree_gist.h" #include "btree_utils_num.h" -#include "utils/builtins.h" #include "utils/datetime.h" +#include "utils/float.h" typedef struct { Timestamp lower; Timestamp upper; } tsKEY; /* ** timestamp ops */ diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 3feddef..01335d9 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -7,21 +7,21 @@ ******************************************************************************/ #include "postgres.h" #include #include #include "access/gist.h" #include "access/stratnum.h" #include "utils/array.h" -#include "utils/builtins.h" +#include "utils/float.h" #include "cubedata.h" PG_MODULE_MAGIC; /* * Taken from the intarray contrib header */ #define ARRPTR(x) ( (double *) ARR_DATA_PTR(x) ) #define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index daf0438..0bd98a1 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -26,20 +26,21 @@ #include "nodes/nodeFuncs.h" #include "optimizer/cost.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" #include "optimizer/restrictinfo.h" #include "optimizer/var.h" #include "optimizer/tlist.h" #include "parser/parsetree.h" #include "utils/builtins.h" +#include "utils/float.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/rel.h" #include "utils/sampling.h" PG_MODULE_MAGIC; /* Default CPU cost to start up a foreign query. */ #define DEFAULT_FDW_STARTUP_COST 100.0 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 #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 887c58b..db9bea5 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -14,21 +14,21 @@ #include "postgres.h" #include #include "access/gist_private.h" #include "access/htup_details.h" #include "access/reloptions.h" #include "catalog/pg_opclass.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" -#include "utils/builtins.h" +#include "utils/float.h" #include "utils/syscache.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; diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 8aa17e1..d4bb818 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -16,61 +16,24 @@ #include #include #include #include #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,187 @@ 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 */ - } - else - { - if (a > b) - return 1; - else if (a < b) - return -1; - else - return 0; - } + if (FLOAT_GT(a, b)) + return 1; + if (FLOAT_LT(a, b)) + return -1; + 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 +962,79 @@ 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 */ - } - else - { - if (a > b) - return 1; - else if (a < b) - return -1; - else - return 0; - } + if (FLOAT_GT(a, b)) + return 1; + if (FLOAT_LT(a, b)) + return -1; + 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 +2267,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 +2292,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 +2394,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 +2463,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 +2752,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 +3128,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 bbd97dc..b67477f 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 #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 #include #include #include #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 384e672..ece1d4b 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 56504fc..69f6623 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 c1d6f05..792c32a 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 c5178f7..1b36555 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 2ae212a..22ba041 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -334,33 +334,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)