diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 77a5d7d42f..b9a83683d5 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1212,15 +1212,8 @@ dtoi4(PG_FUNCTION_ARGS)
 	 */
 	num = rint(num);
 
-	/*
-	 * Range check.  We must be careful here that the boundary values are
-	 * expressed exactly in the float domain.  We expect PG_INT32_MIN to be an
-	 * exact power of 2, so it will be represented exactly; but PG_INT32_MAX
-	 * isn't, and might get rounded off, so avoid using it.
-	 */
-	if (unlikely(num < (float8) PG_INT32_MIN ||
-				 num >= -((float8) PG_INT32_MIN) ||
-				 isnan(num)))
+	/* Range check */
+	if (unlikely(!FLOAT8_FITS_IN_INT32(num)))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
@@ -1244,15 +1237,8 @@ dtoi2(PG_FUNCTION_ARGS)
 	 */
 	num = rint(num);
 
-	/*
-	 * Range check.  We must be careful here that the boundary values are
-	 * expressed exactly in the float domain.  We expect PG_INT16_MIN to be an
-	 * exact power of 2, so it will be represented exactly; but PG_INT16_MAX
-	 * isn't, and might get rounded off, so avoid using it.
-	 */
-	if (unlikely(num < (float8) PG_INT16_MIN ||
-				 num >= -((float8) PG_INT16_MIN) ||
-				 isnan(num)))
+	/* Range check */
+	if (unlikely(!FLOAT8_FITS_IN_INT16(num)))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
@@ -1300,15 +1286,8 @@ ftoi4(PG_FUNCTION_ARGS)
 	 */
 	num = rint(num);
 
-	/*
-	 * Range check.  We must be careful here that the boundary values are
-	 * expressed exactly in the float domain.  We expect PG_INT32_MIN to be an
-	 * exact power of 2, so it will be represented exactly; but PG_INT32_MAX
-	 * isn't, and might get rounded off, so avoid using it.
-	 */
-	if (unlikely(num < (float4) PG_INT32_MIN ||
-				 num >= -((float4) PG_INT32_MIN) ||
-				 isnan(num)))
+	/* Range check */
+	if (unlikely(!FLOAT4_FITS_IN_INT32(num)))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("integer out of range")));
@@ -1332,15 +1311,8 @@ ftoi2(PG_FUNCTION_ARGS)
 	 */
 	num = rint(num);
 
-	/*
-	 * Range check.  We must be careful here that the boundary values are
-	 * expressed exactly in the float domain.  We expect PG_INT16_MIN to be an
-	 * exact power of 2, so it will be represented exactly; but PG_INT16_MAX
-	 * isn't, and might get rounded off, so avoid using it.
-	 */
-	if (unlikely(num < (float4) PG_INT16_MIN ||
-				 num >= -((float4) PG_INT16_MIN) ||
-				 isnan(num)))
+	/* Range check */
+	if (unlikely(!FLOAT4_FITS_IN_INT16(num)))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("smallint out of range")));
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 0ff9394a2f..f0f9b97deb 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -1216,15 +1216,8 @@ dtoi8(PG_FUNCTION_ARGS)
 	 */
 	num = rint(num);
 
-	/*
-	 * Range check.  We must be careful here that the boundary values are
-	 * expressed exactly in the float domain.  We expect PG_INT64_MIN to be an
-	 * exact power of 2, so it will be represented exactly; but PG_INT64_MAX
-	 * isn't, and might get rounded off, so avoid using it.
-	 */
-	if (unlikely(num < (float8) PG_INT64_MIN ||
-				 num >= -((float8) PG_INT64_MIN) ||
-				 isnan(num)))
+	/* Range check */
+	if (unlikely(!FLOAT8_FITS_IN_INT64(num)))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
@@ -1258,15 +1251,8 @@ ftoi8(PG_FUNCTION_ARGS)
 	 */
 	num = rint(num);
 
-	/*
-	 * Range check.  We must be careful here that the boundary values are
-	 * expressed exactly in the float domain.  We expect PG_INT64_MIN to be an
-	 * exact power of 2, so it will be represented exactly; but PG_INT64_MAX
-	 * isn't, and might get rounded off, so avoid using it.
-	 */
-	if (unlikely(num < (float4) PG_INT64_MIN ||
-				 num >= -((float4) PG_INT64_MIN) ||
-				 isnan(num)))
+	/* Range check */
+	if (unlikely(!FLOAT4_FITS_IN_INT64(num)))
 		ereport(ERROR,
 				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 				 errmsg("bigint out of range")));
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 1dc4c820de..8c1572bb2a 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -3233,7 +3233,7 @@ interval_mul(PG_FUNCTION_ARGS)
 	/* cascade units down */
 	result->day += (int32) month_remainder_days;
 	result_double = rint(span->time * factor + sec_remainder * USECS_PER_SEC);
-	if (result_double > PG_INT64_MAX || result_double < PG_INT64_MIN)
+	if (!FLOAT8_FITS_IN_INT64(result_double))
 		ereport(ERROR,
 				(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 				 errmsg("interval out of range")));
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 03bcd22996..3d697cf7f0 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -1676,7 +1676,7 @@ coerceToInt(PgBenchValue *pval, int64 *ival)
 	{
 		double		dval = pval->u.dval;
 
-		if (dval < PG_INT64_MIN || PG_INT64_MAX < dval)
+		if (!FLOAT8_FITS_IN_INT64(dval))
 		{
 			fprintf(stderr, "double to int overflow for %f\n", dval);
 			return false;
diff --git a/src/include/c.h b/src/include/c.h
index d752cc07dc..359f2ce937 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -444,6 +444,19 @@ typedef unsigned PG_INT128_TYPE uint128
 #define PG_INT64_MAX	INT64CONST(0x7FFFFFFFFFFFFFFF)
 #define PG_UINT64_MAX	UINT64CONST(0xFFFFFFFFFFFFFFFF)
 
+#define FLOAT4_FITS_IN_INT16(num) \
+	((num) >= (float4) PG_INT16_MIN && (num) < -((float4) PG_INT16_MIN))
+#define FLOAT4_FITS_IN_INT32(num) \
+	((num) >= (float4) PG_INT32_MIN && (num) < -((float4) PG_INT32_MIN))
+#define FLOAT4_FITS_IN_INT64(num) \
+	((num) >= (float4) PG_INT64_MIN && (num) < -((float4) PG_INT64_MIN))
+#define FLOAT8_FITS_IN_INT16(num) \
+	((num) >= (float8) PG_INT16_MIN && (num) < -((float8) PG_INT16_MIN))
+#define FLOAT8_FITS_IN_INT32(num) \
+	((num) >= (float8) PG_INT32_MIN && (num) < -((float8) PG_INT32_MIN))
+#define FLOAT8_FITS_IN_INT64(num) \
+	((num) >= (float8) PG_INT64_MIN && (num) < -((float8) PG_INT64_MIN))
+
 /* Max value of size_t might also be missing if we don't have stdint.h */
 #ifndef SIZE_MAX
 #if SIZEOF_SIZE_T == 8
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index f88f34550a..ec81b95606 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -232,6 +232,10 @@ INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483648 years');
 ERROR:  interval out of range
 LINE 1: INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483648 years'...
                                                  ^
+-- Test an interval whose epoch is not representable as 64 bits
+-- The next should fail as out-of-range
+select extract(epoch from '256 microseconds'::interval * (2^55)::float8);
+ERROR:  interval out of range
 SELECT r1.*, r2.*
    FROM INTERVAL_TBL_OF r1, INTERVAL_TBL_OF r2
    WHERE r1.f1 > r2.f1
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index bc5537d1b9..ddd414e2aa 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -73,6 +73,10 @@ INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483649 days');
 INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('2147483647 years');
 INSERT INTO INTERVAL_TBL_OF (f1) VALUES ('-2147483648 years');
 
+-- Test an interval whose epoch is not representable as 64 bits
+-- The next should fail as out-of-range
+select extract(epoch from '256 microseconds'::interval * (2^55)::float8);
+
 SELECT r1.*, r2.*
    FROM INTERVAL_TBL_OF r1, INTERVAL_TBL_OF r2
    WHERE r1.f1 > r2.f1
