*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.131 2006/12/23 02:13:24 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.132 2007/01/02 20:00:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-/*----------
- * OLD COMMENTS
- * Basic float4 ops:
- * float4in, float4out, float4recv, float4send
- * float4abs, float4um, float4up
- * Basic float8 ops:
- * float8in, float8out, float8recv, float8send
- * float8abs, float8um, float8up
- * Arithmetic operators:
- * float4pl, float4mi, float4mul, float4div
- * float8pl, float8mi, float8mul, float8div
- * Comparison operators:
- * float4eq, float4ne, float4lt, float4le, float4gt, float4ge, float4cmp
- * float8eq, float8ne, float8lt, float8le, float8gt, float8ge, float8cmp
- * Conversion routines:
- * ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
- *
- * Random float8 ops:
- * dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
- * Arithmetic operators:
- * float48pl, float48mi, float48mul, float48div
- * float84pl, float84mi, float84mul, float84div
- * Comparison operators:
- * float48eq, float48ne, float48lt, float48le, float48gt, float48ge
- * float84eq, float84ne, float84lt, float84le, float84gt, float84ge
- *
- * (You can do the arithmetic and comparison stuff using conversion
- * routines, but then you pay the overhead of invoking a separate
- * conversion function...)
- *
- * XXX GLUESOME STUFF. FIX IT! -AY '94
- *
- * Added some additional conversion routines and cleaned up
- * a bit of the existing code. Need to change the error checking
- * for calls to pow(), exp() since on some machines (my Linux box
- * included) these routines do not set errno. - tgl 97/05/10
- *----------
- */
#include "postgres.h"
#include <ctype.h>
-#include <float.h>
#include <math.h>
#include <limits.h>
/* for finite() on Solaris */
#define MAXFLOATWIDTH 64
#define MAXDOUBLEWIDTH 128
-/* ========== USER I/O ROUTINES ========== */
+/*
+ * 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)
-#define FLOAT4_MAX FLT_MAX
-#define FLOAT4_MIN FLT_MIN
-#define FLOAT8_MAX DBL_MAX
-#define FLOAT8_MIN DBL_MIN
+/* ========== USER I/O ROUTINES ========== */
/* Configurable GUC parameter */
int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
-static void CheckFloat4Val(double val);
-static void CheckFloat8Val(double val);
static int float4_cmp_internal(float4 a, float4 b);
static int float8_cmp_internal(float8 a, float8 b);
}
-/*
- * check to see if a float4 val is outside of the FLOAT4_MIN,
- * FLOAT4_MAX bounds.
- *
- * raise an ereport() error if it is
- */
-static void
-CheckFloat4Val(double val)
-{
- if (fabs(val) > FLOAT4_MAX)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("type \"real\" value out of range: overflow")));
- if (val != 0.0 && fabs(val) < FLOAT4_MIN)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("type \"real\" value out of range: underflow")));
-}
-
-/*
- * check to see if a float8 val is outside of the FLOAT8_MIN,
- * FLOAT8_MAX bounds.
- *
- * raise an ereport() error if it is
- */
-static void
-CheckFloat8Val(double val)
-{
- if (fabs(val) > FLOAT8_MAX)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("type \"double precision\" value out of range: overflow")));
- if (val != 0.0 && fabs(val) < FLOAT8_MIN)
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("type \"double precision\" value out of range: underflow")));
-}
-
/*
* float4in - converts "num" to float
* restricted syntax:
* if we get here, we have a legal double, still need to check to see if
* it's a legal float4
*/
- if (!isinf(val))
- CheckFloat4Val(val);
+ CHECKFLOATVAL((float4) val, isinf(val), val == 0);
PG_RETURN_FLOAT4((float4) val);
}
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
- if (!isinf(val))
- CheckFloat8Val(val);
+ CHECKFLOATVAL(val, true, true);
PG_RETURN_FLOAT8(val);
}
float4um(PG_FUNCTION_ARGS)
{
float4 arg1 = PG_GETARG_FLOAT4(0);
+ float4 result;
+
+ result = ((arg1 != 0) ? -(arg1) : arg1);
- PG_RETURN_FLOAT4((float4) -arg1);
+ CHECKFLOATVAL(result, isinf(arg1), true);
+ PG_RETURN_FLOAT4(result);
}
Datum
float8abs(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
- float8 result;
-
- result = fabs(arg1);
- CheckFloat8Val(result);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(fabs(arg1));
}
result = ((arg1 != 0) ? -(arg1) : arg1);
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
Datum
float4pl(PG_FUNCTION_ARGS)
{
- float4 arg1 = PG_GETARG_FLOAT4(0);
- float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float8 arg1 = PG_GETARG_FLOAT4(0);
+ float8 arg2 = PG_GETARG_FLOAT4(1);
+ float4 result;
result = arg1 + arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ /*
+ * There isn't any way to check for underflow of addition/subtraction
+ * because numbers near the underflow value have been already been
+ * to the point where we can't detect the 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
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float4 result;
result = arg1 - arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
+ PG_RETURN_FLOAT4(result);
}
Datum
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float4 result;
result = arg1 * arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
+ arg1 == 0 || arg2 == 0);
+ PG_RETURN_FLOAT4(result);
}
Datum
{
float4 arg1 = PG_GETARG_FLOAT4(0);
float4 arg2 = PG_GETARG_FLOAT4(1);
- double result;
+ float4 result;
if (arg2 == 0.0)
ereport(ERROR,
errmsg("division by zero")));
/* Do division in float8, then check for overflow */
- result = (float8) arg1 / (float8) arg2;
+ result = arg1 / arg2;
- CheckFloat4Val(result);
- PG_RETURN_FLOAT4((float4) result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+ PG_RETURN_FLOAT4(result);
}
/*
result = arg1 + arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
result = arg1 - arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
result = arg1 * arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
+ arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT8(result);
}
result = arg1 / arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
{
float8 num = PG_GETARG_FLOAT8(0);
- CheckFloat4Val(num);
+ CHECKFLOATVAL((float4) num, isinf(num), num == 0);
PG_RETURN_FLOAT4((float4) num);
}
float8 num = PG_GETARG_FLOAT8(0);
int32 result;
- if (num < INT_MIN || num > INT_MAX)
+ /* 'Inf' is handled by INT_MAX */
+ if (num < INT_MIN || num > INT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
dtoi2(PG_FUNCTION_ARGS)
{
float8 num = PG_GETARG_FLOAT8(0);
- int16 result;
- if (num < SHRT_MIN || num > SHRT_MAX)
+ if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
- result = (int16) rint(num);
- PG_RETURN_INT16(result);
+ PG_RETURN_INT16((int16) rint(num));
}
i4tod(PG_FUNCTION_ARGS)
{
int32 num = PG_GETARG_INT32(0);
- float8 result;
- result = num;
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8((float8) num);
}
i2tod(PG_FUNCTION_ARGS)
{
int16 num = PG_GETARG_INT16(0);
- float8 result;
- result = num;
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8((float8) num);
}
ftoi4(PG_FUNCTION_ARGS)
{
float4 num = PG_GETARG_FLOAT4(0);
- int32 result;
- if (num < INT_MIN || num > INT_MAX)
+ if (num < INT_MIN || num > INT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
- result = (int32) rint(num);
- PG_RETURN_INT32(result);
+ PG_RETURN_INT32((int32) rint(num));
}
ftoi2(PG_FUNCTION_ARGS)
{
float4 num = PG_GETARG_FLOAT4(0);
- int16 result;
- if (num < SHRT_MIN || num > SHRT_MAX)
+ if (num < SHRT_MIN || num > SHRT_MAX || isnan(num))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
- result = (int16) rint(num);
- PG_RETURN_INT16(result);
+ PG_RETURN_INT16((int16) rint(num));
}
/*
- * i4tof - converts an int4 number to a float8 number
+ * i4tof - converts an int4 number to a float4 number
*/
Datum
i4tof(PG_FUNCTION_ARGS)
{
int32 num = PG_GETARG_INT32(0);
- float4 result;
- result = num;
- PG_RETURN_FLOAT4(result);
+ PG_RETURN_FLOAT4((float4) num);
}
i2tof(PG_FUNCTION_ARGS)
{
int16 num = PG_GETARG_INT16(0);
- float4 result;
- result = num;
- PG_RETURN_FLOAT4(result);
+ PG_RETURN_FLOAT4((float4) num);
}
dround(PG_FUNCTION_ARGS)
{
float8 arg1 = PG_GETARG_FLOAT8(0);
- float8 result;
-
- result = rint(arg1);
- PG_RETURN_FLOAT8(result);
+ PG_RETURN_FLOAT8(rint(arg1));
}
/*
result = sqrt(arg1);
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
float8 result;
result = cbrt(arg1);
+ CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
*/
errno = 0;
result = pow(arg1, arg2);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
/*
* We must check both for errno getting set and for a NaN result, in order
- * to deal with the vagaries of different platforms. Also, a zero result
- * implies unreported underflow.
+ * to deal with the vagaries of different platforms.
*/
errno = 0;
result = exp(arg1);
- if (errno != 0 || result == 0.0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), false);
PG_RETURN_FLOAT8(result);
}
result = log(arg1);
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
result = log10(arg1);
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = acos(arg1);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = asin(arg1);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = atan(arg1);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = atan2(arg1, arg2);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = cos(arg1);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = tan(arg1);
- if (errno != 0 || result == 0.0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
result = 1.0 / result;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */, true);
PG_RETURN_FLOAT8(result);
}
errno = 0;
result = sin(arg1);
- if (errno != 0
-#ifdef HAVE_FINITE
- || !finite(result)
-#endif
- )
+ if (errno != 0)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), true);
PG_RETURN_FLOAT8(result);
}
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, true /* tan(pi/2) == Inf */, true);
PG_RETURN_FLOAT8(result);
}
result = arg1 * (180.0 / M_PI);
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
result = arg1 * (M_PI / 180.0);
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
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 by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
float4_accum(PG_FUNCTION_ARGS)
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
- float4 newval4 = PG_GETARG_FLOAT4(1);
+ /* do computations as float8 */
+ float8 newval = PG_GETARG_FLOAT4(1);
float8 *transvalues;
float8 N,
sumX,
- sumX2,
- newval;
+ sumX2;
transvalues = check_float8_array(transarray, "float4_accum", 3);
N = transvalues[0];
sumX = transvalues[1];
sumX2 = transvalues[2];
- /* Do arithmetic in float8 for best accuracy */
- newval = newval4;
-
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 by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CHECKFLOATVAL(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);
/* 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);
/* 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);
/* 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);
sumX2 += newvalX * newvalX;
+ CHECKFLOATVAL(sumX2, isinf(transvalues[2]) || isinf(newvalX), true);
sumY += newvalY;
+ CHECKFLOATVAL(sumY, isinf(transvalues[3]) || isinf(newvalY), true);
sumY2 += newvalY * newvalY;
+ CHECKFLOATVAL(sumY2, isinf(transvalues[4]) || isinf(newvalY), true);
sumXY += newvalX * newvalY;
-
+ CHECKFLOATVAL(sumXY, isinf(transvalues[5]) || isinf(newvalX) ||
+ isinf(newvalY), true);
+
/*
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we construct a
PG_RETURN_NULL();
numerator = N * sumX2 - sumX * sumX;
+ CHECKFLOATVAL(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);
/* 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);
/* A negative result is valid here */
PG_RETURN_NULL();
numerator = N * sumXY - sumX * sumY;
+ CHECKFLOATVAL(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);
PG_RETURN_FLOAT8(numerator / (N * (N - 1.0)));
}
PG_RETURN_NULL();
numeratorX = N * sumX2 - sumX * sumX;
+ CHECKFLOATVAL(numeratorX, isinf(sumX2) || isinf(sumX), true);
numeratorY = N * sumY2 - sumY * sumY;
+ CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
numeratorXY = N * sumXY - sumX * sumY;
+ CHECKFLOATVAL(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);
numeratorY = N * sumY2 - sumY * sumY;
+ CHECKFLOATVAL(numeratorY, isinf(sumY2) || isinf(sumY), true);
numeratorXY = N * sumXY - sumX * sumY;
+ CHECKFLOATVAL(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);
numeratorXY = N * sumXY - sumX * sumY;
+ CHECKFLOATVAL(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);
numeratorXXY = sumY * sumX2 - sumX * sumXY;
+ CHECKFLOATVAL(numeratorXXY, isinf(sumY) || isinf(sumX2) ||
+ isinf(sumX) || isinf(sumXY), true);
if (numeratorX <= 0)
PG_RETURN_NULL();
float8 result;
result = arg1 + arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
float8 result;
result = arg1 - arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
float8 result;
result = arg1 * arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
+ arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT8(result);
}
errmsg("division by zero")));
result = arg1 / arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
result = arg1 + arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
result = arg1 - arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true);
PG_RETURN_FLOAT8(result);
}
result = arg1 * arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2),
+ arg1 == 0 || arg2 == 0);
PG_RETURN_FLOAT8(result);
}
result = arg1 / arg2;
- CheckFloat8Val(result);
+ CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), arg1 == 0);
PG_RETURN_FLOAT8(result);
}