aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/float.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/float.c')
-rw-r--r--src/backend/utils/adt/float.c163
1 files changed, 120 insertions, 43 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index a90d4db2150..012c3252f3c 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -87,6 +87,38 @@ static double cbrt(double x);
/*
+ * We use these out-of-line ereport() calls to report float overflow,
+ * underflow, and zero-divide, because following our usual practice of
+ * repeating them at each call site would lead to a lot of code bloat.
+ *
+ * This does mean that you don't get a useful error location indicator.
+ */
+pg_noinline void
+float_overflow_error(void)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value out of range: overflow")));
+}
+
+pg_noinline void
+float_underflow_error(void)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value out of range: underflow")));
+}
+
+pg_noinline void
+float_zero_divide_error(void)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_DIVISION_BY_ZERO),
+ errmsg("division by zero")));
+}
+
+
+/*
* Returns -1 if 'val' represents negative infinity, 1 if 'val'
* represents (positive) infinity, and 0 otherwise. On some platforms,
* this is equivalent to the isinf() macro, but not everywhere: C99
@@ -1190,10 +1222,15 @@ Datum
dtof(PG_FUNCTION_ARGS)
{
float8 num = PG_GETARG_FLOAT8(0);
+ float4 result;
- check_float4_val((float4) num, isinf(num), num == 0);
+ result = (float4) num;
+ if (unlikely(isinf(result)) && !isinf(num))
+ float_overflow_error();
+ if (unlikely(result == 0.0f) && num != 0.0)
+ float_underflow_error();
- PG_RETURN_FLOAT4((float4) num);
+ PG_RETURN_FLOAT4(result);
}
@@ -1444,8 +1481,11 @@ dsqrt(PG_FUNCTION_ARGS)
errmsg("cannot take square root of a negative number")));
result = sqrt(arg1);
+ if (unlikely(isinf(result)) && !isinf(arg1))
+ float_overflow_error();
+ if (unlikely(result == 0.0) && arg1 != 0.0)
+ float_underflow_error();
- check_float8_val(result, isinf(arg1), arg1 == 0);
PG_RETURN_FLOAT8(result);
}
@@ -1460,7 +1500,11 @@ dcbrt(PG_FUNCTION_ARGS)
float8 result;
result = cbrt(arg1);
- check_float8_val(result, isinf(arg1), arg1 == 0);
+ if (unlikely(isinf(result)) && !isinf(arg1))
+ float_overflow_error();
+ if (unlikely(result == 0.0) && arg1 != 0.0)
+ float_underflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -1532,7 +1576,11 @@ dpow(PG_FUNCTION_ARGS)
else if (errno == ERANGE && result != 0 && !isinf(result))
result = get_float8_infinity();
- check_float8_val(result, isinf(arg1) || isinf(arg2), arg1 == 0);
+ if (unlikely(isinf(result)) && !isinf(arg1) && !isinf(arg2))
+ float_overflow_error();
+ if (unlikely(result == 0.0) && arg1 != 0.0)
+ float_underflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -1551,7 +1599,11 @@ dexp(PG_FUNCTION_ARGS)
if (errno == ERANGE && result != 0 && !isinf(result))
result = get_float8_infinity();
- check_float8_val(result, isinf(arg1), false);
+ if (unlikely(isinf(result)) && !isinf(arg1))
+ float_overflow_error();
+ if (unlikely(result == 0.0))
+ float_underflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -1579,8 +1631,11 @@ dlog1(PG_FUNCTION_ARGS)
errmsg("cannot take logarithm of a negative number")));
result = log(arg1);
+ if (unlikely(isinf(result)) && !isinf(arg1))
+ float_overflow_error();
+ if (unlikely(result == 0.0) && arg1 != 1.0)
+ float_underflow_error();
- check_float8_val(result, isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
@@ -1609,8 +1664,11 @@ dlog10(PG_FUNCTION_ARGS)
errmsg("cannot take logarithm of a negative number")));
result = log10(arg1);
+ if (unlikely(isinf(result)) && !isinf(arg1))
+ float_overflow_error();
+ if (unlikely(result == 0.0) && arg1 != 1.0)
+ float_underflow_error();
- check_float8_val(result, isinf(arg1), arg1 == 1);
PG_RETURN_FLOAT8(result);
}
@@ -1639,8 +1697,9 @@ dacos(PG_FUNCTION_ARGS)
errmsg("input is out of range")));
result = acos(arg1);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
- check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
@@ -1669,8 +1728,9 @@ dasin(PG_FUNCTION_ARGS)
errmsg("input is out of range")));
result = asin(arg1);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
- check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
@@ -1694,8 +1754,9 @@ datan(PG_FUNCTION_ARGS)
* finite, even if the input is infinite.
*/
result = atan(arg1);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
- check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
@@ -1719,8 +1780,9 @@ datan2(PG_FUNCTION_ARGS)
* should always be finite, even if the inputs are infinite.
*/
result = atan2(arg1, arg2);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
- check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
@@ -1759,8 +1821,9 @@ dcos(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
+ if (unlikely(isinf(result)))
+ float_overflow_error();
- check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
@@ -1787,7 +1850,8 @@ dcot(PG_FUNCTION_ARGS)
errmsg("input is out of range")));
result = 1.0 / result;
- check_float8_val(result, true /* cot(0) == Inf */ , true);
+ /* Not checking for overflow because cot(0) == Inf */
+
PG_RETURN_FLOAT8(result);
}
@@ -1812,8 +1876,9 @@ dsin(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
+ if (unlikely(isinf(result)))
+ float_overflow_error();
- check_float8_val(result, false, true);
PG_RETURN_FLOAT8(result);
}
@@ -1838,8 +1903,8 @@ dtan(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("input is out of range")));
+ /* Not checking for overflow because tan(pi/2) == Inf */
- check_float8_val(result, true /* tan(pi/2) == Inf */ , true);
PG_RETURN_FLOAT8(result);
}
@@ -1991,7 +2056,9 @@ dacosd(PG_FUNCTION_ARGS)
else
result = 90.0 + asind_q1(-arg1);
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2026,7 +2093,9 @@ dasind(PG_FUNCTION_ARGS)
else
result = -asind_q1(-arg1);
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2056,7 +2125,9 @@ datand(PG_FUNCTION_ARGS)
atan_arg1 = atan(arg1);
result = (atan_arg1 / atan_1_0) * 45.0;
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2090,7 +2161,9 @@ datan2d(PG_FUNCTION_ARGS)
atan2_arg1_arg2 = atan2(arg1, arg2);
result = (atan2_arg1_arg2 / atan_1_0) * 45.0;
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2211,7 +2284,9 @@ dcosd(PG_FUNCTION_ARGS)
result = sign * cosd_q1(arg1);
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2276,7 +2351,8 @@ dcotd(PG_FUNCTION_ARGS)
if (result == 0.0)
result = 0.0;
- check_float8_val(result, true /* cotd(0) == Inf */ , true);
+ /* Not checking for overflow because cotd(0) == Inf */
+
PG_RETURN_FLOAT8(result);
}
@@ -2330,7 +2406,9 @@ dsind(PG_FUNCTION_ARGS)
result = sign * sind_q1(arg1);
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2395,7 +2473,8 @@ dtand(PG_FUNCTION_ARGS)
if (result == 0.0)
result = 0.0;
- check_float8_val(result, true /* tand(90) == Inf */ , true);
+ /* Not checking for overflow because tand(90) == Inf */
+
PG_RETURN_FLOAT8(result);
}
@@ -2462,7 +2541,6 @@ dsinh(PG_FUNCTION_ARGS)
result = get_float8_infinity();
}
- check_float8_val(result, true, true);
PG_RETURN_FLOAT8(result);
}
@@ -2486,7 +2564,9 @@ dcosh(PG_FUNCTION_ARGS)
if (errno == ERANGE)
result = get_float8_infinity();
- check_float8_val(result, true, false);
+ if (unlikely(result == 0.0))
+ float_underflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2504,7 +2584,9 @@ dtanh(PG_FUNCTION_ARGS)
*/
result = tanh(arg1);
- check_float8_val(result, false, true);
+ if (unlikely(isinf(result)))
+ float_overflow_error();
+
PG_RETURN_FLOAT8(result);
}
@@ -2522,7 +2604,6 @@ dasinh(PG_FUNCTION_ARGS)
*/
result = asinh(arg1);
- check_float8_val(result, true, true);
PG_RETURN_FLOAT8(result);
}
@@ -2548,7 +2629,6 @@ dacosh(PG_FUNCTION_ARGS)
result = acosh(arg1);
- check_float8_val(result, true, true);
PG_RETURN_FLOAT8(result);
}
@@ -2583,7 +2663,6 @@ datanh(PG_FUNCTION_ARGS)
else
result = atanh(arg1);
- check_float8_val(result, true, true);
PG_RETURN_FLOAT8(result);
}
@@ -2784,7 +2863,8 @@ float8_combine(PG_FUNCTION_ARGS)
Sx = float8_pl(Sx1, Sx2);
tmp = Sx1 / N1 - Sx2 / N2;
Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp * tmp / N;
- check_float8_val(Sxx, isinf(Sxx1) || isinf(Sxx2), true);
+ if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
+ float_overflow_error();
}
/*
@@ -2853,9 +2933,7 @@ float8_accum(PG_FUNCTION_ARGS)
if (isinf(Sx) || isinf(Sxx))
{
if (!isinf(transvalues[1]) && !isinf(newval))
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value out of range: overflow")));
+ float_overflow_error();
Sxx = get_float8_nan();
}
@@ -2929,9 +3007,7 @@ float4_accum(PG_FUNCTION_ARGS)
if (isinf(Sx) || isinf(Sxx))
{
if (!isinf(transvalues[1]) && !isinf(newval))
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value out of range: overflow")));
+ float_overflow_error();
Sxx = get_float8_nan();
}
@@ -3152,9 +3228,7 @@ float8_regr_accum(PG_FUNCTION_ARGS)
(isinf(Sxy) &&
!isinf(transvalues[1]) && !isinf(newvalX) &&
!isinf(transvalues[3]) && !isinf(newvalY)))
- ereport(ERROR,
- (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
- errmsg("value out of range: overflow")));
+ float_overflow_error();
if (isinf(Sxx))
Sxx = get_float8_nan();
@@ -3294,13 +3368,16 @@ float8_regr_combine(PG_FUNCTION_ARGS)
Sx = float8_pl(Sx1, Sx2);
tmp1 = Sx1 / N1 - Sx2 / N2;
Sxx = Sxx1 + Sxx2 + N1 * N2 * tmp1 * tmp1 / N;
- check_float8_val(Sxx, isinf(Sxx1) || isinf(Sxx2), true);
+ if (unlikely(isinf(Sxx)) && !isinf(Sxx1) && !isinf(Sxx2))
+ float_overflow_error();
Sy = float8_pl(Sy1, Sy2);
tmp2 = Sy1 / N1 - Sy2 / N2;
Syy = Syy1 + Syy2 + N1 * N2 * tmp2 * tmp2 / N;
- check_float8_val(Syy, isinf(Syy1) || isinf(Syy2), true);
+ if (unlikely(isinf(Syy)) && !isinf(Syy1) && !isinf(Syy2))
+ float_overflow_error();
Sxy = Sxy1 + Sxy2 + N1 * N2 * tmp1 * tmp2 / N;
- check_float8_val(Sxy, isinf(Sxy1) || isinf(Sxy2), true);
+ if (unlikely(isinf(Sxy)) && !isinf(Sxy1) && !isinf(Sxy2))
+ float_overflow_error();
}
/*