summaryrefslogtreecommitdiff
path: root/src/include/utils/float.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/utils/float.h')
-rw-r--r--src/include/utils/float.h66
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;
}