See if Windows likes this one any better.
--
Andrew (irc:RhodiumToad)
diff --git a/configure b/configure
index 06fc3c6835..e3176e24e9 100755
--- a/configure
+++ b/configure
@@ -15802,6 +15802,19 @@ esac
fi
+ac_fn_c_check_func "$LINENO" "strtof" "ac_cv_func_strtof"
+if test "x$ac_cv_func_strtof" = xyes; then :
+ $as_echo "#define HAVE_STRTOF 1" >>confdefs.h
+
+else
+ case " $LIBOBJS " in
+ *" strtof.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS strtof.$ac_objext"
+ ;;
+esac
+
+fi
+
case $host_os in
diff --git a/configure.in b/configure.in
index 4efb912c4d..bdaab717d7 100644
--- a/configure.in
+++ b/configure.in
@@ -1703,6 +1703,7 @@ AC_REPLACE_FUNCS(m4_normalize([
strlcat
strlcpy
strnlen
+ strtof
]))
case $host_os in
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 117ded8d1d..dce6ea31cf 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -104,13 +104,39 @@ is_infinite(double val)
/*
* float4in - converts "num" to float4
+ *
+ * Note that this code now uses strtof(), where it used to use strtod().
+ *
+ * The motivation for using strtof() is to avoid a double-rounding problem:
+ * for certain decimal inputs, if you round the input correctly to a double,
+ * and then round the double to a float, the result is incorrect in that it
+ * does not match the result of rounding the decimal value to float directly.
+ *
+ * One of the best examples is 7.038531e-26:
+ *
+ * 0xAE43FDp-107 = 7.03853069185120912085...e-26
+ * midpoint 7.03853100000000022281...e-26
+ * 0xAE43FEp-107 = 7.03853130814879132477...e-26
+ *
+ * making 0xAE43FDp-107 the correct float result, but if you do the conversion
+ * via a double, you get
+ *
+ * 0xAE43FD.7FFFFFF8p-107 = 7.03853099999999907487...e-26
+ * midpoint 7.03853099999999964884...e-26
+ * 0xAE43FD.80000000p-107 = 7.03853100000000022281...e-26
+ * 0xAE43FD.80000008p-107 = 7.03853100000000137076...e-26
+ *
+ * so the value rounds to the double exactly on the midpoint between the two
+ * nearest floats, and then rounding again to a float gives the incorrect
+ * result of 0xAE43FEp-107.
+ *
*/
Datum
float4in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
char *orig_num;
- double val;
+ float val;
char *endptr;
/*
@@ -135,7 +161,7 @@ float4in(PG_FUNCTION_ARGS)
"real", orig_num)));
errno = 0;
- val = strtod(num, &endptr);
+ val = strtof(num, &endptr);
/* did we not see anything that looks like a double? */
if (endptr == num || errno != 0)
@@ -143,14 +169,14 @@ float4in(PG_FUNCTION_ARGS)
int save_errno = errno;
/*
- * C99 requires that strtod() accept NaN, [+-]Infinity, and [+-]Inf,
+ * C99 requires that strtof() accept NaN, [+-]Infinity, and [+-]Inf,
* but not all platforms support all of these (and some accept them
* but set ERANGE anyway...) Therefore, we check for these inputs
- * ourselves if strtod() fails.
+ * ourselves if strtof() fails.
*
* Note: C99 also requires hexadecimal input as well as some extended
* forms of NaN, but we consider these forms unportable and don't try
- * to support them. You can use 'em if your strtod() takes 'em.
+ * to support them. You can use 'em if your strtof() takes 'em.
*/
if (pg_strncasecmp(num, "NaN", 3) == 0)
{
@@ -196,7 +222,7 @@ float4in(PG_FUNCTION_ARGS)
* detect whether it's a "real" out-of-range condition by checking
* to see if the result is zero or huge.
*/
- if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
+ if (val == 0.0 || val >= HUGE_VALF || val <= -HUGE_VALF)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type real",
@@ -232,13 +258,7 @@ float4in(PG_FUNCTION_ARGS)
errmsg("invalid input syntax for type %s: \"%s\"",
"real", orig_num)));
- /*
- * if we get here, we have a legal double, still need to check to see if
- * it's a legal float4
- */
- check_float4_val((float4) val, isinf(val), val == 0);
-
- PG_RETURN_FLOAT4((float4) val);
+ PG_RETURN_FLOAT4(val);
}
/*
diff --git a/src/include/port.h b/src/include/port.h
index a55c473262..a6950c1526 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -381,6 +381,10 @@ extern int isinf(double x);
#endif /* __clang__ && !__cplusplus */
#endif /* !HAVE_ISINF */
+#ifndef HAVE_STRTOF
+extern float strtof(const char *nptr, char **endptr);
+#endif
+
#ifndef HAVE_MKDTEMP
extern char *mkdtemp(char *path);
#endif
diff --git a/src/include/utils/float.h b/src/include/utils/float.h
index 0f82a25ede..5e11ab4aa9 100644
--- a/src/include/utils/float.h
+++ b/src/include/utils/float.h
@@ -17,6 +17,11 @@
#include <math.h>
+/* this might not be needed */
+#ifndef HUGE_VALF
+#define HUGE_VALF ((float)HUGE_VAL)
+#endif
+
#ifndef M_PI
/* From my RH5.2 gcc math.h file - thomas 2000-04-03 */
#define M_PI 3.14159265358979323846
diff --git a/src/port/strtof.c b/src/port/strtof.c
new file mode 100644
index 0000000000..75a41fbcfa
--- /dev/null
+++ b/src/port/strtof.c
@@ -0,0 +1,52 @@
+/*-------------------------------------------------------------------------
+ *
+ * strtof.c
+ *
+ * Portions Copyright (c) 2019, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * src/port/strtof.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "c.h"
+
+#include <float.h>
+#include <math.h>
+
+/*
+ * strtof() is part of C99; this file is only for the benefit of obsolete
+ * platforms. As such, it is known to return incorrect values for edge cases,
+ * which have to be allowed for in variant files for regression test results
+ * for any such platform.
+ */
+
+float
+strtof(const char *nptr, char **endptr)
+{
+ int caller_errno = errno;
+ double dresult;
+ float fresult;
+
+ errno = 0;
+ dresult = strtod(nptr, endptr);
+ fresult = (float) dresult;
+
+ if (errno == 0)
+ {
+ /*
+ * Value might be in-range for double but not float.
+ */
+ if (dresult != 0 && fresult == 0)
+ caller_errno = ERANGE; /* underflow */
+ if (!isinf(dresult) && isinf(fresult))
+ caller_errno = ERANGE; /* overflow */
+ }
+ else
+ caller_errno = errno;
+
+ errno = caller_errno;
+ return fresult;
+}
diff --git a/src/test/regress/expected/float4-misrounded-input.out b/src/test/regress/expected/float4-misrounded-input.out
new file mode 100644
index 0000000000..b8795c6fdf
--- /dev/null
+++ b/src/test/regress/expected/float4-misrounded-input.out
@@ -0,0 +1,401 @@
+--
+-- FLOAT4
+--
+CREATE TABLE FLOAT4_TBL (f1 float4);
+INSERT INTO FLOAT4_TBL(f1) VALUES (' 0.0');
+INSERT INTO FLOAT4_TBL(f1) VALUES ('1004.30 ');
+INSERT INTO FLOAT4_TBL(f1) VALUES (' -34.84 ');
+INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
+INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
+-- test for over and under flow
+INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
+ERROR: "10e70" is out of range for type real
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
+ERROR: "-10e70" is out of range for type real
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
+ERROR: "10e-70" is out of range for type real
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
+ERROR: "-10e-70" is out of range for type real
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
+ ^
+-- bad input
+INSERT INTO FLOAT4_TBL(f1) VALUES ('');
+ERROR: invalid input syntax for type real: ""
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES (' ');
+ERROR: invalid input syntax for type real: " "
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES (' ');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
+ERROR: invalid input syntax for type real: "xyz"
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
+ERROR: invalid input syntax for type real: "5.0.0"
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
+ERROR: invalid input syntax for type real: "5 . 0"
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('5. 0');
+ERROR: invalid input syntax for type real: "5. 0"
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('5. 0');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES (' - 3.0');
+ERROR: invalid input syntax for type real: " - 3.0"
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES (' - 3.0');
+ ^
+INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
+ERROR: invalid input syntax for type real: "123 5"
+LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
+ ^
+-- special inputs
+SELECT 'NaN'::float4;
+ float4
+--------
+ NaN
+(1 row)
+
+SELECT 'nan'::float4;
+ float4
+--------
+ NaN
+(1 row)
+
+SELECT ' NAN '::float4;
+ float4
+--------
+ NaN
+(1 row)
+
+SELECT 'infinity'::float4;
+ float4
+----------
+ Infinity
+(1 row)
+
+SELECT ' -INFINiTY '::float4;
+ float4
+-----------
+ -Infinity
+(1 row)
+
+-- bad special inputs
+SELECT 'N A N'::float4;
+ERROR: invalid input syntax for type real: "N A N"
+LINE 1: SELECT 'N A N'::float4;
+ ^
+SELECT 'NaN x'::float4;
+ERROR: invalid input syntax for type real: "NaN x"
+LINE 1: SELECT 'NaN x'::float4;
+ ^
+SELECT ' INFINITY x'::float4;
+ERROR: invalid input syntax for type real: " INFINITY x"
+LINE 1: SELECT ' INFINITY x'::float4;
+ ^
+SELECT 'Infinity'::float4 + 100.0;
+ ?column?
+----------
+ Infinity
+(1 row)
+
+SELECT 'Infinity'::float4 / 'Infinity'::float4;
+ ?column?
+----------
+ NaN
+(1 row)
+
+SELECT 'nan'::float4 / 'nan'::float4;
+ ?column?
+----------
+ NaN
+(1 row)
+
+SELECT 'nan'::numeric::float4;
+ float4
+--------
+ NaN
+(1 row)
+
+SELECT '' AS five, * FROM FLOAT4_TBL;
+ five | f1
+------+-------------
+ | 0
+ | 1004.3
+ | -34.84
+ | 1.23457e+20
+ | 1.23457e-20
+(5 rows)
+
+SELECT '' AS four, f.* FROM FLOAT4_TBL f WHERE f.f1 <> '1004.3';
+ four | f1
+------+-------------
+ | 0
+ | -34.84
+ | 1.23457e+20
+ | 1.23457e-20
+(4 rows)
+
+SELECT '' AS one, f.* FROM FLOAT4_TBL f WHERE f.f1 = '1004.3';
+ one | f1
+-----+--------
+ | 1004.3
+(1 row)
+
+SELECT '' AS three, f.* FROM FLOAT4_TBL f WHERE '1004.3' > f.f1;
+ three | f1
+-------+-------------
+ | 0
+ | -34.84
+ | 1.23457e-20
+(3 rows)
+
+SELECT '' AS three, f.* FROM FLOAT4_TBL f WHERE f.f1 < '1004.3';
+ three | f1
+-------+-------------
+ | 0
+ | -34.84
+ | 1.23457e-20
+(3 rows)
+
+SELECT '' AS four, f.* FROM FLOAT4_TBL f WHERE '1004.3' >= f.f1;
+ four | f1
+------+-------------
+ | 0
+ | 1004.3
+ | -34.84
+ | 1.23457e-20
+(4 rows)
+
+SELECT '' AS four, f.* FROM FLOAT4_TBL f WHERE f.f1 <= '1004.3';
+ four | f1
+------+-------------
+ | 0
+ | 1004.3
+ | -34.84
+ | 1.23457e-20
+(4 rows)
+
+SELECT '' AS three, f.f1, f.f1 * '-10' AS x FROM FLOAT4_TBL f
+ WHERE f.f1 > '0.0';
+ three | f1 | x
+-------+-------------+--------------
+ | 1004.3 | -10043
+ | 1.23457e+20 | -1.23457e+21
+ | 1.23457e-20 | -1.23457e-19
+(3 rows)
+
+SELECT '' AS three, f.f1, f.f1 + '-10' AS x FROM FLOAT4_TBL f
+ WHERE f.f1 > '0.0';
+ three | f1 | x
+-------+-------------+-------------
+ | 1004.3 | 994.3
+ | 1.23457e+20 | 1.23457e+20
+ | 1.23457e-20 | -10
+(3 rows)
+
+SELECT '' AS three, f.f1, f.f1 / '-10' AS x FROM FLOAT4_TBL f
+ WHERE f.f1 > '0.0';
+ three | f1 | x
+-------+-------------+--------------
+ | 1004.3 | -100.43
+ | 1.23457e+20 | -1.23457e+19
+ | 1.23457e-20 | -1.23457e-21
+(3 rows)
+
+SELECT '' AS three, f.f1, f.f1 - '-10' AS x FROM FLOAT4_TBL f
+ WHERE f.f1 > '0.0';
+ three | f1 | x
+-------+-------------+-------------
+ | 1004.3 | 1014.3
+ | 1.23457e+20 | 1.23457e+20
+ | 1.23457e-20 | 10
+(3 rows)
+
+-- test divide by zero
+SELECT '' AS bad, f.f1 / '0.0' from FLOAT4_TBL f;
+ERROR: division by zero
+SELECT '' AS five, * FROM FLOAT4_TBL;
+ five | f1
+------+-------------
+ | 0
+ | 1004.3
+ | -34.84
+ | 1.23457e+20
+ | 1.23457e-20
+(5 rows)
+
+-- test the unary float4abs operator
+SELECT '' AS five, f.f1, @f.f1 AS abs_f1 FROM FLOAT4_TBL f;
+ five | f1 | abs_f1
+------+-------------+-------------
+ | 0 | 0
+ | 1004.3 | 1004.3
+ | -34.84 | 34.84
+ | 1.23457e+20 | 1.23457e+20
+ | 1.23457e-20 | 1.23457e-20
+(5 rows)
+
+UPDATE FLOAT4_TBL
+ SET f1 = FLOAT4_TBL.f1 * '-1'
+ WHERE FLOAT4_TBL.f1 > '0.0';
+SELECT '' AS five, * FROM FLOAT4_TBL;
+ five | f1
+------+--------------
+ | 0
+ | -34.84
+ | -1004.3
+ | -1.23457e+20
+ | -1.23457e-20
+(5 rows)
+
+-- test edge-case coercions to integer
+SELECT '32767.4'::float4::int2;
+ int2
+-------
+ 32767
+(1 row)
+
+SELECT '32767.6'::float4::int2;
+ERROR: smallint out of range
+SELECT '-32768.4'::float4::int2;
+ int2
+--------
+ -32768
+(1 row)
+
+SELECT '-32768.6'::float4::int2;
+ERROR: smallint out of range
+SELECT '2147483520'::float4::int4;
+ int4
+------------
+ 2147483520
+(1 row)
+
+SELECT '2147483647'::float4::int4;
+ERROR: integer out of range
+SELECT '-2147483648.5'::float4::int4;
+ int4
+-------------
+ -2147483648
+(1 row)
+
+SELECT '-2147483900'::float4::int4;
+ERROR: integer out of range
+SELECT '9223369837831520256'::float4::int8;
+ int8
+---------------------
+ 9223369837831520256
+(1 row)
+
+SELECT '9223372036854775807'::float4::int8;
+ERROR: bigint out of range
+SELECT '-9223372036854775808.5'::float4::int8;
+ int8
+----------------------
+ -9223372036854775808
+(1 row)
+
+SELECT '-9223380000000000000'::float4::int8;
+ERROR: bigint out of range
+-- Test for correct input rounding in edge cases.
+-- These lists are from Paxson 1991, excluding subnormals and
+-- inputs of over 9 sig. digits.
+SELECT float4send('5e-20'::float4);
+ float4send
+------------
+ \x1f6c1e4a
+(1 row)
+
+SELECT float4send('67e14'::float4);
+ float4send
+------------
+ \x59be6cea
+(1 row)
+
+SELECT float4send('985e15'::float4);
+ float4send
+------------
+ \x5d5ab6c4
+(1 row)
+
+SELECT float4send('55895e-16'::float4);
+ float4send
+------------
+ \x2cc4a9bd
+(1 row)
+
+SELECT float4send('7038531e-32'::float4);
+ float4send
+------------
+ \x15ae43fe
+(1 row)
+
+SELECT float4send('702990899e-20'::float4);
+ float4send
+------------
+ \x2cf757ca
+(1 row)
+
+SELECT float4send('3e-23'::float4);
+ float4send
+------------
+ \x1a111234
+(1 row)
+
+SELECT float4send('57e18'::float4);
+ float4send
+------------
+ \x6045c22c
+(1 row)
+
+SELECT float4send('789e-35'::float4);
+ float4send
+------------
+ \x0a23de70
+(1 row)
+
+SELECT float4send('2539e-18'::float4);
+ float4send
+------------
+ \x2736f449
+(1 row)
+
+SELECT float4send('76173e28'::float4);
+ float4send
+------------
+ \x7616398a
+(1 row)
+
+SELECT float4send('887745e-11'::float4);
+ float4send
+------------
+ \x3714f05c
+(1 row)
+
+SELECT float4send('5382571e-37'::float4);
+ float4send
+------------
+ \x0d2eaca7
+(1 row)
+
+SELECT float4send('82381273e-35'::float4);
+ float4send
+------------
+ \x128289d0
+(1 row)
+
+SELECT float4send('750486563e-38'::float4);
+ float4send
+------------
+ \x0f18377e
+(1 row)
+
diff --git a/src/test/regress/expected/float4.out b/src/test/regress/expected/float4.out
index 2f47e1c202..3aa7f257d5 100644
--- a/src/test/regress/expected/float4.out
+++ b/src/test/regress/expected/float4.out
@@ -9,19 +9,19 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
-- test for over and under flow
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
-ERROR: value out of range: overflow
+ERROR: "10e70" is out of range for type real
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e70');
^
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
-ERROR: value out of range: overflow
+ERROR: "-10e70" is out of range for type real
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e70');
^
INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
-ERROR: value out of range: underflow
+ERROR: "10e-70" is out of range for type real
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-70');
^
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
-ERROR: value out of range: underflow
+ERROR: "-10e-70" is out of range for type real
LINE 1: INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-70');
^
-- bad input
@@ -306,3 +306,96 @@ SELECT '-9223372036854775808.5'::float4::int8;
SELECT '-9223380000000000000'::float4::int8;
ERROR: bigint out of range
+-- Test for correct input rounding in edge cases.
+-- These lists are from Paxson 1991, excluding subnormals and
+-- inputs of over 9 sig. digits.
+SELECT float4send('5e-20'::float4);
+ float4send
+------------
+ \x1f6c1e4a
+(1 row)
+
+SELECT float4send('67e14'::float4);
+ float4send
+------------
+ \x59be6cea
+(1 row)
+
+SELECT float4send('985e15'::float4);
+ float4send
+------------
+ \x5d5ab6c4
+(1 row)
+
+SELECT float4send('55895e-16'::float4);
+ float4send
+------------
+ \x2cc4a9bd
+(1 row)
+
+SELECT float4send('7038531e-32'::float4);
+ float4send
+------------
+ \x15ae43fd
+(1 row)
+
+SELECT float4send('702990899e-20'::float4);
+ float4send
+------------
+ \x2cf757ca
+(1 row)
+
+SELECT float4send('3e-23'::float4);
+ float4send
+------------
+ \x1a111234
+(1 row)
+
+SELECT float4send('57e18'::float4);
+ float4send
+------------
+ \x6045c22c
+(1 row)
+
+SELECT float4send('789e-35'::float4);
+ float4send
+------------
+ \x0a23de70
+(1 row)
+
+SELECT float4send('2539e-18'::float4);
+ float4send
+------------
+ \x2736f449
+(1 row)
+
+SELECT float4send('76173e28'::float4);
+ float4send
+------------
+ \x7616398a
+(1 row)
+
+SELECT float4send('887745e-11'::float4);
+ float4send
+------------
+ \x3714f05c
+(1 row)
+
+SELECT float4send('5382571e-37'::float4);
+ float4send
+------------
+ \x0d2eaca7
+(1 row)
+
+SELECT float4send('82381273e-35'::float4);
+ float4send
+------------
+ \x128289d1
+(1 row)
+
+SELECT float4send('750486563e-38'::float4);
+ float4send
+------------
+ \x0f18377e
+(1 row)
+
diff --git a/src/test/regress/resultmap b/src/test/regress/resultmap
index 46ca5639c2..3bd1585a35 100644
--- a/src/test/regress/resultmap
+++ b/src/test/regress/resultmap
@@ -3,3 +3,4 @@ float8:out:i.86-.*-openbsd=float8-small-is-zero.out
float8:out:i.86-.*-netbsd=float8-small-is-zero.out
float8:out:m68k-.*-netbsd=float8-small-is-zero.out
float8:out:i.86-pc-cygwin=float8-small-is-zero.out
+float4:out:hppa.*-hp-hpux10.*=float4-misrounded-input.out
diff --git a/src/test/regress/sql/float4.sql b/src/test/regress/sql/float4.sql
index 46a9166d13..12421f7c75 100644
--- a/src/test/regress/sql/float4.sql
+++ b/src/test/regress/sql/float4.sql
@@ -95,3 +95,24 @@ SELECT '9223369837831520256'::float4::int8;
SELECT '9223372036854775807'::float4::int8;
SELECT '-9223372036854775808.5'::float4::int8;
SELECT '-9223380000000000000'::float4::int8;
+
+-- Test for correct input rounding in edge cases.
+-- These lists are from Paxson 1991, excluding subnormals and
+-- inputs of over 9 sig. digits.
+
+SELECT float4send('5e-20'::float4);
+SELECT float4send('67e14'::float4);
+SELECT float4send('985e15'::float4);
+SELECT float4send('55895e-16'::float4);
+SELECT float4send('7038531e-32'::float4);
+SELECT float4send('702990899e-20'::float4);
+
+SELECT float4send('3e-23'::float4);
+SELECT float4send('57e18'::float4);
+SELECT float4send('789e-35'::float4);
+SELECT float4send('2539e-18'::float4);
+SELECT float4send('76173e28'::float4);
+SELECT float4send('887745e-11'::float4);
+SELECT float4send('5382571e-37'::float4);
+SELECT float4send('82381273e-35'::float4);
+SELECT float4send('750486563e-38'::float4);