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.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 6a717f19bba..84d37de9304 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1565,7 +1565,7 @@ dpow(PG_FUNCTION_ARGS)
if (unlikely(isinf(result)) && !isinf(arg1) && !isinf(arg2))
float_overflow_error();
- if (unlikely(result == 0.0) && arg1 != 0.0)
+ if (unlikely(result == 0.0) && arg1 != 0.0 && !isinf(arg1) && !isinf(arg2))
float_underflow_error();
PG_RETURN_FLOAT8(result);
@@ -1581,15 +1581,38 @@ dexp(PG_FUNCTION_ARGS)
float8 arg1 = PG_GETARG_FLOAT8(0);
float8 result;
- errno = 0;
- result = exp(arg1);
- if (errno == ERANGE && result != 0 && !isinf(result))
- result = get_float8_infinity();
-
- if (unlikely(isinf(result)) && !isinf(arg1))
- float_overflow_error();
- if (unlikely(result == 0.0))
- float_underflow_error();
+ /*
+ * Handle NaN and Inf cases explicitly. This avoids needing to assume
+ * that the platform's exp() conforms to POSIX for these cases, and it
+ * removes some edge cases for the overflow checks below.
+ */
+ if (isnan(arg1))
+ result = arg1;
+ else if (isinf(arg1))
+ {
+ /* Per POSIX, exp(-Inf) is 0 */
+ result = (arg1 > 0.0) ? arg1 : 0;
+ }
+ else
+ {
+ /*
+ * On some platforms, exp() will not set errno but just return Inf or
+ * zero to report overflow/underflow; therefore, test both cases.
+ */
+ errno = 0;
+ result = exp(arg1);
+ if (unlikely(errno == ERANGE))
+ {
+ if (result != 0.0)
+ float_overflow_error();
+ else
+ float_underflow_error();
+ }
+ else if (unlikely(isinf(result)))
+ float_overflow_error();
+ else if (unlikely(result == 0.0))
+ float_underflow_error();
+ }
PG_RETURN_FLOAT8(result);
}