Provide separate header file for built-in float types
Some data types under adt/ have separate header files, but most simple ones do not, and their public functions are defined in builtins.h. As the patches improving geometric types will require making additional functions public, this seems like a good opportunity to create a header for floats types. Commit 1acf757255 made _cmp functions public to solve NaN issues locally for GiST indexes. This patch reworks it in favour of a more widely applicable API. The API uses inline functions, as they are easier to use compared to macros, and avoid double-evaluation hazards. Author: Emre Hasegeli Reviewed-by: Kyotaro Horiguchi Discussion: https://www.postgresql.org/message-id/CAE2gYzxF7-5djV6-cEvqQu-fNsnt%3DEqbOURx7ZDg%2BVv6ZMTWbg%40mail.gmail.com
This commit is contained in:
parent
a7dc63d904
commit
6bf0bc842b
@ -10,6 +10,7 @@
|
||||
#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"
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "btree_utils_num.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/datetime.h"
|
||||
#include "utils/float.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "access/gist.h"
|
||||
#include "access/stratnum.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
|
||||
#include "cubedata.h"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "cubedata.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
|
||||
/* All grammar constructs return strings */
|
||||
#define YYSTYPE char *
|
||||
|
@ -35,6 +35,7 @@
|
||||
#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"
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "storage/predicate.h"
|
||||
#include "pgstat.h"
|
||||
#include "lib/pairingheap.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "access/gist.h"
|
||||
#include "access/stratnum.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/geo_decls.h"
|
||||
|
||||
|
||||
@ -33,15 +34,6 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
|
||||
/* 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
|
||||
@ -53,10 +45,10 @@ static bool rtree_internal_consistent(BOX *key, BOX *query,
|
||||
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 = 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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -73,8 +65,8 @@ size_box(const BOX *box)
|
||||
*
|
||||
* 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 (float8_le(box->high.x, box->low.x) ||
|
||||
float8_le(box->high.y, box->low.y))
|
||||
return 0.0;
|
||||
|
||||
/*
|
||||
@ -143,13 +135,13 @@ gist_box_consistent(PG_FUNCTION_ARGS)
|
||||
static void
|
||||
adjustBox(BOX *b, const BOX *addon)
|
||||
{
|
||||
if (FLOAT8_LT(b->high.x, addon->high.x))
|
||||
if (float8_lt(b->high.x, addon->high.x))
|
||||
b->high.x = addon->high.x;
|
||||
if (FLOAT8_GT(b->low.x, addon->low.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))
|
||||
if (float8_lt(b->high.y, addon->high.y))
|
||||
b->high.y = addon->high.y;
|
||||
if (FLOAT8_GT(b->low.y, addon->low.y))
|
||||
if (float8_gt(b->low.y, addon->low.y))
|
||||
b->low.y = addon->low.y;
|
||||
}
|
||||
|
||||
@ -615,9 +607,9 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
* Find next lower bound of right group.
|
||||
*/
|
||||
while (i1 < nentries &&
|
||||
FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
|
||||
float8_eq(rightLower, intervalsLower[i1].lower))
|
||||
{
|
||||
if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
|
||||
if (float8_lt(leftUpper, intervalsLower[i1].upper))
|
||||
leftUpper = intervalsLower[i1].upper;
|
||||
i1++;
|
||||
}
|
||||
@ -630,7 +622,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
* left group.
|
||||
*/
|
||||
while (i2 < nentries &&
|
||||
FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
|
||||
float8_le(intervalsUpper[i2].upper, leftUpper))
|
||||
i2++;
|
||||
|
||||
/*
|
||||
@ -652,9 +644,9 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* Find next upper bound of left group.
|
||||
*/
|
||||
while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
|
||||
while (i2 >= 0 && float8_eq(leftUpper, intervalsUpper[i2].upper))
|
||||
{
|
||||
if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
|
||||
if (float8_gt(rightLower, intervalsUpper[i2].lower))
|
||||
rightLower = intervalsUpper[i2].lower;
|
||||
i2--;
|
||||
}
|
||||
@ -666,7 +658,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
* 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 && float8_ge(intervalsLower[i1].lower, rightLower))
|
||||
i1--;
|
||||
|
||||
/*
|
||||
@ -754,10 +746,10 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
upper = box->high.y;
|
||||
}
|
||||
|
||||
if (FLOAT8_LE(upper, context.leftUpper))
|
||||
if (float8_le(upper, context.leftUpper))
|
||||
{
|
||||
/* Fits to the left group */
|
||||
if (FLOAT8_GE(lower, context.rightLower))
|
||||
if (float8_ge(lower, context.rightLower))
|
||||
{
|
||||
/* Fits also to the right group, so "common entry" */
|
||||
commonEntries[commonEntriesCount++].index = i;
|
||||
@ -775,7 +767,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
|
||||
* entry didn't fit on the left group, it better fit in the right
|
||||
* group.
|
||||
*/
|
||||
Assert(FLOAT8_GE(lower, context.rightLower));
|
||||
Assert(float8_ge(lower, context.rightLower));
|
||||
|
||||
/* Doesn't fit to the left group, so join to the right group */
|
||||
PLACE_RIGHT(box, i);
|
||||
@ -859,10 +851,10 @@ gist_box_same(PG_FUNCTION_ARGS)
|
||||
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 = (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);
|
||||
|
@ -21,7 +21,7 @@
|
||||
#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"
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -91,6 +91,7 @@
|
||||
#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"
|
||||
|
@ -21,13 +21,10 @@
|
||||
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/fmgrprotos.h"
|
||||
#include "utils/geo_decls.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Internal routines
|
||||
|
@ -76,7 +76,8 @@
|
||||
#include "access/spgist.h"
|
||||
#include "access/stratnum.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/fmgrprotos.h"
|
||||
#include "utils/geo_decls.h"
|
||||
|
||||
/*
|
||||
|
@ -36,6 +36,7 @@
|
||||
#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"
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
#include "access/gist.h"
|
||||
#include "access/stratnum.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/fmgrprotos.h"
|
||||
#include "utils/datum.h"
|
||||
#include "utils/rangetypes.h"
|
||||
|
||||
|
@ -21,7 +21,8 @@
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_statistic.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/fmgrprotos.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/rangetypes.h"
|
||||
#include "utils/selfuncs.h"
|
||||
|
@ -26,7 +26,8 @@
|
||||
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "commands/vacuum.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/float.h"
|
||||
#include "utils/fmgrprotos.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/rangetypes.h"
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#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
|
||||
|
@ -80,6 +80,7 @@
|
||||
#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"
|
||||
|
@ -52,20 +52,6 @@ extern char *pg_ltostr_zeropad(char *str, int32 value, int32 minwidth);
|
||||
extern char *pg_ltostr(char *str, int32 value);
|
||||
extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* oid.c */
|
||||
extern oidvector *buildoidvector(const Oid *oids, int n);
|
||||
extern Oid oidparse(Node *node);
|
||||
|
376
src/include/utils/float.h
Normal file
376
src/include/utils/float.h
Normal file
@ -0,0 +1,376 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
|
||||
#include <math.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. */
|
||||
#if defined(WIN32) && !defined(NAN)
|
||||
static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
|
||||
|
||||
#define NAN (*(const float8 *) nan)
|
||||
#endif
|
||||
|
||||
extern PGDLLIMPORT int extra_float_digits;
|
||||
|
||||
/*
|
||||
* Utility functions in float.c
|
||||
*/
|
||||
extern int is_infinite(float8 val);
|
||||
extern float8 float8in_internal(char *num, char **endptr_p,
|
||||
const char *type_name, const char *orig_string);
|
||||
extern char *float8out_internal(float8 num);
|
||||
extern int float4_cmp_internal(float4 a, float4 b);
|
||||
extern int float8_cmp_internal(float8 a, float8 b);
|
||||
|
||||
/*
|
||||
* Routines to provide reasonably platform-independent handling of
|
||||
* infinity and NaN
|
||||
*
|
||||
* We assume that isinf() and isnan() are available and work per spec.
|
||||
* (On some platforms, we have to supply our own; see src/port.) However,
|
||||
* generating an Infinity or NaN in the first place is less well standardized;
|
||||
* pre-C99 systems tend not to have C99's INFINITY and NaN macros. We
|
||||
* centralize our workarounds for this here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The funny placements of the two #pragmas is necessary because of a
|
||||
* long lived bug in the Microsoft compilers.
|
||||
* See http://support.microsoft.com/kb/120968/en-us for details
|
||||
*/
|
||||
#if (_MSC_VER >= 1800)
|
||||
#pragma warning(disable:4756)
|
||||
#endif
|
||||
static inline float4
|
||||
get_float4_infinity(void)
|
||||
{
|
||||
#ifdef INFINITY
|
||||
/* C99 standard way */
|
||||
return (float4) INFINITY;
|
||||
#else
|
||||
#if (_MSC_VER >= 1800)
|
||||
#pragma warning(default:4756)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
|
||||
* largest normal float8. We assume forcing an overflow will get us a
|
||||
* true infinity.
|
||||
*/
|
||||
return (float4) (HUGE_VAL * HUGE_VAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline float8
|
||||
get_float8_infinity(void)
|
||||
{
|
||||
#ifdef INFINITY
|
||||
/* C99 standard way */
|
||||
return (float8) INFINITY;
|
||||
#else
|
||||
|
||||
/*
|
||||
* On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
|
||||
* largest normal float8. We assume forcing an overflow will get us a
|
||||
* true infinity.
|
||||
*/
|
||||
return (float8) (HUGE_VAL * HUGE_VAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline float4
|
||||
get_float4_nan(void)
|
||||
{
|
||||
#ifdef NAN
|
||||
/* C99 standard way */
|
||||
return (float4) NAN;
|
||||
#else
|
||||
/* Assume we can get a NAN via zero divide */
|
||||
return (float4) (0.0 / 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline float8
|
||||
get_float8_nan(void)
|
||||
{
|
||||
/* (float8) NAN doesn't work on some NetBSD/MIPS releases */
|
||||
#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
|
||||
/* C99 standard way */
|
||||
return (float8) NAN;
|
||||
#else
|
||||
/* Assume we can get a NaN via zero divide */
|
||||
return (float8) (0.0 / 0.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if a float4/8 val has underflowed or overflowed
|
||||
*/
|
||||
|
||||
static inline void
|
||||
check_float4_val(const float4 val, const bool inf_is_valid,
|
||||
const bool zero_is_valid)
|
||||
{
|
||||
if (!inf_is_valid && unlikely(isinf(val)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("value out of range: overflow")));
|
||||
|
||||
if (!zero_is_valid && unlikely(val == 0.0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("value out of range: underflow")));
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_float8_val(const float8 val, const bool inf_is_valid,
|
||||
const bool zero_is_valid)
|
||||
{
|
||||
if (!inf_is_valid && unlikely(isinf(val)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("value out of range: overflow")));
|
||||
|
||||
if (!zero_is_valid && unlikely(val == 0.0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
||||
errmsg("value out of range: underflow")));
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines for operations with the checks above
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static inline float4
|
||||
float4_pl(const float4 val1, const float4 val2)
|
||||
{
|
||||
float4 result;
|
||||
|
||||
result = val1 + val2;
|
||||
check_float4_val(result, isinf(val1) || isinf(val2), true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float8
|
||||
float8_pl(const float8 val1, const float8 val2)
|
||||
{
|
||||
float8 result;
|
||||
|
||||
result = val1 + val2;
|
||||
check_float8_val(result, isinf(val1) || isinf(val2), true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float4
|
||||
float4_mi(const float4 val1, const float4 val2)
|
||||
{
|
||||
float4 result;
|
||||
|
||||
result = val1 - val2;
|
||||
check_float4_val(result, isinf(val1) || isinf(val2), true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float8
|
||||
float8_mi(const float8 val1, const float8 val2)
|
||||
{
|
||||
float8 result;
|
||||
|
||||
result = val1 - val2;
|
||||
check_float8_val(result, isinf(val1) || isinf(val2), true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float4
|
||||
float4_mul(const float4 val1, const float4 val2)
|
||||
{
|
||||
float4 result;
|
||||
|
||||
result = val1 * val2;
|
||||
check_float4_val(result, isinf(val1) || isinf(val2),
|
||||
val1 == 0.0f || val2 == 0.0f);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float8
|
||||
float8_mul(const float8 val1, const float8 val2)
|
||||
{
|
||||
float8 result;
|
||||
|
||||
result = val1 * val2;
|
||||
check_float8_val(result, isinf(val1) || isinf(val2),
|
||||
val1 == 0.0 || val2 == 0.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float4
|
||||
float4_div(const float4 val1, const float4 val2)
|
||||
{
|
||||
float4 result;
|
||||
|
||||
if (val2 == 0.0f)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
||||
errmsg("division by zero")));
|
||||
|
||||
result = val1 / val2;
|
||||
check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline float8
|
||||
float8_div(const float8 val1, const float8 val2)
|
||||
{
|
||||
float8 result;
|
||||
|
||||
if (val2 == 0.0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
||||
errmsg("division by zero")));
|
||||
|
||||
result = val1 / val2;
|
||||
check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routines 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.
|
||||
*/
|
||||
|
||||
static inline bool
|
||||
float4_eq(const float4 val1, const float4 val2)
|
||||
{
|
||||
return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float8_eq(const float8 val1, const float8 val2)
|
||||
{
|
||||
return isnan(val1) ? isnan(val2) : !isnan(val2) && val1 == val2;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float4_ne(const float4 val1, const float4 val2)
|
||||
{
|
||||
return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float8_ne(const float8 val1, const float8 val2)
|
||||
{
|
||||
return isnan(val1) ? !isnan(val2) : isnan(val2) || val1 != val2;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float4_lt(const float4 val1, const float4 val2)
|
||||
{
|
||||
return !isnan(val1) && (isnan(val2) || val1 < val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float8_lt(const float8 val1, const float8 val2)
|
||||
{
|
||||
return !isnan(val1) && (isnan(val2) || val1 < val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float4_le(const float4 val1, const float4 val2)
|
||||
{
|
||||
return isnan(val2) || (!isnan(val1) && val1 <= val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float8_le(const float8 val1, const float8 val2)
|
||||
{
|
||||
return isnan(val2) || (!isnan(val1) && val1 <= val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float4_gt(const float4 val1, const float4 val2)
|
||||
{
|
||||
return !isnan(val2) && (isnan(val1) || val1 > val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float8_gt(const float8 val1, const float8 val2)
|
||||
{
|
||||
return !isnan(val2) && (isnan(val1) || val1 > val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float4_ge(const float4 val1, const float4 val2)
|
||||
{
|
||||
return isnan(val1) || (!isnan(val2) && val1 >= val2);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
float8_ge(const float8 val1, const float8 val2)
|
||||
{
|
||||
return isnan(val1) || (!isnan(val2) && val1 >= val2);
|
||||
}
|
||||
|
||||
static inline float4
|
||||
float4_min(const float4 val1, const float4 val2)
|
||||
{
|
||||
return float4_lt(val1, val2) ? val1 : val2;
|
||||
}
|
||||
|
||||
static inline float8
|
||||
float8_min(const float8 val1, const float8 val2)
|
||||
{
|
||||
return float8_lt(val1, val2) ? val1 : val2;
|
||||
}
|
||||
|
||||
static inline float4
|
||||
float4_max(const float4 val1, const float4 val2)
|
||||
{
|
||||
return float4_gt(val1, val2) ? val1 : val2;
|
||||
}
|
||||
|
||||
static inline float8
|
||||
float8_max(const float8 val1, const float8 val2)
|
||||
{
|
||||
return float8_gt(val1, val2) ? val1 : val2;
|
||||
}
|
||||
|
||||
#endif /* FLOAT_H */
|
Loading…
x
Reference in New Issue
Block a user