diff options
Diffstat (limited to 'src/include/utils/float.h')
-rw-r--r-- | src/include/utils/float.h | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/src/include/utils/float.h b/src/include/utils/float.h index 543d00e5910..e5acc0f0aa4 100644 --- a/src/include/utils/float.h +++ b/src/include/utils/float.h @@ -37,6 +37,9 @@ extern PGDLLIMPORT int extra_float_digits; /* * Utility functions in float.c */ +extern void float_overflow_error(void) pg_attribute_noreturn(); +extern void float_underflow_error(void) pg_attribute_noreturn(); +extern void float_zero_divide_error(void) pg_attribute_noreturn(); extern int is_infinite(float8 val); extern float8 float8in_internal(char *num, char **endptr_p, const char *type_name, const char *orig_string); @@ -130,18 +133,23 @@ get_float8_nan(void) /* * Checks to see if a float4/8 val has underflowed or overflowed + * + * These subroutines are no longer used in the core code because of the + * performance issues they cause, but they remain for now for backwards + * compatibility for extensions. Note that we can't rely on + * float_over/underflow_error() to exist in v12, so don't call those here. */ 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))) + if (unlikely(isinf(val)) && !inf_is_valid) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value out of range: overflow"))); - if (!zero_is_valid && unlikely(val == 0.0)) + if (unlikely(val == 0.0f) && !zero_is_valid) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value out of range: underflow"))); @@ -151,19 +159,19 @@ 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))) + if (unlikely(isinf(val)) && !inf_is_valid) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value out of range: overflow"))); - if (!zero_is_valid && unlikely(val == 0.0)) + if (unlikely(val == 0.0) && !zero_is_valid) ereport(ERROR, (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("value out of range: underflow"))); } /* - * Routines for operations with the checks above + * Floating-point arithmetic with overflow/underflow reported as errors * * There isn't any way to check for underflow of addition/subtraction * because numbers near the underflow value have already been rounded to @@ -178,7 +186,8 @@ float4_pl(const float4 val1, const float4 val2) float4 result; result = val1 + val2; - check_float4_val(result, isinf(val1) || isinf(val2), true); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); return result; } @@ -189,7 +198,8 @@ float8_pl(const float8 val1, const float8 val2) float8 result; result = val1 + val2; - check_float8_val(result, isinf(val1) || isinf(val2), true); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); return result; } @@ -200,7 +210,8 @@ float4_mi(const float4 val1, const float4 val2) float4 result; result = val1 - val2; - check_float4_val(result, isinf(val1) || isinf(val2), true); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); return result; } @@ -211,7 +222,8 @@ float8_mi(const float8 val1, const float8 val2) float8 result; result = val1 - val2; - check_float8_val(result, isinf(val1) || isinf(val2), true); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); return result; } @@ -222,8 +234,10 @@ 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); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + if (unlikely(result == 0.0f) && val1 != 0.0f && val2 != 0.0f) + float_underflow_error(); return result; } @@ -234,8 +248,10 @@ 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); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + if (unlikely(result == 0.0) && val1 != 0.0 && val2 != 0.0) + float_underflow_error(); return result; } @@ -245,13 +261,13 @@ 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"))); - + if (unlikely(val2 == 0.0f)) + float_zero_divide_error(); result = val1 / val2; - check_float4_val(result, isinf(val1) || isinf(val2), val1 == 0.0f); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + if (unlikely(result == 0.0f) && val1 != 0.0f) + float_underflow_error(); return result; } @@ -261,13 +277,13 @@ 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"))); - + if (unlikely(val2 == 0.0)) + float_zero_divide_error(); result = val1 / val2; - check_float8_val(result, isinf(val1) || isinf(val2), val1 == 0.0); + if (unlikely(isinf(result)) && !isinf(val1) && !isinf(val2)) + float_overflow_error(); + if (unlikely(result == 0.0) && val1 != 0.0) + float_underflow_error(); return result; } |