#include "common/int.h"
#include "libpq/pqformat.h"
#include "utils/array.h"
-#include "utils/builtins.h"
+#include "utils/float.h"
+#include "utils/fmgrprotos.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
-
-/*
- * 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 */
#endif /* HAVE_CBRT */
-/*
- * 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.
- */
-
-double
-get_float8_infinity(void)
-{
-#ifdef INFINITY
- /* C99 standard way */
- return (double) INFINITY;
-#else
-
- /*
- * On some platforms, HUGE_VAL is an infinity, elsewhere it's just the
- * largest normal double. We assume forcing an overflow will get us a
- * true infinity.
- */
- return (double) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-/*
-* 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
-float
-get_float4_infinity(void)
-{
-#ifdef INFINITY
- /* C99 standard way */
- return (float) 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 double. We assume forcing an overflow will get us a
- * true infinity.
- */
- return (float) (HUGE_VAL * HUGE_VAL);
-#endif
-}
-
-double
-get_float8_nan(void)
-{
- /* (double) NAN doesn't work on some NetBSD/MIPS releases */
-#if defined(NAN) && !(defined(__NetBSD__) && defined(__mips__))
- /* C99 standard way */
- return (double) NAN;
-#else
- /* Assume we can get a NAN via zero divide */
- return (double) (0.0 / 0.0);
-#endif
-}
-
-float
-get_float4_nan(void)
-{
-#ifdef NAN
- /* C99 standard way */
- return (float) NAN;
-#else
- /* Assume we can get a NAN via zero divide */
- return (float) (0.0 / 0.0);
-#endif
-}
-
-
/*
* Returns -1 if 'val' represents negative infinity, 1 if 'val'
* represents (positive) infinity, and 0 otherwise. On some platforms,
* if we get here, we have a legal double, still need to check to see if
* it's a legal float4
*/
- CHECKFLOATVAL((float4) val, isinf(val), val == 0);
+ check_float4_val((float4) val, isinf(val), val == 0);
PG_RETURN_FLOAT4((float4) val);
}
float4 arg2 = PG_GETARG_FLOAT4(1);
float4 result;
- if (float4_cmp_internal(arg1, arg2) > 0)
+ if (float4_gt(arg1, arg2))
result = arg1;
else
result = arg2;
float4 arg2 = PG_GETARG_FLOAT4(1);
float4 result;
- if (float4_cmp_internal(arg1, arg2) < 0)
+ if (float4_lt(arg1, arg2))
result = arg1;
else
result = arg2;
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
- if (float8_cmp_internal(arg1, arg2) > 0)
+ if (float8_gt(arg1, arg2))
result = arg1;
else
result = arg2;
float8 arg2 = PG_GETARG_FLOAT8(1);
float8 result;
- if (float8_cmp_internal(arg1, arg2) < 0)
+ if (float8_lt(arg1, arg2))
result = arg1;
else
result = arg2;
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- float4 result;
-
- 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);
+ PG_RETURN_FLOAT4(float4_pl(arg1, arg2));
}
Datum
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- float4 result;
- result = arg1 - arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT4(result);
+ PG_RETURN_FLOAT4(float4_mi(arg1, arg2));
}
Datum
{
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);
- PG_RETURN_FLOAT4(result);
+ PG_RETURN_FLOAT4(float4_mul(arg1, arg2));
}
Datum
{
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")));
- result = arg1 / arg2;
-
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
- PG_RETURN_FLOAT4(result);
+ PG_RETURN_FLOAT4(float4_div(arg1, arg2));
}
/*
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- float8 result;
-
- result = arg1 + arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_pl(arg1, arg2));
}
Datum
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- float8 result;
-
- result = arg1 - arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mi(arg1, arg2));
}
Datum
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- float8 result;
-
- result = arg1 * arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
- arg1 == 0 || arg2 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mul(arg1, arg2));
}
Datum
{
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")));
-
- result = arg1 / arg2;
-
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_div(arg1, arg2));
}
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 (float4_gt(a, b))
+ return 1;
+ if (float4_lt(a, b))
+ return -1;
+ return 0;
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) == 0);
+ PG_RETURN_BOOL(float4_eq(arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) != 0);
+ PG_RETURN_BOOL(float4_ne(arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) < 0);
+ PG_RETURN_BOOL(float4_lt(arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) <= 0);
+ PG_RETURN_BOOL(float4_le(arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) > 0);
+ PG_RETURN_BOOL(float4_gt(arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float4_cmp_internal(arg1, arg2) >= 0);
+ PG_RETURN_BOOL(float4_ge(arg1, arg2));
}
Datum
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 (float8_gt(a, b))
+ return 1;
+ if (float8_lt(a, b))
+ return -1;
+ return 0;
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+ PG_RETURN_BOOL(float8_eq(arg1, arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+ PG_RETURN_BOOL(float8_ne(arg1, arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+ PG_RETURN_BOOL(float8_lt(arg1, arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+ PG_RETURN_BOOL(float8_le(arg1, arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+ PG_RETURN_BOOL(float8_gt(arg1, arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+ PG_RETURN_BOOL(float8_ge(arg1, arg2));
}
Datum
{
float8 num = PG_GETARG_FLOAT8(0);
- CHECKFLOATVAL((float4) num, isinf(num), num == 0);
+ check_float4_val((float4) num, isinf(num), num == 0);
PG_RETURN_FLOAT4((float4) num);
}
result = sqrt(arg1);
- CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+ check_float8_val(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
float8 result;
result = cbrt(arg1);
- CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
+ check_float8_val(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
else if (errno == ERANGE && result != 0 && !isinf(result))
result = get_float8_infinity();
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+ check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
if (errno == ERANGE && result != 0 && !isinf(result))
result = get_float8_infinity();
- CHECKFLOATVAL(result, isinf(arg1), false);
+ check_float8_val(result, isinf(arg1), false);
PG_RETURN_FLOAT8(result);
}
result = log(arg1);
- CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+ check_float8_val(result, isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
result = log10(arg1);
- CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
+ check_float8_val(result, isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
result = acos(arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
result = asin(arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
*/
result = atan(arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
*/
result = atan2(arg1, arg2);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
errmsg("input is out of range")));
result = 1.0 / result;
- CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true);
+ check_float8_val(result, true /* cot(0) == Inf */ , true);
PG_RETURN_FLOAT8(result);
}
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */ , true);
+ check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
PG_RETURN_FLOAT8(result);
}
else
result = 90.0 + asind_q1(-arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
else
result = -asind_q1(-arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
atan_arg1 = atan(arg1);
result = (atan_arg1 / atan_1_0) * 45.0;
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
atan2_arg1_arg2 = atan2(arg1, arg2);
result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
result = sign * cosd_q1(arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
if (result == 0.0)
result = 0.0;
- CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true);
+ check_float8_val(result, true /* cotd(0) == Inf */ , true);
PG_RETURN_FLOAT8(result);
}
result = sign * sind_q1(arg1);
- CHECKFLOATVAL(result, false, true);
+ check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
if (result == 0.0)
result = 0.0;
- CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true);
+ check_float8_val(result, true /* tand(90) == Inf */ , true);
PG_RETURN_FLOAT8(result);
}
degrees(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
- float8 result;
-
- result = arg1 / RADIANS_PER_DEGREE;
- CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_div(arg1, RADIANS_PER_DEGREE));
}
radians(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
- float8 result;
- result = arg1 * RADIANS_PER_DEGREE;
-
- CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mul(arg1, RADIANS_PER_DEGREE));
}
ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
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);
-
- transvalues1[0] = N;
- transvalues1[1] = sumX;
- transvalues1[2] = sumX2;
+ transvalues1[0] = transvalues1[0] + transvalues2[0];
+ transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+ transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
PG_RETURN_ARRAYTYPE_P(transarray1);
}
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
float8 newval = PG_GETARG_FLOAT8(1);
float8 *transvalues;
- float8 N,
- 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);
/*
* If we're invoked as an aggregate, we can cheat and modify our first
*/
if (AggCheckCallContext(fcinfo, NULL))
{
- transvalues[0] = N;
- transvalues[1] = sumX;
- transvalues[2] = sumX2;
+ transvalues[0] = transvalues[0] + 1.0;
+ transvalues[1] = float8_pl(transvalues[1], newval);
+ transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
PG_RETURN_ARRAYTYPE_P(transarray);
}
Datum transdatums[3];
ArrayType *result;
- transdatums[0] = Float8GetDatumFast(N);
- transdatums[1] = Float8GetDatumFast(sumX);
- transdatums[2] = Float8GetDatumFast(sumX2);
+ transvalues[0] = transvalues[0] + 1.0;
+ transvalues[1] = float8_pl(transvalues[1], newval);
+ transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
result = construct_array(transdatums, 3,
FLOAT8OID,
/* do computations as float8 */
float8 newval = PG_GETARG_FLOAT4(1);
float8 *transvalues;
- float8 N,
- 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);
/*
* If we're invoked as an aggregate, we can cheat and modify our first
*/
if (AggCheckCallContext(fcinfo, NULL))
{
- transvalues[0] = N;
- transvalues[1] = sumX;
- transvalues[2] = sumX2;
+ transvalues[0] = transvalues[0] + 1.0;
+ transvalues[1] = float8_pl(transvalues[1], newval);
+ transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
PG_RETURN_ARRAYTYPE_P(transarray);
}
Datum transdatums[3];
ArrayType *result;
- transdatums[0] = Float8GetDatumFast(N);
- transdatums[1] = Float8GetDatumFast(sumX);
- transdatums[2] = Float8GetDatumFast(sumX2);
+ transvalues[0] = transvalues[0] + 1.0;
+ transvalues[1] = float8_pl(transvalues[1], newval);
+ transvalues[2] = float8_pl(transvalues[2], float8_mul(newval, newval));
result = construct_array(transdatums, 3,
FLOAT8OID,
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
N += 1.0;
sumX += newvalX;
- CHECKFLOATVAL(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
+ check_float8_val(sumX, isinf(transvalues[1]) || isinf(newvalX), true);
sumX2 += newvalX * newvalX;
- CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
+ check_float8_val(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
sumY += newvalY;
- CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
+ check_float8_val(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
sumY2 += newvalY * newvalY;
- CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
+ check_float8_val(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
sumXY += newvalX * newvalY;
- CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
- isinf(newvalY), true);
+ check_float8_val(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+ isinf(newvalY), true);
/*
* If we're invoked as an aggregate, we can cheat and modify our first
ArrayType *transarray2 = PG_GETARG_ARRAYTYPE_P(1);
float8 *transvalues1;
float8 *transvalues2;
- float8 N,
- 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);
-
- transvalues1[0] = N;
- transvalues1[1] = sumX;
- transvalues1[2] = sumX2;
- transvalues1[3] = sumY;
- transvalues1[4] = sumY2;
- transvalues1[5] = sumXY;
+ transvalues1[0] = transvalues1[0] + transvalues2[0];
+ transvalues1[1] = float8_pl(transvalues1[1], transvalues2[1]);
+ transvalues1[2] = float8_pl(transvalues1[2], transvalues2[2]);
+ transvalues1[3] = float8_pl(transvalues1[3], transvalues2[3]);
+ transvalues1[4] = float8_pl(transvalues1[4], transvalues2[4]);
+ transvalues1[5] = float8_pl(transvalues1[5], transvalues2[5]);
PG_RETURN_ARRAYTYPE_P(transarray1);
}
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numerator, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numerator, isinf(sumX2) || isinf(sumX), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
PG_RETURN_NULL();
numerator = N * sumY2 - sumY * sumY;
- CHECKFLOATVAL(numerator, isinf(sumY2) || isinf(sumY), true);
+ check_float8_val(numerator, isinf(sumY2) || isinf(sumY), true);
/* Watch out for roundoff error producing a negative numerator */
if (numerator <= 0.0)
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
- CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
- isinf(sumY), true);
+ check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+ isinf(sumY), true);
/* A negative result is valid here */
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
- CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
- isinf(sumY), true);
+ check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+ isinf(sumY), true);
PG_RETURN_FLOAT8(numerator / (N * N));
}
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
- CHECKFLOATVAL(numerator, isinf(sumXY) || isinf(sumX) ||
- isinf(sumY), true);
+ check_float8_val(numerator, isinf(sumXY) || isinf(sumX) ||
+ isinf(sumY), true);
PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
}
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
numeratorY = N * sumY2 - sumY * sumY;
- CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+ check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
numeratorXY = N * sumXY - sumX * sumY;
- CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
- isinf(sumY), true);
+ check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+ isinf(sumY), true);
if (numeratorX <= 0 || numeratorY <= 0)
PG_RETURN_NULL();
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
numeratorY = N * sumY2 - sumY * sumY;
- CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
+ check_float8_val(numeratorY, isinf(sumY2) || isinf(sumY), true);
numeratorXY = N * sumXY - sumX * sumY;
- CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
- isinf(sumY), true);
+ check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+ isinf(sumY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
/* per spec, horizontal line produces 1.0 */
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
numeratorXY = N * sumXY - sumX * sumY;
- CHECKFLOATVAL(numeratorXY, isinf(sumXY) || isinf(sumX) ||
- isinf(sumY), true);
+ check_float8_val(numeratorXY, isinf(sumXY) || isinf(sumX) ||
+ isinf(sumY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
- CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
+ check_float8_val(numeratorX, isinf(sumX2) || isinf(sumX), true);
numeratorXXY = sumY * sumX2 - sumX * sumXY;
- CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
- isinf(sumX) || isinf(sumXY), true);
+ check_float8_val(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+ isinf(sumX) || isinf(sumXY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- float8 result;
- result = arg1 + arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_pl((float8) arg1, arg2));
}
Datum
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- float8 result;
- result = arg1 - arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mi((float8) arg1, arg2));
}
Datum
{
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);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mul((float8) arg1, arg2));
}
Datum
{
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")));
-
- result = arg1 / arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_div((float8) arg1, arg2));
}
/*
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- float8 result;
-
- result = arg1 + arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_pl(arg1, (float8) arg2));
}
Datum
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- float8 result;
-
- result = arg1 - arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mi(arg1, (float8) arg2));
}
Datum
{
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- float8 result;
-
- result = arg1 * arg2;
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
- arg1 == 0 || arg2 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_mul(arg1, (float8) arg2));
}
Datum
{
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")));
-
- result = arg1 / arg2;
-
- CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(float8_div(arg1, (float8) arg2));
}
/*
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+ PG_RETURN_BOOL(float8_eq((float8) arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+ PG_RETURN_BOOL(float8_ne((float8) arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+ PG_RETURN_BOOL(float8_lt((float8) arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+ PG_RETURN_BOOL(float8_le((float8) arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+ PG_RETURN_BOOL(float8_gt((float8) arg1, arg2));
}
Datum
float4 arg1 = PG_GETARG_FLOAT4(0);
float8 arg2 = PG_GETARG_FLOAT8(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+ PG_RETURN_BOOL(float8_ge((float8) arg1, arg2));
}
/*
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) == 0);
+ PG_RETURN_BOOL(float8_eq(arg1, (float8) arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) != 0);
+ PG_RETURN_BOOL(float8_ne(arg1, (float8) arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) < 0);
+ PG_RETURN_BOOL(float8_lt(arg1, (float8) arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) <= 0);
+ PG_RETURN_BOOL(float8_le(arg1, (float8) arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) > 0);
+ PG_RETURN_BOOL(float8_gt(arg1, (float8) arg2));
}
Datum
float8 arg1 = PG_GETARG_FLOAT8(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- PG_RETURN_BOOL(float8_cmp_internal(arg1, arg2) >= 0);
+ PG_RETURN_BOOL(float8_ge(arg1, (float8) arg2));
}
/*
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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 */