Change floating-point output format for improved performance.
authorAndrew Gierth <rhodiumtoad@postgresql.org>
Wed, 13 Feb 2019 15:20:33 +0000 (15:20 +0000)
committerAndrew Gierth <rhodiumtoad@postgresql.org>
Wed, 13 Feb 2019 15:20:33 +0000 (15:20 +0000)
Previously, floating-point output was done by rounding to a specific
decimal precision; by default, to 6 or 15 decimal digits (losing
information) or as requested using extra_float_digits. Drivers that
wanted exact float values, and applications like pg_dump that must
preserve values exactly, set extra_float_digits=3 (or sometimes 2 for
historical reasons, though this isn't enough for float4).

Unfortunately, decimal rounded output is slow enough to become a
noticable bottleneck when dealing with large result sets or COPY of
large tables when many floating-point values are involved.

Floating-point output can be done much faster when the output is not
rounded to a specific decimal length, but rather is chosen as the
shortest decimal representation that is closer to the original float
value than to any other value representable in the same precision. The
recently published Ryu algorithm by Ulf Adams is both relatively
simple and remarkably fast.

Accordingly, change float4out/float8out to output shortest decimal
representations if extra_float_digits is greater than 0, and make that
the new default. Applications that need rounded output can set
extra_float_digits back to 0 or below, and take the resulting
performance hit.

We make one concession to portability for systems with buggy
floating-point input: we do not output decimal values that fall
exactly halfway between adjacent representable binary values (which
would rely on the reader doing round-to-nearest-even correctly). This
is known to be a problem at least for VS2013 on Windows.

Our version of the Ryu code originates from
https://github.com/ulfjack/ryu/ at commit c9c3fb1979, but with the
following (significant) modifications:

 - Output format is changed to use fixed-point notation for small
   exponents, as printf would, and also to use lowercase 'e', a
   minimum of 2 exponent digits, and a mandatory sign on the exponent,
   to keep the formatting as close as possible to previous output.

 - The output of exact midpoint values is disabled as noted above.

 - The integer fast-path code is changed somewhat (since we have
   fixed-point output and the upstream did not).

 - Our project style has been largely applied to the code with the
   exception of C99 declaration-after-statement, which has been
   retained as an exception to our present policy.

 - Most of upstream's debugging and conditionals are removed, and we
   use our own configure tests to determine things like uint128
   availability.

Changing the float output format obviously affects a number of
regression tests. This patch uses an explicit setting of
extra_float_digits=0 for test output that is not expected to be
exactly reproducible (e.g. due to numerical instability or differing
algorithms for transcendental functions).

Conversions from floats to numeric are unchanged by this patch. These
may appear in index expressions and it is not yet clear whether any
change should be made, so that can be left for another day.

This patch assumes that the only supported floating point format is
now IEEE format, and the documentation is updated to reflect that.

Code by me, adapting the work of Ulf Adams and other contributors.

References:
https://dl.acm.org/citation.cfm?id=3192369

Reviewed-by: Tom Lane, Andres Freund, Donald Dong
Discussion: https://postgr.es/m/87r2el1bx6.fsf@news-spur.riddles.org.uk

50 files changed:
configure
configure.in
contrib/btree_gist/expected/float4.out
contrib/btree_gist/expected/float8.out
contrib/cube/expected/cube.out
contrib/cube/expected/cube_sci.out
contrib/cube/sql/cube.sql
contrib/pg_trgm/expected/pg_strict_word_trgm.out
contrib/pg_trgm/expected/pg_trgm.out
contrib/pg_trgm/expected/pg_word_trgm.out
contrib/pg_trgm/sql/pg_strict_word_trgm.sql
contrib/pg_trgm/sql/pg_trgm.sql
contrib/pg_trgm/sql/pg_word_trgm.sql
contrib/seg/expected/seg.out
doc/src/sgml/config.sgml
doc/src/sgml/datatype.sgml
src/Makefile.global.in
src/backend/utils/adt/float.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/common/Makefile
src/common/d2s.c [new file with mode: 0644]
src/common/d2s_full_table.h [new file with mode: 0644]
src/common/d2s_intrinsics.h [new file with mode: 0644]
src/common/digit_table.h [new file with mode: 0644]
src/common/f2s.c [new file with mode: 0644]
src/common/ryu_common.h [new file with mode: 0644]
src/include/common/shortest_dec.h [new file with mode: 0644]
src/test/regress/expected/aggregates.out
src/test/regress/expected/circle.out
src/test/regress/expected/float4-misrounded-input.out
src/test/regress/expected/float4.out
src/test/regress/expected/float8-small-is-zero.out
src/test/regress/expected/float8.out
src/test/regress/expected/int8.out
src/test/regress/expected/jsonb.out
src/test/regress/expected/line.out
src/test/regress/expected/point.out
src/test/regress/expected/rules.out
src/test/regress/expected/tsearch.out
src/test/regress/expected/tstypes.out
src/test/regress/expected/updatable_views.out
src/test/regress/expected/window.out
src/test/regress/sql/aggregates.sql
src/test/regress/sql/circle.sql
src/test/regress/sql/float4.sql
src/test/regress/sql/float8.sql
src/test/regress/sql/point.sql
src/test/regress/sql/updatable_views.sql
src/tools/msvc/Mkvcbuild.pm

index 0bc4a69b04abb050dbef03cd95bf4342e7114c3c..7291311ae38624ae1ce42a1073ed4ca1b521658e 100755 (executable)
--- a/configure
+++ b/configure
@@ -732,6 +732,7 @@ CPP
 BITCODE_CXXFLAGS
 BITCODE_CFLAGS
 CFLAGS_VECTOR
+PERMIT_DECLARATION_AFTER_STATEMENT
 LLVM_BINPATH
 LLVM_CXXFLAGS
 LLVM_CFLAGS
@@ -5261,6 +5262,7 @@ if test "$GCC" = yes -a "$ICC" = no; then
   CFLAGS="-Wall -Wmissing-prototypes -Wpointer-arith"
   CXXFLAGS="-Wall -Wpointer-arith"
   # These work in some but not all gcc versions
+  save_CFLAGS=$CFLAGS
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Wdeclaration-after-statement, for CFLAGS" >&5
 $as_echo_n "checking whether ${CC} supports -Wdeclaration-after-statement, for CFLAGS... " >&6; }
@@ -5301,7 +5303,13 @@ if test x"$pgac_cv_prog_CC_cflags__Wdeclaration_after_statement" = x"yes"; then
 fi
 
 
-  # -Wdeclaration-after-statement isn't applicable for C++
+  # -Wdeclaration-after-statement isn't applicable for C++.  Specific C files
+  # disable it, so AC_SUBST the negative form.
+  PERMIT_DECLARATION_AFTER_STATEMENT=
+  if test x"save_$CFLAGS" != x"$CFLAGS"; then
+    PERMIT_DECLARATION_AFTER_STATEMENT=-Wno-declaration-after-statement
+  fi
+
   # Really don't want VLAs to be used in our dialect of C
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports -Werror=vla, for CFLAGS" >&5
index 5960a3c2b28e80786fab94bd3e538641a6c46bc3..8a55e8e8a5941d47f7c8d7843c188981fcf63789 100644 (file)
@@ -476,8 +476,15 @@ if test "$GCC" = yes -a "$ICC" = no; then
   CFLAGS="-Wall -Wmissing-prototypes -Wpointer-arith"
   CXXFLAGS="-Wall -Wpointer-arith"
   # These work in some but not all gcc versions
+  save_CFLAGS=$CFLAGS
   PGAC_PROG_CC_CFLAGS_OPT([-Wdeclaration-after-statement])
-  # -Wdeclaration-after-statement isn't applicable for C++
+  # -Wdeclaration-after-statement isn't applicable for C++.  Specific C files
+  # disable it, so AC_SUBST the negative form.
+  PERMIT_DECLARATION_AFTER_STATEMENT=
+  if test x"save_$CFLAGS" != x"$CFLAGS"; then
+    PERMIT_DECLARATION_AFTER_STATEMENT=-Wno-declaration-after-statement
+  fi
+  AC_SUBST(PERMIT_DECLARATION_AFTER_STATEMENT)
   # Really don't want VLAs to be used in our dialect of C
   PGAC_PROG_CC_CFLAGS_OPT([-Werror=vla])
   # -Wvla is not applicable for C++
index abbd9eef4e8aa4c1a4ea905197f2cc379d05ec36..dfe732049e6d6b7b7b5541ca25047c0b55978657 100644 (file)
@@ -33,11 +33,11 @@ SELECT count(*) FROM float4tmp WHERE a >  -179.0;
 (1 row)
 
 SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
-    a     | ?column? 
-----------+----------
-     -179 |        0
- -189.024 |  10.0239
- -158.177 |  20.8226
+     a      | ?column?  
+------------+-----------
+       -179 |         0
+ -189.02386 | 10.023865
+ -158.17741 | 20.822586
 (3 rows)
 
 CREATE INDEX float4idx ON float4tmp USING gist ( a );
@@ -82,10 +82,10 @@ SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
 (3 rows)
 
 SELECT a, a <-> '-179.0' FROM float4tmp ORDER BY a <-> '-179.0' LIMIT 3;
-    a     | ?column? 
-----------+----------
-     -179 |        0
- -189.024 |  10.0239
- -158.177 |  20.8226
+     a      | ?column?  
+------------+-----------
+       -179 |         0
+ -189.02386 | 10.023865
+ -158.17741 | 20.822586
 (3 rows)
 
index 5111dbdfaea033cd845e563a526df67ac713c940..ebd0ef3d689a14a40e6ca991352753065c764eba 100644 (file)
@@ -33,11 +33,11 @@ SELECT count(*) FROM float8tmp WHERE a >  -1890.0;
 (1 row)
 
 SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
-      a       |  ?column?  
---------------+------------
-        -1890 |          0
- -2003.634512 | 113.634512
-  -1769.73634 |  120.26366
+      a       |      ?column?      
+--------------+--------------------
+        -1890 |                  0
+ -2003.634512 | 113.63451200000009
+  -1769.73634 | 120.26366000000007
 (3 rows)
 
 CREATE INDEX float8idx ON float8tmp USING gist ( a );
@@ -82,10 +82,10 @@ SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
 (3 rows)
 
 SELECT a, a <-> '-1890.0' FROM float8tmp ORDER BY a <-> '-1890.0' LIMIT 3;
-      a       |  ?column?  
---------------+------------
-        -1890 |          0
- -2003.634512 | 113.634512
-  -1769.73634 |  120.26366
+      a       |      ?column?      
+--------------+--------------------
+        -1890 |                  0
+ -2003.634512 | 113.63451200000009
+  -1769.73634 | 120.26366000000007
 (3 rows)
 
index 1a65e6944abd57e6d853193e895d37716dd85729..5b89cb1a26b144168a15fd0a9fd1b93fe63db50c 100644 (file)
@@ -81,21 +81,21 @@ SELECT 'NaN'::cube AS cube;
 (1 row)
 
 SELECT '.1234567890123456'::cube AS cube;
-        cube         
----------------------
- (0.123456789012346)
+         cube         
+----------------------
+ (0.1234567890123456)
 (1 row)
 
 SELECT '+.1234567890123456'::cube AS cube;
-        cube         
----------------------
- (0.123456789012346)
+         cube         
+----------------------
+ (0.1234567890123456)
 (1 row)
 
 SELECT '-.1234567890123456'::cube AS cube;
-         cube         
-----------------------
- (-0.123456789012346)
+         cube          
+-----------------------
+ (-0.1234567890123456)
 (1 row)
 
 -- simple lists (points)
@@ -943,9 +943,9 @@ SELECT cube_distance('(42,42,42,42)'::cube,'(137,137,137,137)'::cube);
 (1 row)
 
 SELECT cube_distance('(42,42,42)'::cube,'(137,137)'::cube);
-  cube_distance   
-------------------
- 140.762210837994
+   cube_distance    
+--------------------
+ 140.76221083799445
 (1 row)
 
 -- Test of cube function (text to cube)
@@ -1356,8 +1356,9 @@ SELECT cube_size('(42,137)'::cube);
          0
 (1 row)
 
--- Test of distances
+-- Test of distances (euclidean distance may not be bit-exact)
 --
+SET extra_float_digits = 0;
 SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
  cube_distance 
 ---------------
@@ -1370,6 +1371,7 @@ SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
    5
 (1 row)
 
+RESET extra_float_digits;
 SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
  distance_chebyshev 
 --------------------
@@ -1557,6 +1559,7 @@ RESET enable_bitmapscan;
 INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some corner cases
 SET enable_seqscan = false;
 -- Test different metrics
+SET extra_float_digits = 0;
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
             c            |       dist       
 -------------------------+------------------
@@ -1567,6 +1570,7 @@ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c
  (1444, 403),(1346, 344) |              846
 (5 rows)
 
+RESET extra_float_digits;
 SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
             c            | dist 
 -------------------------+------
@@ -1751,6 +1755,7 @@ SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upp
 -- Same queries with sequential scan (should give the same results as above)
 RESET enable_seqscan;
 SET enable_indexscan = OFF;
+SET extra_float_digits = 0;
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
             c            |       dist       
 -------------------------+------------------
@@ -1761,6 +1766,7 @@ SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c
  (1444, 403),(1346, 344) |              846
 (5 rows)
 
+RESET extra_float_digits;
 SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
             c            | dist 
 -------------------------+------
index 1e8269cdf006e3ed2057292b1120cc7f4851272a..488499ac8eaf25f85ca297a7535577dd7cadf3fa 100644 (file)
@@ -87,20 +87,20 @@ SELECT '-1e-300'::cube AS cube;
 (1 row)
 
 SELECT '1234567890123456'::cube AS cube;
-          cube          
-------------------------
- (1.23456789012346e+15)
+          cube           
+-------------------------
+ (1.234567890123456e+15)
 (1 row)
 
 SELECT '+1234567890123456'::cube AS cube;
-          cube          
-------------------------
- (1.23456789012346e+15)
+          cube           
+-------------------------
+ (1.234567890123456e+15)
 (1 row)
 
 SELECT '-1234567890123456'::cube AS cube;
-          cube           
--------------------------
- (-1.23456789012346e+15)
+           cube           
+--------------------------
+ (-1.234567890123456e+15)
 (1 row)
 
index 59e7e4159d6119123bde0b890df708ec049fbe03..7f8b2e3979926c7be168ae6212e4aa0f60098f51 100644 (file)
@@ -336,10 +336,12 @@ SELECT cube_inter('(1,2,3)'::cube, '(5,6,3)'::cube); -- point args
 SELECT cube_size('(4,8),(15,16)'::cube);
 SELECT cube_size('(42,137)'::cube);
 
--- Test of distances
+-- Test of distances (euclidean distance may not be bit-exact)
 --
+SET extra_float_digits = 0;
 SELECT cube_distance('(1,1)'::cube, '(4,5)'::cube);
 SELECT '(1,1)'::cube <-> '(4,5)'::cube as d_e;
+RESET extra_float_digits;
 SELECT distance_chebyshev('(1,1)'::cube, '(4,5)'::cube);
 SELECT '(1,1)'::cube <=> '(4,5)'::cube as d_c;
 SELECT distance_taxicab('(1,1)'::cube, '(4,5)'::cube);
@@ -395,7 +397,9 @@ INSERT INTO test_cube VALUES ('(1,1)'), ('(100000)'), ('(0, 100000)'); -- Some c
 SET enable_seqscan = false;
 
 -- Test different metrics
+SET extra_float_digits = 0;
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+RESET extra_float_digits;
 SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
 SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
 
@@ -412,7 +416,9 @@ SELECT c~>(-4), c FROM test_cube ORDER BY c~>(-4) LIMIT 15; -- descending by upp
 -- Same queries with sequential scan (should give the same results as above)
 RESET enable_seqscan;
 SET enable_indexscan = OFF;
+SET extra_float_digits = 0;
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
+RESET extra_float_digits;
 SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
 SELECT *, c <#> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <#> '(100, 100),(500, 500)'::cube LIMIT 5;
 SELECT c~>1, c FROM test_cube ORDER BY c~>1 LIMIT 15; -- ascending by left bound
index 43898a3b980091987a5ef3909d2d7345c02b0ee0..1e1ee16ce95347d79100062e55eb6bc8f0d0c7a3 100644 (file)
@@ -1,6 +1,8 @@
 DROP INDEX trgm_idx2;
 \copy test_trgm3 from 'data/trgm2.data'
 ERROR:  relation "test_trgm3" does not exist
+-- reduce noise
+set extra_float_digits = 0;
 select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
                   t                  |   sml    
 -------------------------------------+----------
index 6efc54356a1cc177e31eb3287b56d811ec1c240d..b3e709f4962b90394692b95bfeecc6452026af74 100644 (file)
@@ -10,6 +10,8 @@ WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid);
 --backslash is used in tests below, installcheck will fail if
 --standard_conforming_string is off
 set standard_conforming_strings=on;
+-- reduce noise
+set extra_float_digits = 0;
 select show_trgm('');
  show_trgm 
 -----------
index bed61c4922a84e61c887731ad63a938c491b9c11..936d489390e401cb09824191b077f55671112f6c 100644 (file)
@@ -1,5 +1,7 @@
 CREATE TABLE test_trgm2(t text COLLATE "C");
 \copy test_trgm2 from 'data/trgm2.data'
+-- reduce noise
+set extra_float_digits = 0;
 select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
                   t                  |   sml    
 -------------------------------------+----------
index 98e0d379f85b18cb81c77488a741f6dfbce79c05..ce0791f29b73c957070df40edc81a02d93fed6a5 100644 (file)
@@ -2,6 +2,9 @@ DROP INDEX trgm_idx2;
 
 \copy test_trgm3 from 'data/trgm2.data'
 
+-- reduce noise
+set extra_float_digits = 0;
+
 select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
 select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
 select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
index 96ae542320d09f4d22e59b49a07f8b4aced17150..08459e64c3063a8bf805e5322ceb8e82431078b6 100644 (file)
@@ -9,6 +9,9 @@ WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid);
 --standard_conforming_string is off
 set standard_conforming_strings=on;
 
+-- reduce noise
+set extra_float_digits = 0;
+
 select show_trgm('');
 select show_trgm('(*&^$@%@');
 select show_trgm('a b c');
index 4b1db9706a95b8b0af7e07ee258ac4aa3e8b5e55..d9fa1c55e5e7995791bcd0694f5a184ecdca4d67 100644 (file)
@@ -2,6 +2,9 @@ CREATE TABLE test_trgm2(t text COLLATE "C");
 
 \copy test_trgm2 from 'data/trgm2.data'
 
+-- reduce noise
+set extra_float_digits = 0;
+
 select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
 select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
 select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
index a289dbe5f99c3c995404d3464939af0e4110b784..80b0bca15687edbca20d3d09df196c572a92ecc7 100644 (file)
@@ -1127,7 +1127,7 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
        2.1 |       6.95 |      11.8
        2.3 |   Infinity |  Infinity
        2.3 |   Infinity |  Infinity
-       2.4 |       6.85 |      11.3
+       2.4 |  6.8500004 |      11.3
        2.5 |          7 |      11.5
        2.5 |       7.15 |      11.8
        2.6 |   Infinity |  Infinity
@@ -1155,7 +1155,7 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
        4.5 |      59.75 |       115
        4.7 |       8.25 |      11.8
        4.8 |       8.15 |      11.5
-       4.8 |        8.2 |      11.6
+       4.8 |   8.200001 |      11.6
        4.8 |       8.65 |      12.5
        4.8 |   Infinity |  Infinity
        4.9 |       8.45 |        12
@@ -1244,7 +1244,7 @@ FROM test_seg WHERE s @> '11.2..11.3' OR s IS NULL ORDER BY s;
          9 |       10.5 |        12
          9 |   Infinity |  Infinity
        9.2 |       10.6 |        12
-       9.4 |       10.8 |      12.2
+       9.4 |  10.799999 |      12.2
        9.5 |      10.75 |        12
        9.5 |      10.85 |      12.2
        9.5 |   Infinity |  Infinity
index 07b847a8e9632d23e922edd3b91c65d3e8e84c6b..8bd57f376b25969ae1d4b3d8837bc8ef7aa284e4 100644 (file)
@@ -7871,16 +7871,37 @@ SET XML OPTION { DOCUMENT | CONTENT };
       </term>
       <listitem>
        <para>
-        This parameter adjusts the number of digits displayed for
+        This parameter adjusts the number of digits used for textual output of
         floating-point values, including <type>float4</type>, <type>float8</type>,
-        and geometric data types.  The parameter value is added to the
-        standard number of digits (<literal>FLT_DIG</literal> or <literal>DBL_DIG</literal>
-        as appropriate).  The value can be set as high as 3, to include
-        partially-significant digits; this is especially useful for dumping
-        float data that needs to be restored exactly.  Or it can be set
-        negative to suppress unwanted digits.
-        See also <xref linkend="datatype-float"/>.
+        and geometric data types.
        </para>
+       <para>
+        If the value is 1 (the default) or above, float values are output in
+        shortest-precise format; see <xref linkend="datatype-float"/>. The
+        actual number of digits generated depends only on the value being
+        output, not on the value of this parameter. At most 17 digits are
+        required for <type>float8</type> values, and 9 for <type>float4</type>
+        values. This format is both fast and precise, preserving the original
+        binary float value exactly when correctly read. For historical
+        compatibility, values up to 3 are permitted.
+       </para>
+       <para>
+        If the value is zero or negative, then the output is rounded to a
+        given decimal precision. The precision used is the standard number of
+        digits for the type (<literal>FLT_DIG</literal>
+        or <literal>DBL_DIG</literal> as appropriate) reduced according to the
+        value of this parameter. (For example, specifying -1 will cause float4
+        values to be output rounded to 5 significant digits, and float8 values
+        rounded to 14 digits.) This format is slower and does not preserve all
+        the bits of the binary float value, but may be more human-readable.
+       </para>
+       <note>
+        <para>
+         The meaning of this parameter, and its default value, changed
+         in <productname>PostgreSQL</productname> 12;
+         see <xref linkend="datatype-float"/> for further discussion.
+        </para>
+       </note>
       </listitem>
      </varlistentry>
 
index 7807210b3626a73653fb742ef02b33212357fb81..b462c069900155875f69d76c87746969ee0f5e72 100644 (file)
@@ -671,13 +671,12 @@ FROM generate_series(-3.5, 3.5, 1) as x;
     </indexterm>
 
     <para>
-     The data types <type>real</type> and <type>double
-     precision</type> are inexact, variable-precision numeric types.
-     In practice, these types are usually implementations of
-     <acronym>IEEE</acronym> Standard 754 for Binary Floating-Point
-     Arithmetic (single and double precision, respectively), to the
-     extent that the underlying processor, operating system, and
-     compiler support it.
+     The data types <type>real</type> and <type>double precision</type> are
+     inexact, variable-precision numeric types. On all currently supported
+     platforms, these types are implementations of <acronym>IEEE</acronym>
+     Standard 754 for Binary Floating-Point Arithmetic (single and double
+     precision, respectively), to the extent that the underlying processor,
+     operating system, and compiler support it.
     </para>
 
     <para>
@@ -715,24 +714,57 @@ FROM generate_series(-3.5, 3.5, 1) as x;
     </para>
 
     <para>
-     On most platforms, the <type>real</type> type has a range of at least
-     1E-37 to 1E+37 with a precision of at least 6 decimal digits.  The
-     <type>double precision</type> type typically has a range of around
-     1E-307 to 1E+308 with a precision of at least 15 digits.  Values that
-     are too large or too small will cause an error.  Rounding might
-     take place if the precision of an input number is too high.
-     Numbers too close to zero that are not representable as distinct
-     from zero will cause an underflow error.
+     On all currently supported platforms, the <type>real</type> type has a
+     range of around 1E-37 to 1E+37 with a precision of at least 6 decimal
+     digits. The <type>double precision</type> type has a range of around
+     1E-307 to 1E+308 with a precision of at least 15 digits. Values that are
+     too large or too small will cause an error. Rounding might take place if
+     the precision of an input number is too high. Numbers too close to zero
+     that are not representable as distinct from zero will cause an underflow
+     error.
+    </para>
+
+    <para>
+     By default, floating point values are output in text form in their
+     shortest precise decimal representation; the decimal value produced is
+     closer to the true stored binary value than to any other value
+     representable in the same binary precision. (However, the output value is
+     currently never <emphasis>exactly</emphasis> midway between two
+     representable values, in order to avoid a widespread bug where input
+     routines do not properly respect the round-to-even rule.) This value will
+     use at most 17 significant decimal digits for <type>float8</type>
+     values, and at most 9 digits for <type>float4</type> values.
     </para>
 
     <note>
      <para>
-      The <xref linkend="guc-extra-float-digits"/> setting controls the
-      number of extra significant digits included when a floating point
-      value is converted to text for output.  With the default value of
-      <literal>0</literal>, the output is the same on every platform
-      supported by PostgreSQL.  Increasing it will produce output that
-      more accurately represents the stored value, but may be unportable.
+      This shortest-precise output format is much faster to generate than the
+      historical rounded format.
+     </para>
+    </note>
+
+    <para>
+     For compatibility with output generated by older versions
+     of <productname>PostgreSQL</productname>, and to allow the output
+     precision to be reduced, the <xref linkend="guc-extra-float-digits"/>
+     parameter can be used to select rounded decimal output instead. Setting a
+     value of 0 restores the previous default of rounding the value to 6
+     (for <type>float4</type>) or 15 (for <type>float8</type>)
+     significant decimal digits. Setting a negative value reduces the number
+     of digits further; for example -2 would round output to 4 or 13 digits
+     respectively.
+    </para>
+
+    <para>
+     Any value of <xref linkend="guc-extra-float-digits"/> greater than 0
+     selects the shortest-precise format.
+    </para>
+
+    <note>
+     <para>
+      Applications that wanted precise values have historically had to set
+      <xref linkend="guc-extra-float-digits"/> to 3 obtain them. For maximum
+      compatibility between versions, they should continue to do so.
      </para>
     </note>
 
@@ -751,9 +783,7 @@ FROM generate_series(-3.5, 3.5, 1) as x;
 </literallayout>
      These represent the IEEE 754 special values
      <quote>infinity</quote>, <quote>negative infinity</quote>, and
-     <quote>not-a-number</quote>, respectively.  (On a machine whose
-     floating-point arithmetic does not follow IEEE 754, these values
-     will probably not work as expected.)  When writing these values
+     <quote>not-a-number</quote>, respectively. When writing these values
      as constants in an SQL command, you must put quotes around them,
      for example <literal>UPDATE table SET x = '-Infinity'</literal>.  On input,
      these strings are recognized in a case-insensitive manner.
@@ -786,17 +816,6 @@ FROM generate_series(-3.5, 3.5, 1) as x;
      <type>double precision</type>.
     </para>
 
-    <note>
-     <para>
-      The assumption that <type>real</type> and
-      <type>double precision</type> have exactly 24 and 53 bits in the
-      mantissa respectively is correct for IEEE-standard floating point
-      implementations.  On non-IEEE platforms it might be off a little, but
-      for simplicity the same ranges of <replaceable>p</replaceable> are used
-      on all platforms.
-     </para>
-    </note>
-
    </sect2>
 
    <sect2 id="datatype-serial">
index a84b2f96eb609a8f66fc906ab60a3146acd2d85f..c118f64040ceee2e0302e34d0d59c079ae128cf3 100644 (file)
@@ -261,6 +261,7 @@ CFLAGS = @CFLAGS@
 CFLAGS_VECTOR = @CFLAGS_VECTOR@
 CFLAGS_SSE42 = @CFLAGS_SSE42@
 CFLAGS_ARMV8_CRC32C = @CFLAGS_ARMV8_CRC32C@
+PERMIT_DECLARATION_AFTER_STATEMENT = @PERMIT_DECLARATION_AFTER_STATEMENT@
 CXXFLAGS = @CXXFLAGS@
 
 LLVM_CPPFLAGS = @LLVM_CPPFLAGS@
index eb111ee2dbfb3264ee6f416d82d1739734ef0bd6..37c202d21cac71db8ed26fd312280bd053f8cdba 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
+#include "common/shortest_dec.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "utils/array.h"
 #include "utils/timestamp.h"
 
 
-/* Configurable GUC parameter */
-int            extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */
+/*
+ * Configurable GUC parameter
+ *
+ * If >0, use shortest-decimal format for output; this is both the default and
+ * allows for compatibility with clients that explicitly set a value here to
+ * get round-trip-accurate results. If 0 or less, then use the old, slow,
+ * decimal rounding method.
+ */
+int            extra_float_digits = 1;
 
 /* Cached constants for degree-based trig functions */
 static bool degree_consts_set = false;
@@ -282,6 +290,12 @@ float4out(PG_FUNCTION_ARGS)
    char       *ascii = (char *) palloc(32);
    int         ndig = FLT_DIG + extra_float_digits;
 
+   if (extra_float_digits > 0)
+   {
+       float_to_shortest_decimal_buf(num, ascii);
+       PG_RETURN_CSTRING(ascii);
+   }
+
    (void) pg_strfromd(ascii, 32, ndig, num);
    PG_RETURN_CSTRING(ascii);
 }
@@ -498,6 +512,12 @@ float8out_internal(double num)
    char       *ascii = (char *) palloc(32);
    int         ndig = DBL_DIG + extra_float_digits;
 
+   if (extra_float_digits > 0)
+   {
+       double_to_shortest_decimal_buf(num, ascii);
+       return ascii;
+   }
+
    (void) pg_strfromd(ascii, 32, ndig, num);
    return ascii;
 }
index 3a4a113b6259f1f93abd11968d524266aa0a32c6..156d147c85be8377374214c22f9195f403bb237d 100644 (file)
@@ -2667,11 +2667,12 @@ static struct config_int ConfigureNamesInt[] =
        {"extra_float_digits", PGC_USERSET, CLIENT_CONN_LOCALE,
            gettext_noop("Sets the number of digits displayed for floating-point values."),
            gettext_noop("This affects real, double precision, and geometric data types. "
-                        "The parameter value is added to the standard number of digits "
-                        "(FLT_DIG or DBL_DIG as appropriate).")
+                        "A zero or negative parameter value is added to the standard "
+                        "number of digits (FLT_DIG or DBL_DIG as appropriate). "
+                        "Any value greater than zero selects precise output mode.")
        },
        &extra_float_digits,
-       0, -15, 3,
+       1, -15, 3,
        NULL, NULL, NULL
    },
 
index ad6c436f93f9664afa5cdc4b9c24f489da553c54..194f31209645dc9dd2e2e27c222b98a53b0b2885 100644 (file)
                    #   India
                    # You can create your own file in
                    # share/timezonesets/.
-#extra_float_digits = 0            # min -15, max 3
+#extra_float_digits = 1            # min -15, max 3; any value >0 actually
+                   # selects precise output mode
 #client_encoding = sql_ascii       # actually, defaults to database
                    # encoding
 
index d0c2b970eb36fbebfd96909c096ec2d92537250c..d84c7b6e6aec14856e5672bfabfd622c1d9cf983 100644 (file)
@@ -44,9 +44,11 @@ override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
 override CPPFLAGS := -DFRONTEND -I. -I$(top_srcdir)/src/common $(CPPFLAGS)
 LIBS += $(PTHREAD_LIBS)
 
-OBJS_COMMON = base64.o config_info.o controldata_utils.o exec.o file_perm.o \
-   ip.o keywords.o kwlookup.o link-canary.o md5.o pg_lzcompress.o \
-   pgfnames.o psprintf.o relpath.o \
+# If you add objects here, see also src/tools/msvc/Mkvcbuild.pm
+
+OBJS_COMMON = base64.o config_info.o controldata_utils.o d2s.o exec.o f2s.o \
+   file_perm.o ip.o keywords.o kwlookup.o link-canary.o md5.o \
+   pg_lzcompress.o pgfnames.o psprintf.o relpath.o \
    rmtree.o saslprep.o scram-common.o string.o unicode_norm.o \
    username.o wait_error.o
 
@@ -130,6 +132,13 @@ kwlist_d.h: $(top_srcdir)/src/include/parser/kwlist.h $(GEN_KEYWORDLIST_DEPS)
 # that you don't get broken parsing code, even in a non-enable-depend build.
 keywords.o keywords_shlib.o keywords_srv.o: kwlist_d.h
 
+# The code imported from Ryu gets a pass on declaration-after-statement,
+# in order to keep it more closely aligned with its upstream.
+RYU_FILES = d2s.o f2s.o
+RYU_OBJS = $(RYU_FILES) $(RYU_FILES:%.o=%_shlib.o) $(RYU_FILES:%.o=%_srv.o)
+
+$(RYU_OBJS): CFLAGS += $(PERMIT_DECLARATION_AFTER_STATEMENT)
+
 # kwlist_d.h is in the distribution tarball, so it is not cleaned here.
 clean distclean:
    rm -f libpgcommon.a libpgcommon_shlib.a libpgcommon_srv.a
diff --git a/src/common/d2s.c b/src/common/d2s.c
new file mode 100644 (file)
index 0000000..58f6097
--- /dev/null
@@ -0,0 +1,1076 @@
+/*---------------------------------------------------------------------------
+ *
+ * Ryu floating-point output for double precision.
+ *
+ * Portions Copyright (c) 2018-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/common/d2s.c
+ *
+ * This is a modification of code taken from github.com/ulfjack/ryu under the
+ * terms of the Boost license (not the Apache license). The original copyright
+ * notice follows:
+ *
+ * Copyright 2018 Ulf Adams
+ *
+ * The contents of this file may be used under the terms of the Apache
+ * License, Version 2.0.
+ *
+ *     (See accompanying file LICENSE-Apache or copy at
+ *      http://www.apache.org/licenses/LICENSE-2.0)
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Boost Software License, Version 1.0.
+ *
+ *     (See accompanying file LICENSE-Boost or copy at
+ *      https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Unless required by applicable law or agreed to in writing, this software is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+/*
+ *  Runtime compiler options:
+ *
+ *  -DRYU_ONLY_64_BIT_OPS Avoid using uint128 or 64-bit intrinsics. Slower,
+ *      depending on your compiler.
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/shortest_dec.h"
+
+/*
+ * For consistency, we use 128-bit types if and only if the rest of PG also
+ * does, even though we could use them here without worrying about the
+ * alignment concerns that apply elsewhere.
+ */
+#if !defined(HAVE_INT128) && defined(_MSC_VER) \
+   && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64)
+#define HAS_64_BIT_INTRINSICS
+#endif
+
+#include "ryu_common.h"
+#include "digit_table.h"
+#include "d2s_full_table.h"
+#include "d2s_intrinsics.h"
+
+#define DOUBLE_MANTISSA_BITS 52
+#define DOUBLE_EXPONENT_BITS 11
+#define DOUBLE_BIAS 1023
+
+#define DOUBLE_POW5_INV_BITCOUNT 122
+#define DOUBLE_POW5_BITCOUNT 121
+
+
+static inline uint32
+pow5Factor(uint64 value)
+{
+   uint32      count = 0;
+
+   for (;;)
+   {
+       Assert(value != 0);
+       const uint64 q = div5(value);
+       const uint32 r = (uint32) (value - 5 * q);
+
+       if (r != 0)
+           break;
+
+       value = q;
+       ++count;
+   }
+   return count;
+}
+
+/*  Returns true if value is divisible by 5^p. */
+static inline bool
+multipleOfPowerOf5(const uint64 value, const uint32 p)
+{
+   /*
+    * I tried a case distinction on p, but there was no performance
+    * difference.
+    */
+   return pow5Factor(value) >= p;
+}
+
+/*  Returns true if value is divisible by 2^p. */
+static inline bool
+multipleOfPowerOf2(const uint64 value, const uint32 p)
+{
+   /* return __builtin_ctzll(value) >= p; */
+   return (value & ((UINT64CONST(1) << p) - 1)) == 0;
+}
+
+/*
+ * We need a 64x128-bit multiplication and a subsequent 128-bit shift.
+ *
+ * Multiplication:
+ *
+ *    The 64-bit factor is variable and passed in, the 128-bit factor comes
+ *    from a lookup table. We know that the 64-bit factor only has 55
+ *    significant bits (i.e., the 9 topmost bits are zeros). The 128-bit
+ *    factor only has 124 significant bits (i.e., the 4 topmost bits are
+ *    zeros).
+ *
+ * Shift:
+ *
+ *    In principle, the multiplication result requires 55 + 124 = 179 bits to
+ *    represent. However, we then shift this value to the right by j, which is
+ *    at least j >= 115, so the result is guaranteed to fit into 179 - 115 =
+ *    64 bits. This means that we only need the topmost 64 significant bits of
+ *    the 64x128-bit multiplication.
+ *
+ * There are several ways to do this:
+ *
+ *  1. Best case: the compiler exposes a 128-bit type.
+ *     We perform two 64x64-bit multiplications, add the higher 64 bits of the
+ *     lower result to the higher result, and shift by j - 64 bits.
+ *
+ *     We explicitly cast from 64-bit to 128-bit, so the compiler can tell
+ *     that these are only 64-bit inputs, and can map these to the best
+ *     possible sequence of assembly instructions. x86-64 machines happen to
+ *     have matching assembly instructions for 64x64-bit multiplications and
+ *     128-bit shifts.
+ *
+ *  2. Second best case: the compiler exposes intrinsics for the x86-64
+ *     assembly instructions mentioned in 1.
+ *
+ *  3. We only have 64x64 bit instructions that return the lower 64 bits of
+ *     the result, i.e., we have to use plain C.
+ *
+ *     Our inputs are less than the full width, so we have three options:
+ *     a. Ignore this fact and just implement the intrinsics manually.
+ *     b. Split both into 31-bit pieces, which guarantees no internal
+ *        overflow, but requires extra work upfront (unless we change the
+ *        lookup table).
+ *     c. Split only the first factor into 31-bit pieces, which also
+ *        guarantees no internal overflow, but requires extra work since the
+ *        intermediate results are not perfectly aligned.
+ */
+#if defined(HAVE_INT128)
+
+/*  Best case: use 128-bit type. */
+static inline uint64
+mulShift(const uint64 m, const uint64 *const mul, const int32 j)
+{
+   const uint128 b0 = ((uint128) m) * mul[0];
+   const uint128 b2 = ((uint128) m) * mul[1];
+
+   return (uint64) (((b0 >> 64) + b2) >> (j - 64));
+}
+
+static inline uint64
+mulShiftAll(const uint64 m, const uint64 *const mul, const int32 j,
+           uint64 *const vp, uint64 *const vm, const uint32 mmShift)
+{
+   *vp = mulShift(4 * m + 2, mul, j);
+   *vm = mulShift(4 * m - 1 - mmShift, mul, j);
+   return mulShift(4 * m, mul, j);
+}
+
+#elif defined(HAS_64_BIT_INTRINSICS)
+
+static inline uint64
+mulShift(const uint64 m, const uint64 *const mul, const int32 j)
+{
+   /* m is maximum 55 bits */
+   uint64      high1;
+
+   /* 128 */
+   const uint64 low1 = umul128(m, mul[1], &high1);
+
+   /* 64 */
+   uint64      high0;
+   uint64      sum;
+
+   /* 64 */
+   umul128(m, mul[0], &high0);
+   /* 0 */
+   sum = high0 + low1;
+
+   if (sum < high0)
+   {
+       ++high1;
+       /* overflow into high1 */
+   }
+   return shiftright128(sum, high1, j - 64);
+}
+
+static inline uint64
+mulShiftAll(const uint64 m, const uint64 *const mul, const int32 j,
+           uint64 *const vp, uint64 *const vm, const uint32 mmShift)
+{
+   *vp = mulShift(4 * m + 2, mul, j);
+   *vm = mulShift(4 * m - 1 - mmShift, mul, j);
+   return mulShift(4 * m, mul, j);
+}
+
+#else                          /* // !defined(HAVE_INT128) &&
+                                * !defined(HAS_64_BIT_INTRINSICS) */
+
+static inline uint64
+mulShiftAll(uint64 m, const uint64 *const mul, const int32 j,
+           uint64 *const vp, uint64 *const vm, const uint32 mmShift)
+{
+   m <<= 1;                    /* m is maximum 55 bits */
+
+   uint64      tmp;
+   const uint64 lo = umul128(m, mul[0], &tmp);
+   uint64      hi;
+   const uint64 mid = tmp + umul128(m, mul[1], &hi);
+
+   hi += mid < tmp;            /* overflow into hi */
+
+   const uint64 lo2 = lo + mul[0];
+   const uint64 mid2 = mid + mul[1] + (lo2 < lo);
+   const uint64 hi2 = hi + (mid2 < mid);
+
+   *vp = shiftright128(mid2, hi2, j - 64 - 1);
+
+   if (mmShift == 1)
+   {
+       const uint64 lo3 = lo - mul[0];
+       const uint64 mid3 = mid - mul[1] - (lo3 > lo);
+       const uint64 hi3 = hi - (mid3 > mid);
+
+       *vm = shiftright128(mid3, hi3, j - 64 - 1);
+   }
+   else
+   {
+       const uint64 lo3 = lo + lo;
+       const uint64 mid3 = mid + mid + (lo3 < lo);
+       const uint64 hi3 = hi + hi + (mid3 < mid);
+       const uint64 lo4 = lo3 - mul[0];
+       const uint64 mid4 = mid3 - mul[1] - (lo4 > lo3);
+       const uint64 hi4 = hi3 - (mid4 > mid3);
+
+       *vm = shiftright128(mid4, hi4, j - 64);
+   }
+
+   return shiftright128(mid, hi, j - 64 - 1);
+}
+
+#endif                         /* // HAS_64_BIT_INTRINSICS */
+
+static inline uint32
+decimalLength(const uint64 v)
+{
+   /* This is slightly faster than a loop. */
+   /* The average output length is 16.38 digits, so we check high-to-low. */
+   /* Function precondition: v is not an 18, 19, or 20-digit number. */
+   /* (17 digits are sufficient for round-tripping.) */
+   Assert(v < 100000000000000000L);
+   if (v >= 10000000000000000L)
+   {
+       return 17;
+   }
+   if (v >= 1000000000000000L)
+   {
+       return 16;
+   }
+   if (v >= 100000000000000L)
+   {
+       return 15;
+   }
+   if (v >= 10000000000000L)
+   {
+       return 14;
+   }
+   if (v >= 1000000000000L)
+   {
+       return 13;
+   }
+   if (v >= 100000000000L)
+   {
+       return 12;
+   }
+   if (v >= 10000000000L)
+   {
+       return 11;
+   }
+   if (v >= 1000000000L)
+   {
+       return 10;
+   }
+   if (v >= 100000000L)
+   {
+       return 9;
+   }
+   if (v >= 10000000L)
+   {
+       return 8;
+   }
+   if (v >= 1000000L)
+   {
+       return 7;
+   }
+   if (v >= 100000L)
+   {
+       return 6;
+   }
+   if (v >= 10000L)
+   {
+       return 5;
+   }
+   if (v >= 1000L)
+   {
+       return 4;
+   }
+   if (v >= 100L)
+   {
+       return 3;
+   }
+   if (v >= 10L)
+   {
+       return 2;
+   }
+   return 1;
+}
+
+/*  A floating decimal representing m * 10^e. */
+typedef struct floating_decimal_64
+{
+   uint64      mantissa;
+   int32       exponent;
+} floating_decimal_64;
+
+static inline floating_decimal_64
+d2d(const uint64 ieeeMantissa, const uint32 ieeeExponent)
+{
+   int32       e2;
+   uint64      m2;
+
+   if (ieeeExponent == 0)
+   {
+       /* We subtract 2 so that the bounds computation has 2 additional bits. */
+       e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
+       m2 = ieeeMantissa;
+   }
+   else
+   {
+       e2 = ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
+       m2 = (UINT64CONST(1) << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
+   }
+
+#if STRICTLY_SHORTEST
+   const bool  even = (m2 & 1) == 0;
+   const bool  acceptBounds = even;
+#else
+   const bool  acceptBounds = false;
+#endif
+
+   /* Step 2: Determine the interval of legal decimal representations. */
+   const uint64 mv = 4 * m2;
+
+   /* Implicit bool -> int conversion. True is 1, false is 0. */
+   const uint32 mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
+
+   /* We would compute mp and mm like this: */
+   /* uint64 mp = 4 * m2 + 2; */
+   /* uint64 mm = mv - 1 - mmShift; */
+
+   /* Step 3: Convert to a decimal power base using 128-bit arithmetic. */
+   uint64      vr,
+               vp,
+               vm;
+   int32       e10;
+   bool        vmIsTrailingZeros = false;
+   bool        vrIsTrailingZeros = false;
+
+   if (e2 >= 0)
+   {
+       /*
+        * I tried special-casing q == 0, but there was no effect on
+        * performance.
+        *
+        * This expr is slightly faster than max(0, log10Pow2(e2) - 1).
+        */
+       const uint32 q = log10Pow2(e2) - (e2 > 3);
+       const int32 k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q) - 1;
+       const int32 i = -e2 + q + k;
+
+       e10 = q;
+
+       vr = mulShiftAll(m2, DOUBLE_POW5_INV_SPLIT[q], i, &vp, &vm, mmShift);
+
+       if (q <= 21)
+       {
+           /*
+            * This should use q <= 22, but I think 21 is also safe. Smaller
+            * values may still be safe, but it's more difficult to reason
+            * about them.
+            *
+            * Only one of mp, mv, and mm can be a multiple of 5, if any.
+            */
+           const uint32 mvMod5 = (uint32) (mv - 5 * div5(mv));
+
+           if (mvMod5 == 0)
+           {
+               vrIsTrailingZeros = multipleOfPowerOf5(mv, q);
+           }
+           else if (acceptBounds)
+           {
+               /*----
+                * Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
+                * <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
+                * <=> true && pow5Factor(mm) >= q, since e2 >= q.
+                *----
+                */
+               vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
+           }
+           else
+           {
+               /* Same as min(e2 + 1, pow5Factor(mp)) >= q. */
+               vp -= multipleOfPowerOf5(mv + 2, q);
+           }
+       }
+   }
+   else
+   {
+       /*
+        * This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
+        */
+       const uint32 q = log10Pow5(-e2) - (-e2 > 1);
+       const int32 i = -e2 - q;
+       const int32 k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
+       const int32 j = q - k;
+
+       e10 = q + e2;
+
+       vr = mulShiftAll(m2, DOUBLE_POW5_SPLIT[i], j, &vp, &vm, mmShift);
+
+       if (q <= 1)
+       {
+           /*
+            * {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q
+            * trailing 0 bits.
+            */
+           /* mv = 4 * m2, so it always has at least two trailing 0 bits. */
+           vrIsTrailingZeros = true;
+           if (acceptBounds)
+           {
+               /*
+                * mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff
+                * mmShift == 1.
+                */
+               vmIsTrailingZeros = mmShift == 1;
+           }
+           else
+           {
+               /*
+                * mp = mv + 2, so it always has at least one trailing 0 bit.
+                */
+               --vp;
+           }
+       }
+       else if (q < 63)
+       {
+           /* TODO(ulfjack):Use a tighter bound here. */
+           /*
+            * We need to compute min(ntz(mv), pow5Factor(mv) - e2) >= q - 1
+            */
+           /* <=> ntz(mv) >= q - 1 && pow5Factor(mv) - e2 >= q - 1 */
+           /* <=> ntz(mv) >= q - 1 (e2 is negative and -e2 >= q) */
+           /* <=> (mv & ((1 << (q - 1)) - 1)) == 0 */
+
+           /*
+            * We also need to make sure that the left shift does not
+            * overflow.
+            */
+           vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1);
+       }
+   }
+
+   /*
+    * Step 4: Find the shortest decimal representation in the interval of
+    * legal representations.
+    */
+   uint32      removed = 0;
+   uint8       lastRemovedDigit = 0;
+   uint64      output;
+
+   /* On average, we remove ~2 digits. */
+   if (vmIsTrailingZeros || vrIsTrailingZeros)
+   {
+       /* General case, which happens rarely (~0.7%). */
+       for (;;)
+       {
+           const uint64 vpDiv10 = div10(vp);
+           const uint64 vmDiv10 = div10(vm);
+
+           if (vpDiv10 <= vmDiv10)
+               break;
+
+           const uint32 vmMod10 = (uint32) (vm - 10 * vmDiv10);
+           const uint64 vrDiv10 = div10(vr);
+           const uint32 vrMod10 = (uint32) (vr - 10 * vrDiv10);
+
+           vmIsTrailingZeros &= vmMod10 == 0;
+           vrIsTrailingZeros &= lastRemovedDigit == 0;
+           lastRemovedDigit = (uint8) vrMod10;
+           vr = vrDiv10;
+           vp = vpDiv10;
+           vm = vmDiv10;
+           ++removed;
+       }
+
+       if (vmIsTrailingZeros)
+       {
+           for (;;)
+           {
+               const uint64 vmDiv10 = div10(vm);
+               const uint32 vmMod10 = (uint32) (vm - 10 * vmDiv10);
+
+               if (vmMod10 != 0)
+                   break;
+
+               const uint64 vpDiv10 = div10(vp);
+               const uint64 vrDiv10 = div10(vr);
+               const uint32 vrMod10 = (uint32) (vr - 10 * vrDiv10);
+
+               vrIsTrailingZeros &= lastRemovedDigit == 0;
+               lastRemovedDigit = (uint8) vrMod10;
+               vr = vrDiv10;
+               vp = vpDiv10;
+               vm = vmDiv10;
+               ++removed;
+           }
+       }
+
+       if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0)
+       {
+           /* Round even if the exact number is .....50..0. */
+           lastRemovedDigit = 4;
+       }
+
+       /*
+        * We need to take vr + 1 if vr is outside bounds or we need to round
+        * up.
+        */
+       output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5);
+   }
+   else
+   {
+       /*
+        * Specialized for the common case (~99.3%). Percentages below are
+        * relative to this.
+        */
+       bool        roundUp = false;
+       const uint64 vpDiv100 = div100(vp);
+       const uint64 vmDiv100 = div100(vm);
+
+       if (vpDiv100 > vmDiv100)
+       {
+           /* Optimization:remove two digits at a time(~86.2 %). */
+           const uint64 vrDiv100 = div100(vr);
+           const uint32 vrMod100 = (uint32) (vr - 100 * vrDiv100);
+
+           roundUp = vrMod100 >= 50;
+           vr = vrDiv100;
+           vp = vpDiv100;
+           vm = vmDiv100;
+           removed += 2;
+       }
+
+       /*----
+        * Loop iterations below (approximately), without optimization
+        * above:
+        *
+        * 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%,
+        * 6+: 0.02%
+        *
+        * Loop iterations below (approximately), with optimization
+        * above:
+        *
+        * 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
+        *----
+        */
+       for (;;)
+       {
+           const uint64 vpDiv10 = div10(vp);
+           const uint64 vmDiv10 = div10(vm);
+
+           if (vpDiv10 <= vmDiv10)
+               break;
+
+           const uint64 vrDiv10 = div10(vr);
+           const uint32 vrMod10 = (uint32) (vr - 10 * vrDiv10);
+
+           roundUp = vrMod10 >= 5;
+           vr = vrDiv10;
+           vp = vpDiv10;
+           vm = vmDiv10;
+           ++removed;
+       }
+
+       /*
+        * We need to take vr + 1 if vr is outside bounds or we need to round
+        * up.
+        */
+       output = vr + (vr == vm || roundUp);
+   }
+
+   const int32 exp = e10 + removed;
+
+   floating_decimal_64 fd;
+
+   fd.exponent = exp;
+   fd.mantissa = output;
+   return fd;
+}
+
+static inline int
+to_chars_df(const floating_decimal_64 v, const uint32 olength, char *const result)
+{
+   /* Step 5: Print the decimal representation. */
+   int         index = 0;
+
+   uint64      output = v.mantissa;
+   int32       exp = v.exponent;
+
+   /*----
+    * On entry, mantissa * 10^exp is the result to be output.
+    * Caller has already done the - sign if needed.
+    *
+    * We want to insert the point somewhere depending on the output length
+    * and exponent, which might mean adding zeros:
+    *
+    *            exp  | format
+    *            1+   |  ddddddddd000000
+    *            0    |  ddddddddd
+    *  -1 .. -len+1   |  dddddddd.d to d.ddddddddd
+    *  -len ...       |  0.ddddddddd to 0.000dddddd
+    */
+   uint32      i = 0;
+   int32       nexp = exp + olength;
+
+   if (nexp <= 0)
+   {
+       /* -nexp is number of 0s to add after '.' */
+       Assert(nexp >= -3);
+       /* 0.000ddddd */
+       index = 2 - nexp;
+       /* won't need more than this many 0s */
+       memcpy(result, "0.000000", 8);
+   }
+   else if (exp < 0)
+   {
+       /*
+        * dddd.dddd; leave space at the start and move the '.' in after
+        */
+       index = 1;
+   }
+   else
+   {
+       /*
+        * We can save some code later by pre-filling with zeros. We know
+        * that there can be no more than 16 output digits in this form,
+        * otherwise we would not choose fixed-point output.
+        */
+       Assert(exp < 16 && exp + olength <= 16);
+       memset(result, '0', 16);
+   }
+
+   /*
+    * We prefer 32-bit operations, even on 64-bit platforms. We have at most
+    * 17 digits, and uint32 can store 9 digits. If output doesn't fit into
+    * uint32, we cut off 8 digits, so the rest will fit into uint32.
+    */
+   if ((output >> 32) != 0)
+   {
+       /* Expensive 64-bit division. */
+       const uint64 q = div1e8(output);
+       uint32      output2 = (uint32) (output - 100000000 * q);
+       const uint32 c = output2 % 10000;
+
+       output = q;
+       output2 /= 10000;
+
+       const uint32 d = output2 % 10000;
+       const uint32 c0 = (c % 100) << 1;
+       const uint32 c1 = (c / 100) << 1;
+       const uint32 d0 = (d % 100) << 1;
+       const uint32 d1 = (d / 100) << 1;
+
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c0, 2);
+       memcpy(result + index + olength - i - 4, DIGIT_TABLE + c1, 2);
+       memcpy(result + index + olength - i - 6, DIGIT_TABLE + d0, 2);
+       memcpy(result + index + olength - i - 8, DIGIT_TABLE + d1, 2);
+       i += 8;
+   }
+
+   uint32      output2 = (uint32) output;
+
+   while (output2 >= 10000)
+   {
+       const uint32 c = output2 - 10000 * (output2 / 10000);
+       const uint32 c0 = (c % 100) << 1;
+       const uint32 c1 = (c / 100) << 1;
+
+       output2 /= 10000;
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c0, 2);
+       memcpy(result + index + olength - i - 4, DIGIT_TABLE + c1, 2);
+       i += 4;
+   }
+   if (output2 >= 100)
+   {
+       const uint32 c = (output2 % 100) << 1;
+
+       output2 /= 100;
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2);
+       i += 2;
+   }
+   if (output2 >= 10)
+   {
+       const uint32 c = output2 << 1;
+
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2);
+   }
+   else
+   {
+       result[index] = (char) ('0' + output2);
+   }
+
+   if (index == 1)
+   {
+       /*
+        * nexp is 1..15 here, representing the number of digits before the
+        * point. A value of 16 is not possible because we switch to
+        * scientific notation when the display exponent reaches 15.
+        */
+       Assert(nexp < 16);
+       /* gcc only seems to want to optimize memmove for small 2^n */
+       if (nexp & 8)
+       {
+           memmove(result + index - 1, result + index, 8);
+           index += 8;
+       }
+       if (nexp & 4)
+       {
+           memmove(result + index - 1, result + index, 4);
+           index += 4;
+       }
+       if (nexp & 2)
+       {
+           memmove(result + index - 1, result + index, 2);
+           index += 2;
+       }
+       if (nexp & 1)
+       {
+           result[index - 1] = result[index];
+       }
+       result[nexp] = '.';
+       index = olength + 1;
+   }
+   else if (exp >= 0)
+   {
+       /* we supplied the trailing zeros earlier, now just set the length. */
+       index = olength + exp;
+   }
+   else
+   {
+       index = olength + (2 - nexp);
+   }
+
+   return index;
+}
+
+static inline int
+to_chars(floating_decimal_64 v, const bool sign, char *const result)
+{
+   /* Step 5: Print the decimal representation. */
+   int         index = 0;
+
+   uint64      output = v.mantissa;
+   uint32      olength = decimalLength(output);
+   int32       exp = v.exponent + olength - 1;
+
+   if (sign)
+   {
+       result[index++] = '-';
+   }
+
+   /*
+    * The thresholds for fixed-point output are chosen to match printf
+    * defaults. Beware that both the code of to_chars_df and the value
+    * of DOUBLE_SHORTEST_DECIMAL_LEN are sensitive to these thresholds.
+    */
+   if (exp >= -4 && exp < 15)
+       return to_chars_df(v, olength, result + index) + sign;
+
+   /*
+    * If v.exponent is exactly 0, we might have reached here via the small
+    * integer fast path, in which case v.mantissa might contain trailing
+    * (decimal) zeros. For scientific notation we need to move these zeros
+    * into the exponent. (For fixed point this doesn't matter, which is why
+    * we do this here rather than above.)
+    *
+    * Since we already calculated the display exponent (exp) above based on
+    * the old decimal length, that value does not change here. Instead, we
+    * just reduce the display length for each digit removed.
+    *
+    * If we didn't get here via the fast path, the raw exponent will not
+    * usually be 0, and there will be no trailing zeros, so we pay no more
+    * than one div10/multiply extra cost. We claw back half of that by
+    * checking for divisibility by 2 before dividing by 10.
+    */
+   if (v.exponent == 0)
+   {
+       while ((output & 1) == 0)
+       {
+           const uint64 q = div10(output);
+           const uint32 r = (uint32) (output - 10 * q);
+
+           if (r != 0)
+               break;
+           output = q;
+           --olength;
+       }
+   }
+
+   /*----
+    * Print the decimal digits.
+    *
+    * The following code is equivalent to:
+    *
+    * for (uint32 i = 0; i < olength - 1; ++i) {
+    *   const uint32 c = output % 10; output /= 10;
+    *   result[index + olength - i] = (char) ('0' + c);
+    * }
+    * result[index] = '0' + output % 10;
+    *----
+    */
+
+   uint32      i = 0;
+
+   /*
+    * We prefer 32-bit operations, even on 64-bit platforms. We have at most
+    * 17 digits, and uint32 can store 9 digits. If output doesn't fit into
+    * uint32, we cut off 8 digits, so the rest will fit into uint32.
+    */
+   if ((output >> 32) != 0)
+   {
+       /* Expensive 64-bit division. */
+       const uint64 q = div1e8(output);
+       uint32      output2 = (uint32) (output - 100000000 * q);
+
+       output = q;
+
+       const uint32 c = output2 % 10000;
+
+       output2 /= 10000;
+
+       const uint32 d = output2 % 10000;
+       const uint32 c0 = (c % 100) << 1;
+       const uint32 c1 = (c / 100) << 1;
+       const uint32 d0 = (d % 100) << 1;
+       const uint32 d1 = (d / 100) << 1;
+
+       memcpy(result + index + olength - i - 1, DIGIT_TABLE + c0, 2);
+       memcpy(result + index + olength - i - 3, DIGIT_TABLE + c1, 2);
+       memcpy(result + index + olength - i - 5, DIGIT_TABLE + d0, 2);
+       memcpy(result + index + olength - i - 7, DIGIT_TABLE + d1, 2);
+       i += 8;
+   }
+
+   uint32      output2 = (uint32) output;
+
+   while (output2 >= 10000)
+   {
+       const uint32 c = output2 - 10000 * (output2 / 10000);
+
+       output2 /= 10000;
+
+       const uint32 c0 = (c % 100) << 1;
+       const uint32 c1 = (c / 100) << 1;
+
+       memcpy(result + index + olength - i - 1, DIGIT_TABLE + c0, 2);
+       memcpy(result + index + olength - i - 3, DIGIT_TABLE + c1, 2);
+       i += 4;
+   }
+   if (output2 >= 100)
+   {
+       const uint32 c = (output2 % 100) << 1;
+
+       output2 /= 100;
+       memcpy(result + index + olength - i - 1, DIGIT_TABLE + c, 2);
+       i += 2;
+   }
+   if (output2 >= 10)
+   {
+       const uint32 c = output2 << 1;
+
+       /*
+        * We can't use memcpy here: the decimal dot goes between these two
+        * digits.
+        */
+       result[index + olength - i] = DIGIT_TABLE[c + 1];
+       result[index] = DIGIT_TABLE[c];
+   }
+   else
+   {
+       result[index] = (char) ('0' + output2);
+   }
+
+   /* Print decimal point if needed. */
+   if (olength > 1)
+   {
+       result[index + 1] = '.';
+       index += olength + 1;
+   }
+   else
+   {
+       ++index;
+   }
+
+   /* Print the exponent. */
+   result[index++] = 'e';
+   if (exp < 0)
+   {
+       result[index++] = '-';
+       exp = -exp;
+   }
+   else
+       result[index++] = '+';
+
+   if (exp >= 100)
+   {
+       const int32 c = exp % 10;
+
+       memcpy(result + index, DIGIT_TABLE + 2 * (exp / 10), 2);
+       result[index + 2] = (char) ('0' + c);
+       index += 3;
+   }
+   else
+   {
+       memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
+       index += 2;
+   }
+
+   return index;
+}
+
+static inline bool
+d2d_small_int(const uint64 ieeeMantissa,
+             const uint32 ieeeExponent,
+             floating_decimal_64 *v)
+{
+   const int32 e2 = (int32) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;
+
+   /*
+    * Avoid using multiple "return false;" here since it tends to provoke the
+    * compiler into inlining multiple copies of d2d, which is undesirable.
+    */
+
+   if (e2 >= -DOUBLE_MANTISSA_BITS && e2 <= 0)
+   {
+       /*----
+        * Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52:
+        *   1 <= f = m2 / 2^-e2 < 2^53.
+        *
+        * Test if the lower -e2 bits of the significand are 0, i.e. whether
+        * the fraction is 0. We can use ieeeMantissa here, since the implied
+        * 1 bit can never be tested by this; the implied 1 can only be part
+        * of a fraction if e2 < -DOUBLE_MANTISSA_BITS which we already
+        * checked. (e.g. 0.5 gives ieeeMantissa == 0 and e2 == -53)
+        */
+       const uint64 mask = (UINT64CONST(1) << -e2) - 1;
+       const uint64 fraction = ieeeMantissa & mask;
+
+       if (fraction == 0)
+       {
+           /*----
+            * f is an integer in the range [1, 2^53).
+            * Note: mantissa might contain trailing (decimal) 0's.
+            * Note: since 2^53 < 10^16, there is no need to adjust
+            * decimalLength().
+            */
+           const uint64 m2 = (UINT64CONST(1) << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
+
+           v->mantissa = m2 >> -e2;
+           v->exponent = 0;
+           return true;
+       }
+   }
+
+   return false;
+}
+
+/*
+ * Store the shortest decimal representation of the given double as an
+ * UNTERMINATED string in the caller's supplied buffer (which must be at least
+ * DOUBLE_SHORTEST_DECIMAL_LEN-1 bytes long).
+ *
+ * Returns the number of bytes stored.
+ */
+int
+double_to_shortest_decimal_bufn(double f, char *result)
+{
+   /*
+    * Step 1: Decode the floating-point number, and unify normalized and
+    * subnormal cases.
+    */
+   const uint64 bits = double_to_bits(f);
+
+   /* Decode bits into sign, mantissa, and exponent. */
+   const bool  ieeeSign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
+   const uint64 ieeeMantissa = bits & ((UINT64CONST(1) << DOUBLE_MANTISSA_BITS) - 1);
+   const uint32 ieeeExponent = (uint32) ((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1));
+
+   /* Case distinction; exit early for the easy cases. */
+   if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0))
+   {
+       return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa);
+   }
+
+   floating_decimal_64 v;
+   const bool  isSmallInt = d2d_small_int(ieeeMantissa, ieeeExponent, &v);
+
+   if (!isSmallInt)
+   {
+       v = d2d(ieeeMantissa, ieeeExponent);
+   }
+
+   return to_chars(v, ieeeSign, result);
+}
+
+/*
+ * Store the shortest decimal representation of the given double as a
+ * null-terminated string in the caller's supplied buffer (which must be at
+ * least DOUBLE_SHORTEST_DECIMAL_LEN bytes long).
+ *
+ * Returns the string length.
+ */
+int
+double_to_shortest_decimal_buf(double f, char *result)
+{
+   const int   index = double_to_shortest_decimal_bufn(f, result);
+
+   /* Terminate the string. */
+   Assert(index < DOUBLE_SHORTEST_DECIMAL_LEN);
+   result[index] = '\0';
+   return index;
+}
+
+/*
+ * Return the shortest decimal representation as a null-terminated palloc'd
+ * string (outside the backend, uses malloc() instead).
+ *
+ * Caller is responsible for freeing the result.
+ */
+char *
+double_to_shortest_decimal(double f)
+{
+   char       *const result = (char *) palloc(DOUBLE_SHORTEST_DECIMAL_LEN);
+
+   double_to_shortest_decimal_buf(f, result);
+   return result;
+}
diff --git a/src/common/d2s_full_table.h b/src/common/d2s_full_table.h
new file mode 100644 (file)
index 0000000..d6520b4
--- /dev/null
@@ -0,0 +1,358 @@
+/*---------------------------------------------------------------------------
+ *
+ * Ryu floating-point output for double precision.
+ *
+ * Portions Copyright (c) 2018-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/common/d2s_full_table.h
+ *
+ * This is a modification of code taken from github.com/ulfjack/ryu under the
+ * terms of the Boost license (not the Apache license). The original copyright
+ * notice follows:
+ *
+ * Copyright 2018 Ulf Adams
+ *
+ * The contents of this file may be used under the terms of the Apache
+ * License, Version 2.0.
+ *
+ *     (See accompanying file LICENSE-Apache or copy at
+ *      http://www.apache.org/licenses/LICENSE-2.0)
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Boost Software License, Version 1.0.
+ *
+ *     (See accompanying file LICENSE-Boost or copy at
+ *      https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Unless required by applicable law or agreed to in writing, this software is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef RYU_D2S_FULL_TABLE_H
+#define RYU_D2S_FULL_TABLE_H
+
+/*
+ * These tables are generated (by the upstream) using PrintDoubleLookupTable
+ * from the upstream sources at github.com/ulfjack/ryu, and then modified (by
+ * us) by adding UINT64CONST.
+ */
+static const uint64 DOUBLE_POW5_INV_SPLIT[292][2] = {
+   {UINT64CONST(1), UINT64CONST(288230376151711744)}, {UINT64CONST(3689348814741910324), UINT64CONST(230584300921369395)},
+   {UINT64CONST(2951479051793528259), UINT64CONST(184467440737095516)}, {UINT64CONST(17118578500402463900), UINT64CONST(147573952589676412)},
+   {UINT64CONST(12632330341676300947), UINT64CONST(236118324143482260)}, {UINT64CONST(10105864273341040758), UINT64CONST(188894659314785808)},
+   {UINT64CONST(15463389048156653253), UINT64CONST(151115727451828646)}, {UINT64CONST(17362724847566824558), UINT64CONST(241785163922925834)},
+   {UINT64CONST(17579528692795369969), UINT64CONST(193428131138340667)}, {UINT64CONST(6684925324752475329), UINT64CONST(154742504910672534)},
+   {UINT64CONST(18074578149087781173), UINT64CONST(247588007857076054)}, {UINT64CONST(18149011334012135262), UINT64CONST(198070406285660843)},
+   {UINT64CONST(3451162622983977240), UINT64CONST(158456325028528675)}, {UINT64CONST(5521860196774363583), UINT64CONST(253530120045645880)},
+   {UINT64CONST(4417488157419490867), UINT64CONST(202824096036516704)}, {UINT64CONST(7223339340677503017), UINT64CONST(162259276829213363)},
+   {UINT64CONST(7867994130342094503), UINT64CONST(259614842926741381)}, {UINT64CONST(2605046489531765280), UINT64CONST(207691874341393105)},
+   {UINT64CONST(2084037191625412224), UINT64CONST(166153499473114484)}, {UINT64CONST(10713157136084480204), UINT64CONST(265845599156983174)},
+   {UINT64CONST(12259874523609494487), UINT64CONST(212676479325586539)}, {UINT64CONST(13497248433629505913), UINT64CONST(170141183460469231)},
+   {UINT64CONST(14216899864323388813), UINT64CONST(272225893536750770)}, {UINT64CONST(11373519891458711051), UINT64CONST(217780714829400616)},
+   {UINT64CONST(5409467098425058518), UINT64CONST(174224571863520493)}, {UINT64CONST(4965798542738183305), UINT64CONST(278759314981632789)},
+   {UINT64CONST(7661987648932456967), UINT64CONST(223007451985306231)}, {UINT64CONST(2440241304404055250), UINT64CONST(178405961588244985)},
+   {UINT64CONST(3904386087046488400), UINT64CONST(285449538541191976)}, {UINT64CONST(17880904128604832013), UINT64CONST(228359630832953580)},
+   {UINT64CONST(14304723302883865611), UINT64CONST(182687704666362864)}, {UINT64CONST(15133127457049002812), UINT64CONST(146150163733090291)},
+   {UINT64CONST(16834306301794583852), UINT64CONST(233840261972944466)}, {UINT64CONST(9778096226693756759), UINT64CONST(187072209578355573)},
+   {UINT64CONST(15201174610838826053), UINT64CONST(149657767662684458)}, {UINT64CONST(2185786488890659746), UINT64CONST(239452428260295134)},
+   {UINT64CONST(5437978005854438120), UINT64CONST(191561942608236107)}, {UINT64CONST(15418428848909281466), UINT64CONST(153249554086588885)},
+   {UINT64CONST(6222742084545298729), UINT64CONST(245199286538542217)}, {UINT64CONST(16046240111861969953), UINT64CONST(196159429230833773)},
+   {UINT64CONST(1768945645263844993), UINT64CONST(156927543384667019)}, {UINT64CONST(10209010661905972635), UINT64CONST(251084069415467230)},
+   {UINT64CONST(8167208529524778108), UINT64CONST(200867255532373784)}, {UINT64CONST(10223115638361732810), UINT64CONST(160693804425899027)},
+   {UINT64CONST(1599589762411131202), UINT64CONST(257110087081438444)}, {UINT64CONST(4969020624670815285), UINT64CONST(205688069665150755)},
+   {UINT64CONST(3975216499736652228), UINT64CONST(164550455732120604)}, {UINT64CONST(13739044029062464211), UINT64CONST(263280729171392966)},
+   {UINT64CONST(7301886408508061046), UINT64CONST(210624583337114373)}, {UINT64CONST(13220206756290269483), UINT64CONST(168499666669691498)},
+   {UINT64CONST(17462981995322520850), UINT64CONST(269599466671506397)}, {UINT64CONST(6591687966774196033), UINT64CONST(215679573337205118)},
+   {UINT64CONST(12652048002903177473), UINT64CONST(172543658669764094)}, {UINT64CONST(9175230360419352987), UINT64CONST(276069853871622551)},
+   {UINT64CONST(3650835473593572067), UINT64CONST(220855883097298041)}, {UINT64CONST(17678063637842498946), UINT64CONST(176684706477838432)},
+   {UINT64CONST(13527506561580357021), UINT64CONST(282695530364541492)}, {UINT64CONST(3443307619780464970), UINT64CONST(226156424291633194)},
+   {UINT64CONST(6443994910566282300), UINT64CONST(180925139433306555)}, {UINT64CONST(5155195928453025840), UINT64CONST(144740111546645244)},
+   {UINT64CONST(15627011115008661990), UINT64CONST(231584178474632390)}, {UINT64CONST(12501608892006929592), UINT64CONST(185267342779705912)},
+   {UINT64CONST(2622589484121723027), UINT64CONST(148213874223764730)}, {UINT64CONST(4196143174594756843), UINT64CONST(237142198758023568)},
+   {UINT64CONST(10735612169159626121), UINT64CONST(189713759006418854)}, {UINT64CONST(12277838550069611220), UINT64CONST(151771007205135083)},
+   {UINT64CONST(15955192865369467629), UINT64CONST(242833611528216133)}, {UINT64CONST(1696107848069843133), UINT64CONST(194266889222572907)},
+   {UINT64CONST(12424932722681605476), UINT64CONST(155413511378058325)}, {UINT64CONST(1433148282581017146), UINT64CONST(248661618204893321)},
+   {UINT64CONST(15903913885032455010), UINT64CONST(198929294563914656)}, {UINT64CONST(9033782293284053685), UINT64CONST(159143435651131725)},
+   {UINT64CONST(14454051669254485895), UINT64CONST(254629497041810760)}, {UINT64CONST(11563241335403588716), UINT64CONST(203703597633448608)},
+   {UINT64CONST(16629290697806691620), UINT64CONST(162962878106758886)}, {UINT64CONST(781423413297334329), UINT64CONST(260740604970814219)},
+   {UINT64CONST(4314487545379777786), UINT64CONST(208592483976651375)}, {UINT64CONST(3451590036303822229), UINT64CONST(166873987181321100)},
+   {UINT64CONST(5522544058086115566), UINT64CONST(266998379490113760)}, {UINT64CONST(4418035246468892453), UINT64CONST(213598703592091008)},
+   {UINT64CONST(10913125826658934609), UINT64CONST(170878962873672806)}, {UINT64CONST(10082303693170474728), UINT64CONST(273406340597876490)},
+   {UINT64CONST(8065842954536379782), UINT64CONST(218725072478301192)}, {UINT64CONST(17520720807854834795), UINT64CONST(174980057982640953)},
+   {UINT64CONST(5897060404116273733), UINT64CONST(279968092772225526)}, {UINT64CONST(1028299508551108663), UINT64CONST(223974474217780421)},
+   {UINT64CONST(15580034865808528224), UINT64CONST(179179579374224336)}, {UINT64CONST(17549358155809824511), UINT64CONST(286687326998758938)},
+   {UINT64CONST(2971440080422128639), UINT64CONST(229349861599007151)}, {UINT64CONST(17134547323305344204), UINT64CONST(183479889279205720)},
+   {UINT64CONST(13707637858644275364), UINT64CONST(146783911423364576)}, {UINT64CONST(14553522944347019935), UINT64CONST(234854258277383322)},
+   {UINT64CONST(4264120725993795302), UINT64CONST(187883406621906658)}, {UINT64CONST(10789994210278856888), UINT64CONST(150306725297525326)},
+   {UINT64CONST(9885293106962350374), UINT64CONST(240490760476040522)}, {UINT64CONST(529536856086059653), UINT64CONST(192392608380832418)},
+   {UINT64CONST(7802327114352668369), UINT64CONST(153914086704665934)}, {UINT64CONST(1415676938738538420), UINT64CONST(246262538727465495)},
+   {UINT64CONST(1132541550990830736), UINT64CONST(197010030981972396)}, {UINT64CONST(15663428499760305882), UINT64CONST(157608024785577916)},
+   {UINT64CONST(17682787970132668764), UINT64CONST(252172839656924666)}, {UINT64CONST(10456881561364224688), UINT64CONST(201738271725539733)},
+   {UINT64CONST(15744202878575200397), UINT64CONST(161390617380431786)}, {UINT64CONST(17812026976236499989), UINT64CONST(258224987808690858)},
+   {UINT64CONST(3181575136763469022), UINT64CONST(206579990246952687)}, {UINT64CONST(13613306553636506187), UINT64CONST(165263992197562149)},
+   {UINT64CONST(10713244041592678929), UINT64CONST(264422387516099439)}, {UINT64CONST(12259944048016053467), UINT64CONST(211537910012879551)},
+   {UINT64CONST(6118606423670932450), UINT64CONST(169230328010303641)}, {UINT64CONST(2411072648389671274), UINT64CONST(270768524816485826)},
+   {UINT64CONST(16686253377679378312), UINT64CONST(216614819853188660)}, {UINT64CONST(13349002702143502650), UINT64CONST(173291855882550928)},
+   {UINT64CONST(17669055508687693916), UINT64CONST(277266969412081485)}, {UINT64CONST(14135244406950155133), UINT64CONST(221813575529665188)},
+   {UINT64CONST(240149081334393137), UINT64CONST(177450860423732151)}, {UINT64CONST(11452284974360759988), UINT64CONST(283921376677971441)},
+   {UINT64CONST(5472479164746697667), UINT64CONST(227137101342377153)}, {UINT64CONST(11756680961281178780), UINT64CONST(181709681073901722)},
+   {UINT64CONST(2026647139541122378), UINT64CONST(145367744859121378)}, {UINT64CONST(18000030682233437097), UINT64CONST(232588391774594204)},
+   {UINT64CONST(18089373360528660001), UINT64CONST(186070713419675363)}, {UINT64CONST(3403452244197197031), UINT64CONST(148856570735740291)},
+   {UINT64CONST(16513570034941246220), UINT64CONST(238170513177184465)}, {UINT64CONST(13210856027952996976), UINT64CONST(190536410541747572)},
+   {UINT64CONST(3189987192878576934), UINT64CONST(152429128433398058)}, {UINT64CONST(1414630693863812771), UINT64CONST(243886605493436893)},
+   {UINT64CONST(8510402184574870864), UINT64CONST(195109284394749514)}, {UINT64CONST(10497670562401807014), UINT64CONST(156087427515799611)},
+   {UINT64CONST(9417575270359070576), UINT64CONST(249739884025279378)}, {UINT64CONST(14912757845771077107), UINT64CONST(199791907220223502)},
+   {UINT64CONST(4551508647133041040), UINT64CONST(159833525776178802)}, {UINT64CONST(10971762650154775986), UINT64CONST(255733641241886083)},
+   {UINT64CONST(16156107749607641435), UINT64CONST(204586912993508866)}, {UINT64CONST(9235537384944202825), UINT64CONST(163669530394807093)},
+   {UINT64CONST(11087511001168814197), UINT64CONST(261871248631691349)}, {UINT64CONST(12559357615676961681), UINT64CONST(209496998905353079)},
+   {UINT64CONST(13736834907283479668), UINT64CONST(167597599124282463)}, {UINT64CONST(18289587036911657145), UINT64CONST(268156158598851941)},
+   {UINT64CONST(10942320814787415393), UINT64CONST(214524926879081553)}, {UINT64CONST(16132554281313752961), UINT64CONST(171619941503265242)},
+   {UINT64CONST(11054691591134363444), UINT64CONST(274591906405224388)}, {UINT64CONST(16222450902391311402), UINT64CONST(219673525124179510)},
+   {UINT64CONST(12977960721913049122), UINT64CONST(175738820099343608)}, {UINT64CONST(17075388340318968271), UINT64CONST(281182112158949773)},
+   {UINT64CONST(2592264228029443648), UINT64CONST(224945689727159819)}, {UINT64CONST(5763160197165465241), UINT64CONST(179956551781727855)},
+   {UINT64CONST(9221056315464744386), UINT64CONST(287930482850764568)}, {UINT64CONST(14755542681855616155), UINT64CONST(230344386280611654)},
+   {UINT64CONST(15493782960226403247), UINT64CONST(184275509024489323)}, {UINT64CONST(1326979923955391628), UINT64CONST(147420407219591459)},
+   {UINT64CONST(9501865507812447252), UINT64CONST(235872651551346334)}, {UINT64CONST(11290841220991868125), UINT64CONST(188698121241077067)},
+   {UINT64CONST(1653975347309673853), UINT64CONST(150958496992861654)}, {UINT64CONST(10025058185179298811), UINT64CONST(241533595188578646)},
+   {UINT64CONST(4330697733401528726), UINT64CONST(193226876150862917)}, {UINT64CONST(14532604630946953951), UINT64CONST(154581500920690333)},
+   {UINT64CONST(1116074521063664381), UINT64CONST(247330401473104534)}, {UINT64CONST(4582208431592841828), UINT64CONST(197864321178483627)},
+   {UINT64CONST(14733813189500004432), UINT64CONST(158291456942786901)}, {UINT64CONST(16195403473716186445), UINT64CONST(253266331108459042)},
+   {UINT64CONST(5577625149489128510), UINT64CONST(202613064886767234)}, {UINT64CONST(8151448934333213131), UINT64CONST(162090451909413787)},
+   {UINT64CONST(16731667109675051333), UINT64CONST(259344723055062059)}, {UINT64CONST(17074682502481951390), UINT64CONST(207475778444049647)},
+   {UINT64CONST(6281048372501740465), UINT64CONST(165980622755239718)}, {UINT64CONST(6360328581260874421), UINT64CONST(265568996408383549)},
+   {UINT64CONST(8777611679750609860), UINT64CONST(212455197126706839)}, {UINT64CONST(10711438158542398211), UINT64CONST(169964157701365471)},
+   {UINT64CONST(9759603424184016492), UINT64CONST(271942652322184754)}, {UINT64CONST(11497031554089123517), UINT64CONST(217554121857747803)},
+   {UINT64CONST(16576322872755119460), UINT64CONST(174043297486198242)}, {UINT64CONST(11764721337440549842), UINT64CONST(278469275977917188)},
+   {UINT64CONST(16790474699436260520), UINT64CONST(222775420782333750)}, {UINT64CONST(13432379759549008416), UINT64CONST(178220336625867000)},
+   {UINT64CONST(3045063541568861850), UINT64CONST(285152538601387201)}, {UINT64CONST(17193446092222730773), UINT64CONST(228122030881109760)},
+   {UINT64CONST(13754756873778184618), UINT64CONST(182497624704887808)}, {UINT64CONST(18382503128506368341), UINT64CONST(145998099763910246)},
+   {UINT64CONST(3586563302416817083), UINT64CONST(233596959622256395)}, {UINT64CONST(2869250641933453667), UINT64CONST(186877567697805116)},
+   {UINT64CONST(17052795772514404226), UINT64CONST(149502054158244092)}, {UINT64CONST(12527077977055405469), UINT64CONST(239203286653190548)},
+   {UINT64CONST(17400360011128145022), UINT64CONST(191362629322552438)}, {UINT64CONST(2852241564676785048), UINT64CONST(153090103458041951)},
+   {UINT64CONST(15631632947708587046), UINT64CONST(244944165532867121)}, {UINT64CONST(8815957543424959314), UINT64CONST(195955332426293697)},
+   {UINT64CONST(18120812478965698421), UINT64CONST(156764265941034957)}, {UINT64CONST(14235904707377476180), UINT64CONST(250822825505655932)},
+   {UINT64CONST(4010026136418160298), UINT64CONST(200658260404524746)}, {UINT64CONST(17965416168102169531), UINT64CONST(160526608323619796)},
+   {UINT64CONST(2919224165770098987), UINT64CONST(256842573317791675)}, {UINT64CONST(2335379332616079190), UINT64CONST(205474058654233340)},
+   {UINT64CONST(1868303466092863352), UINT64CONST(164379246923386672)}, {UINT64CONST(6678634360490491686), UINT64CONST(263006795077418675)},
+   {UINT64CONST(5342907488392393349), UINT64CONST(210405436061934940)}, {UINT64CONST(4274325990713914679), UINT64CONST(168324348849547952)},
+   {UINT64CONST(10528270399884173809), UINT64CONST(269318958159276723)}, {UINT64CONST(15801313949391159694), UINT64CONST(215455166527421378)},
+   {UINT64CONST(1573004715287196786), UINT64CONST(172364133221937103)}, {UINT64CONST(17274202803427156150), UINT64CONST(275782613155099364)},
+   {UINT64CONST(17508711057483635243), UINT64CONST(220626090524079491)}, {UINT64CONST(10317620031244997871), UINT64CONST(176500872419263593)},
+   {UINT64CONST(12818843235250086271), UINT64CONST(282401395870821749)}, {UINT64CONST(13944423402941979340), UINT64CONST(225921116696657399)},
+   {UINT64CONST(14844887537095493795), UINT64CONST(180736893357325919)}, {UINT64CONST(15565258844418305359), UINT64CONST(144589514685860735)},
+   {UINT64CONST(6457670077359736959), UINT64CONST(231343223497377177)}, {UINT64CONST(16234182506113520537), UINT64CONST(185074578797901741)},
+   {UINT64CONST(9297997190148906106), UINT64CONST(148059663038321393)}, {UINT64CONST(11187446689496339446), UINT64CONST(236895460861314229)},
+   {UINT64CONST(12639306166338981880), UINT64CONST(189516368689051383)}, {UINT64CONST(17490142562555006151), UINT64CONST(151613094951241106)},
+   {UINT64CONST(2158786396894637579), UINT64CONST(242580951921985771)}, {UINT64CONST(16484424376483351356), UINT64CONST(194064761537588616)},
+   {UINT64CONST(9498190686444770762), UINT64CONST(155251809230070893)}, {UINT64CONST(11507756283569722895), UINT64CONST(248402894768113429)},
+   {UINT64CONST(12895553841597688639), UINT64CONST(198722315814490743)}, {UINT64CONST(17695140702761971558), UINT64CONST(158977852651592594)},
+   {UINT64CONST(17244178680193423523), UINT64CONST(254364564242548151)}, {UINT64CONST(10105994129412828495), UINT64CONST(203491651394038521)},
+   {UINT64CONST(4395446488788352473), UINT64CONST(162793321115230817)}, {UINT64CONST(10722063196803274280), UINT64CONST(260469313784369307)},
+   {UINT64CONST(1198952927958798777), UINT64CONST(208375451027495446)}, {UINT64CONST(15716557601334680315), UINT64CONST(166700360821996356)},
+   {UINT64CONST(17767794532651667857), UINT64CONST(266720577315194170)}, {UINT64CONST(14214235626121334286), UINT64CONST(213376461852155336)},
+   {UINT64CONST(7682039686155157106), UINT64CONST(170701169481724269)}, {UINT64CONST(1223217053622520399), UINT64CONST(273121871170758831)},
+   {UINT64CONST(15735968901865657612), UINT64CONST(218497496936607064)}, {UINT64CONST(16278123936234436413), UINT64CONST(174797997549285651)},
+   {UINT64CONST(219556594781725998), UINT64CONST(279676796078857043)}, {UINT64CONST(7554342905309201445), UINT64CONST(223741436863085634)},
+   {UINT64CONST(9732823138989271479), UINT64CONST(178993149490468507)}, {UINT64CONST(815121763415193074), UINT64CONST(286389039184749612)},
+   {UINT64CONST(11720143854957885429), UINT64CONST(229111231347799689)}, {UINT64CONST(13065463898708218666), UINT64CONST(183288985078239751)},
+   {UINT64CONST(6763022304224664610), UINT64CONST(146631188062591801)}, {UINT64CONST(3442138057275642729), UINT64CONST(234609900900146882)},
+   {UINT64CONST(13821756890046245153), UINT64CONST(187687920720117505)}, {UINT64CONST(11057405512036996122), UINT64CONST(150150336576094004)},
+   {UINT64CONST(6623802375033462826), UINT64CONST(240240538521750407)}, {UINT64CONST(16367088344252501231), UINT64CONST(192192430817400325)},
+   {UINT64CONST(13093670675402000985), UINT64CONST(153753944653920260)}, {UINT64CONST(2503129006933649959), UINT64CONST(246006311446272417)},
+   {UINT64CONST(13070549649772650937), UINT64CONST(196805049157017933)}, {UINT64CONST(17835137349301941396), UINT64CONST(157444039325614346)},
+   {UINT64CONST(2710778055689733971), UINT64CONST(251910462920982955)}, {UINT64CONST(2168622444551787177), UINT64CONST(201528370336786364)},
+   {UINT64CONST(5424246770383340065), UINT64CONST(161222696269429091)}, {UINT64CONST(1300097203129523457), UINT64CONST(257956314031086546)},
+   {UINT64CONST(15797473021471260058), UINT64CONST(206365051224869236)}, {UINT64CONST(8948629602435097724), UINT64CONST(165092040979895389)},
+   {UINT64CONST(3249760919670425388), UINT64CONST(264147265567832623)}, {UINT64CONST(9978506365220160957), UINT64CONST(211317812454266098)},
+   {UINT64CONST(15361502721659949412), UINT64CONST(169054249963412878)}, {UINT64CONST(2442311466204457120), UINT64CONST(270486799941460606)},
+   {UINT64CONST(16711244431931206989), UINT64CONST(216389439953168484)}, {UINT64CONST(17058344360286875914), UINT64CONST(173111551962534787)},
+   {UINT64CONST(12535955717491360170), UINT64CONST(276978483140055660)}, {UINT64CONST(10028764573993088136), UINT64CONST(221582786512044528)},
+   {UINT64CONST(15401709288678291155), UINT64CONST(177266229209635622)}, {UINT64CONST(9885339602917624555), UINT64CONST(283625966735416996)},
+   {UINT64CONST(4218922867592189321), UINT64CONST(226900773388333597)}, {UINT64CONST(14443184738299482427), UINT64CONST(181520618710666877)},
+   {UINT64CONST(4175850161155765295), UINT64CONST(145216494968533502)}, {UINT64CONST(10370709072591134795), UINT64CONST(232346391949653603)},
+   {UINT64CONST(15675264887556728482), UINT64CONST(185877113559722882)}, {UINT64CONST(5161514280561562140), UINT64CONST(148701690847778306)},
+   {UINT64CONST(879725219414678777), UINT64CONST(237922705356445290)}, {UINT64CONST(703780175531743021), UINT64CONST(190338164285156232)},
+   {UINT64CONST(11631070584651125387), UINT64CONST(152270531428124985)}, {UINT64CONST(162968861732249003), UINT64CONST(243632850284999977)},
+   {UINT64CONST(11198421533611530172), UINT64CONST(194906280227999981)}, {UINT64CONST(5269388412147313814), UINT64CONST(155925024182399985)},
+   {UINT64CONST(8431021459435702103), UINT64CONST(249480038691839976)}, {UINT64CONST(3055468352806651359), UINT64CONST(199584030953471981)},
+   {UINT64CONST(17201769941212962380), UINT64CONST(159667224762777584)}, {UINT64CONST(16454785461715008838), UINT64CONST(255467559620444135)},
+   {UINT64CONST(13163828369372007071), UINT64CONST(204374047696355308)}, {UINT64CONST(17909760324981426303), UINT64CONST(163499238157084246)},
+   {UINT64CONST(2830174816776909822), UINT64CONST(261598781051334795)}, {UINT64CONST(2264139853421527858), UINT64CONST(209279024841067836)},
+   {UINT64CONST(16568707141704863579), UINT64CONST(167423219872854268)}, {UINT64CONST(4373838538276319787), UINT64CONST(267877151796566830)},
+   {UINT64CONST(3499070830621055830), UINT64CONST(214301721437253464)}, {UINT64CONST(6488605479238754987), UINT64CONST(171441377149802771)},
+   {UINT64CONST(3003071137298187333), UINT64CONST(274306203439684434)}, {UINT64CONST(6091805724580460189), UINT64CONST(219444962751747547)},
+   {UINT64CONST(15941491023890099121), UINT64CONST(175555970201398037)}, {UINT64CONST(10748990379256517301), UINT64CONST(280889552322236860)},
+   {UINT64CONST(8599192303405213841), UINT64CONST(224711641857789488)}, {UINT64CONST(14258051472207991719), UINT64CONST(179769313486231590)}
+};
+
+static const uint64 DOUBLE_POW5_SPLIT[326][2] = {
+   {UINT64CONST(0), UINT64CONST(72057594037927936)}, {UINT64CONST(0), UINT64CONST(90071992547409920)},
+   {UINT64CONST(0), UINT64CONST(112589990684262400)}, {UINT64CONST(0), UINT64CONST(140737488355328000)},
+   {UINT64CONST(0), UINT64CONST(87960930222080000)}, {UINT64CONST(0), UINT64CONST(109951162777600000)},
+   {UINT64CONST(0), UINT64CONST(137438953472000000)}, {UINT64CONST(0), UINT64CONST(85899345920000000)},
+   {UINT64CONST(0), UINT64CONST(107374182400000000)}, {UINT64CONST(0), UINT64CONST(134217728000000000)},
+   {UINT64CONST(0), UINT64CONST(83886080000000000)}, {UINT64CONST(0), UINT64CONST(104857600000000000)},
+   {UINT64CONST(0), UINT64CONST(131072000000000000)}, {UINT64CONST(0), UINT64CONST(81920000000000000)},
+   {UINT64CONST(0), UINT64CONST(102400000000000000)}, {UINT64CONST(0), UINT64CONST(128000000000000000)},
+   {UINT64CONST(0), UINT64CONST(80000000000000000)}, {UINT64CONST(0), UINT64CONST(100000000000000000)},
+   {UINT64CONST(0), UINT64CONST(125000000000000000)}, {UINT64CONST(0), UINT64CONST(78125000000000000)},
+   {UINT64CONST(0), UINT64CONST(97656250000000000)}, {UINT64CONST(0), UINT64CONST(122070312500000000)},
+   {UINT64CONST(0), UINT64CONST(76293945312500000)}, {UINT64CONST(0), UINT64CONST(95367431640625000)},
+   {UINT64CONST(0), UINT64CONST(119209289550781250)}, {UINT64CONST(4611686018427387904), UINT64CONST(74505805969238281)},
+   {UINT64CONST(10376293541461622784), UINT64CONST(93132257461547851)}, {UINT64CONST(8358680908399640576), UINT64CONST(116415321826934814)},
+   {UINT64CONST(612489549322387456), UINT64CONST(72759576141834259)}, {UINT64CONST(14600669991935148032), UINT64CONST(90949470177292823)},
+   {UINT64CONST(13639151471491547136), UINT64CONST(113686837721616029)}, {UINT64CONST(3213881284082270208), UINT64CONST(142108547152020037)},
+   {UINT64CONST(4314518811765112832), UINT64CONST(88817841970012523)}, {UINT64CONST(781462496279003136), UINT64CONST(111022302462515654)},
+   {UINT64CONST(10200200157203529728), UINT64CONST(138777878078144567)}, {UINT64CONST(13292654125893287936), UINT64CONST(86736173798840354)},
+   {UINT64CONST(7392445620511834112), UINT64CONST(108420217248550443)}, {UINT64CONST(4628871007212404736), UINT64CONST(135525271560688054)},
+   {UINT64CONST(16728102434789916672), UINT64CONST(84703294725430033)}, {UINT64CONST(7075069988205232128), UINT64CONST(105879118406787542)},
+   {UINT64CONST(18067209522111315968), UINT64CONST(132348898008484427)}, {UINT64CONST(8986162942105878528), UINT64CONST(82718061255302767)},
+   {UINT64CONST(6621017659204960256), UINT64CONST(103397576569128459)}, {UINT64CONST(3664586055578812416), UINT64CONST(129246970711410574)},
+   {UINT64CONST(16125424340018921472), UINT64CONST(80779356694631608)}, {UINT64CONST(1710036351314100224), UINT64CONST(100974195868289511)},
+   {UINT64CONST(15972603494424788992), UINT64CONST(126217744835361888)}, {UINT64CONST(9982877184015493120), UINT64CONST(78886090522101180)},
+   {UINT64CONST(12478596480019366400), UINT64CONST(98607613152626475)}, {UINT64CONST(10986559581596820096), UINT64CONST(123259516440783094)},
+   {UINT64CONST(2254913720070624656), UINT64CONST(77037197775489434)}, {UINT64CONST(12042014186943056628), UINT64CONST(96296497219361792)},
+   {UINT64CONST(15052517733678820785), UINT64CONST(120370621524202240)}, {UINT64CONST(9407823583549262990), UINT64CONST(75231638452626400)},
+   {UINT64CONST(11759779479436578738), UINT64CONST(94039548065783000)}, {UINT64CONST(14699724349295723422), UINT64CONST(117549435082228750)},
+   {UINT64CONST(4575641699882439235), UINT64CONST(73468396926392969)}, {UINT64CONST(10331238143280436948), UINT64CONST(91835496157991211)},
+   {UINT64CONST(8302361660673158281), UINT64CONST(114794370197489014)}, {UINT64CONST(1154580038986672043), UINT64CONST(143492962746861268)},
+   {UINT64CONST(9944984561221445835), UINT64CONST(89683101716788292)}, {UINT64CONST(12431230701526807293), UINT64CONST(112103877145985365)},
+   {UINT64CONST(1703980321626345405), UINT64CONST(140129846432481707)}, {UINT64CONST(17205888765512323542), UINT64CONST(87581154020301066)},
+   {UINT64CONST(12283988920035628619), UINT64CONST(109476442525376333)}, {UINT64CONST(1519928094762372062), UINT64CONST(136845553156720417)},
+   {UINT64CONST(12479170105294952299), UINT64CONST(85528470722950260)}, {UINT64CONST(15598962631618690374), UINT64CONST(106910588403687825)},
+   {UINT64CONST(5663645234241199255), UINT64CONST(133638235504609782)}, {UINT64CONST(17374836326682913246), UINT64CONST(83523897190381113)},
+   {UINT64CONST(7883487353071477846), UINT64CONST(104404871487976392)}, {UINT64CONST(9854359191339347308), UINT64CONST(130506089359970490)},
+   {UINT64CONST(10770660513014479971), UINT64CONST(81566305849981556)}, {UINT64CONST(13463325641268099964), UINT64CONST(101957882312476945)},
+   {UINT64CONST(2994098996302961243), UINT64CONST(127447352890596182)}, {UINT64CONST(15706369927971514489), UINT64CONST(79654595556622613)},
+   {UINT64CONST(5797904354682229399), UINT64CONST(99568244445778267)}, {UINT64CONST(2635694424925398845), UINT64CONST(124460305557222834)},
+   {UINT64CONST(6258995034005762182), UINT64CONST(77787690973264271)}, {UINT64CONST(3212057774079814824), UINT64CONST(97234613716580339)},
+   {UINT64CONST(17850130272881932242), UINT64CONST(121543267145725423)}, {UINT64CONST(18073860448192289507), UINT64CONST(75964541966078389)},
+   {UINT64CONST(8757267504958198172), UINT64CONST(94955677457597987)}, {UINT64CONST(6334898362770359811), UINT64CONST(118694596821997484)},
+   {UINT64CONST(13182683513586250689), UINT64CONST(74184123013748427)}, {UINT64CONST(11866668373555425458), UINT64CONST(92730153767185534)},
+   {UINT64CONST(5609963430089506015), UINT64CONST(115912692208981918)}, {UINT64CONST(17341285199088104971), UINT64CONST(72445432630613698)},
+   {UINT64CONST(12453234462005355406), UINT64CONST(90556790788267123)}, {UINT64CONST(10954857059079306353), UINT64CONST(113195988485333904)},
+   {UINT64CONST(13693571323849132942), UINT64CONST(141494985606667380)}, {UINT64CONST(17781854114260483896), UINT64CONST(88434366004167112)},
+   {UINT64CONST(3780573569116053255), UINT64CONST(110542957505208891)}, {UINT64CONST(114030942967678664), UINT64CONST(138178696881511114)},
+   {UINT64CONST(4682955357782187069), UINT64CONST(86361685550944446)}, {UINT64CONST(15077066234082509644), UINT64CONST(107952106938680557)},
+   {UINT64CONST(5011274737320973344), UINT64CONST(134940133673350697)}, {UINT64CONST(14661261756894078100), UINT64CONST(84337583545844185)},
+   {UINT64CONST(4491519140835433913), UINT64CONST(105421979432305232)}, {UINT64CONST(5614398926044292391), UINT64CONST(131777474290381540)},
+   {UINT64CONST(12732371365632458552), UINT64CONST(82360921431488462)}, {UINT64CONST(6692092170185797382), UINT64CONST(102951151789360578)},
+   {UINT64CONST(17588487249587022536), UINT64CONST(128688939736700722)}, {UINT64CONST(15604490549419276989), UINT64CONST(80430587335437951)},
+   {UINT64CONST(14893927168346708332), UINT64CONST(100538234169297439)}, {UINT64CONST(14005722942005997511), UINT64CONST(125672792711621799)},
+   {UINT64CONST(15671105866394830300), UINT64CONST(78545495444763624)}, {UINT64CONST(1142138259283986260), UINT64CONST(98181869305954531)},
+   {UINT64CONST(15262730879387146537), UINT64CONST(122727336632443163)}, {UINT64CONST(7233363790403272633), UINT64CONST(76704585395276977)},
+   {UINT64CONST(13653390756431478696), UINT64CONST(95880731744096221)}, {UINT64CONST(3231680390257184658), UINT64CONST(119850914680120277)},
+   {UINT64CONST(4325643253124434363), UINT64CONST(74906821675075173)}, {UINT64CONST(10018740084832930858), UINT64CONST(93633527093843966)},
+   {UINT64CONST(3300053069186387764), UINT64CONST(117041908867304958)}, {UINT64CONST(15897591223523656064), UINT64CONST(73151193042065598)},
+   {UINT64CONST(10648616992549794273), UINT64CONST(91438991302581998)}, {UINT64CONST(4087399203832467033), UINT64CONST(114298739128227498)},
+   {UINT64CONST(14332621041645359599), UINT64CONST(142873423910284372)}, {UINT64CONST(18181260187883125557), UINT64CONST(89295889943927732)},
+   {UINT64CONST(4279831161144355331), UINT64CONST(111619862429909666)}, {UINT64CONST(14573160988285219972), UINT64CONST(139524828037387082)},
+   {UINT64CONST(13719911636105650386), UINT64CONST(87203017523366926)}, {UINT64CONST(7926517508277287175), UINT64CONST(109003771904208658)},
+   {UINT64CONST(684774848491833161), UINT64CONST(136254714880260823)}, {UINT64CONST(7345513307948477581), UINT64CONST(85159196800163014)},
+   {UINT64CONST(18405263671790372785), UINT64CONST(106448996000203767)}, {UINT64CONST(18394893571310578077), UINT64CONST(133061245000254709)},
+   {UINT64CONST(13802651491282805250), UINT64CONST(83163278125159193)}, {UINT64CONST(3418256308821342851), UINT64CONST(103954097656448992)},
+   {UINT64CONST(4272820386026678563), UINT64CONST(129942622070561240)}, {UINT64CONST(2670512741266674102), UINT64CONST(81214138794100775)},
+   {UINT64CONST(17173198981865506339), UINT64CONST(101517673492625968)}, {UINT64CONST(3019754653622331308), UINT64CONST(126897091865782461)},
+   {UINT64CONST(4193189667727651020), UINT64CONST(79310682416114038)}, {UINT64CONST(14464859121514339583), UINT64CONST(99138353020142547)},
+   {UINT64CONST(13469387883465536574), UINT64CONST(123922941275178184)}, {UINT64CONST(8418367427165960359), UINT64CONST(77451838296986365)},
+   {UINT64CONST(15134645302384838353), UINT64CONST(96814797871232956)}, {UINT64CONST(471562554271496325), UINT64CONST(121018497339041196)},
+   {UINT64CONST(9518098633274461011), UINT64CONST(75636560836900747)}, {UINT64CONST(7285937273165688360), UINT64CONST(94545701046125934)},
+   {UINT64CONST(18330793628311886258), UINT64CONST(118182126307657417)}, {UINT64CONST(4539216990053847055), UINT64CONST(73863828942285886)},
+   {UINT64CONST(14897393274422084627), UINT64CONST(92329786177857357)}, {UINT64CONST(4786683537745442072), UINT64CONST(115412232722321697)},
+   {UINT64CONST(14520892257159371055), UINT64CONST(72132645451451060)}, {UINT64CONST(18151115321449213818), UINT64CONST(90165806814313825)},
+   {UINT64CONST(8853836096529353561), UINT64CONST(112707258517892282)}, {UINT64CONST(1843923083806916143), UINT64CONST(140884073147365353)},
+   {UINT64CONST(12681666973447792349), UINT64CONST(88052545717103345)}, {UINT64CONST(2017025661527576725), UINT64CONST(110065682146379182)},
+   {UINT64CONST(11744654113764246714), UINT64CONST(137582102682973977)}, {UINT64CONST(422879793461572340), UINT64CONST(85988814176858736)},
+   {UINT64CONST(528599741826965425), UINT64CONST(107486017721073420)}, {UINT64CONST(660749677283706782), UINT64CONST(134357522151341775)},
+   {UINT64CONST(7330497575943398595), UINT64CONST(83973451344588609)}, {UINT64CONST(13774807988356636147), UINT64CONST(104966814180735761)},
+   {UINT64CONST(3383451930163631472), UINT64CONST(131208517725919702)}, {UINT64CONST(15949715511634433382), UINT64CONST(82005323578699813)},
+   {UINT64CONST(6102086334260878016), UINT64CONST(102506654473374767)}, {UINT64CONST(3015921899398709616), UINT64CONST(128133318091718459)},
+   {UINT64CONST(18025852251620051174), UINT64CONST(80083323807324036)}, {UINT64CONST(4085571240815512351), UINT64CONST(100104154759155046)},
+   {UINT64CONST(14330336087874166247), UINT64CONST(125130193448943807)}, {UINT64CONST(15873989082562435760), UINT64CONST(78206370905589879)},
+   {UINT64CONST(15230800334775656796), UINT64CONST(97757963631987349)}, {UINT64CONST(5203442363187407284), UINT64CONST(122197454539984187)},
+   {UINT64CONST(946308467778435600), UINT64CONST(76373409087490117)}, {UINT64CONST(5794571603150432404), UINT64CONST(95466761359362646)},
+   {UINT64CONST(16466586540792816313), UINT64CONST(119333451699203307)}, {UINT64CONST(7985773578781816244), UINT64CONST(74583407312002067)},
+   {UINT64CONST(5370530955049882401), UINT64CONST(93229259140002584)}, {UINT64CONST(6713163693812353001), UINT64CONST(116536573925003230)},
+   {UINT64CONST(18030785363914884337), UINT64CONST(72835358703127018)}, {UINT64CONST(13315109668038829614), UINT64CONST(91044198378908773)},
+   {UINT64CONST(2808829029766373305), UINT64CONST(113805247973635967)}, {UINT64CONST(17346094342490130344), UINT64CONST(142256559967044958)},
+   {UINT64CONST(6229622945628943561), UINT64CONST(88910349979403099)}, {UINT64CONST(3175342663608791547), UINT64CONST(111137937474253874)},
+   {UINT64CONST(13192550366365765242), UINT64CONST(138922421842817342)}, {UINT64CONST(3633657960551215372), UINT64CONST(86826513651760839)},
+   {UINT64CONST(18377130505971182927), UINT64CONST(108533142064701048)}, {UINT64CONST(4524669058754427043), UINT64CONST(135666427580876311)},
+   {UINT64CONST(9745447189362598758), UINT64CONST(84791517238047694)}, {UINT64CONST(2958436949848472639), UINT64CONST(105989396547559618)},
+   {UINT64CONST(12921418224165366607), UINT64CONST(132486745684449522)}, {UINT64CONST(12687572408530742033), UINT64CONST(82804216052780951)},
+   {UINT64CONST(11247779492236039638), UINT64CONST(103505270065976189)}, {UINT64CONST(224666310012885835), UINT64CONST(129381587582470237)},
+   {UINT64CONST(2446259452971747599), UINT64CONST(80863492239043898)}, {UINT64CONST(12281196353069460307), UINT64CONST(101079365298804872)},
+   {UINT64CONST(15351495441336825384), UINT64CONST(126349206623506090)}, {UINT64CONST(14206370669262903769), UINT64CONST(78968254139691306)},
+   {UINT64CONST(8534591299723853903), UINT64CONST(98710317674614133)}, {UINT64CONST(15279925143082205283), UINT64CONST(123387897093267666)},
+   {UINT64CONST(14161639232853766206), UINT64CONST(77117435683292291)}, {UINT64CONST(13090363022639819853), UINT64CONST(96396794604115364)},
+   {UINT64CONST(16362953778299774816), UINT64CONST(120495993255144205)}, {UINT64CONST(12532689120651053212), UINT64CONST(75309995784465128)},
+   {UINT64CONST(15665861400813816515), UINT64CONST(94137494730581410)}, {UINT64CONST(10358954714162494836), UINT64CONST(117671868413226763)},
+   {UINT64CONST(4168503687137865320), UINT64CONST(73544917758266727)}, {UINT64CONST(598943590494943747), UINT64CONST(91931147197833409)},
+   {UINT64CONST(5360365506546067587), UINT64CONST(114913933997291761)}, {UINT64CONST(11312142901609972388), UINT64CONST(143642417496614701)},
+   {UINT64CONST(9375932322719926695), UINT64CONST(89776510935384188)}, {UINT64CONST(11719915403399908368), UINT64CONST(112220638669230235)},
+   {UINT64CONST(10038208235822497557), UINT64CONST(140275798336537794)}, {UINT64CONST(10885566165816448877), UINT64CONST(87672373960336121)},
+   {UINT64CONST(18218643725697949000), UINT64CONST(109590467450420151)}, {UINT64CONST(18161618638695048346), UINT64CONST(136988084313025189)},
+   {UINT64CONST(13656854658398099168), UINT64CONST(85617552695640743)}, {UINT64CONST(12459382304570236056), UINT64CONST(107021940869550929)},
+   {UINT64CONST(1739169825430631358), UINT64CONST(133777426086938662)}, {UINT64CONST(14922039196176308311), UINT64CONST(83610891304336663)},
+   {UINT64CONST(14040862976792997485), UINT64CONST(104513614130420829)}, {UINT64CONST(3716020665709083144), UINT64CONST(130642017663026037)},
+   {UINT64CONST(4628355925281870917), UINT64CONST(81651261039391273)}, {UINT64CONST(10397130925029726550), UINT64CONST(102064076299239091)},
+   {UINT64CONST(8384727637859770284), UINT64CONST(127580095374048864)}, {UINT64CONST(5240454773662356427), UINT64CONST(79737559608780540)},
+   {UINT64CONST(6550568467077945534), UINT64CONST(99671949510975675)}, {UINT64CONST(3576524565420044014), UINT64CONST(124589936888719594)},
+   {UINT64CONST(6847013871814915412), UINT64CONST(77868710555449746)}, {UINT64CONST(17782139376623420074), UINT64CONST(97335888194312182)},
+   {UINT64CONST(13004302183924499284), UINT64CONST(121669860242890228)}, {UINT64CONST(17351060901807587860), UINT64CONST(76043662651806392)},
+   {UINT64CONST(3242082053549933210), UINT64CONST(95054578314757991)}, {UINT64CONST(17887660622219580224), UINT64CONST(118818222893447488)},
+   {UINT64CONST(11179787888887237640), UINT64CONST(74261389308404680)}, {UINT64CONST(13974734861109047050), UINT64CONST(92826736635505850)},
+   {UINT64CONST(8245046539531533005), UINT64CONST(116033420794382313)}, {UINT64CONST(16682369133275677888), UINT64CONST(72520887996488945)},
+   {UINT64CONST(7017903361312433648), UINT64CONST(90651109995611182)}, {UINT64CONST(17995751238495317868), UINT64CONST(113313887494513977)},
+   {UINT64CONST(8659630992836983623), UINT64CONST(141642359368142472)}, {UINT64CONST(5412269370523114764), UINT64CONST(88526474605089045)},
+   {UINT64CONST(11377022731581281359), UINT64CONST(110658093256361306)}, {UINT64CONST(4997906377621825891), UINT64CONST(138322616570451633)},
+   {UINT64CONST(14652906532082110942), UINT64CONST(86451635356532270)}, {UINT64CONST(9092761128247862869), UINT64CONST(108064544195665338)},
+   {UINT64CONST(2142579373455052779), UINT64CONST(135080680244581673)}, {UINT64CONST(12868327154477877747), UINT64CONST(84425425152863545)},
+   {UINT64CONST(2250350887815183471), UINT64CONST(105531781441079432)}, {UINT64CONST(2812938609768979339), UINT64CONST(131914726801349290)},
+   {UINT64CONST(6369772649532999991), UINT64CONST(82446704250843306)}, {UINT64CONST(17185587848771025797), UINT64CONST(103058380313554132)},
+   {UINT64CONST(3035240737254230630), UINT64CONST(128822975391942666)}, {UINT64CONST(6508711479211282048), UINT64CONST(80514359619964166)},
+   {UINT64CONST(17359261385868878368), UINT64CONST(100642949524955207)}, {UINT64CONST(17087390713908710056), UINT64CONST(125803686906194009)},
+   {UINT64CONST(3762090168551861929), UINT64CONST(78627304316371256)}, {UINT64CONST(4702612710689827411), UINT64CONST(98284130395464070)},
+   {UINT64CONST(15101637925217060072), UINT64CONST(122855162994330087)}, {UINT64CONST(16356052730901744401), UINT64CONST(76784476871456304)},
+   {UINT64CONST(1998321839917628885), UINT64CONST(95980596089320381)}, {UINT64CONST(7109588318324424010), UINT64CONST(119975745111650476)},
+   {UINT64CONST(13666864735807540814), UINT64CONST(74984840694781547)}, {UINT64CONST(12471894901332038114), UINT64CONST(93731050868476934)},
+   {UINT64CONST(6366496589810271835), UINT64CONST(117163813585596168)}, {UINT64CONST(3979060368631419896), UINT64CONST(73227383490997605)},
+   {UINT64CONST(9585511479216662775), UINT64CONST(91534229363747006)}, {UINT64CONST(2758517312166052660), UINT64CONST(114417786704683758)},
+   {UINT64CONST(12671518677062341634), UINT64CONST(143022233380854697)}, {UINT64CONST(1002170145522881665), UINT64CONST(89388895863034186)},
+   {UINT64CONST(10476084718758377889), UINT64CONST(111736119828792732)}, {UINT64CONST(13095105898447972362), UINT64CONST(139670149785990915)},
+   {UINT64CONST(5878598177316288774), UINT64CONST(87293843616244322)}, {UINT64CONST(16571619758500136775), UINT64CONST(109117304520305402)},
+   {UINT64CONST(11491152661270395161), UINT64CONST(136396630650381753)}, {UINT64CONST(264441385652915120), UINT64CONST(85247894156488596)},
+   {UINT64CONST(330551732066143900), UINT64CONST(106559867695610745)}, {UINT64CONST(5024875683510067779), UINT64CONST(133199834619513431)},
+   {UINT64CONST(10058076329834874218), UINT64CONST(83249896637195894)}, {UINT64CONST(3349223375438816964), UINT64CONST(104062370796494868)},
+   {UINT64CONST(4186529219298521205), UINT64CONST(130077963495618585)}, {UINT64CONST(14145795808130045513), UINT64CONST(81298727184761615)},
+   {UINT64CONST(13070558741735168987), UINT64CONST(101623408980952019)}, {UINT64CONST(11726512408741573330), UINT64CONST(127029261226190024)},
+   {UINT64CONST(7329070255463483331), UINT64CONST(79393288266368765)}, {UINT64CONST(13773023837756742068), UINT64CONST(99241610332960956)},
+   {UINT64CONST(17216279797195927585), UINT64CONST(124052012916201195)}, {UINT64CONST(8454331864033760789), UINT64CONST(77532508072625747)},
+   {UINT64CONST(5956228811614813082), UINT64CONST(96915635090782184)}, {UINT64CONST(7445286014518516353), UINT64CONST(121144543863477730)},
+   {UINT64CONST(9264989777501460624), UINT64CONST(75715339914673581)}, {UINT64CONST(16192923240304213684), UINT64CONST(94644174893341976)},
+   {UINT64CONST(1794409976670715490), UINT64CONST(118305218616677471)}, {UINT64CONST(8039035263060279037), UINT64CONST(73940761635423419)},
+   {UINT64CONST(5437108060397960892), UINT64CONST(92425952044279274)}, {UINT64CONST(16019757112352226923), UINT64CONST(115532440055349092)},
+   {UINT64CONST(788976158365366019), UINT64CONST(72207775034593183)}, {UINT64CONST(14821278253238871236), UINT64CONST(90259718793241478)},
+   {UINT64CONST(9303225779693813237), UINT64CONST(112824648491551848)}, {UINT64CONST(11629032224617266546), UINT64CONST(141030810614439810)},
+   {UINT64CONST(11879831158813179495), UINT64CONST(88144256634024881)}, {UINT64CONST(1014730893234310657), UINT64CONST(110180320792531102)},
+   {UINT64CONST(10491785653397664129), UINT64CONST(137725400990663877)}, {UINT64CONST(8863209042587234033), UINT64CONST(86078375619164923)},
+   {UINT64CONST(6467325284806654637), UINT64CONST(107597969523956154)}, {UINT64CONST(17307528642863094104), UINT64CONST(134497461904945192)},
+   {UINT64CONST(10817205401789433815), UINT64CONST(84060913690590745)}, {UINT64CONST(18133192770664180173), UINT64CONST(105076142113238431)},
+   {UINT64CONST(18054804944902837312), UINT64CONST(131345177641548039)}, {UINT64CONST(18201782118205355176), UINT64CONST(82090736025967524)},
+   {UINT64CONST(4305483574047142354), UINT64CONST(102613420032459406)}, {UINT64CONST(14605226504413703751), UINT64CONST(128266775040574257)},
+   {UINT64CONST(2210737537617482988), UINT64CONST(80166734400358911)}, {UINT64CONST(16598479977304017447), UINT64CONST(100208418000448638)},
+   {UINT64CONST(11524727934775246001), UINT64CONST(125260522500560798)}, {UINT64CONST(2591268940807140847), UINT64CONST(78287826562850499)},
+   {UINT64CONST(17074144231291089770), UINT64CONST(97859783203563123)}, {UINT64CONST(16730994270686474309), UINT64CONST(122324729004453904)},
+   {UINT64CONST(10456871419179046443), UINT64CONST(76452955627783690)}, {UINT64CONST(3847717237119032246), UINT64CONST(95566194534729613)},
+   {UINT64CONST(9421332564826178211), UINT64CONST(119457743168412016)}, {UINT64CONST(5888332853016361382), UINT64CONST(74661089480257510)},
+   {UINT64CONST(16583788103125227536), UINT64CONST(93326361850321887)}, {UINT64CONST(16118049110479146516), UINT64CONST(116657952312902359)},
+   {UINT64CONST(16991309721690548428), UINT64CONST(72911220195563974)}, {UINT64CONST(12015765115258409727), UINT64CONST(91139025244454968)},
+   {UINT64CONST(15019706394073012159), UINT64CONST(113923781555568710)}, {UINT64CONST(9551260955736489391), UINT64CONST(142404726944460888)},
+   {UINT64CONST(5969538097335305869), UINT64CONST(89002954340288055)}, {UINT64CONST(2850236603241744433), UINT64CONST(111253692925360069)}
+};
+
+#endif                         /* RYU_D2S_FULL_TABLE_H */
diff --git a/src/common/d2s_intrinsics.h b/src/common/d2s_intrinsics.h
new file mode 100644 (file)
index 0000000..248889e
--- /dev/null
@@ -0,0 +1,202 @@
+/*---------------------------------------------------------------------------
+ *
+ * Ryu floating-point output for double precision.
+ *
+ * Portions Copyright (c) 2018-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/common/d2s_intrinsics.h
+ *
+ * This is a modification of code taken from github.com/ulfjack/ryu under the
+ * terms of the Boost license (not the Apache license). The original copyright
+ * notice follows:
+ *
+ * Copyright 2018 Ulf Adams
+ *
+ * The contents of this file may be used under the terms of the Apache
+ * License, Version 2.0.
+ *
+ *     (See accompanying file LICENSE-Apache or copy at
+ *      http://www.apache.org/licenses/LICENSE-2.0)
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Boost Software License, Version 1.0.
+ *
+ *     (See accompanying file LICENSE-Boost or copy at
+ *      https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Unless required by applicable law or agreed to in writing, this software is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.
+ *
+ *---------------------------------------------------------------------------
+ */
+#ifndef RYU_D2S_INTRINSICS_H
+#define RYU_D2S_INTRINSICS_H
+
+#if defined(HAS_64_BIT_INTRINSICS)
+
+#include <intrin.h>
+
+static inline uint64
+umul128(const uint64 a, const uint64 b, uint64 *const productHi)
+{
+   return _umul128(a, b, productHi);
+}
+
+static inline uint64
+shiftright128(const uint64 lo, const uint64 hi, const uint32 dist)
+{
+   /*
+    * For the __shiftright128 intrinsic, the shift value is always modulo 64.
+    * In the current implementation of the double-precision version of Ryu,
+    * the shift value is always < 64. (In the case RYU_OPTIMIZE_SIZE == 0,
+    * the shift value is in the range [49, 58]. Otherwise in the range [2,
+    * 59].) Check this here in case a future change requires larger shift
+    * values. In this case this function needs to be adjusted.
+    */
+   Assert(dist < 64);
+   return __shiftright128(lo, hi, (unsigned char) dist);
+}
+
+#else                          /* defined(HAS_64_BIT_INTRINSICS) */
+
+static inline uint64
+umul128(const uint64 a, const uint64 b, uint64 *const productHi)
+{
+   /*
+    * The casts here help MSVC to avoid calls to the __allmul library
+    * function.
+    */
+   const uint32 aLo = (uint32) a;
+   const uint32 aHi = (uint32) (a >> 32);
+   const uint32 bLo = (uint32) b;
+   const uint32 bHi = (uint32) (b >> 32);
+
+   const uint64 b00 = (uint64) aLo * bLo;
+   const uint64 b01 = (uint64) aLo * bHi;
+   const uint64 b10 = (uint64) aHi * bLo;
+   const uint64 b11 = (uint64) aHi * bHi;
+
+   const uint32 b00Lo = (uint32) b00;
+   const uint32 b00Hi = (uint32) (b00 >> 32);
+
+   const uint64 mid1 = b10 + b00Hi;
+   const uint32 mid1Lo = (uint32) (mid1);
+   const uint32 mid1Hi = (uint32) (mid1 >> 32);
+
+   const uint64 mid2 = b01 + mid1Lo;
+   const uint32 mid2Lo = (uint32) (mid2);
+   const uint32 mid2Hi = (uint32) (mid2 >> 32);
+
+   const uint64 pHi = b11 + mid1Hi + mid2Hi;
+   const uint64 pLo = ((uint64) mid2Lo << 32) + b00Lo;
+
+   *productHi = pHi;
+   return pLo;
+}
+
+static inline uint64
+shiftright128(const uint64 lo, const uint64 hi, const uint32 dist)
+{
+   /* We don't need to handle the case dist >= 64 here (see above). */
+   Assert(dist < 64);
+#if !defined(RYU_32_BIT_PLATFORM)
+   Assert(dist > 0);
+   return (hi << (64 - dist)) | (lo >> dist);
+#else
+   /* Avoid a 64-bit shift by taking advantage of the range of shift values. */
+   Assert(dist >= 32);
+   return (hi << (64 - dist)) | ((uint32) (lo >> 32) >> (dist - 32));
+#endif
+}
+
+#endif                         /* // defined(HAS_64_BIT_INTRINSICS) */
+
+#ifdef RYU_32_BIT_PLATFORM
+
+/*  Returns the high 64 bits of the 128-bit product of a and b. */
+static inline uint64
+umulh(const uint64 a, const uint64 b)
+{
+   /*
+    * Reuse the umul128 implementation. Optimizers will likely eliminate the
+    * instructions used to compute the low part of the product.
+    */
+   uint64      hi;
+
+   umul128(a, b, &hi);
+   return hi;
+}
+
+/*----
+ *  On 32-bit platforms, compilers typically generate calls to library
+ *  functions for 64-bit divisions, even if the divisor is a constant.
+ *
+ *  E.g.:
+ *  https://bugs.llvm.org/show_bug.cgi?id=37932
+ *  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=17958
+ *  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37443
+ *
+ *  The functions here perform division-by-constant using multiplications
+ *  in the same way as 64-bit compilers would do.
+ *
+ *  NB:
+ *  The multipliers and shift values are the ones generated by clang x64
+ *  for expressions like x/5, x/10, etc.
+ *----
+ */
+
+static inline uint64
+div5(const uint64 x)
+{
+   return umulh(x, UINT64CONST(0xCCCCCCCCCCCCCCCD)) >> 2;
+}
+
+static inline uint64
+div10(const uint64 x)
+{
+   return umulh(x, UINT64CONST(0xCCCCCCCCCCCCCCCD)) >> 3;
+}
+
+static inline uint64
+div100(const uint64 x)
+{
+   return umulh(x >> 2, UINT64CONST(0x28F5C28F5C28F5C3)) >> 2;
+}
+
+static inline uint64
+div1e8(const uint64 x)
+{
+   return umulh(x, UINT64CONST(0xABCC77118461CEFD)) >> 26;
+}
+
+#else                          /* RYU_32_BIT_PLATFORM */
+
+static inline uint64
+div5(const uint64 x)
+{
+   return x / 5;
+}
+
+static inline uint64
+div10(const uint64 x)
+{
+   return x / 10;
+}
+
+static inline uint64
+div100(const uint64 x)
+{
+   return x / 100;
+}
+
+static inline uint64
+div1e8(const uint64 x)
+{
+   return x / 100000000;
+}
+
+#endif                         /* RYU_32_BIT_PLATFORM */
+
+#endif                         /* RYU_D2S_INTRINSICS_H */
diff --git a/src/common/digit_table.h b/src/common/digit_table.h
new file mode 100644 (file)
index 0000000..483aa17
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef RYU_DIGIT_TABLE_H
+#define RYU_DIGIT_TABLE_H
+
+/*
+ * A table of all two-digit numbers. This is used to speed up decimal digit
+ * generation by copying pairs of digits into the final output.
+ */
+static const char DIGIT_TABLE[200] = {
+   '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
+   '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
+   '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
+   '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
+   '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
+   '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
+   '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
+   '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
+   '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
+   '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
+};
+
+#endif                         /* RYU_DIGIT_TABLE_H */
diff --git a/src/common/f2s.c b/src/common/f2s.c
new file mode 100644 (file)
index 0000000..4f36e1a
--- /dev/null
@@ -0,0 +1,804 @@
+/*---------------------------------------------------------------------------
+ *
+ * Ryu floating-point output for single precision.
+ *
+ * Portions Copyright (c) 2018-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/common/f2s.c
+ *
+ * This is a modification of code taken from github.com/ulfjack/ryu under the
+ * terms of the Boost license (not the Apache license). The original copyright
+ * notice follows:
+ *
+ * Copyright 2018 Ulf Adams
+ *
+ * The contents of this file may be used under the terms of the Apache
+ * License, Version 2.0.
+ *
+ *     (See accompanying file LICENSE-Apache or copy at
+ *      http://www.apache.org/licenses/LICENSE-2.0)
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Boost Software License, Version 1.0.
+ *
+ *     (See accompanying file LICENSE-Boost or copy at
+ *      https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Unless required by applicable law or agreed to in writing, this software is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/shortest_dec.h"
+
+#include "ryu_common.h"
+#include "digit_table.h"
+
+#define FLOAT_MANTISSA_BITS 23
+#define FLOAT_EXPONENT_BITS 8
+#define FLOAT_BIAS 127
+
+/*
+ * This table is generated (by the upstream) by PrintFloatLookupTable,
+ * and modified (by us) to add UINT64CONST.
+ */
+#define FLOAT_POW5_INV_BITCOUNT 59
+static const uint64 FLOAT_POW5_INV_SPLIT[31] = {
+   UINT64CONST(576460752303423489), UINT64CONST(461168601842738791), UINT64CONST(368934881474191033), UINT64CONST(295147905179352826),
+   UINT64CONST(472236648286964522), UINT64CONST(377789318629571618), UINT64CONST(302231454903657294), UINT64CONST(483570327845851670),
+   UINT64CONST(386856262276681336), UINT64CONST(309485009821345069), UINT64CONST(495176015714152110), UINT64CONST(396140812571321688),
+   UINT64CONST(316912650057057351), UINT64CONST(507060240091291761), UINT64CONST(405648192073033409), UINT64CONST(324518553658426727),
+   UINT64CONST(519229685853482763), UINT64CONST(415383748682786211), UINT64CONST(332306998946228969), UINT64CONST(531691198313966350),
+   UINT64CONST(425352958651173080), UINT64CONST(340282366920938464), UINT64CONST(544451787073501542), UINT64CONST(435561429658801234),
+   UINT64CONST(348449143727040987), UINT64CONST(557518629963265579), UINT64CONST(446014903970612463), UINT64CONST(356811923176489971),
+   UINT64CONST(570899077082383953), UINT64CONST(456719261665907162), UINT64CONST(365375409332725730)
+};
+#define FLOAT_POW5_BITCOUNT 61
+static const uint64 FLOAT_POW5_SPLIT[47] = {
+   UINT64CONST(1152921504606846976), UINT64CONST(1441151880758558720), UINT64CONST(1801439850948198400), UINT64CONST(2251799813685248000),
+   UINT64CONST(1407374883553280000), UINT64CONST(1759218604441600000), UINT64CONST(2199023255552000000), UINT64CONST(1374389534720000000),
+   UINT64CONST(1717986918400000000), UINT64CONST(2147483648000000000), UINT64CONST(1342177280000000000), UINT64CONST(1677721600000000000),
+   UINT64CONST(2097152000000000000), UINT64CONST(1310720000000000000), UINT64CONST(1638400000000000000), UINT64CONST(2048000000000000000),
+   UINT64CONST(1280000000000000000), UINT64CONST(1600000000000000000), UINT64CONST(2000000000000000000), UINT64CONST(1250000000000000000),
+   UINT64CONST(1562500000000000000), UINT64CONST(1953125000000000000), UINT64CONST(1220703125000000000), UINT64CONST(1525878906250000000),
+   UINT64CONST(1907348632812500000), UINT64CONST(1192092895507812500), UINT64CONST(1490116119384765625), UINT64CONST(1862645149230957031),
+   UINT64CONST(1164153218269348144), UINT64CONST(1455191522836685180), UINT64CONST(1818989403545856475), UINT64CONST(2273736754432320594),
+   UINT64CONST(1421085471520200371), UINT64CONST(1776356839400250464), UINT64CONST(2220446049250313080), UINT64CONST(1387778780781445675),
+   UINT64CONST(1734723475976807094), UINT64CONST(2168404344971008868), UINT64CONST(1355252715606880542), UINT64CONST(1694065894508600678),
+   UINT64CONST(2117582368135750847), UINT64CONST(1323488980084844279), UINT64CONST(1654361225106055349), UINT64CONST(2067951531382569187),
+   UINT64CONST(1292469707114105741), UINT64CONST(1615587133892632177), UINT64CONST(2019483917365790221)
+};
+
+static inline uint32
+pow5Factor(uint32 value)
+{
+   uint32      count = 0;
+
+   for (;;)
+   {
+       Assert(value != 0);
+       const uint32 q = value / 5;
+       const uint32 r = value % 5;
+
+       if (r != 0)
+           break;
+
+       value = q;
+       ++count;
+   }
+   return count;
+}
+
+/*  Returns true if value is divisible by 5^p. */
+static inline bool
+multipleOfPowerOf5(const uint32 value, const uint32 p)
+{
+   return pow5Factor(value) >= p;
+}
+
+/*  Returns true if value is divisible by 2^p. */
+static inline bool
+multipleOfPowerOf2(const uint32 value, const uint32 p)
+{
+   /* return __builtin_ctz(value) >= p; */
+   return (value & ((1u << p) - 1)) == 0;
+}
+
+/*
+ * It seems to be slightly faster to avoid uint128_t here, although the
+ * generated code for uint128_t looks slightly nicer.
+ */
+static inline uint32
+mulShift(const uint32 m, const uint64 factor, const int32 shift)
+{
+   /*
+    * The casts here help MSVC to avoid calls to the __allmul library
+    * function.
+    */
+   const uint32 factorLo = (uint32) (factor);
+   const uint32 factorHi = (uint32) (factor >> 32);
+   const uint64 bits0 = (uint64) m * factorLo;
+   const uint64 bits1 = (uint64) m * factorHi;
+
+   Assert(shift > 32);
+
+#ifdef RYU_32_BIT_PLATFORM
+
+   /*
+    * On 32-bit platforms we can avoid a 64-bit shift-right since we only
+    * need the upper 32 bits of the result and the shift value is > 32.
+    */
+   const uint32 bits0Hi = (uint32) (bits0 >> 32);
+   uint32      bits1Lo = (uint32) (bits1);
+   uint32      bits1Hi = (uint32) (bits1 >> 32);
+
+   bits1Lo += bits0Hi;
+   bits1Hi += (bits1Lo < bits0Hi);
+
+   const int32 s = shift - 32;
+
+   return (bits1Hi << (32 - s)) | (bits1Lo >> s);
+
+#else                          /* RYU_32_BIT_PLATFORM */
+
+   const uint64 sum = (bits0 >> 32) + bits1;
+   const uint64 shiftedSum = sum >> (shift - 32);
+
+   Assert(shiftedSum <= UINT32_MAX);
+   return (uint32) shiftedSum;
+
+#endif                         /* RYU_32_BIT_PLATFORM */
+}
+
+static inline uint32
+mulPow5InvDivPow2(const uint32 m, const uint32 q, const int32 j)
+{
+   return mulShift(m, FLOAT_POW5_INV_SPLIT[q], j);
+}
+
+static inline uint32
+mulPow5divPow2(const uint32 m, const uint32 i, const int32 j)
+{
+   return mulShift(m, FLOAT_POW5_SPLIT[i], j);
+}
+
+static inline uint32
+decimalLength(const uint32 v)
+{
+   /* Function precondition: v is not a 10-digit number. */
+   /* (9 digits are sufficient for round-tripping.) */
+   Assert(v < 1000000000);
+   if (v >= 100000000)
+   {
+       return 9;
+   }
+   if (v >= 10000000)
+   {
+       return 8;
+   }
+   if (v >= 1000000)
+   {
+       return 7;
+   }
+   if (v >= 100000)
+   {
+       return 6;
+   }
+   if (v >= 10000)
+   {
+       return 5;
+   }
+   if (v >= 1000)
+   {
+       return 4;
+   }
+   if (v >= 100)
+   {
+       return 3;
+   }
+   if (v >= 10)
+   {
+       return 2;
+   }
+   return 1;
+}
+
+/*  A floating decimal representing m * 10^e. */
+typedef struct floating_decimal_32
+{
+   uint32      mantissa;
+   int32       exponent;
+} floating_decimal_32;
+
+static inline floating_decimal_32
+f2d(const uint32 ieeeMantissa, const uint32 ieeeExponent)
+{
+   int32       e2;
+   uint32      m2;
+
+   if (ieeeExponent == 0)
+   {
+       /* We subtract 2 so that the bounds computation has 2 additional bits. */
+       e2 = 1 - FLOAT_BIAS - FLOAT_MANTISSA_BITS - 2;
+       m2 = ieeeMantissa;
+   }
+   else
+   {
+       e2 = ieeeExponent - FLOAT_BIAS - FLOAT_MANTISSA_BITS - 2;
+       m2 = (1u << FLOAT_MANTISSA_BITS) | ieeeMantissa;
+   }
+
+#if STRICTLY_SHORTEST
+   const bool  even = (m2 & 1) == 0;
+   const bool  acceptBounds = even;
+#else
+   const bool  acceptBounds = false;
+#endif
+
+   /* Step 2: Determine the interval of legal decimal representations. */
+   const uint32 mv = 4 * m2;
+   const uint32 mp = 4 * m2 + 2;
+
+   /* Implicit bool -> int conversion. True is 1, false is 0. */
+   const uint32 mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
+   const uint32 mm = 4 * m2 - 1 - mmShift;
+
+   /* Step 3: Convert to a decimal power base using 64-bit arithmetic. */
+   uint32      vr,
+               vp,
+               vm;
+   int32       e10;
+   bool        vmIsTrailingZeros = false;
+   bool        vrIsTrailingZeros = false;
+   uint8       lastRemovedDigit = 0;
+
+   if (e2 >= 0)
+   {
+       const uint32 q = log10Pow2(e2);
+
+       e10 = q;
+
+       const int32 k = FLOAT_POW5_INV_BITCOUNT + pow5bits(q) - 1;
+       const int32 i = -e2 + q + k;
+
+       vr = mulPow5InvDivPow2(mv, q, i);
+       vp = mulPow5InvDivPow2(mp, q, i);
+       vm = mulPow5InvDivPow2(mm, q, i);
+
+       if (q != 0 && (vp - 1) / 10 <= vm / 10)
+       {
+           /*
+            * We need to know one removed digit even if we are not going to
+            * loop below. We could use q = X - 1 above, except that would
+            * require 33 bits for the result, and we've found that 32-bit
+            * arithmetic is faster even on 64-bit machines.
+            */
+           const int32 l = FLOAT_POW5_INV_BITCOUNT + pow5bits(q - 1) - 1;
+
+           lastRemovedDigit = (uint8) (mulPow5InvDivPow2(mv, q - 1, -e2 + q - 1 + l) % 10);
+       }
+       if (q <= 9)
+       {
+           /*
+            * The largest power of 5 that fits in 24 bits is 5^10, but q <= 9
+            * seems to be safe as well.
+            *
+            * Only one of mp, mv, and mm can be a multiple of 5, if any.
+            */
+           if (mv % 5 == 0)
+           {
+               vrIsTrailingZeros = multipleOfPowerOf5(mv, q);
+           }
+           else if (acceptBounds)
+           {
+               vmIsTrailingZeros = multipleOfPowerOf5(mm, q);
+           }
+           else
+           {
+               vp -= multipleOfPowerOf5(mp, q);
+           }
+       }
+   }
+   else
+   {
+       const uint32 q = log10Pow5(-e2);
+
+       e10 = q + e2;
+
+       const int32 i = -e2 - q;
+       const int32 k = pow5bits(i) - FLOAT_POW5_BITCOUNT;
+       int32       j = q - k;
+
+       vr = mulPow5divPow2(mv, i, j);
+       vp = mulPow5divPow2(mp, i, j);
+       vm = mulPow5divPow2(mm, i, j);
+
+       if (q != 0 && (vp - 1) / 10 <= vm / 10)
+       {
+           j = q - 1 - (pow5bits(i + 1) - FLOAT_POW5_BITCOUNT);
+           lastRemovedDigit = (uint8) (mulPow5divPow2(mv, i + 1, j) % 10);
+       }
+       if (q <= 1)
+       {
+           /*
+            * {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q
+            * trailing 0 bits.
+            */
+           /* mv = 4 * m2, so it always has at least two trailing 0 bits. */
+           vrIsTrailingZeros = true;
+           if (acceptBounds)
+           {
+               /*
+                * mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff
+                * mmShift == 1.
+                */
+               vmIsTrailingZeros = mmShift == 1;
+           }
+           else
+           {
+               /*
+                * mp = mv + 2, so it always has at least one trailing 0 bit.
+                */
+               --vp;
+           }
+       }
+       else if (q < 31)
+       {
+           /* TODO(ulfjack):Use a tighter bound here. */
+           vrIsTrailingZeros = multipleOfPowerOf2(mv, q - 1);
+       }
+   }
+
+   /*
+    * Step 4: Find the shortest decimal representation in the interval of
+    * legal representations.
+    */
+   uint32      removed = 0;
+   uint32      output;
+
+   if (vmIsTrailingZeros || vrIsTrailingZeros)
+   {
+       /* General case, which happens rarely (~4.0%). */
+       while (vp / 10 > vm / 10)
+       {
+           vmIsTrailingZeros &= vm - (vm / 10) * 10 == 0;
+           vrIsTrailingZeros &= lastRemovedDigit == 0;
+           lastRemovedDigit = (uint8) (vr % 10);
+           vr /= 10;
+           vp /= 10;
+           vm /= 10;
+           ++removed;
+       }
+       if (vmIsTrailingZeros)
+       {
+           while (vm % 10 == 0)
+           {
+               vrIsTrailingZeros &= lastRemovedDigit == 0;
+               lastRemovedDigit = (uint8) (vr % 10);
+               vr /= 10;
+               vp /= 10;
+               vm /= 10;
+               ++removed;
+           }
+       }
+
+       if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0)
+       {
+           /* Round even if the exact number is .....50..0. */
+           lastRemovedDigit = 4;
+       }
+
+       /*
+        * We need to take vr + 1 if vr is outside bounds or we need to round
+        * up.
+        */
+       output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5);
+   }
+   else
+   {
+       /*
+        * Specialized for the common case (~96.0%). Percentages below are
+        * relative to this.
+        *
+        * Loop iterations below (approximately): 0: 13.6%, 1: 70.7%, 2:
+        * 14.1%, 3: 1.39%, 4: 0.14%, 5+: 0.01%
+        */
+       while (vp / 10 > vm / 10)
+       {
+           lastRemovedDigit = (uint8) (vr % 10);
+           vr /= 10;
+           vp /= 10;
+           vm /= 10;
+           ++removed;
+       }
+
+       /*
+        * We need to take vr + 1 if vr is outside bounds or we need to round
+        * up.
+        */
+       output = vr + (vr == vm || lastRemovedDigit >= 5);
+   }
+
+   const int32 exp = e10 + removed;
+
+   floating_decimal_32 fd;
+
+   fd.exponent = exp;
+   fd.mantissa = output;
+   return fd;
+}
+
+static inline int
+to_chars_f(const floating_decimal_32 v, const uint32 olength, char *const result)
+{
+   /* Step 5: Print the decimal representation. */
+   int         index = 0;
+
+   uint32      output = v.mantissa;
+   int32       exp = v.exponent;
+
+   /*----
+    * On entry, mantissa * 10^exp is the result to be output.
+    * Caller has already done the - sign if needed.
+    *
+    * We want to insert the point somewhere depending on the output length
+    * and exponent, which might mean adding zeros:
+    *
+    *            exp  | format
+    *            1+   |  ddddddddd000000
+    *            0    |  ddddddddd
+    *  -1 .. -len+1   |  dddddddd.d to d.ddddddddd
+    *  -len ...       |  0.ddddddddd to 0.000dddddd
+    */
+   uint32      i = 0;
+   int32       nexp = exp + olength;
+
+   if (nexp <= 0)
+   {
+       /* -nexp is number of 0s to add after '.' */
+       Assert(nexp >= -3);
+       /* 0.000ddddd */
+       index = 2 - nexp;
+       /* copy 8 bytes rather than 5 to let compiler optimize */
+       memcpy(result, "0.000000", 8);
+   }
+   else if (exp < 0)
+   {
+       /*
+        * dddd.dddd; leave space at the start and move the '.' in after
+        */
+       index = 1;
+   }
+   else
+   {
+       /*
+        * We can save some code later by pre-filling with zeros. We know
+        * that there can be no more than 6 output digits in this form,
+        * otherwise we would not choose fixed-point output. memset 8
+        * rather than 6 bytes to let the compiler optimize it.
+        */
+       Assert(exp < 6 && exp + olength <= 6);
+       memset(result, '0', 8);
+   }
+
+   while (output >= 10000)
+   {
+       const uint32 c = output - 10000 * (output / 10000);
+       const uint32 c0 = (c % 100) << 1;
+       const uint32 c1 = (c / 100) << 1;
+
+       output /= 10000;
+
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c0, 2);
+       memcpy(result + index + olength - i - 4, DIGIT_TABLE + c1, 2);
+       i += 4;
+   }
+   if (output >= 100)
+   {
+       const uint32 c = (output % 100) << 1;
+
+       output /= 100;
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2);
+       i += 2;
+   }
+   if (output >= 10)
+   {
+       const uint32 c = output << 1;
+
+       memcpy(result + index + olength - i - 2, DIGIT_TABLE + c, 2);
+   }
+   else
+   {
+       result[index] = (char) ('0' + output);
+   }
+
+   if (index == 1)
+   {
+       /*
+        * nexp is 1..6 here, representing the number of digits before the
+        * point. A value of 7+ is not possible because we switch to
+        * scientific notation when the display exponent reaches 6.
+        */
+       Assert(nexp < 7);
+       /* gcc only seems to want to optimize memmove for small 2^n */
+       if (nexp & 4)
+       {
+           memmove(result + index - 1, result + index, 4);
+           index += 4;
+       }
+       if (nexp & 2)
+       {
+           memmove(result + index - 1, result + index, 2);
+           index += 2;
+       }
+       if (nexp & 1)
+       {
+           result[index - 1] = result[index];
+       }
+       result[nexp] = '.';
+       index = olength + 1;
+   }
+   else if (exp >= 0)
+   {
+       /* we supplied the trailing zeros earlier, now just set the length. */
+       index = olength + exp;
+   }
+   else
+   {
+       index = olength + (2 - nexp);
+   }
+
+   return index;
+}
+
+static inline int
+to_chars(const floating_decimal_32 v, const bool sign, char *const result)
+{
+   /* Step 5: Print the decimal representation. */
+   int         index = 0;
+
+   uint32      output = v.mantissa;
+   uint32      olength = decimalLength(output);
+   int32       exp = v.exponent + olength - 1;
+
+   if (sign)
+       result[index++] = '-';
+
+   /*
+    * The thresholds for fixed-point output are chosen to match printf
+    * defaults. Beware that both the code of to_chars_f and the value
+    * of FLOAT_SHORTEST_DECIMAL_LEN are sensitive to these thresholds.
+    */
+   if (exp >= -4 && exp < 6)
+       return to_chars_f(v, olength, result + index) + sign;
+
+   /*
+    * If v.exponent is exactly 0, we might have reached here via the small
+    * integer fast path, in which case v.mantissa might contain trailing
+    * (decimal) zeros. For scientific notation we need to move these zeros
+    * into the exponent. (For fixed point this doesn't matter, which is why
+    * we do this here rather than above.)
+    *
+    * Since we already calculated the display exponent (exp) above based on
+    * the old decimal length, that value does not change here. Instead, we
+    * just reduce the display length for each digit removed.
+    *
+    * If we didn't get here via the fast path, the raw exponent will not
+    * usually be 0, and there will be no trailing zeros, so we pay no more
+    * than one div10/multiply extra cost. We claw back half of that by
+    * checking for divisibility by 2 before dividing by 10.
+    */
+   if (v.exponent == 0)
+   {
+       while ((output & 1) == 0)
+       {
+           const uint32 q = output / 10;
+           const uint32 r = output - 10 * q;
+
+           if (r != 0)
+               break;
+           output = q;
+           --olength;
+       }
+   }
+
+   /*----
+    * Print the decimal digits.
+    * The following code is equivalent to:
+    *
+    * for (uint32 i = 0; i < olength - 1; ++i) {
+    *   const uint32 c = output % 10; output /= 10;
+    *   result[index + olength - i] = (char) ('0' + c);
+    * }
+    * result[index] = '0' + output % 10;
+    */
+   uint32      i = 0;
+
+   while (output >= 10000)
+   {
+       const uint32 c = output - 10000 * (output / 10000);
+       const uint32 c0 = (c % 100) << 1;
+       const uint32 c1 = (c / 100) << 1;
+
+       output /= 10000;
+
+       memcpy(result + index + olength - i - 1, DIGIT_TABLE + c0, 2);
+       memcpy(result + index + olength - i - 3, DIGIT_TABLE + c1, 2);
+       i += 4;
+   }
+   if (output >= 100)
+   {
+       const uint32 c = (output % 100) << 1;
+
+       output /= 100;
+       memcpy(result + index + olength - i - 1, DIGIT_TABLE + c, 2);
+       i += 2;
+   }
+   if (output >= 10)
+   {
+       const uint32 c = output << 1;
+
+       /*
+        * We can't use memcpy here: the decimal dot goes between these two
+        * digits.
+        */
+       result[index + olength - i] = DIGIT_TABLE[c + 1];
+       result[index] = DIGIT_TABLE[c];
+   }
+   else
+   {
+       result[index] = (char) ('0' + output);
+   }
+
+   /* Print decimal point if needed. */
+   if (olength > 1)
+   {
+       result[index + 1] = '.';
+       index += olength + 1;
+   }
+   else
+   {
+       ++index;
+   }
+
+   /* Print the exponent. */
+   result[index++] = 'e';
+   if (exp < 0)
+   {
+       result[index++] = '-';
+       exp = -exp;
+   }
+   else
+       result[index++] = '+';
+
+   memcpy(result + index, DIGIT_TABLE + 2 * exp, 2);
+   index += 2;
+
+   return index;
+}
+
+static inline bool
+f2d_small_int(const uint32 ieeeMantissa,
+             const uint32 ieeeExponent,
+             floating_decimal_32 *v)
+{
+   const int32 e2 = (int32) ieeeExponent - FLOAT_BIAS - FLOAT_MANTISSA_BITS;
+
+   /*
+    * Avoid using multiple "return false;" here since it tends to provoke the
+    * compiler into inlining multiple copies of f2d, which is undesirable.
+    */
+
+   if (e2 >= -FLOAT_MANTISSA_BITS && e2 <= 0)
+   {
+       /*----
+        * Since 2^23 <= m2 < 2^24 and 0 <= -e2 <= 23:
+        *   1 <= f = m2 / 2^-e2 < 2^24.
+        *
+        * Test if the lower -e2 bits of the significand are 0, i.e. whether
+        * the fraction is 0. We can use ieeeMantissa here, since the implied
+        * 1 bit can never be tested by this; the implied 1 can only be part
+        * of a fraction if e2 < -FLOAT_MANTISSA_BITS which we already
+        * checked. (e.g. 0.5 gives ieeeMantissa == 0 and e2 == -24)
+        */
+       const uint32 mask = (1U << -e2) - 1;
+       const uint32 fraction = ieeeMantissa & mask;
+
+       if (fraction == 0)
+       {
+           /*----
+            * f is an integer in the range [1, 2^24).
+            * Note: mantissa might contain trailing (decimal) 0's.
+            * Note: since 2^24 < 10^9, there is no need to adjust
+            * decimalLength().
+            */
+           const uint32 m2 = (1U << FLOAT_MANTISSA_BITS) | ieeeMantissa;
+
+           v->mantissa = m2 >> -e2;
+           v->exponent = 0;
+           return true;
+       }
+   }
+
+   return false;
+}
+
+/*
+ * Store the shortest decimal representation of the given float as an
+ * UNTERMINATED string in the caller's supplied buffer (which must be at least
+ * FLOAT_SHORTEST_DECIMAL_LEN-1 bytes long).
+ *
+ * Returns the number of bytes stored.
+ */
+int
+float_to_shortest_decimal_bufn(float f, char *result)
+{
+   /*
+    * Step 1: Decode the floating-point number, and unify normalized and
+    * subnormal cases.
+    */
+   const uint32 bits = float_to_bits(f);
+
+   /* Decode bits into sign, mantissa, and exponent. */
+   const bool  ieeeSign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
+   const uint32 ieeeMantissa = bits & ((1u << FLOAT_MANTISSA_BITS) - 1);
+   const uint32 ieeeExponent = (bits >> FLOAT_MANTISSA_BITS) & ((1u << FLOAT_EXPONENT_BITS) - 1);
+
+   /* Case distinction; exit early for the easy cases. */
+   if (ieeeExponent == ((1u << FLOAT_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0))
+   {
+       return copy_special_str(result, ieeeSign, ieeeExponent, ieeeMantissa);
+   }
+
+   floating_decimal_32 v;
+   const bool  isSmallInt = f2d_small_int(ieeeMantissa, ieeeExponent, &v);
+
+   if (!isSmallInt)
+   {
+       v = f2d(ieeeMantissa, ieeeExponent);
+   }
+
+   return to_chars(v, ieeeSign, result);
+}
+
+/*
+ * Store the shortest decimal representation of the given float as a
+ * null-terminated string in the caller's supplied buffer (which must be at
+ * least FLOAT_SHORTEST_DECIMAL_LEN bytes long).
+ *
+ * Returns the string length.
+ */
+int
+float_to_shortest_decimal_buf(float f, char *result)
+{
+   const int   index = float_to_shortest_decimal_bufn(f, result);
+
+   /* Terminate the string. */
+   Assert(index < FLOAT_SHORTEST_DECIMAL_LEN);
+   result[index] = '\0';
+   return index;
+}
+
+/*
+ * Return the shortest decimal representation as a null-terminated palloc'd
+ * string (outside the backend, uses malloc() instead).
+ *
+ * Caller is responsible for freeing the result.
+ */
+char *
+float_to_shortest_decimal(float f)
+{
+   char       *const result = (char *) palloc(FLOAT_SHORTEST_DECIMAL_LEN);
+
+   float_to_shortest_decimal_buf(f, result);
+   return result;
+}
diff --git a/src/common/ryu_common.h b/src/common/ryu_common.h
new file mode 100644 (file)
index 0000000..14639af
--- /dev/null
@@ -0,0 +1,133 @@
+/*---------------------------------------------------------------------------
+ *
+ * Common routines for Ryu floating-point output.
+ *
+ * Portions Copyright (c) 2018-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/common/ryu_common.h
+ *
+ * This is a modification of code taken from github.com/ulfjack/ryu under the
+ * terms of the Boost license (not the Apache license). The original copyright
+ * notice follows:
+ *
+ * Copyright 2018 Ulf Adams
+ *
+ * The contents of this file may be used under the terms of the Apache
+ * License, Version 2.0.
+ *
+ *     (See accompanying file LICENSE-Apache or copy at
+ *      http://www.apache.org/licenses/LICENSE-2.0)
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Boost Software License, Version 1.0.
+ *
+ *     (See accompanying file LICENSE-Boost or copy at
+ *      https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Unless required by applicable law or agreed to in writing, this software is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.
+ *
+ *---------------------------------------------------------------------------
+ */
+#ifndef RYU_COMMON_H
+#define RYU_COMMON_H
+
+/*
+ * Upstream Ryu's output is always the shortest possible. But we adjust that
+ * slightly to improve portability: we avoid outputting the exact midpoint
+ * value between two representable floats, since that relies on the reader
+ * getting the round-to-even rule correct, which seems to be the common
+ * failure mode.
+ *
+ * Defining this to 1 would restore the upstream behavior.
+ */
+#define STRICTLY_SHORTEST 0
+
+#if SIZEOF_SIZE_T < 8
+#define RYU_32_BIT_PLATFORM
+#endif
+
+/*  Returns e == 0 ? 1 : ceil(log_2(5^e)). */
+static inline uint32
+pow5bits(const int32 e)
+{
+   /*
+    * This approximation works up to the point that the multiplication
+    * overflows at e = 3529.
+    *
+    * If the multiplication were done in 64 bits, it would fail at 5^4004
+    * which is just greater than 2^9297.
+    */
+   Assert(e >= 0);
+   Assert(e <= 3528);
+   return ((((uint32) e) * 1217359) >> 19) + 1;
+}
+
+/*  Returns floor(log_10(2^e)). */
+static inline int32
+log10Pow2(const int32 e)
+{
+   /*
+    * The first value this approximation fails for is 2^1651 which is just
+    * greater than 10^297.
+    */
+   Assert(e >= 0);
+   Assert(e <= 1650);
+   return (int32) ((((uint32) e) * 78913) >> 18);
+}
+
+/*  Returns floor(log_10(5^e)). */
+static inline int32
+log10Pow5(const int32 e)
+{
+   /*
+    * The first value this approximation fails for is 5^2621 which is just
+    * greater than 10^1832.
+    */
+   Assert(e >= 0);
+   Assert(e <= 2620);
+   return (int32) ((((uint32) e) * 732923) >> 20);
+}
+
+static inline int
+copy_special_str(char *const result, const bool sign, const bool exponent, const bool mantissa)
+{
+   if (mantissa)
+   {
+       memcpy(result, "NaN", 3);
+       return 3;
+   }
+   if (sign)
+   {
+       result[0] = '-';
+   }
+   if (exponent)
+   {
+       memcpy(result + sign, "Infinity", 8);
+       return sign + 8;
+   }
+   result[sign] = '0';
+   return sign + 1;
+}
+
+static inline uint32
+float_to_bits(const float f)
+{
+   uint32      bits = 0;
+
+   memcpy(&bits, &f, sizeof(float));
+   return bits;
+}
+
+static inline uint64
+double_to_bits(const double d)
+{
+   uint64      bits = 0;
+
+   memcpy(&bits, &d, sizeof(double));
+   return bits;
+}
+
+#endif                         /* RYU_COMMON_H */
diff --git a/src/include/common/shortest_dec.h b/src/include/common/shortest_dec.h
new file mode 100644 (file)
index 0000000..4c3dcd3
--- /dev/null
@@ -0,0 +1,63 @@
+/*---------------------------------------------------------------------------
+ *
+ * Ryu floating-point output.
+ *
+ * Portions Copyright (c) 2018-2019, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/include/common/shortest_dec.h
+ *
+ * This is a modification of code taken from github.com/ulfjack/ryu under the
+ * terms of the Boost license (not the Apache license). The original copyright
+ * notice follows:
+ *
+ * Copyright 2018 Ulf Adams
+ *
+ * The contents of this file may be used under the terms of the Apache
+ * License, Version 2.0.
+ *
+ *     (See accompanying file LICENSE-Apache or copy at
+ *      http://www.apache.org/licenses/LICENSE-2.0)
+ *
+ * Alternatively, the contents of this file may be used under the terms of the
+ * Boost Software License, Version 1.0.
+ *
+ *     (See accompanying file LICENSE-Boost or copy at
+ *      https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Unless required by applicable law or agreed to in writing, this software is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.
+ *
+ *---------------------------------------------------------------------------
+ */
+#ifndef SHORTEST_DEC_H
+#define SHORTEST_DEC_H
+
+/*----
+ * The length of 25 comes from:
+ *
+ * Case 1: -9.9999999999999999e-299  = 24 bytes, plus 1 for null
+ *
+ * Case 2: -0.00099999999999999999   = 23 bytes, plus 1 for null
+ */
+#define DOUBLE_SHORTEST_DECIMAL_LEN 25
+
+int            double_to_shortest_decimal_bufn(double f, char *result);
+int            double_to_shortest_decimal_buf(double f, char *result);
+char      *double_to_shortest_decimal(double f);
+
+/*
+ * The length of 16 comes from:
+ *
+ * Case 1: -9.99999999e+29  = 15 bytes, plus 1 for null
+ *
+ * Case 2: -0.000999999999  = 15 bytes, plus 1 for null
+ */
+#define FLOAT_SHORTEST_DECIMAL_LEN 16
+
+int            float_to_shortest_decimal_bufn(float f, char *result);
+int            float_to_shortest_decimal_buf(float f, char *result);
+char      *float_to_shortest_decimal(float f);
+
+#endif                         /* SHORTEST_DEC_H */
index 918db6cb67e39601214ec41552474877c1b4a9b0..129c1e5075f4ec88da3a107ed5ec919f0ed871e1 100644 (file)
@@ -1,6 +1,8 @@
 --
 -- AGGREGATES
 --
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
 SELECT avg(four) AS avg_1 FROM onek;
        avg_1        
 --------------------
index 2ed74cc6aaf1ee135455ec5648bea81c0c685c0d..756c7e37efc28677e7065fe8912204302386815d 100644 (file)
@@ -1,6 +1,8 @@
 --
 -- CIRCLE
 --
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
 CREATE TABLE CIRCLE_TBL (f1 circle);
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
 INSERT INTO CIRCLE_TBL VALUES ('<(1,2),100>');
index 9898d92928d13ef53466806586edac0b7d452c65..54de939a6e8d5a83272625fe44dde51daa19b871 100644 (file)
@@ -142,22 +142,22 @@ SELECT 'nan'::numeric::float4;
 (1 row)
 
 SELECT '' AS five, * FROM FLOAT4_TBL;
- five |     f1      
-------+-------------
-      |           0
-      |      1004.3
-      |      -34.84
-      | 1.23457e+20
-      | 1.23457e-20
+ five |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e+20
+      | 1.2345679e-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
+ four |      f1       
+------+---------------
+      |             0
+      |        -34.84
+      | 1.2345679e+20
+      | 1.2345679e-20
 (4 rows)
 
 SELECT '' AS one, f.* FROM FLOAT4_TBL f WHERE f.f1 = '1004.3';
@@ -167,110 +167,110 @@ SELECT '' AS one, f.* FROM FLOAT4_TBL f WHERE f.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
+ three |      f1       
+-------+---------------
+       |             0
+       |        -34.84
+       | 1.2345679e-20
 (3 rows)
 
 SELECT '' AS three, f.* FROM FLOAT4_TBL f WHERE  f.f1 < '1004.3';
- three |     f1      
--------+-------------
-       |           0
-       |      -34.84
-       | 1.23457e-20
+ three |      f1       
+-------+---------------
+       |             0
+       |        -34.84
+       | 1.2345679e-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
+ four |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e-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
+ four |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e-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
+ three |      f1       |       x        
+-------+---------------+----------------
+       |        1004.3 |         -10043
+       | 1.2345679e+20 | -1.2345678e+21
+       | 1.2345679e-20 | -1.2345678e-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
+ three |      f1       |       x       
+-------+---------------+---------------
+       |        1004.3 |         994.3
+       | 1.2345679e+20 | 1.2345679e+20
+       | 1.2345679e-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
+ three |      f1       |       x        
+-------+---------------+----------------
+       |        1004.3 |        -100.43
+       | 1.2345679e+20 | -1.2345679e+19
+       | 1.2345679e-20 | -1.2345679e-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
+ three |      f1       |       x       
+-------+---------------+---------------
+       |        1004.3 |        1014.3
+       | 1.2345679e+20 | 1.2345679e+20
+       | 1.2345679e-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
+ five |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e+20
+      | 1.2345679e-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
+ five |      f1       |    abs_f1     
+------+---------------+---------------
+      |             0 |             0
+      |        1004.3 |        1004.3
+      |        -34.84 |         34.84
+      | 1.2345679e+20 | 1.2345679e+20
+      | 1.2345679e-20 | 1.2345679e-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
+ five |       f1       
+------+----------------
+      |              0
+      |         -34.84
+      |        -1004.3
+      | -1.2345679e+20
+      | -1.2345679e-20
 (5 rows)
 
 -- test edge-case coercions to integer
@@ -434,3 +434,507 @@ SELECT float4send('1.1754944e-38'::float4);
  \x00800000
 (1 row)
 
+-- test output (and round-trip safety) of various values.
+-- To ensure we're testing what we think we're testing, start with
+-- float values specified by bit patterns (as a useful side effect,
+-- this means we'll fail on non-IEEE platforms).
+create type xfloat4;
+create function xfloat4in(cstring) returns xfloat4 immutable strict
+  language internal as 'int4in';
+NOTICE:  return type xfloat4 is only a shell
+create function xfloat4out(xfloat4) returns cstring immutable strict
+  language internal as 'int4out';
+NOTICE:  argument type xfloat4 is only a shell
+create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4);
+create cast (xfloat4 as float4) without function;
+create cast (float4 as xfloat4) without function;
+create cast (xfloat4 as integer) without function;
+create cast (integer as xfloat4) without function;
+-- float4: seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
+-- we don't care to assume the platform's strtod() handles subnormals
+-- correctly; those are "use at your own risk". However we do test
+-- subnormal outputs, since those are under our control.
+with testdata(bits) as (values
+  -- small subnormals
+  (x'00000001'),
+  (x'00000002'), (x'00000003'),
+  (x'00000010'), (x'00000011'), (x'00000100'), (x'00000101'),
+  (x'00004000'), (x'00004001'), (x'00080000'), (x'00080001'),
+  -- stress values
+  (x'0053c4f4'),  -- 7693e-42
+  (x'006c85c4'),  -- 996622e-44
+  (x'0041ca76'),  -- 60419369e-46
+  (x'004b7678'),  -- 6930161142e-48
+  -- taken from upstream testsuite
+  (x'00000007'),
+  (x'00424fe2'),
+  -- borderline between subnormal and normal
+  (x'007ffff0'), (x'007ffff1'), (x'007ffffe'), (x'007fffff'))
+select float4send(flt) as ibits,
+       flt
+  from (select bits::integer::xfloat4::float4 as flt
+          from testdata
+   offset 0) s;
+   ibits    |      flt      
+------------+---------------
+ \x00000001 |         1e-45
+ \x00000002 |         3e-45
+ \x00000003 |         4e-45
+ \x00000010 |       2.2e-44
+ \x00000011 |       2.4e-44
+ \x00000100 |      3.59e-43
+ \x00000101 |       3.6e-43
+ \x00004000 |    2.2959e-41
+ \x00004001 |     2.296e-41
+ \x00080000 |   7.34684e-40
+ \x00080001 |   7.34685e-40
+ \x0053c4f4 |     7.693e-39
+ \x006c85c4 |   9.96622e-39
+ \x0041ca76 |  6.041937e-39
+ \x004b7678 |  6.930161e-39
+ \x00000007 |         1e-44
+ \x00424fe2 |    6.0898e-39
+ \x007ffff0 | 1.1754921e-38
+ \x007ffff1 | 1.1754922e-38
+ \x007ffffe | 1.1754941e-38
+ \x007fffff | 1.1754942e-38
+(21 rows)
+
+with testdata(bits) as (values
+  (x'00000000'),
+  -- smallest normal values
+  (x'00800000'), (x'00800001'), (x'00800004'), (x'00800005'),
+  (x'00800006'),
+  -- small normal values chosen for short vs. long output
+  (x'008002f1'), (x'008002f2'), (x'008002f3'),
+  (x'00800e17'), (x'00800e18'), (x'00800e19'),
+  -- assorted values (random mantissae)
+  (x'01000001'), (x'01102843'), (x'01a52c98'),
+  (x'0219c229'), (x'02e4464d'), (x'037343c1'), (x'03a91b36'),
+  (x'047ada65'), (x'0496fe87'), (x'0550844f'), (x'05999da3'),
+  (x'060ea5e2'), (x'06e63c45'), (x'07f1e548'), (x'0fc5282b'),
+  (x'1f850283'), (x'2874a9d6'),
+  -- values around 5e-08
+  (x'3356bf94'), (x'3356bf95'), (x'3356bf96'),
+  -- around 1e-07
+  (x'33d6bf94'), (x'33d6bf95'), (x'33d6bf96'),
+  -- around 3e-07 .. 1e-04
+  (x'34a10faf'), (x'34a10fb0'), (x'34a10fb1'),
+  (x'350637bc'), (x'350637bd'), (x'350637be'),
+  (x'35719786'), (x'35719787'), (x'35719788'),
+  (x'358637bc'), (x'358637bd'), (x'358637be'),
+  (x'36a7c5ab'), (x'36a7c5ac'), (x'36a7c5ad'),
+  (x'3727c5ab'), (x'3727c5ac'), (x'3727c5ad'),
+  -- format crossover at 1e-04
+  (x'38d1b714'), (x'38d1b715'), (x'38d1b716'),
+  (x'38d1b717'), (x'38d1b718'), (x'38d1b719'),
+  (x'38d1b71a'), (x'38d1b71b'), (x'38d1b71c'),
+  (x'38d1b71d'),
+  --
+  (x'38dffffe'), (x'38dfffff'), (x'38e00000'),
+  (x'38efffff'), (x'38f00000'), (x'38f00001'),
+  (x'3a83126e'), (x'3a83126f'), (x'3a831270'),
+  (x'3c23d709'), (x'3c23d70a'), (x'3c23d70b'),
+  (x'3dcccccc'), (x'3dcccccd'), (x'3dccccce'),
+  -- chosen to need 9 digits for 3dcccd70
+  (x'3dcccd6f'), (x'3dcccd70'), (x'3dcccd71'),
+  --
+  (x'3effffff'), (x'3f000000'), (x'3f000001'),
+  (x'3f333332'), (x'3f333333'), (x'3f333334'),
+  -- approach 1.0 with increasing numbers of 9s
+  (x'3f666665'), (x'3f666666'), (x'3f666667'),
+  (x'3f7d70a3'), (x'3f7d70a4'), (x'3f7d70a5'),
+  (x'3f7fbe76'), (x'3f7fbe77'), (x'3f7fbe78'),
+  (x'3f7ff971'), (x'3f7ff972'), (x'3f7ff973'),
+  (x'3f7fff57'), (x'3f7fff58'), (x'3f7fff59'),
+  (x'3f7fffee'), (x'3f7fffef'),
+  -- values very close to 1
+  (x'3f7ffff0'), (x'3f7ffff1'), (x'3f7ffff2'),
+  (x'3f7ffff3'), (x'3f7ffff4'), (x'3f7ffff5'),
+  (x'3f7ffff6'), (x'3f7ffff7'), (x'3f7ffff8'),
+  (x'3f7ffff9'), (x'3f7ffffa'), (x'3f7ffffb'),
+  (x'3f7ffffc'), (x'3f7ffffd'), (x'3f7ffffe'),
+  (x'3f7fffff'),
+  (x'3f800000'),
+  (x'3f800001'), (x'3f800002'), (x'3f800003'),
+  (x'3f800004'), (x'3f800005'), (x'3f800006'),
+  (x'3f800007'), (x'3f800008'), (x'3f800009'),
+  -- values 1 to 1.1
+  (x'3f80000f'), (x'3f800010'), (x'3f800011'),
+  (x'3f800012'), (x'3f800013'), (x'3f800014'),
+  (x'3f800017'), (x'3f800018'), (x'3f800019'),
+  (x'3f80001a'), (x'3f80001b'), (x'3f80001c'),
+  (x'3f800029'), (x'3f80002a'), (x'3f80002b'),
+  (x'3f800053'), (x'3f800054'), (x'3f800055'),
+  (x'3f800346'), (x'3f800347'), (x'3f800348'),
+  (x'3f8020c4'), (x'3f8020c5'), (x'3f8020c6'),
+  (x'3f8147ad'), (x'3f8147ae'), (x'3f8147af'),
+  (x'3f8ccccc'), (x'3f8ccccd'), (x'3f8cccce'),
+  --
+  (x'3fc90fdb'), -- pi/2
+  (x'402df854'), -- e
+  (x'40490fdb'), -- pi
+  --
+  (x'409fffff'), (x'40a00000'), (x'40a00001'),
+  (x'40afffff'), (x'40b00000'), (x'40b00001'),
+  (x'411fffff'), (x'41200000'), (x'41200001'),
+  (x'42c7ffff'), (x'42c80000'), (x'42c80001'),
+  (x'4479ffff'), (x'447a0000'), (x'447a0001'),
+  (x'461c3fff'), (x'461c4000'), (x'461c4001'),
+  (x'47c34fff'), (x'47c35000'), (x'47c35001'),
+  (x'497423ff'), (x'49742400'), (x'49742401'),
+  (x'4b18967f'), (x'4b189680'), (x'4b189681'),
+  (x'4cbebc1f'), (x'4cbebc20'), (x'4cbebc21'),
+  (x'4e6e6b27'), (x'4e6e6b28'), (x'4e6e6b29'),
+  (x'501502f8'), (x'501502f9'), (x'501502fa'),
+  (x'51ba43b6'), (x'51ba43b7'), (x'51ba43b8'),
+  -- stress values
+  (x'1f6c1e4a'),  -- 5e-20
+  (x'59be6cea'),  -- 67e14
+  (x'5d5ab6c4'),  -- 985e15
+  (x'2cc4a9bd'),  -- 55895e-16
+  (x'15ae43fd'),  -- 7038531e-32
+  (x'2cf757ca'),  -- 702990899e-20
+  (x'665ba998'),  -- 25933168707e13
+  (x'743c3324'),  -- 596428896559e20
+  -- exercise fixed-point memmoves
+  (x'47f1205a'),
+  (x'4640e6ae'),
+  (x'449a5225'),
+  (x'42f6e9d5'),
+  (x'414587dd'),
+  (x'3f9e064b'),
+  -- these cases come from the upstream's testsuite
+  -- BoundaryRoundEven
+  (x'4c000004'),
+  (x'50061c46'),
+  (x'510006a8'),
+  -- ExactValueRoundEven
+  (x'48951f84'),
+  (x'45fd1840'),
+  -- LotsOfTrailingZeros
+  (x'39800000'),
+  (x'3b200000'),
+  (x'3b900000'),
+  (x'3bd00000'),
+  -- Regression
+  (x'63800000'),
+  (x'4b000000'),
+  (x'4b800000'),
+  (x'4c000001'),
+  (x'4c800b0d'),
+  (x'00d24584'),
+  (x'800000b0'),
+  (x'00d90b88'),
+  (x'45803f34'),
+  (x'4f9f24f7'),
+  (x'3a8722c3'),
+  (x'5c800041'),
+  (x'15ae43fd'),
+  (x'5d4cccfb'),
+  (x'4c800001'),
+  (x'57800ed8'),
+  (x'5f000000'),
+  (x'700000f0'),
+  (x'5f23e9ac'),
+  (x'5e9502f9'),
+  (x'5e8012b1'),
+  (x'3c000028'),
+  (x'60cde861'),
+  (x'03aa2a50'),
+  (x'43480000'),
+  (x'4c000000'),
+  -- LooksLikePow5
+  (x'5D1502F9'),
+  (x'5D9502F9'),
+  (x'5E1502F9'),
+  -- OutputLength
+  (x'3f99999a'),
+  (x'3f9d70a4'),
+  (x'3f9df3b6'),
+  (x'3f9e0419'),
+  (x'3f9e0610'),
+  (x'3f9e064b'),
+  (x'3f9e0651'),
+  (x'03d20cfe')
+)
+select float4send(flt) as ibits,
+       flt,
+       flt::text::float4 as r_flt,
+       float4send(flt::text::float4) as obits,
+       float4send(flt::text::float4) = float4send(flt) as correct
+  from (select bits::integer::xfloat4::float4 as flt
+          from testdata
+   offset 0) s;
+   ibits    |      flt       |     r_flt      |   obits    | correct 
+------------+----------------+----------------+------------+---------
+ \x00000000 |              0 |              0 | \x00000000 | t
+ \x00800000 |  1.1754944e-38 |  1.1754944e-38 | \x00800000 | t
+ \x00800001 |  1.1754945e-38 |  1.1754945e-38 | \x00800001 | t
+ \x00800004 |  1.1754949e-38 |  1.1754949e-38 | \x00800004 | t
+ \x00800005 |   1.175495e-38 |   1.175495e-38 | \x00800005 | t
+ \x00800006 |  1.1754952e-38 |  1.1754952e-38 | \x00800006 | t
+ \x008002f1 |  1.1755999e-38 |  1.1755999e-38 | \x008002f1 | t
+ \x008002f2 |     1.1756e-38 |     1.1756e-38 | \x008002f2 | t
+ \x008002f3 |  1.1756001e-38 |  1.1756001e-38 | \x008002f3 | t
+ \x00800e17 |  1.1759998e-38 |  1.1759998e-38 | \x00800e17 | t
+ \x00800e18 |      1.176e-38 |      1.176e-38 | \x00800e18 | t
+ \x00800e19 |  1.1760001e-38 |  1.1760001e-38 | \x00800e19 | t
+ \x01000001 |   2.350989e-38 |   2.350989e-38 | \x01000001 | t
+ \x01102843 |   2.647751e-38 |   2.647751e-38 | \x01102843 | t
+ \x01a52c98 |  6.0675416e-38 |  6.0675416e-38 | \x01a52c98 | t
+ \x0219c229 |  1.1296386e-37 |  1.1296386e-37 | \x0219c229 | t
+ \x02e4464d |   3.354194e-37 |   3.354194e-37 | \x02e4464d | t
+ \x037343c1 |   7.148906e-37 |   7.148906e-37 | \x037343c1 | t
+ \x03a91b36 |   9.939175e-37 |   9.939175e-37 | \x03a91b36 | t
+ \x047ada65 |   2.948764e-36 |   2.948764e-36 | \x047ada65 | t
+ \x0496fe87 |  3.5498577e-36 |  3.5498577e-36 | \x0496fe87 | t
+ \x0550844f |   9.804414e-36 |   9.804414e-36 | \x0550844f | t
+ \x05999da3 |  1.4445957e-35 |  1.4445957e-35 | \x05999da3 | t
+ \x060ea5e2 |  2.6829103e-35 |  2.6829103e-35 | \x060ea5e2 | t
+ \x06e63c45 |   8.660494e-35 |   8.660494e-35 | \x06e63c45 | t
+ \x07f1e548 |   3.639641e-34 |   3.639641e-34 | \x07f1e548 | t
+ \x0fc5282b |  1.9441172e-29 |  1.9441172e-29 | \x0fc5282b | t
+ \x1f850283 |  5.6331846e-20 |  5.6331846e-20 | \x1f850283 | t
+ \x2874a9d6 |  1.3581548e-14 |  1.3581548e-14 | \x2874a9d6 | t
+ \x3356bf94 |  4.9999997e-08 |  4.9999997e-08 | \x3356bf94 | t
+ \x3356bf95 |          5e-08 |          5e-08 | \x3356bf95 | t
+ \x3356bf96 |  5.0000004e-08 |  5.0000004e-08 | \x3356bf96 | t
+ \x33d6bf94 |  9.9999994e-08 |  9.9999994e-08 | \x33d6bf94 | t
+ \x33d6bf95 |          1e-07 |          1e-07 | \x33d6bf95 | t
+ \x33d6bf96 |  1.0000001e-07 |  1.0000001e-07 | \x33d6bf96 | t
+ \x34a10faf |  2.9999998e-07 |  2.9999998e-07 | \x34a10faf | t
+ \x34a10fb0 |          3e-07 |          3e-07 | \x34a10fb0 | t
+ \x34a10fb1 |  3.0000004e-07 |  3.0000004e-07 | \x34a10fb1 | t
+ \x350637bc |  4.9999994e-07 |  4.9999994e-07 | \x350637bc | t
+ \x350637bd |          5e-07 |          5e-07 | \x350637bd | t
+ \x350637be |  5.0000006e-07 |  5.0000006e-07 | \x350637be | t
+ \x35719786 |   8.999999e-07 |   8.999999e-07 | \x35719786 | t
+ \x35719787 |          9e-07 |          9e-07 | \x35719787 | t
+ \x35719788 |  9.0000003e-07 |  9.0000003e-07 | \x35719788 | t
+ \x358637bc |   9.999999e-07 |   9.999999e-07 | \x358637bc | t
+ \x358637bd |          1e-06 |          1e-06 | \x358637bd | t
+ \x358637be |  1.0000001e-06 |  1.0000001e-06 | \x358637be | t
+ \x36a7c5ab |  4.9999994e-06 |  4.9999994e-06 | \x36a7c5ab | t
+ \x36a7c5ac |          5e-06 |          5e-06 | \x36a7c5ac | t
+ \x36a7c5ad |  5.0000003e-06 |  5.0000003e-06 | \x36a7c5ad | t
+ \x3727c5ab |   9.999999e-06 |   9.999999e-06 | \x3727c5ab | t
+ \x3727c5ac |          1e-05 |          1e-05 | \x3727c5ac | t
+ \x3727c5ad |  1.0000001e-05 |  1.0000001e-05 | \x3727c5ad | t
+ \x38d1b714 |  9.9999976e-05 |  9.9999976e-05 | \x38d1b714 | t
+ \x38d1b715 |   9.999998e-05 |   9.999998e-05 | \x38d1b715 | t
+ \x38d1b716 |   9.999999e-05 |   9.999999e-05 | \x38d1b716 | t
+ \x38d1b717 |         0.0001 |         0.0001 | \x38d1b717 | t
+ \x38d1b718 | 0.000100000005 | 0.000100000005 | \x38d1b718 | t
+ \x38d1b719 |  0.00010000001 |  0.00010000001 | \x38d1b719 | t
+ \x38d1b71a |  0.00010000002 |  0.00010000002 | \x38d1b71a | t
+ \x38d1b71b |  0.00010000003 |  0.00010000003 | \x38d1b71b | t
+ \x38d1b71c | 0.000100000034 | 0.000100000034 | \x38d1b71c | t
+ \x38d1b71d |  0.00010000004 |  0.00010000004 | \x38d1b71d | t
+ \x38dffffe |  0.00010681151 |  0.00010681151 | \x38dffffe | t
+ \x38dfffff | 0.000106811516 | 0.000106811516 | \x38dfffff | t
+ \x38e00000 |  0.00010681152 |  0.00010681152 | \x38e00000 | t
+ \x38efffff |  0.00011444091 |  0.00011444091 | \x38efffff | t
+ \x38f00000 |  0.00011444092 |  0.00011444092 | \x38f00000 | t
+ \x38f00001 | 0.000114440925 | 0.000114440925 | \x38f00001 | t
+ \x3a83126e |   0.0009999999 |   0.0009999999 | \x3a83126e | t
+ \x3a83126f |          0.001 |          0.001 | \x3a83126f | t
+ \x3a831270 |   0.0010000002 |   0.0010000002 | \x3a831270 | t
+ \x3c23d709 |    0.009999999 |    0.009999999 | \x3c23d709 | t
+ \x3c23d70a |           0.01 |           0.01 | \x3c23d70a | t
+ \x3c23d70b |    0.010000001 |    0.010000001 | \x3c23d70b | t
+ \x3dcccccc |    0.099999994 |    0.099999994 | \x3dcccccc | t
+ \x3dcccccd |            0.1 |            0.1 | \x3dcccccd | t
+ \x3dccccce |     0.10000001 |     0.10000001 | \x3dccccce | t
+ \x3dcccd6f |     0.10000121 |     0.10000121 | \x3dcccd6f | t
+ \x3dcccd70 |    0.100001216 |    0.100001216 | \x3dcccd70 | t
+ \x3dcccd71 |     0.10000122 |     0.10000122 | \x3dcccd71 | t
+ \x3effffff |     0.49999997 |     0.49999997 | \x3effffff | t
+ \x3f000000 |            0.5 |            0.5 | \x3f000000 | t
+ \x3f000001 |     0.50000006 |     0.50000006 | \x3f000001 | t
+ \x3f333332 |      0.6999999 |      0.6999999 | \x3f333332 | t
+ \x3f333333 |            0.7 |            0.7 | \x3f333333 | t
+ \x3f333334 |     0.70000005 |     0.70000005 | \x3f333334 | t
+ \x3f666665 |      0.8999999 |      0.8999999 | \x3f666665 | t
+ \x3f666666 |            0.9 |            0.9 | \x3f666666 | t
+ \x3f666667 |     0.90000004 |     0.90000004 | \x3f666667 | t
+ \x3f7d70a3 |     0.98999995 |     0.98999995 | \x3f7d70a3 | t
+ \x3f7d70a4 |           0.99 |           0.99 | \x3f7d70a4 | t
+ \x3f7d70a5 |     0.99000007 |     0.99000007 | \x3f7d70a5 | t
+ \x3f7fbe76 |     0.99899995 |     0.99899995 | \x3f7fbe76 | t
+ \x3f7fbe77 |          0.999 |          0.999 | \x3f7fbe77 | t
+ \x3f7fbe78 |      0.9990001 |      0.9990001 | \x3f7fbe78 | t
+ \x3f7ff971 |      0.9998999 |      0.9998999 | \x3f7ff971 | t
+ \x3f7ff972 |         0.9999 |         0.9999 | \x3f7ff972 | t
+ \x3f7ff973 |     0.99990004 |     0.99990004 | \x3f7ff973 | t
+ \x3f7fff57 |      0.9999899 |      0.9999899 | \x3f7fff57 | t
+ \x3f7fff58 |        0.99999 |        0.99999 | \x3f7fff58 | t
+ \x3f7fff59 |     0.99999005 |     0.99999005 | \x3f7fff59 | t
+ \x3f7fffee |      0.9999989 |      0.9999989 | \x3f7fffee | t
+ \x3f7fffef |       0.999999 |       0.999999 | \x3f7fffef | t
+ \x3f7ffff0 |     0.99999905 |     0.99999905 | \x3f7ffff0 | t
+ \x3f7ffff1 |      0.9999991 |      0.9999991 | \x3f7ffff1 | t
+ \x3f7ffff2 |     0.99999917 |     0.99999917 | \x3f7ffff2 | t
+ \x3f7ffff3 |      0.9999992 |      0.9999992 | \x3f7ffff3 | t
+ \x3f7ffff4 |      0.9999993 |      0.9999993 | \x3f7ffff4 | t
+ \x3f7ffff5 |     0.99999934 |     0.99999934 | \x3f7ffff5 | t
+ \x3f7ffff6 |      0.9999994 |      0.9999994 | \x3f7ffff6 | t
+ \x3f7ffff7 |     0.99999946 |     0.99999946 | \x3f7ffff7 | t
+ \x3f7ffff8 |      0.9999995 |      0.9999995 | \x3f7ffff8 | t
+ \x3f7ffff9 |      0.9999996 |      0.9999996 | \x3f7ffff9 | t
+ \x3f7ffffa |     0.99999964 |     0.99999964 | \x3f7ffffa | t
+ \x3f7ffffb |      0.9999997 |      0.9999997 | \x3f7ffffb | t
+ \x3f7ffffc |     0.99999976 |     0.99999976 | \x3f7ffffc | t
+ \x3f7ffffd |      0.9999998 |      0.9999998 | \x3f7ffffd | t
+ \x3f7ffffe |      0.9999999 |      0.9999999 | \x3f7ffffe | t
+ \x3f7fffff |     0.99999994 |     0.99999994 | \x3f7fffff | t
+ \x3f800000 |              1 |              1 | \x3f800000 | t
+ \x3f800001 |      1.0000001 |      1.0000001 | \x3f800001 | t
+ \x3f800002 |      1.0000002 |      1.0000002 | \x3f800002 | t
+ \x3f800003 |      1.0000004 |      1.0000004 | \x3f800003 | t
+ \x3f800004 |      1.0000005 |      1.0000005 | \x3f800004 | t
+ \x3f800005 |      1.0000006 |      1.0000006 | \x3f800005 | t
+ \x3f800006 |      1.0000007 |      1.0000007 | \x3f800006 | t
+ \x3f800007 |      1.0000008 |      1.0000008 | \x3f800007 | t
+ \x3f800008 |       1.000001 |       1.000001 | \x3f800008 | t
+ \x3f800009 |      1.0000011 |      1.0000011 | \x3f800009 | t
+ \x3f80000f |      1.0000018 |      1.0000018 | \x3f80000f | t
+ \x3f800010 |      1.0000019 |      1.0000019 | \x3f800010 | t
+ \x3f800011 |       1.000002 |       1.000002 | \x3f800011 | t
+ \x3f800012 |      1.0000021 |      1.0000021 | \x3f800012 | t
+ \x3f800013 |      1.0000023 |      1.0000023 | \x3f800013 | t
+ \x3f800014 |      1.0000024 |      1.0000024 | \x3f800014 | t
+ \x3f800017 |      1.0000027 |      1.0000027 | \x3f800017 | t
+ \x3f800018 |      1.0000029 |      1.0000029 | \x3f800018 | t
+ \x3f800019 |       1.000003 |       1.000003 | \x3f800019 | t
+ \x3f80001a |      1.0000031 |      1.0000031 | \x3f80001a | t
+ \x3f80001b |      1.0000032 |      1.0000032 | \x3f80001b | t
+ \x3f80001c |      1.0000033 |      1.0000033 | \x3f80001c | t
+ \x3f800029 |      1.0000049 |      1.0000049 | \x3f800029 | t
+ \x3f80002a |       1.000005 |       1.000005 | \x3f80002a | t
+ \x3f80002b |      1.0000051 |      1.0000051 | \x3f80002b | t
+ \x3f800053 |      1.0000099 |      1.0000099 | \x3f800053 | t
+ \x3f800054 |        1.00001 |        1.00001 | \x3f800054 | t
+ \x3f800055 |      1.0000101 |      1.0000101 | \x3f800055 | t
+ \x3f800346 |      1.0000999 |      1.0000999 | \x3f800346 | t
+ \x3f800347 |         1.0001 |         1.0001 | \x3f800347 | t
+ \x3f800348 |      1.0001001 |      1.0001001 | \x3f800348 | t
+ \x3f8020c4 |      1.0009999 |      1.0009999 | \x3f8020c4 | t
+ \x3f8020c5 |          1.001 |          1.001 | \x3f8020c5 | t
+ \x3f8020c6 |      1.0010002 |      1.0010002 | \x3f8020c6 | t
+ \x3f8147ad |      1.0099999 |      1.0099999 | \x3f8147ad | t
+ \x3f8147ae |           1.01 |           1.01 | \x3f8147ae | t
+ \x3f8147af |      1.0100001 |      1.0100001 | \x3f8147af | t
+ \x3f8ccccc |      1.0999999 |      1.0999999 | \x3f8ccccc | t
+ \x3f8ccccd |            1.1 |            1.1 | \x3f8ccccd | t
+ \x3f8cccce |      1.1000001 |      1.1000001 | \x3f8cccce | t
+ \x3fc90fdb |      1.5707964 |      1.5707964 | \x3fc90fdb | t
+ \x402df854 |      2.7182817 |      2.7182817 | \x402df854 | t
+ \x40490fdb |      3.1415927 |      3.1415927 | \x40490fdb | t
+ \x409fffff |      4.9999995 |      4.9999995 | \x409fffff | t
+ \x40a00000 |              5 |              5 | \x40a00000 | t
+ \x40a00001 |      5.0000005 |      5.0000005 | \x40a00001 | t
+ \x40afffff |      5.4999995 |      5.4999995 | \x40afffff | t
+ \x40b00000 |            5.5 |            5.5 | \x40b00000 | t
+ \x40b00001 |      5.5000005 |      5.5000005 | \x40b00001 | t
+ \x411fffff |       9.999999 |       9.999999 | \x411fffff | t
+ \x41200000 |             10 |             10 | \x41200000 | t
+ \x41200001 |      10.000001 |      10.000001 | \x41200001 | t
+ \x42c7ffff |       99.99999 |       99.99999 | \x42c7ffff | t
+ \x42c80000 |            100 |            100 | \x42c80000 | t
+ \x42c80001 |      100.00001 |      100.00001 | \x42c80001 | t
+ \x4479ffff |      999.99994 |      999.99994 | \x4479ffff | t
+ \x447a0000 |           1000 |           1000 | \x447a0000 | t
+ \x447a0001 |     1000.00006 |     1000.00006 | \x447a0001 | t
+ \x461c3fff |       9999.999 |       9999.999 | \x461c3fff | t
+ \x461c4000 |          10000 |          10000 | \x461c4000 | t
+ \x461c4001 |      10000.001 |      10000.001 | \x461c4001 | t
+ \x47c34fff |       99999.99 |       99999.99 | \x47c34fff | t
+ \x47c35000 |         100000 |         100000 | \x47c35000 | t
+ \x47c35001 |      100000.01 |      100000.01 | \x47c35001 | t
+ \x497423ff |      999999.94 |      999999.94 | \x497423ff | t
+ \x49742400 |          1e+06 |          1e+06 | \x49742400 | t
+ \x49742401 | 1.00000006e+06 | 1.00000006e+06 | \x49742401 | t
+ \x4b18967f |   9.999999e+06 |   9.999999e+06 | \x4b18967f | t
+ \x4b189680 |          1e+07 |          1e+07 | \x4b189680 | t
+ \x4b189681 |  1.0000001e+07 |  1.0000001e+07 | \x4b189681 | t
+ \x4cbebc1f |   9.999999e+07 |   9.999999e+07 | \x4cbebc1f | t
+ \x4cbebc20 |          1e+08 |          1e+08 | \x4cbebc20 | t
+ \x4cbebc21 |  1.0000001e+08 |  1.0000001e+08 | \x4cbebc21 | t
+ \x4e6e6b27 |  9.9999994e+08 |  9.9999994e+08 | \x4e6e6b27 | t
+ \x4e6e6b28 |          1e+09 |          1e+09 | \x4e6e6b28 | t
+ \x4e6e6b29 | 1.00000006e+09 | 1.00000006e+09 | \x4e6e6b29 | t
+ \x501502f8 |   9.999999e+09 |   9.999999e+09 | \x501502f8 | t
+ \x501502f9 |          1e+10 |          1e+10 | \x501502f9 | t
+ \x501502fa |  1.0000001e+10 |  1.0000001e+10 | \x501502fa | t
+ \x51ba43b6 |   9.999999e+10 |   9.999999e+10 | \x51ba43b6 | t
+ \x51ba43b7 |          1e+11 |          1e+11 | \x51ba43b7 | t
+ \x51ba43b8 |  1.0000001e+11 |  1.0000001e+11 | \x51ba43b8 | t
+ \x1f6c1e4a |          5e-20 |          5e-20 | \x1f6c1e4a | t
+ \x59be6cea |        6.7e+15 |        6.7e+15 | \x59be6cea | t
+ \x5d5ab6c4 |       9.85e+17 |       9.85e+17 | \x5d5ab6c4 | t
+ \x2cc4a9bd |     5.5895e-12 |     5.5895e-12 | \x2cc4a9bd | t
+ \x15ae43fd |   7.038531e-26 |  7.0385313e-26 | \x15ae43fe | f
+ \x2cf757ca |  7.0299088e-12 |  7.0299088e-12 | \x2cf757ca | t
+ \x665ba998 |  2.5933168e+23 |  2.5933168e+23 | \x665ba998 | t
+ \x743c3324 |  5.9642887e+31 |  5.9642887e+31 | \x743c3324 | t
+ \x47f1205a |       123456.7 |       123456.7 | \x47f1205a | t
+ \x4640e6ae |       12345.67 |       12345.67 | \x4640e6ae | t
+ \x449a5225 |       1234.567 |       1234.567 | \x449a5225 | t
+ \x42f6e9d5 |       123.4567 |       123.4567 | \x42f6e9d5 | t
+ \x414587dd |       12.34567 |       12.34567 | \x414587dd | t
+ \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
+ \x4c000004 |  3.3554448e+07 |  3.3554448e+07 | \x4c000004 | t
+ \x50061c46 |   8.999999e+09 |   8.999999e+09 | \x50061c46 | t
+ \x510006a8 |  3.4366718e+10 |  3.4366718e+10 | \x510006a8 | t
+ \x48951f84 |      305404.12 |      305404.12 | \x48951f84 | t
+ \x45fd1840 |      8099.0312 |      8099.0312 | \x45fd1840 | t
+ \x39800000 |  0.00024414062 |  0.00024414062 | \x39800000 | t
+ \x3b200000 |   0.0024414062 |   0.0024414062 | \x3b200000 | t
+ \x3b900000 |   0.0043945312 |   0.0043945312 | \x3b900000 | t
+ \x3bd00000 |   0.0063476562 |   0.0063476562 | \x3bd00000 | t
+ \x63800000 |  4.7223665e+21 |  4.7223665e+21 | \x63800000 | t
+ \x4b000000 |   8.388608e+06 |   8.388608e+06 | \x4b000000 | t
+ \x4b800000 |  1.6777216e+07 |  1.6777216e+07 | \x4b800000 | t
+ \x4c000001 |  3.3554436e+07 |  3.3554436e+07 | \x4c000001 | t
+ \x4c800b0d |  6.7131496e+07 |  6.7131496e+07 | \x4c800b0d | t
+ \x00d24584 |  1.9310392e-38 |  1.9310392e-38 | \x00d24584 | t
+ \x800000b0 |      -2.47e-43 |      -2.47e-43 | \x800000b0 | t
+ \x00d90b88 |   1.993244e-38 |   1.993244e-38 | \x00d90b88 | t
+ \x45803f34 |      4103.9004 |      4103.9004 | \x45803f34 | t
+ \x4f9f24f7 |  5.3399997e+09 |  5.3399997e+09 | \x4f9f24f7 | t
+ \x3a8722c3 |   0.0010310042 |   0.0010310042 | \x3a8722c3 | t
+ \x5c800041 |   2.882326e+17 |   2.882326e+17 | \x5c800041 | t
+ \x15ae43fd |   7.038531e-26 |  7.0385313e-26 | \x15ae43fe | f
+ \x5d4cccfb |   9.223404e+17 |   9.223404e+17 | \x5d4cccfb | t
+ \x4c800001 |   6.710887e+07 |   6.710887e+07 | \x4c800001 | t
+ \x57800ed8 |   2.816025e+14 |   2.816025e+14 | \x57800ed8 | t
+ \x5f000000 |   9.223372e+18 |   9.223372e+18 | \x5f000000 | t
+ \x700000f0 |  1.5846086e+29 |  1.5846086e+29 | \x700000f0 | t
+ \x5f23e9ac |  1.1811161e+19 |  1.1811161e+19 | \x5f23e9ac | t
+ \x5e9502f9 |   5.368709e+18 |   5.368709e+18 | \x5e9502f9 | t
+ \x5e8012b1 |  4.6143166e+18 |  4.6143166e+18 | \x5e8012b1 | t
+ \x3c000028 |    0.007812537 |    0.007812537 | \x3c000028 | t
+ \x60cde861 | 1.18697725e+20 | 1.18697725e+20 | \x60cde861 | t
+ \x03aa2a50 | 1.00014165e-36 | 1.00014165e-36 | \x03aa2a50 | t
+ \x43480000 |            200 |            200 | \x43480000 | t
+ \x4c000000 |  3.3554432e+07 |  3.3554432e+07 | \x4c000000 | t
+ \x5d1502f9 |  6.7108864e+17 |  6.7108864e+17 | \x5d1502f9 | t
+ \x5d9502f9 |  1.3421773e+18 |  1.3421773e+18 | \x5d9502f9 | t
+ \x5e1502f9 |  2.6843546e+18 |  2.6843546e+18 | \x5e1502f9 | t
+ \x3f99999a |            1.2 |            1.2 | \x3f99999a | t
+ \x3f9d70a4 |           1.23 |           1.23 | \x3f9d70a4 | t
+ \x3f9df3b6 |          1.234 |          1.234 | \x3f9df3b6 | t
+ \x3f9e0419 |         1.2345 |         1.2345 | \x3f9e0419 | t
+ \x3f9e0610 |        1.23456 |        1.23456 | \x3f9e0610 | t
+ \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
+ \x3f9e0651 |      1.2345678 |      1.2345678 | \x3f9e0651 | t
+ \x03d20cfe | 1.23456735e-36 | 1.23456735e-36 | \x03d20cfe | t
+(262 rows)
+
+-- clean up, lest opr_sanity complain
+\set VERBOSITY terse
+drop type xfloat4 cascade;
+NOTICE:  drop cascades to 6 other objects
+\set VERBOSITY default
+--
index 9b8b4d4280dc9d9f1ac97dfd70b44d35dae6d0db..dff192194406519de50962add27b7d9bea9d275f 100644 (file)
@@ -142,22 +142,22 @@ SELECT 'nan'::numeric::float4;
 (1 row)
 
 SELECT '' AS five, * FROM FLOAT4_TBL;
- five |     f1      
-------+-------------
-      |           0
-      |      1004.3
-      |      -34.84
-      | 1.23457e+20
-      | 1.23457e-20
+ five |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e+20
+      | 1.2345679e-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
+ four |      f1       
+------+---------------
+      |             0
+      |        -34.84
+      | 1.2345679e+20
+      | 1.2345679e-20
 (4 rows)
 
 SELECT '' AS one, f.* FROM FLOAT4_TBL f WHERE f.f1 = '1004.3';
@@ -167,110 +167,110 @@ SELECT '' AS one, f.* FROM FLOAT4_TBL f WHERE f.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
+ three |      f1       
+-------+---------------
+       |             0
+       |        -34.84
+       | 1.2345679e-20
 (3 rows)
 
 SELECT '' AS three, f.* FROM FLOAT4_TBL f WHERE  f.f1 < '1004.3';
- three |     f1      
--------+-------------
-       |           0
-       |      -34.84
-       | 1.23457e-20
+ three |      f1       
+-------+---------------
+       |             0
+       |        -34.84
+       | 1.2345679e-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
+ four |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e-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
+ four |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e-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
+ three |      f1       |       x        
+-------+---------------+----------------
+       |        1004.3 |         -10043
+       | 1.2345679e+20 | -1.2345678e+21
+       | 1.2345679e-20 | -1.2345678e-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
+ three |      f1       |       x       
+-------+---------------+---------------
+       |        1004.3 |         994.3
+       | 1.2345679e+20 | 1.2345679e+20
+       | 1.2345679e-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
+ three |      f1       |       x        
+-------+---------------+----------------
+       |        1004.3 |        -100.43
+       | 1.2345679e+20 | -1.2345679e+19
+       | 1.2345679e-20 | -1.2345679e-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
+ three |      f1       |       x       
+-------+---------------+---------------
+       |        1004.3 |        1014.3
+       | 1.2345679e+20 | 1.2345679e+20
+       | 1.2345679e-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
+ five |      f1       
+------+---------------
+      |             0
+      |        1004.3
+      |        -34.84
+      | 1.2345679e+20
+      | 1.2345679e-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
+ five |      f1       |    abs_f1     
+------+---------------+---------------
+      |             0 |             0
+      |        1004.3 |        1004.3
+      |        -34.84 |         34.84
+      | 1.2345679e+20 | 1.2345679e+20
+      | 1.2345679e-20 | 1.2345679e-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
+ five |       f1       
+------+----------------
+      |              0
+      |         -34.84
+      |        -1004.3
+      | -1.2345679e+20
+      | -1.2345679e-20
 (5 rows)
 
 -- test edge-case coercions to integer
@@ -434,3 +434,507 @@ SELECT float4send('1.1754944e-38'::float4);
  \x00800000
 (1 row)
 
+-- test output (and round-trip safety) of various values.
+-- To ensure we're testing what we think we're testing, start with
+-- float values specified by bit patterns (as a useful side effect,
+-- this means we'll fail on non-IEEE platforms).
+create type xfloat4;
+create function xfloat4in(cstring) returns xfloat4 immutable strict
+  language internal as 'int4in';
+NOTICE:  return type xfloat4 is only a shell
+create function xfloat4out(xfloat4) returns cstring immutable strict
+  language internal as 'int4out';
+NOTICE:  argument type xfloat4 is only a shell
+create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4);
+create cast (xfloat4 as float4) without function;
+create cast (float4 as xfloat4) without function;
+create cast (xfloat4 as integer) without function;
+create cast (integer as xfloat4) without function;
+-- float4: seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
+-- we don't care to assume the platform's strtod() handles subnormals
+-- correctly; those are "use at your own risk". However we do test
+-- subnormal outputs, since those are under our control.
+with testdata(bits) as (values
+  -- small subnormals
+  (x'00000001'),
+  (x'00000002'), (x'00000003'),
+  (x'00000010'), (x'00000011'), (x'00000100'), (x'00000101'),
+  (x'00004000'), (x'00004001'), (x'00080000'), (x'00080001'),
+  -- stress values
+  (x'0053c4f4'),  -- 7693e-42
+  (x'006c85c4'),  -- 996622e-44
+  (x'0041ca76'),  -- 60419369e-46
+  (x'004b7678'),  -- 6930161142e-48
+  -- taken from upstream testsuite
+  (x'00000007'),
+  (x'00424fe2'),
+  -- borderline between subnormal and normal
+  (x'007ffff0'), (x'007ffff1'), (x'007ffffe'), (x'007fffff'))
+select float4send(flt) as ibits,
+       flt
+  from (select bits::integer::xfloat4::float4 as flt
+          from testdata
+   offset 0) s;
+   ibits    |      flt      
+------------+---------------
+ \x00000001 |         1e-45
+ \x00000002 |         3e-45
+ \x00000003 |         4e-45
+ \x00000010 |       2.2e-44
+ \x00000011 |       2.4e-44
+ \x00000100 |      3.59e-43
+ \x00000101 |       3.6e-43
+ \x00004000 |    2.2959e-41
+ \x00004001 |     2.296e-41
+ \x00080000 |   7.34684e-40
+ \x00080001 |   7.34685e-40
+ \x0053c4f4 |     7.693e-39
+ \x006c85c4 |   9.96622e-39
+ \x0041ca76 |  6.041937e-39
+ \x004b7678 |  6.930161e-39
+ \x00000007 |         1e-44
+ \x00424fe2 |    6.0898e-39
+ \x007ffff0 | 1.1754921e-38
+ \x007ffff1 | 1.1754922e-38
+ \x007ffffe | 1.1754941e-38
+ \x007fffff | 1.1754942e-38
+(21 rows)
+
+with testdata(bits) as (values
+  (x'00000000'),
+  -- smallest normal values
+  (x'00800000'), (x'00800001'), (x'00800004'), (x'00800005'),
+  (x'00800006'),
+  -- small normal values chosen for short vs. long output
+  (x'008002f1'), (x'008002f2'), (x'008002f3'),
+  (x'00800e17'), (x'00800e18'), (x'00800e19'),
+  -- assorted values (random mantissae)
+  (x'01000001'), (x'01102843'), (x'01a52c98'),
+  (x'0219c229'), (x'02e4464d'), (x'037343c1'), (x'03a91b36'),
+  (x'047ada65'), (x'0496fe87'), (x'0550844f'), (x'05999da3'),
+  (x'060ea5e2'), (x'06e63c45'), (x'07f1e548'), (x'0fc5282b'),
+  (x'1f850283'), (x'2874a9d6'),
+  -- values around 5e-08
+  (x'3356bf94'), (x'3356bf95'), (x'3356bf96'),
+  -- around 1e-07
+  (x'33d6bf94'), (x'33d6bf95'), (x'33d6bf96'),
+  -- around 3e-07 .. 1e-04
+  (x'34a10faf'), (x'34a10fb0'), (x'34a10fb1'),
+  (x'350637bc'), (x'350637bd'), (x'350637be'),
+  (x'35719786'), (x'35719787'), (x'35719788'),
+  (x'358637bc'), (x'358637bd'), (x'358637be'),
+  (x'36a7c5ab'), (x'36a7c5ac'), (x'36a7c5ad'),
+  (x'3727c5ab'), (x'3727c5ac'), (x'3727c5ad'),
+  -- format crossover at 1e-04
+  (x'38d1b714'), (x'38d1b715'), (x'38d1b716'),
+  (x'38d1b717'), (x'38d1b718'), (x'38d1b719'),
+  (x'38d1b71a'), (x'38d1b71b'), (x'38d1b71c'),
+  (x'38d1b71d'),
+  --
+  (x'38dffffe'), (x'38dfffff'), (x'38e00000'),
+  (x'38efffff'), (x'38f00000'), (x'38f00001'),
+  (x'3a83126e'), (x'3a83126f'), (x'3a831270'),
+  (x'3c23d709'), (x'3c23d70a'), (x'3c23d70b'),
+  (x'3dcccccc'), (x'3dcccccd'), (x'3dccccce'),
+  -- chosen to need 9 digits for 3dcccd70
+  (x'3dcccd6f'), (x'3dcccd70'), (x'3dcccd71'),
+  --
+  (x'3effffff'), (x'3f000000'), (x'3f000001'),
+  (x'3f333332'), (x'3f333333'), (x'3f333334'),
+  -- approach 1.0 with increasing numbers of 9s
+  (x'3f666665'), (x'3f666666'), (x'3f666667'),
+  (x'3f7d70a3'), (x'3f7d70a4'), (x'3f7d70a5'),
+  (x'3f7fbe76'), (x'3f7fbe77'), (x'3f7fbe78'),
+  (x'3f7ff971'), (x'3f7ff972'), (x'3f7ff973'),
+  (x'3f7fff57'), (x'3f7fff58'), (x'3f7fff59'),
+  (x'3f7fffee'), (x'3f7fffef'),
+  -- values very close to 1
+  (x'3f7ffff0'), (x'3f7ffff1'), (x'3f7ffff2'),
+  (x'3f7ffff3'), (x'3f7ffff4'), (x'3f7ffff5'),
+  (x'3f7ffff6'), (x'3f7ffff7'), (x'3f7ffff8'),
+  (x'3f7ffff9'), (x'3f7ffffa'), (x'3f7ffffb'),
+  (x'3f7ffffc'), (x'3f7ffffd'), (x'3f7ffffe'),
+  (x'3f7fffff'),
+  (x'3f800000'),
+  (x'3f800001'), (x'3f800002'), (x'3f800003'),
+  (x'3f800004'), (x'3f800005'), (x'3f800006'),
+  (x'3f800007'), (x'3f800008'), (x'3f800009'),
+  -- values 1 to 1.1
+  (x'3f80000f'), (x'3f800010'), (x'3f800011'),
+  (x'3f800012'), (x'3f800013'), (x'3f800014'),
+  (x'3f800017'), (x'3f800018'), (x'3f800019'),
+  (x'3f80001a'), (x'3f80001b'), (x'3f80001c'),
+  (x'3f800029'), (x'3f80002a'), (x'3f80002b'),
+  (x'3f800053'), (x'3f800054'), (x'3f800055'),
+  (x'3f800346'), (x'3f800347'), (x'3f800348'),
+  (x'3f8020c4'), (x'3f8020c5'), (x'3f8020c6'),
+  (x'3f8147ad'), (x'3f8147ae'), (x'3f8147af'),
+  (x'3f8ccccc'), (x'3f8ccccd'), (x'3f8cccce'),
+  --
+  (x'3fc90fdb'), -- pi/2
+  (x'402df854'), -- e
+  (x'40490fdb'), -- pi
+  --
+  (x'409fffff'), (x'40a00000'), (x'40a00001'),
+  (x'40afffff'), (x'40b00000'), (x'40b00001'),
+  (x'411fffff'), (x'41200000'), (x'41200001'),
+  (x'42c7ffff'), (x'42c80000'), (x'42c80001'),
+  (x'4479ffff'), (x'447a0000'), (x'447a0001'),
+  (x'461c3fff'), (x'461c4000'), (x'461c4001'),
+  (x'47c34fff'), (x'47c35000'), (x'47c35001'),
+  (x'497423ff'), (x'49742400'), (x'49742401'),
+  (x'4b18967f'), (x'4b189680'), (x'4b189681'),
+  (x'4cbebc1f'), (x'4cbebc20'), (x'4cbebc21'),
+  (x'4e6e6b27'), (x'4e6e6b28'), (x'4e6e6b29'),
+  (x'501502f8'), (x'501502f9'), (x'501502fa'),
+  (x'51ba43b6'), (x'51ba43b7'), (x'51ba43b8'),
+  -- stress values
+  (x'1f6c1e4a'),  -- 5e-20
+  (x'59be6cea'),  -- 67e14
+  (x'5d5ab6c4'),  -- 985e15
+  (x'2cc4a9bd'),  -- 55895e-16
+  (x'15ae43fd'),  -- 7038531e-32
+  (x'2cf757ca'),  -- 702990899e-20
+  (x'665ba998'),  -- 25933168707e13
+  (x'743c3324'),  -- 596428896559e20
+  -- exercise fixed-point memmoves
+  (x'47f1205a'),
+  (x'4640e6ae'),
+  (x'449a5225'),
+  (x'42f6e9d5'),
+  (x'414587dd'),
+  (x'3f9e064b'),
+  -- these cases come from the upstream's testsuite
+  -- BoundaryRoundEven
+  (x'4c000004'),
+  (x'50061c46'),
+  (x'510006a8'),
+  -- ExactValueRoundEven
+  (x'48951f84'),
+  (x'45fd1840'),
+  -- LotsOfTrailingZeros
+  (x'39800000'),
+  (x'3b200000'),
+  (x'3b900000'),
+  (x'3bd00000'),
+  -- Regression
+  (x'63800000'),
+  (x'4b000000'),
+  (x'4b800000'),
+  (x'4c000001'),
+  (x'4c800b0d'),
+  (x'00d24584'),
+  (x'800000b0'),
+  (x'00d90b88'),
+  (x'45803f34'),
+  (x'4f9f24f7'),
+  (x'3a8722c3'),
+  (x'5c800041'),
+  (x'15ae43fd'),
+  (x'5d4cccfb'),
+  (x'4c800001'),
+  (x'57800ed8'),
+  (x'5f000000'),
+  (x'700000f0'),
+  (x'5f23e9ac'),
+  (x'5e9502f9'),
+  (x'5e8012b1'),
+  (x'3c000028'),
+  (x'60cde861'),
+  (x'03aa2a50'),
+  (x'43480000'),
+  (x'4c000000'),
+  -- LooksLikePow5
+  (x'5D1502F9'),
+  (x'5D9502F9'),
+  (x'5E1502F9'),
+  -- OutputLength
+  (x'3f99999a'),
+  (x'3f9d70a4'),
+  (x'3f9df3b6'),
+  (x'3f9e0419'),
+  (x'3f9e0610'),
+  (x'3f9e064b'),
+  (x'3f9e0651'),
+  (x'03d20cfe')
+)
+select float4send(flt) as ibits,
+       flt,
+       flt::text::float4 as r_flt,
+       float4send(flt::text::float4) as obits,
+       float4send(flt::text::float4) = float4send(flt) as correct
+  from (select bits::integer::xfloat4::float4 as flt
+          from testdata
+   offset 0) s;
+   ibits    |      flt       |     r_flt      |   obits    | correct 
+------------+----------------+----------------+------------+---------
+ \x00000000 |              0 |              0 | \x00000000 | t
+ \x00800000 |  1.1754944e-38 |  1.1754944e-38 | \x00800000 | t
+ \x00800001 |  1.1754945e-38 |  1.1754945e-38 | \x00800001 | t
+ \x00800004 |  1.1754949e-38 |  1.1754949e-38 | \x00800004 | t
+ \x00800005 |   1.175495e-38 |   1.175495e-38 | \x00800005 | t
+ \x00800006 |  1.1754952e-38 |  1.1754952e-38 | \x00800006 | t
+ \x008002f1 |  1.1755999e-38 |  1.1755999e-38 | \x008002f1 | t
+ \x008002f2 |     1.1756e-38 |     1.1756e-38 | \x008002f2 | t
+ \x008002f3 |  1.1756001e-38 |  1.1756001e-38 | \x008002f3 | t
+ \x00800e17 |  1.1759998e-38 |  1.1759998e-38 | \x00800e17 | t
+ \x00800e18 |      1.176e-38 |      1.176e-38 | \x00800e18 | t
+ \x00800e19 |  1.1760001e-38 |  1.1760001e-38 | \x00800e19 | t
+ \x01000001 |   2.350989e-38 |   2.350989e-38 | \x01000001 | t
+ \x01102843 |   2.647751e-38 |   2.647751e-38 | \x01102843 | t
+ \x01a52c98 |  6.0675416e-38 |  6.0675416e-38 | \x01a52c98 | t
+ \x0219c229 |  1.1296386e-37 |  1.1296386e-37 | \x0219c229 | t
+ \x02e4464d |   3.354194e-37 |   3.354194e-37 | \x02e4464d | t
+ \x037343c1 |   7.148906e-37 |   7.148906e-37 | \x037343c1 | t
+ \x03a91b36 |   9.939175e-37 |   9.939175e-37 | \x03a91b36 | t
+ \x047ada65 |   2.948764e-36 |   2.948764e-36 | \x047ada65 | t
+ \x0496fe87 |  3.5498577e-36 |  3.5498577e-36 | \x0496fe87 | t
+ \x0550844f |   9.804414e-36 |   9.804414e-36 | \x0550844f | t
+ \x05999da3 |  1.4445957e-35 |  1.4445957e-35 | \x05999da3 | t
+ \x060ea5e2 |  2.6829103e-35 |  2.6829103e-35 | \x060ea5e2 | t
+ \x06e63c45 |   8.660494e-35 |   8.660494e-35 | \x06e63c45 | t
+ \x07f1e548 |   3.639641e-34 |   3.639641e-34 | \x07f1e548 | t
+ \x0fc5282b |  1.9441172e-29 |  1.9441172e-29 | \x0fc5282b | t
+ \x1f850283 |  5.6331846e-20 |  5.6331846e-20 | \x1f850283 | t
+ \x2874a9d6 |  1.3581548e-14 |  1.3581548e-14 | \x2874a9d6 | t
+ \x3356bf94 |  4.9999997e-08 |  4.9999997e-08 | \x3356bf94 | t
+ \x3356bf95 |          5e-08 |          5e-08 | \x3356bf95 | t
+ \x3356bf96 |  5.0000004e-08 |  5.0000004e-08 | \x3356bf96 | t
+ \x33d6bf94 |  9.9999994e-08 |  9.9999994e-08 | \x33d6bf94 | t
+ \x33d6bf95 |          1e-07 |          1e-07 | \x33d6bf95 | t
+ \x33d6bf96 |  1.0000001e-07 |  1.0000001e-07 | \x33d6bf96 | t
+ \x34a10faf |  2.9999998e-07 |  2.9999998e-07 | \x34a10faf | t
+ \x34a10fb0 |          3e-07 |          3e-07 | \x34a10fb0 | t
+ \x34a10fb1 |  3.0000004e-07 |  3.0000004e-07 | \x34a10fb1 | t
+ \x350637bc |  4.9999994e-07 |  4.9999994e-07 | \x350637bc | t
+ \x350637bd |          5e-07 |          5e-07 | \x350637bd | t
+ \x350637be |  5.0000006e-07 |  5.0000006e-07 | \x350637be | t
+ \x35719786 |   8.999999e-07 |   8.999999e-07 | \x35719786 | t
+ \x35719787 |          9e-07 |          9e-07 | \x35719787 | t
+ \x35719788 |  9.0000003e-07 |  9.0000003e-07 | \x35719788 | t
+ \x358637bc |   9.999999e-07 |   9.999999e-07 | \x358637bc | t
+ \x358637bd |          1e-06 |          1e-06 | \x358637bd | t
+ \x358637be |  1.0000001e-06 |  1.0000001e-06 | \x358637be | t
+ \x36a7c5ab |  4.9999994e-06 |  4.9999994e-06 | \x36a7c5ab | t
+ \x36a7c5ac |          5e-06 |          5e-06 | \x36a7c5ac | t
+ \x36a7c5ad |  5.0000003e-06 |  5.0000003e-06 | \x36a7c5ad | t
+ \x3727c5ab |   9.999999e-06 |   9.999999e-06 | \x3727c5ab | t
+ \x3727c5ac |          1e-05 |          1e-05 | \x3727c5ac | t
+ \x3727c5ad |  1.0000001e-05 |  1.0000001e-05 | \x3727c5ad | t
+ \x38d1b714 |  9.9999976e-05 |  9.9999976e-05 | \x38d1b714 | t
+ \x38d1b715 |   9.999998e-05 |   9.999998e-05 | \x38d1b715 | t
+ \x38d1b716 |   9.999999e-05 |   9.999999e-05 | \x38d1b716 | t
+ \x38d1b717 |         0.0001 |         0.0001 | \x38d1b717 | t
+ \x38d1b718 | 0.000100000005 | 0.000100000005 | \x38d1b718 | t
+ \x38d1b719 |  0.00010000001 |  0.00010000001 | \x38d1b719 | t
+ \x38d1b71a |  0.00010000002 |  0.00010000002 | \x38d1b71a | t
+ \x38d1b71b |  0.00010000003 |  0.00010000003 | \x38d1b71b | t
+ \x38d1b71c | 0.000100000034 | 0.000100000034 | \x38d1b71c | t
+ \x38d1b71d |  0.00010000004 |  0.00010000004 | \x38d1b71d | t
+ \x38dffffe |  0.00010681151 |  0.00010681151 | \x38dffffe | t
+ \x38dfffff | 0.000106811516 | 0.000106811516 | \x38dfffff | t
+ \x38e00000 |  0.00010681152 |  0.00010681152 | \x38e00000 | t
+ \x38efffff |  0.00011444091 |  0.00011444091 | \x38efffff | t
+ \x38f00000 |  0.00011444092 |  0.00011444092 | \x38f00000 | t
+ \x38f00001 | 0.000114440925 | 0.000114440925 | \x38f00001 | t
+ \x3a83126e |   0.0009999999 |   0.0009999999 | \x3a83126e | t
+ \x3a83126f |          0.001 |          0.001 | \x3a83126f | t
+ \x3a831270 |   0.0010000002 |   0.0010000002 | \x3a831270 | t
+ \x3c23d709 |    0.009999999 |    0.009999999 | \x3c23d709 | t
+ \x3c23d70a |           0.01 |           0.01 | \x3c23d70a | t
+ \x3c23d70b |    0.010000001 |    0.010000001 | \x3c23d70b | t
+ \x3dcccccc |    0.099999994 |    0.099999994 | \x3dcccccc | t
+ \x3dcccccd |            0.1 |            0.1 | \x3dcccccd | t
+ \x3dccccce |     0.10000001 |     0.10000001 | \x3dccccce | t
+ \x3dcccd6f |     0.10000121 |     0.10000121 | \x3dcccd6f | t
+ \x3dcccd70 |    0.100001216 |    0.100001216 | \x3dcccd70 | t
+ \x3dcccd71 |     0.10000122 |     0.10000122 | \x3dcccd71 | t
+ \x3effffff |     0.49999997 |     0.49999997 | \x3effffff | t
+ \x3f000000 |            0.5 |            0.5 | \x3f000000 | t
+ \x3f000001 |     0.50000006 |     0.50000006 | \x3f000001 | t
+ \x3f333332 |      0.6999999 |      0.6999999 | \x3f333332 | t
+ \x3f333333 |            0.7 |            0.7 | \x3f333333 | t
+ \x3f333334 |     0.70000005 |     0.70000005 | \x3f333334 | t
+ \x3f666665 |      0.8999999 |      0.8999999 | \x3f666665 | t
+ \x3f666666 |            0.9 |            0.9 | \x3f666666 | t
+ \x3f666667 |     0.90000004 |     0.90000004 | \x3f666667 | t
+ \x3f7d70a3 |     0.98999995 |     0.98999995 | \x3f7d70a3 | t
+ \x3f7d70a4 |           0.99 |           0.99 | \x3f7d70a4 | t
+ \x3f7d70a5 |     0.99000007 |     0.99000007 | \x3f7d70a5 | t
+ \x3f7fbe76 |     0.99899995 |     0.99899995 | \x3f7fbe76 | t
+ \x3f7fbe77 |          0.999 |          0.999 | \x3f7fbe77 | t
+ \x3f7fbe78 |      0.9990001 |      0.9990001 | \x3f7fbe78 | t
+ \x3f7ff971 |      0.9998999 |      0.9998999 | \x3f7ff971 | t
+ \x3f7ff972 |         0.9999 |         0.9999 | \x3f7ff972 | t
+ \x3f7ff973 |     0.99990004 |     0.99990004 | \x3f7ff973 | t
+ \x3f7fff57 |      0.9999899 |      0.9999899 | \x3f7fff57 | t
+ \x3f7fff58 |        0.99999 |        0.99999 | \x3f7fff58 | t
+ \x3f7fff59 |     0.99999005 |     0.99999005 | \x3f7fff59 | t
+ \x3f7fffee |      0.9999989 |      0.9999989 | \x3f7fffee | t
+ \x3f7fffef |       0.999999 |       0.999999 | \x3f7fffef | t
+ \x3f7ffff0 |     0.99999905 |     0.99999905 | \x3f7ffff0 | t
+ \x3f7ffff1 |      0.9999991 |      0.9999991 | \x3f7ffff1 | t
+ \x3f7ffff2 |     0.99999917 |     0.99999917 | \x3f7ffff2 | t
+ \x3f7ffff3 |      0.9999992 |      0.9999992 | \x3f7ffff3 | t
+ \x3f7ffff4 |      0.9999993 |      0.9999993 | \x3f7ffff4 | t
+ \x3f7ffff5 |     0.99999934 |     0.99999934 | \x3f7ffff5 | t
+ \x3f7ffff6 |      0.9999994 |      0.9999994 | \x3f7ffff6 | t
+ \x3f7ffff7 |     0.99999946 |     0.99999946 | \x3f7ffff7 | t
+ \x3f7ffff8 |      0.9999995 |      0.9999995 | \x3f7ffff8 | t
+ \x3f7ffff9 |      0.9999996 |      0.9999996 | \x3f7ffff9 | t
+ \x3f7ffffa |     0.99999964 |     0.99999964 | \x3f7ffffa | t
+ \x3f7ffffb |      0.9999997 |      0.9999997 | \x3f7ffffb | t
+ \x3f7ffffc |     0.99999976 |     0.99999976 | \x3f7ffffc | t
+ \x3f7ffffd |      0.9999998 |      0.9999998 | \x3f7ffffd | t
+ \x3f7ffffe |      0.9999999 |      0.9999999 | \x3f7ffffe | t
+ \x3f7fffff |     0.99999994 |     0.99999994 | \x3f7fffff | t
+ \x3f800000 |              1 |              1 | \x3f800000 | t
+ \x3f800001 |      1.0000001 |      1.0000001 | \x3f800001 | t
+ \x3f800002 |      1.0000002 |      1.0000002 | \x3f800002 | t
+ \x3f800003 |      1.0000004 |      1.0000004 | \x3f800003 | t
+ \x3f800004 |      1.0000005 |      1.0000005 | \x3f800004 | t
+ \x3f800005 |      1.0000006 |      1.0000006 | \x3f800005 | t
+ \x3f800006 |      1.0000007 |      1.0000007 | \x3f800006 | t
+ \x3f800007 |      1.0000008 |      1.0000008 | \x3f800007 | t
+ \x3f800008 |       1.000001 |       1.000001 | \x3f800008 | t
+ \x3f800009 |      1.0000011 |      1.0000011 | \x3f800009 | t
+ \x3f80000f |      1.0000018 |      1.0000018 | \x3f80000f | t
+ \x3f800010 |      1.0000019 |      1.0000019 | \x3f800010 | t
+ \x3f800011 |       1.000002 |       1.000002 | \x3f800011 | t
+ \x3f800012 |      1.0000021 |      1.0000021 | \x3f800012 | t
+ \x3f800013 |      1.0000023 |      1.0000023 | \x3f800013 | t
+ \x3f800014 |      1.0000024 |      1.0000024 | \x3f800014 | t
+ \x3f800017 |      1.0000027 |      1.0000027 | \x3f800017 | t
+ \x3f800018 |      1.0000029 |      1.0000029 | \x3f800018 | t
+ \x3f800019 |       1.000003 |       1.000003 | \x3f800019 | t
+ \x3f80001a |      1.0000031 |      1.0000031 | \x3f80001a | t
+ \x3f80001b |      1.0000032 |      1.0000032 | \x3f80001b | t
+ \x3f80001c |      1.0000033 |      1.0000033 | \x3f80001c | t
+ \x3f800029 |      1.0000049 |      1.0000049 | \x3f800029 | t
+ \x3f80002a |       1.000005 |       1.000005 | \x3f80002a | t
+ \x3f80002b |      1.0000051 |      1.0000051 | \x3f80002b | t
+ \x3f800053 |      1.0000099 |      1.0000099 | \x3f800053 | t
+ \x3f800054 |        1.00001 |        1.00001 | \x3f800054 | t
+ \x3f800055 |      1.0000101 |      1.0000101 | \x3f800055 | t
+ \x3f800346 |      1.0000999 |      1.0000999 | \x3f800346 | t
+ \x3f800347 |         1.0001 |         1.0001 | \x3f800347 | t
+ \x3f800348 |      1.0001001 |      1.0001001 | \x3f800348 | t
+ \x3f8020c4 |      1.0009999 |      1.0009999 | \x3f8020c4 | t
+ \x3f8020c5 |          1.001 |          1.001 | \x3f8020c5 | t
+ \x3f8020c6 |      1.0010002 |      1.0010002 | \x3f8020c6 | t
+ \x3f8147ad |      1.0099999 |      1.0099999 | \x3f8147ad | t
+ \x3f8147ae |           1.01 |           1.01 | \x3f8147ae | t
+ \x3f8147af |      1.0100001 |      1.0100001 | \x3f8147af | t
+ \x3f8ccccc |      1.0999999 |      1.0999999 | \x3f8ccccc | t
+ \x3f8ccccd |            1.1 |            1.1 | \x3f8ccccd | t
+ \x3f8cccce |      1.1000001 |      1.1000001 | \x3f8cccce | t
+ \x3fc90fdb |      1.5707964 |      1.5707964 | \x3fc90fdb | t
+ \x402df854 |      2.7182817 |      2.7182817 | \x402df854 | t
+ \x40490fdb |      3.1415927 |      3.1415927 | \x40490fdb | t
+ \x409fffff |      4.9999995 |      4.9999995 | \x409fffff | t
+ \x40a00000 |              5 |              5 | \x40a00000 | t
+ \x40a00001 |      5.0000005 |      5.0000005 | \x40a00001 | t
+ \x40afffff |      5.4999995 |      5.4999995 | \x40afffff | t
+ \x40b00000 |            5.5 |            5.5 | \x40b00000 | t
+ \x40b00001 |      5.5000005 |      5.5000005 | \x40b00001 | t
+ \x411fffff |       9.999999 |       9.999999 | \x411fffff | t
+ \x41200000 |             10 |             10 | \x41200000 | t
+ \x41200001 |      10.000001 |      10.000001 | \x41200001 | t
+ \x42c7ffff |       99.99999 |       99.99999 | \x42c7ffff | t
+ \x42c80000 |            100 |            100 | \x42c80000 | t
+ \x42c80001 |      100.00001 |      100.00001 | \x42c80001 | t
+ \x4479ffff |      999.99994 |      999.99994 | \x4479ffff | t
+ \x447a0000 |           1000 |           1000 | \x447a0000 | t
+ \x447a0001 |     1000.00006 |     1000.00006 | \x447a0001 | t
+ \x461c3fff |       9999.999 |       9999.999 | \x461c3fff | t
+ \x461c4000 |          10000 |          10000 | \x461c4000 | t
+ \x461c4001 |      10000.001 |      10000.001 | \x461c4001 | t
+ \x47c34fff |       99999.99 |       99999.99 | \x47c34fff | t
+ \x47c35000 |         100000 |         100000 | \x47c35000 | t
+ \x47c35001 |      100000.01 |      100000.01 | \x47c35001 | t
+ \x497423ff |      999999.94 |      999999.94 | \x497423ff | t
+ \x49742400 |          1e+06 |          1e+06 | \x49742400 | t
+ \x49742401 | 1.00000006e+06 | 1.00000006e+06 | \x49742401 | t
+ \x4b18967f |   9.999999e+06 |   9.999999e+06 | \x4b18967f | t
+ \x4b189680 |          1e+07 |          1e+07 | \x4b189680 | t
+ \x4b189681 |  1.0000001e+07 |  1.0000001e+07 | \x4b189681 | t
+ \x4cbebc1f |   9.999999e+07 |   9.999999e+07 | \x4cbebc1f | t
+ \x4cbebc20 |          1e+08 |          1e+08 | \x4cbebc20 | t
+ \x4cbebc21 |  1.0000001e+08 |  1.0000001e+08 | \x4cbebc21 | t
+ \x4e6e6b27 |  9.9999994e+08 |  9.9999994e+08 | \x4e6e6b27 | t
+ \x4e6e6b28 |          1e+09 |          1e+09 | \x4e6e6b28 | t
+ \x4e6e6b29 | 1.00000006e+09 | 1.00000006e+09 | \x4e6e6b29 | t
+ \x501502f8 |   9.999999e+09 |   9.999999e+09 | \x501502f8 | t
+ \x501502f9 |          1e+10 |          1e+10 | \x501502f9 | t
+ \x501502fa |  1.0000001e+10 |  1.0000001e+10 | \x501502fa | t
+ \x51ba43b6 |   9.999999e+10 |   9.999999e+10 | \x51ba43b6 | t
+ \x51ba43b7 |          1e+11 |          1e+11 | \x51ba43b7 | t
+ \x51ba43b8 |  1.0000001e+11 |  1.0000001e+11 | \x51ba43b8 | t
+ \x1f6c1e4a |          5e-20 |          5e-20 | \x1f6c1e4a | t
+ \x59be6cea |        6.7e+15 |        6.7e+15 | \x59be6cea | t
+ \x5d5ab6c4 |       9.85e+17 |       9.85e+17 | \x5d5ab6c4 | t
+ \x2cc4a9bd |     5.5895e-12 |     5.5895e-12 | \x2cc4a9bd | t
+ \x15ae43fd |   7.038531e-26 |   7.038531e-26 | \x15ae43fd | t
+ \x2cf757ca |  7.0299088e-12 |  7.0299088e-12 | \x2cf757ca | t
+ \x665ba998 |  2.5933168e+23 |  2.5933168e+23 | \x665ba998 | t
+ \x743c3324 |  5.9642887e+31 |  5.9642887e+31 | \x743c3324 | t
+ \x47f1205a |       123456.7 |       123456.7 | \x47f1205a | t
+ \x4640e6ae |       12345.67 |       12345.67 | \x4640e6ae | t
+ \x449a5225 |       1234.567 |       1234.567 | \x449a5225 | t
+ \x42f6e9d5 |       123.4567 |       123.4567 | \x42f6e9d5 | t
+ \x414587dd |       12.34567 |       12.34567 | \x414587dd | t
+ \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
+ \x4c000004 |  3.3554448e+07 |  3.3554448e+07 | \x4c000004 | t
+ \x50061c46 |   8.999999e+09 |   8.999999e+09 | \x50061c46 | t
+ \x510006a8 |  3.4366718e+10 |  3.4366718e+10 | \x510006a8 | t
+ \x48951f84 |      305404.12 |      305404.12 | \x48951f84 | t
+ \x45fd1840 |      8099.0312 |      8099.0312 | \x45fd1840 | t
+ \x39800000 |  0.00024414062 |  0.00024414062 | \x39800000 | t
+ \x3b200000 |   0.0024414062 |   0.0024414062 | \x3b200000 | t
+ \x3b900000 |   0.0043945312 |   0.0043945312 | \x3b900000 | t
+ \x3bd00000 |   0.0063476562 |   0.0063476562 | \x3bd00000 | t
+ \x63800000 |  4.7223665e+21 |  4.7223665e+21 | \x63800000 | t
+ \x4b000000 |   8.388608e+06 |   8.388608e+06 | \x4b000000 | t
+ \x4b800000 |  1.6777216e+07 |  1.6777216e+07 | \x4b800000 | t
+ \x4c000001 |  3.3554436e+07 |  3.3554436e+07 | \x4c000001 | t
+ \x4c800b0d |  6.7131496e+07 |  6.7131496e+07 | \x4c800b0d | t
+ \x00d24584 |  1.9310392e-38 |  1.9310392e-38 | \x00d24584 | t
+ \x800000b0 |      -2.47e-43 |      -2.47e-43 | \x800000b0 | t
+ \x00d90b88 |   1.993244e-38 |   1.993244e-38 | \x00d90b88 | t
+ \x45803f34 |      4103.9004 |      4103.9004 | \x45803f34 | t
+ \x4f9f24f7 |  5.3399997e+09 |  5.3399997e+09 | \x4f9f24f7 | t
+ \x3a8722c3 |   0.0010310042 |   0.0010310042 | \x3a8722c3 | t
+ \x5c800041 |   2.882326e+17 |   2.882326e+17 | \x5c800041 | t
+ \x15ae43fd |   7.038531e-26 |   7.038531e-26 | \x15ae43fd | t
+ \x5d4cccfb |   9.223404e+17 |   9.223404e+17 | \x5d4cccfb | t
+ \x4c800001 |   6.710887e+07 |   6.710887e+07 | \x4c800001 | t
+ \x57800ed8 |   2.816025e+14 |   2.816025e+14 | \x57800ed8 | t
+ \x5f000000 |   9.223372e+18 |   9.223372e+18 | \x5f000000 | t
+ \x700000f0 |  1.5846086e+29 |  1.5846086e+29 | \x700000f0 | t
+ \x5f23e9ac |  1.1811161e+19 |  1.1811161e+19 | \x5f23e9ac | t
+ \x5e9502f9 |   5.368709e+18 |   5.368709e+18 | \x5e9502f9 | t
+ \x5e8012b1 |  4.6143166e+18 |  4.6143166e+18 | \x5e8012b1 | t
+ \x3c000028 |    0.007812537 |    0.007812537 | \x3c000028 | t
+ \x60cde861 | 1.18697725e+20 | 1.18697725e+20 | \x60cde861 | t
+ \x03aa2a50 | 1.00014165e-36 | 1.00014165e-36 | \x03aa2a50 | t
+ \x43480000 |            200 |            200 | \x43480000 | t
+ \x4c000000 |  3.3554432e+07 |  3.3554432e+07 | \x4c000000 | t
+ \x5d1502f9 |  6.7108864e+17 |  6.7108864e+17 | \x5d1502f9 | t
+ \x5d9502f9 |  1.3421773e+18 |  1.3421773e+18 | \x5d9502f9 | t
+ \x5e1502f9 |  2.6843546e+18 |  2.6843546e+18 | \x5e1502f9 | t
+ \x3f99999a |            1.2 |            1.2 | \x3f99999a | t
+ \x3f9d70a4 |           1.23 |           1.23 | \x3f9d70a4 | t
+ \x3f9df3b6 |          1.234 |          1.234 | \x3f9df3b6 | t
+ \x3f9e0419 |         1.2345 |         1.2345 | \x3f9e0419 | t
+ \x3f9e0610 |        1.23456 |        1.23456 | \x3f9e0610 | t
+ \x3f9e064b |       1.234567 |       1.234567 | \x3f9e064b | t
+ \x3f9e0651 |      1.2345678 |      1.2345678 | \x3f9e0651 | t
+ \x03d20cfe | 1.23456735e-36 | 1.23456735e-36 | \x03d20cfe | t
+(262 rows)
+
+-- clean up, lest opr_sanity complain
+\set VERBOSITY terse
+drop type xfloat4 cascade;
+NOTICE:  drop cascades to 6 other objects
+\set VERBOSITY default
+--
index 1c3bbae6b8bb484a0b6ddcbcc9b59a61423f34f6..f67c22e9fa9101519e2c39d36a0ddc81975ed128 100644 (file)
@@ -28,6 +28,13 @@ SELECT '-10e-400'::float8;
      -0
 (1 row)
 
+-- test smallest normalized input
+SELECT float8send('2.2250738585072014E-308'::float8);
+     float8send     
+--------------------
+ \x0010000000000000
+(1 row)
+
 -- bad input
 INSERT INTO FLOAT8_TBL(f1) VALUES ('');
 ERROR:  invalid input syntax for type double precision: ""
@@ -213,7 +220,7 @@ SELECT '' AS three, f.f1, f.f1 / '-10' AS x
    WHERE f.f1 > '0.0';
  three |          f1          |           x           
 -------+----------------------+-----------------------
-       |               1004.3 |               -100.43
+       |               1004.3 |   -100.42999999999999
        | 1.2345678901234e+200 | -1.2345678901234e+199
        | 1.2345678901234e-200 | -1.2345678901234e-201
 (3 rows)
@@ -230,9 +237,9 @@ SELECT '' AS three, f.f1, f.f1 - '-10' AS x
 
 SELECT '' AS one, f.f1 ^ '2.0' AS square_f1
    FROM FLOAT8_TBL f where f.f1 = '1004.3';
- one | square_f1  
------+------------
-     | 1008618.49
+ one |     square_f1      
+-----+--------------------
+     | 1008618.4899999999
 (1 row)
 
 -- absolute value
@@ -314,6 +321,8 @@ select sign(f1) as sign_f1 from float8_tbl f;
        1
 (5 rows)
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
 -- square root
 SELECT sqrt(float8 '64') AS eight;
  eight 
@@ -449,6 +458,7 @@ SELECT '' AS five, * FROM FLOAT8_TBL;
       | -1.2345678901234e-200
 (5 rows)
 
+RESET extra_float_digits;
 -- test for over- and underflow
 INSERT INTO FLOAT8_TBL(f1) VALUES ('10e400');
 ERROR:  "10e400" is out of range for type double precision
@@ -528,7 +538,6 @@ SELECT '-9223372036854775808.5'::float8::int8;
 SELECT '-9223372036854780000'::float8::int8;
 ERROR:  bigint out of range
 -- test exact cases for trigonometric functions in degrees
-SET extra_float_digits = 3;
 SELECT x,
        sind(x),
        sind(x) IN (-1,-0.5,0,0.5,1) AS sind_exact
@@ -630,4 +639,432 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
   10 |   0 |      0 | t
 (5 rows)
 
-RESET extra_float_digits;
+--
+-- test output (and round-trip safety) of various values.
+-- To ensure we're testing what we think we're testing, start with
+-- float values specified by bit patterns (as a useful side effect,
+-- this means we'll fail on non-IEEE platforms).
+create type xfloat8;
+create function xfloat8in(cstring) returns xfloat8 immutable strict
+  language internal as 'int8in';
+NOTICE:  return type xfloat8 is only a shell
+create function xfloat8out(xfloat8) returns cstring immutable strict
+  language internal as 'int8out';
+NOTICE:  argument type xfloat8 is only a shell
+create type xfloat8 (input = xfloat8in, output = xfloat8out, like = float8);
+create cast (xfloat8 as float8) without function;
+create cast (float8 as xfloat8) without function;
+create cast (xfloat8 as bigint) without function;
+create cast (bigint as xfloat8) without function;
+-- float8: seeeeeee eeeeeeee eeeeeeee mmmmmmmm mmmmmmmm(x4)
+-- we don't care to assume the platform's strtod() handles subnormals
+-- correctly; those are "use at your own risk". However we do test
+-- subnormal outputs, since those are under our control.
+with testdata(bits) as (values
+  -- small subnormals
+  (x'0000000000000001'),
+  (x'0000000000000002'), (x'0000000000000003'),
+  (x'0000000000001000'), (x'0000000100000000'),
+  (x'0000010000000000'), (x'0000010100000000'),
+  (x'0000400000000000'), (x'0000400100000000'),
+  (x'0000800000000000'), (x'0000800000000001'),
+  -- these values taken from upstream testsuite
+  (x'00000000000f4240'),
+  (x'00000000016e3600'),
+  (x'0000008cdcdea440'),
+  -- borderline between subnormal and normal
+  (x'000ffffffffffff0'), (x'000ffffffffffff1'),
+  (x'000ffffffffffffe'), (x'000fffffffffffff'))
+select float8send(flt) as ibits,
+       flt
+  from (select bits::bigint::xfloat8::float8 as flt
+          from testdata
+   offset 0) s;
+       ibits        |           flt           
+--------------------+-------------------------
+ \x0000000000000001 |                  5e-324
+ \x0000000000000002 |                  1e-323
+ \x0000000000000003 |                1.5e-323
+ \x0000000000001000 |             2.0237e-320
+ \x0000000100000000 |        2.121995791e-314
+ \x0000010000000000 |      5.43230922487e-312
+ \x0000010100000000 |      5.45352918278e-312
+ \x0000400000000000 |    3.4766779039175e-310
+ \x0000400100000000 |    3.4768901034966e-310
+ \x0000800000000000 |     6.953355807835e-310
+ \x0000800000000001 |   6.95335580783505e-310
+ \x00000000000f4240 |           4.940656e-318
+ \x00000000016e3600 |         1.18575755e-316
+ \x0000008cdcdea440 |     2.989102097996e-312
+ \x000ffffffffffff0 | 2.2250738585071935e-308
+ \x000ffffffffffff1 |  2.225073858507194e-308
+ \x000ffffffffffffe | 2.2250738585072004e-308
+ \x000fffffffffffff |  2.225073858507201e-308
+(18 rows)
+
+-- round-trip tests
+with testdata(bits) as (values
+  (x'0000000000000000'),
+  -- smallest normal values
+  (x'0010000000000000'), (x'0010000000000001'),
+  (x'0010000000000002'), (x'0018000000000000'),
+  --
+  (x'3ddb7cdfd9d7bdba'), (x'3ddb7cdfd9d7bdbb'), (x'3ddb7cdfd9d7bdbc'),
+  (x'3e112e0be826d694'), (x'3e112e0be826d695'), (x'3e112e0be826d696'),
+  (x'3e45798ee2308c39'), (x'3e45798ee2308c3a'), (x'3e45798ee2308c3b'),
+  (x'3e7ad7f29abcaf47'), (x'3e7ad7f29abcaf48'), (x'3e7ad7f29abcaf49'),
+  (x'3eb0c6f7a0b5ed8c'), (x'3eb0c6f7a0b5ed8d'), (x'3eb0c6f7a0b5ed8e'),
+  (x'3ee4f8b588e368ef'), (x'3ee4f8b588e368f0'), (x'3ee4f8b588e368f1'),
+  (x'3f1a36e2eb1c432c'), (x'3f1a36e2eb1c432d'), (x'3f1a36e2eb1c432e'),
+  (x'3f50624dd2f1a9fb'), (x'3f50624dd2f1a9fc'), (x'3f50624dd2f1a9fd'),
+  (x'3f847ae147ae147a'), (x'3f847ae147ae147b'), (x'3f847ae147ae147c'),
+  (x'3fb9999999999999'), (x'3fb999999999999a'), (x'3fb999999999999b'),
+  -- values very close to 1
+  (x'3feffffffffffff0'), (x'3feffffffffffff1'), (x'3feffffffffffff2'),
+  (x'3feffffffffffff3'), (x'3feffffffffffff4'), (x'3feffffffffffff5'),
+  (x'3feffffffffffff6'), (x'3feffffffffffff7'), (x'3feffffffffffff8'),
+  (x'3feffffffffffff9'), (x'3feffffffffffffa'), (x'3feffffffffffffb'),
+  (x'3feffffffffffffc'), (x'3feffffffffffffd'), (x'3feffffffffffffe'),
+  (x'3fefffffffffffff'),
+  (x'3ff0000000000000'),
+  (x'3ff0000000000001'), (x'3ff0000000000002'), (x'3ff0000000000003'),
+  (x'3ff0000000000004'), (x'3ff0000000000005'), (x'3ff0000000000006'),
+  (x'3ff0000000000007'), (x'3ff0000000000008'), (x'3ff0000000000009'),
+  --
+  (x'3ff921fb54442d18'),
+  (x'4005bf0a8b14576a'),
+  (x'400921fb54442d18'),
+  --
+  (x'4023ffffffffffff'), (x'4024000000000000'), (x'4024000000000001'),
+  (x'4058ffffffffffff'), (x'4059000000000000'), (x'4059000000000001'),
+  (x'408f3fffffffffff'), (x'408f400000000000'), (x'408f400000000001'),
+  (x'40c387ffffffffff'), (x'40c3880000000000'), (x'40c3880000000001'),
+  (x'40f869ffffffffff'), (x'40f86a0000000000'), (x'40f86a0000000001'),
+  (x'412e847fffffffff'), (x'412e848000000000'), (x'412e848000000001'),
+  (x'416312cfffffffff'), (x'416312d000000000'), (x'416312d000000001'),
+  (x'4197d783ffffffff'), (x'4197d78400000000'), (x'4197d78400000001'),
+  (x'41cdcd64ffffffff'), (x'41cdcd6500000000'), (x'41cdcd6500000001'),
+  (x'4202a05f1fffffff'), (x'4202a05f20000000'), (x'4202a05f20000001'),
+  (x'42374876e7ffffff'), (x'42374876e8000000'), (x'42374876e8000001'),
+  (x'426d1a94a1ffffff'), (x'426d1a94a2000000'), (x'426d1a94a2000001'),
+  (x'42a2309ce53fffff'), (x'42a2309ce5400000'), (x'42a2309ce5400001'),
+  (x'42d6bcc41e8fffff'), (x'42d6bcc41e900000'), (x'42d6bcc41e900001'),
+  (x'430c6bf52633ffff'), (x'430c6bf526340000'), (x'430c6bf526340001'),
+  (x'4341c37937e07fff'), (x'4341c37937e08000'), (x'4341c37937e08001'),
+  (x'4376345785d89fff'), (x'4376345785d8a000'), (x'4376345785d8a001'),
+  (x'43abc16d674ec7ff'), (x'43abc16d674ec800'), (x'43abc16d674ec801'),
+  (x'43e158e460913cff'), (x'43e158e460913d00'), (x'43e158e460913d01'),
+  (x'4415af1d78b58c3f'), (x'4415af1d78b58c40'), (x'4415af1d78b58c41'),
+  (x'444b1ae4d6e2ef4f'), (x'444b1ae4d6e2ef50'), (x'444b1ae4d6e2ef51'),
+  (x'4480f0cf064dd591'), (x'4480f0cf064dd592'), (x'4480f0cf064dd593'),
+  (x'44b52d02c7e14af5'), (x'44b52d02c7e14af6'), (x'44b52d02c7e14af7'),
+  (x'44ea784379d99db3'), (x'44ea784379d99db4'), (x'44ea784379d99db5'),
+  (x'45208b2a2c280290'), (x'45208b2a2c280291'), (x'45208b2a2c280292'),
+  --
+  (x'7feffffffffffffe'), (x'7fefffffffffffff'),
+  -- round to even tests (+ve)
+  (x'4350000000000002'),
+  (x'4350000000002e06'),
+  (x'4352000000000003'),
+  (x'4352000000000004'),
+  (x'4358000000000003'),
+  (x'4358000000000004'),
+  (x'435f000000000020'),
+  -- round to even tests (-ve)
+  (x'c350000000000002'),
+  (x'c350000000002e06'),
+  (x'c352000000000003'),
+  (x'c352000000000004'),
+  (x'c358000000000003'),
+  (x'c358000000000004'),
+  (x'c35f000000000020'),
+  -- exercise fixed-point memmoves
+  (x'42dc12218377de66'),
+  (x'42a674e79c5fe51f'),
+  (x'4271f71fb04cb74c'),
+  (x'423cbe991a145879'),
+  (x'4206fee0e1a9e061'),
+  (x'41d26580b487e6b4'),
+  (x'419d6f34540ca453'),
+  (x'41678c29dcd6e9dc'),
+  (x'4132d687e3df217d'),
+  (x'40fe240c9fcb68c8'),
+  (x'40c81cd6e63c53d3'),
+  (x'40934a4584fd0fdc'),
+  (x'405edd3c07fb4c93'),
+  (x'4028b0fcd32f7076'),
+  (x'3ff3c0ca428c59f8'),
+  -- these cases come from the upstream's testsuite
+  -- LotsOfTrailingZeros)
+  (x'3e60000000000000'),
+  -- Regression
+  (x'c352bd2668e077c4'),
+  (x'434018601510c000'),
+  (x'43d055dc36f24000'),
+  (x'43e052961c6f8000'),
+  (x'3ff3c0ca2a5b1d5d'),
+  -- LooksLikePow5
+  (x'4830f0cf064dd592'),
+  (x'4840f0cf064dd592'),
+  (x'4850f0cf064dd592'),
+  -- OutputLength
+  (x'3ff3333333333333'),
+  (x'3ff3ae147ae147ae'),
+  (x'3ff3be76c8b43958'),
+  (x'3ff3c083126e978d'),
+  (x'3ff3c0c1fc8f3238'),
+  (x'3ff3c0c9539b8887'),
+  (x'3ff3c0ca2a5b1d5d'),
+  (x'3ff3c0ca4283de1b'),
+  (x'3ff3c0ca43db770a'),
+  (x'3ff3c0ca428abd53'),
+  (x'3ff3c0ca428c1d2b'),
+  (x'3ff3c0ca428c51f2'),
+  (x'3ff3c0ca428c58fc'),
+  (x'3ff3c0ca428c59dd'),
+  (x'3ff3c0ca428c59f8'),
+  (x'3ff3c0ca428c59fb'),
+  -- 32-bit chunking
+  (x'40112e0be8047a7d'),
+  (x'40112e0be815a889'),
+  (x'40112e0be826d695'),
+  (x'40112e0be83804a1'),
+  (x'40112e0be84932ad'),
+  -- MinMaxShift
+  (x'0040000000000000'),
+  (x'007fffffffffffff'),
+  (x'0290000000000000'),
+  (x'029fffffffffffff'),
+  (x'4350000000000000'),
+  (x'435fffffffffffff'),
+  (x'1330000000000000'),
+  (x'133fffffffffffff'),
+  (x'3a6fa7161a4d6e0c')
+)
+select float8send(flt) as ibits,
+       flt,
+       flt::text::float8 as r_flt,
+       float8send(flt::text::float8) as obits,
+       float8send(flt::text::float8) = float8send(flt) as correct
+  from (select bits::bigint::xfloat8::float8 as flt
+          from testdata
+   offset 0) s;
+       ibits        |           flt           |          r_flt          |       obits        | correct 
+--------------------+-------------------------+-------------------------+--------------------+---------
+ \x0000000000000000 |                       0 |                       0 | \x0000000000000000 | t
+ \x0010000000000000 | 2.2250738585072014e-308 | 2.2250738585072014e-308 | \x0010000000000000 | t
+ \x0010000000000001 |  2.225073858507202e-308 |  2.225073858507202e-308 | \x0010000000000001 | t
+ \x0010000000000002 | 2.2250738585072024e-308 | 2.2250738585072024e-308 | \x0010000000000002 | t
+ \x0018000000000000 |  3.337610787760802e-308 |  3.337610787760802e-308 | \x0018000000000000 | t
+ \x3ddb7cdfd9d7bdba |   9.999999999999999e-11 |   9.999999999999999e-11 | \x3ddb7cdfd9d7bdba | t
+ \x3ddb7cdfd9d7bdbb |                   1e-10 |                   1e-10 | \x3ddb7cdfd9d7bdbb | t
+ \x3ddb7cdfd9d7bdbc |  1.0000000000000002e-10 |  1.0000000000000002e-10 | \x3ddb7cdfd9d7bdbc | t
+ \x3e112e0be826d694 |   9.999999999999999e-10 |   9.999999999999999e-10 | \x3e112e0be826d694 | t
+ \x3e112e0be826d695 |                   1e-09 |                   1e-09 | \x3e112e0be826d695 | t
+ \x3e112e0be826d696 |  1.0000000000000003e-09 |  1.0000000000000003e-09 | \x3e112e0be826d696 | t
+ \x3e45798ee2308c39 |   9.999999999999999e-09 |   9.999999999999999e-09 | \x3e45798ee2308c39 | t
+ \x3e45798ee2308c3a |                   1e-08 |                   1e-08 | \x3e45798ee2308c3a | t
+ \x3e45798ee2308c3b |  1.0000000000000002e-08 |  1.0000000000000002e-08 | \x3e45798ee2308c3b | t
+ \x3e7ad7f29abcaf47 |   9.999999999999998e-08 |   9.999999999999998e-08 | \x3e7ad7f29abcaf47 | t
+ \x3e7ad7f29abcaf48 |                   1e-07 |                   1e-07 | \x3e7ad7f29abcaf48 | t
+ \x3e7ad7f29abcaf49 |  1.0000000000000001e-07 |  1.0000000000000001e-07 | \x3e7ad7f29abcaf49 | t
+ \x3eb0c6f7a0b5ed8c |   9.999999999999997e-07 |   9.999999999999997e-07 | \x3eb0c6f7a0b5ed8c | t
+ \x3eb0c6f7a0b5ed8d |                   1e-06 |                   1e-06 | \x3eb0c6f7a0b5ed8d | t
+ \x3eb0c6f7a0b5ed8e |  1.0000000000000002e-06 |  1.0000000000000002e-06 | \x3eb0c6f7a0b5ed8e | t
+ \x3ee4f8b588e368ef |   9.999999999999997e-06 |   9.999999999999997e-06 | \x3ee4f8b588e368ef | t
+ \x3ee4f8b588e368f0 |   9.999999999999999e-06 |   9.999999999999999e-06 | \x3ee4f8b588e368f0 | t
+ \x3ee4f8b588e368f1 |                   1e-05 |                   1e-05 | \x3ee4f8b588e368f1 | t
+ \x3f1a36e2eb1c432c |   9.999999999999999e-05 |   9.999999999999999e-05 | \x3f1a36e2eb1c432c | t
+ \x3f1a36e2eb1c432d |                  0.0001 |                  0.0001 | \x3f1a36e2eb1c432d | t
+ \x3f1a36e2eb1c432e |  0.00010000000000000002 |  0.00010000000000000002 | \x3f1a36e2eb1c432e | t
+ \x3f50624dd2f1a9fb |   0.0009999999999999998 |   0.0009999999999999998 | \x3f50624dd2f1a9fb | t
+ \x3f50624dd2f1a9fc |                   0.001 |                   0.001 | \x3f50624dd2f1a9fc | t
+ \x3f50624dd2f1a9fd |   0.0010000000000000002 |   0.0010000000000000002 | \x3f50624dd2f1a9fd | t
+ \x3f847ae147ae147a |    0.009999999999999998 |    0.009999999999999998 | \x3f847ae147ae147a | t
+ \x3f847ae147ae147b |                    0.01 |                    0.01 | \x3f847ae147ae147b | t
+ \x3f847ae147ae147c |    0.010000000000000002 |    0.010000000000000002 | \x3f847ae147ae147c | t
+ \x3fb9999999999999 |     0.09999999999999999 |     0.09999999999999999 | \x3fb9999999999999 | t
+ \x3fb999999999999a |                     0.1 |                     0.1 | \x3fb999999999999a | t
+ \x3fb999999999999b |     0.10000000000000002 |     0.10000000000000002 | \x3fb999999999999b | t
+ \x3feffffffffffff0 |      0.9999999999999982 |      0.9999999999999982 | \x3feffffffffffff0 | t
+ \x3feffffffffffff1 |      0.9999999999999983 |      0.9999999999999983 | \x3feffffffffffff1 | t
+ \x3feffffffffffff2 |      0.9999999999999984 |      0.9999999999999984 | \x3feffffffffffff2 | t
+ \x3feffffffffffff3 |      0.9999999999999986 |      0.9999999999999986 | \x3feffffffffffff3 | t
+ \x3feffffffffffff4 |      0.9999999999999987 |      0.9999999999999987 | \x3feffffffffffff4 | t
+ \x3feffffffffffff5 |      0.9999999999999988 |      0.9999999999999988 | \x3feffffffffffff5 | t
+ \x3feffffffffffff6 |      0.9999999999999989 |      0.9999999999999989 | \x3feffffffffffff6 | t
+ \x3feffffffffffff7 |       0.999999999999999 |       0.999999999999999 | \x3feffffffffffff7 | t
+ \x3feffffffffffff8 |      0.9999999999999991 |      0.9999999999999991 | \x3feffffffffffff8 | t
+ \x3feffffffffffff9 |      0.9999999999999992 |      0.9999999999999992 | \x3feffffffffffff9 | t
+ \x3feffffffffffffa |      0.9999999999999993 |      0.9999999999999993 | \x3feffffffffffffa | t
+ \x3feffffffffffffb |      0.9999999999999994 |      0.9999999999999994 | \x3feffffffffffffb | t
+ \x3feffffffffffffc |      0.9999999999999996 |      0.9999999999999996 | \x3feffffffffffffc | t
+ \x3feffffffffffffd |      0.9999999999999997 |      0.9999999999999997 | \x3feffffffffffffd | t
+ \x3feffffffffffffe |      0.9999999999999998 |      0.9999999999999998 | \x3feffffffffffffe | t
+ \x3fefffffffffffff |      0.9999999999999999 |      0.9999999999999999 | \x3fefffffffffffff | t
+ \x3ff0000000000000 |                       1 |                       1 | \x3ff0000000000000 | t
+ \x3ff0000000000001 |      1.0000000000000002 |      1.0000000000000002 | \x3ff0000000000001 | t
+ \x3ff0000000000002 |      1.0000000000000004 |      1.0000000000000004 | \x3ff0000000000002 | t
+ \x3ff0000000000003 |      1.0000000000000007 |      1.0000000000000007 | \x3ff0000000000003 | t
+ \x3ff0000000000004 |      1.0000000000000009 |      1.0000000000000009 | \x3ff0000000000004 | t
+ \x3ff0000000000005 |       1.000000000000001 |       1.000000000000001 | \x3ff0000000000005 | t
+ \x3ff0000000000006 |      1.0000000000000013 |      1.0000000000000013 | \x3ff0000000000006 | t
+ \x3ff0000000000007 |      1.0000000000000016 |      1.0000000000000016 | \x3ff0000000000007 | t
+ \x3ff0000000000008 |      1.0000000000000018 |      1.0000000000000018 | \x3ff0000000000008 | t
+ \x3ff0000000000009 |       1.000000000000002 |       1.000000000000002 | \x3ff0000000000009 | t
+ \x3ff921fb54442d18 |      1.5707963267948966 |      1.5707963267948966 | \x3ff921fb54442d18 | t
+ \x4005bf0a8b14576a |      2.7182818284590455 |      2.7182818284590455 | \x4005bf0a8b14576a | t
+ \x400921fb54442d18 |       3.141592653589793 |       3.141592653589793 | \x400921fb54442d18 | t
+ \x4023ffffffffffff |       9.999999999999998 |       9.999999999999998 | \x4023ffffffffffff | t
+ \x4024000000000000 |                      10 |                      10 | \x4024000000000000 | t
+ \x4024000000000001 |      10.000000000000002 |      10.000000000000002 | \x4024000000000001 | t
+ \x4058ffffffffffff |       99.99999999999999 |       99.99999999999999 | \x4058ffffffffffff | t
+ \x4059000000000000 |                     100 |                     100 | \x4059000000000000 | t
+ \x4059000000000001 |      100.00000000000001 |      100.00000000000001 | \x4059000000000001 | t
+ \x408f3fffffffffff |       999.9999999999999 |       999.9999999999999 | \x408f3fffffffffff | t
+ \x408f400000000000 |                    1000 |                    1000 | \x408f400000000000 | t
+ \x408f400000000001 |      1000.0000000000001 |      1000.0000000000001 | \x408f400000000001 | t
+ \x40c387ffffffffff |       9999.999999999998 |       9999.999999999998 | \x40c387ffffffffff | t
+ \x40c3880000000000 |                   10000 |                   10000 | \x40c3880000000000 | t
+ \x40c3880000000001 |      10000.000000000002 |      10000.000000000002 | \x40c3880000000001 | t
+ \x40f869ffffffffff |       99999.99999999999 |       99999.99999999999 | \x40f869ffffffffff | t
+ \x40f86a0000000000 |                  100000 |                  100000 | \x40f86a0000000000 | t
+ \x40f86a0000000001 |      100000.00000000001 |      100000.00000000001 | \x40f86a0000000001 | t
+ \x412e847fffffffff |       999999.9999999999 |       999999.9999999999 | \x412e847fffffffff | t
+ \x412e848000000000 |                 1000000 |                 1000000 | \x412e848000000000 | t
+ \x412e848000000001 |      1000000.0000000001 |      1000000.0000000001 | \x412e848000000001 | t
+ \x416312cfffffffff |       9999999.999999998 |       9999999.999999998 | \x416312cfffffffff | t
+ \x416312d000000000 |                10000000 |                10000000 | \x416312d000000000 | t
+ \x416312d000000001 |      10000000.000000002 |      10000000.000000002 | \x416312d000000001 | t
+ \x4197d783ffffffff |       99999999.99999999 |       99999999.99999999 | \x4197d783ffffffff | t
+ \x4197d78400000000 |               100000000 |               100000000 | \x4197d78400000000 | t
+ \x4197d78400000001 |      100000000.00000001 |      100000000.00000001 | \x4197d78400000001 | t
+ \x41cdcd64ffffffff |       999999999.9999999 |       999999999.9999999 | \x41cdcd64ffffffff | t
+ \x41cdcd6500000000 |              1000000000 |              1000000000 | \x41cdcd6500000000 | t
+ \x41cdcd6500000001 |      1000000000.0000001 |      1000000000.0000001 | \x41cdcd6500000001 | t
+ \x4202a05f1fffffff |       9999999999.999998 |       9999999999.999998 | \x4202a05f1fffffff | t
+ \x4202a05f20000000 |             10000000000 |             10000000000 | \x4202a05f20000000 | t
+ \x4202a05f20000001 |      10000000000.000002 |      10000000000.000002 | \x4202a05f20000001 | t
+ \x42374876e7ffffff |       99999999999.99998 |       99999999999.99998 | \x42374876e7ffffff | t
+ \x42374876e8000000 |            100000000000 |            100000000000 | \x42374876e8000000 | t
+ \x42374876e8000001 |      100000000000.00002 |      100000000000.00002 | \x42374876e8000001 | t
+ \x426d1a94a1ffffff |       999999999999.9999 |       999999999999.9999 | \x426d1a94a1ffffff | t
+ \x426d1a94a2000000 |           1000000000000 |           1000000000000 | \x426d1a94a2000000 | t
+ \x426d1a94a2000001 |      1000000000000.0001 |      1000000000000.0001 | \x426d1a94a2000001 | t
+ \x42a2309ce53fffff |       9999999999999.998 |       9999999999999.998 | \x42a2309ce53fffff | t
+ \x42a2309ce5400000 |          10000000000000 |          10000000000000 | \x42a2309ce5400000 | t
+ \x42a2309ce5400001 |      10000000000000.002 |      10000000000000.002 | \x42a2309ce5400001 | t
+ \x42d6bcc41e8fffff |       99999999999999.98 |       99999999999999.98 | \x42d6bcc41e8fffff | t
+ \x42d6bcc41e900000 |         100000000000000 |         100000000000000 | \x42d6bcc41e900000 | t
+ \x42d6bcc41e900001 |      100000000000000.02 |      100000000000000.02 | \x42d6bcc41e900001 | t
+ \x430c6bf52633ffff |       999999999999999.9 |       999999999999999.9 | \x430c6bf52633ffff | t
+ \x430c6bf526340000 |                   1e+15 |                   1e+15 | \x430c6bf526340000 | t
+ \x430c6bf526340001 |  1.0000000000000001e+15 |  1.0000000000000001e+15 | \x430c6bf526340001 | t
+ \x4341c37937e07fff |   9.999999999999998e+15 |   9.999999999999998e+15 | \x4341c37937e07fff | t
+ \x4341c37937e08000 |                   1e+16 |                   1e+16 | \x4341c37937e08000 | t
+ \x4341c37937e08001 |  1.0000000000000002e+16 |  1.0000000000000002e+16 | \x4341c37937e08001 | t
+ \x4376345785d89fff |   9.999999999999998e+16 |   9.999999999999998e+16 | \x4376345785d89fff | t
+ \x4376345785d8a000 |                   1e+17 |                   1e+17 | \x4376345785d8a000 | t
+ \x4376345785d8a001 |  1.0000000000000002e+17 |  1.0000000000000002e+17 | \x4376345785d8a001 | t
+ \x43abc16d674ec7ff |   9.999999999999999e+17 |   9.999999999999999e+17 | \x43abc16d674ec7ff | t
+ \x43abc16d674ec800 |                   1e+18 |                   1e+18 | \x43abc16d674ec800 | t
+ \x43abc16d674ec801 |  1.0000000000000001e+18 |  1.0000000000000001e+18 | \x43abc16d674ec801 | t
+ \x43e158e460913cff |   9.999999999999998e+18 |   9.999999999999998e+18 | \x43e158e460913cff | t
+ \x43e158e460913d00 |                   1e+19 |                   1e+19 | \x43e158e460913d00 | t
+ \x43e158e460913d01 |  1.0000000000000002e+19 |  1.0000000000000002e+19 | \x43e158e460913d01 | t
+ \x4415af1d78b58c3f |   9.999999999999998e+19 |   9.999999999999998e+19 | \x4415af1d78b58c3f | t
+ \x4415af1d78b58c40 |                   1e+20 |                   1e+20 | \x4415af1d78b58c40 | t
+ \x4415af1d78b58c41 |  1.0000000000000002e+20 |  1.0000000000000002e+20 | \x4415af1d78b58c41 | t
+ \x444b1ae4d6e2ef4f |   9.999999999999999e+20 |   9.999999999999999e+20 | \x444b1ae4d6e2ef4f | t
+ \x444b1ae4d6e2ef50 |                   1e+21 |                   1e+21 | \x444b1ae4d6e2ef50 | t
+ \x444b1ae4d6e2ef51 |  1.0000000000000001e+21 |  1.0000000000000001e+21 | \x444b1ae4d6e2ef51 | t
+ \x4480f0cf064dd591 |   9.999999999999998e+21 |   9.999999999999998e+21 | \x4480f0cf064dd591 | t
+ \x4480f0cf064dd592 |                   1e+22 |                   1e+22 | \x4480f0cf064dd592 | t
+ \x4480f0cf064dd593 |  1.0000000000000002e+22 |  1.0000000000000002e+22 | \x4480f0cf064dd593 | t
+ \x44b52d02c7e14af5 |   9.999999999999997e+22 |   9.999999999999997e+22 | \x44b52d02c7e14af5 | t
+ \x44b52d02c7e14af6 |   9.999999999999999e+22 |   9.999999999999999e+22 | \x44b52d02c7e14af6 | t
+ \x44b52d02c7e14af7 |  1.0000000000000001e+23 |  1.0000000000000001e+23 | \x44b52d02c7e14af7 | t
+ \x44ea784379d99db3 |   9.999999999999998e+23 |   9.999999999999998e+23 | \x44ea784379d99db3 | t
+ \x44ea784379d99db4 |                   1e+24 |                   1e+24 | \x44ea784379d99db4 | t
+ \x44ea784379d99db5 |  1.0000000000000001e+24 |  1.0000000000000001e+24 | \x44ea784379d99db5 | t
+ \x45208b2a2c280290 |   9.999999999999999e+24 |   9.999999999999999e+24 | \x45208b2a2c280290 | t
+ \x45208b2a2c280291 |                   1e+25 |                   1e+25 | \x45208b2a2c280291 | t
+ \x45208b2a2c280292 |  1.0000000000000003e+25 |  1.0000000000000003e+25 | \x45208b2a2c280292 | t
+ \x7feffffffffffffe | 1.7976931348623155e+308 | 1.7976931348623155e+308 | \x7feffffffffffffe | t
+ \x7fefffffffffffff | 1.7976931348623157e+308 | 1.7976931348623157e+308 | \x7fefffffffffffff | t
+ \x4350000000000002 |  1.8014398509481992e+16 |  1.8014398509481992e+16 | \x4350000000000002 | t
+ \x4350000000002e06 |  1.8014398509529112e+16 |  1.8014398509529112e+16 | \x4350000000002e06 | t
+ \x4352000000000003 |  2.0266198323167244e+16 |  2.0266198323167244e+16 | \x4352000000000003 | t
+ \x4352000000000004 |  2.0266198323167248e+16 |  2.0266198323167248e+16 | \x4352000000000004 | t
+ \x4358000000000003 |  2.7021597764222988e+16 |  2.7021597764222988e+16 | \x4358000000000003 | t
+ \x4358000000000004 |  2.7021597764222992e+16 |  2.7021597764222992e+16 | \x4358000000000004 | t
+ \x435f000000000020 |  3.4902897112121472e+16 |  3.4902897112121472e+16 | \x435f000000000020 | t
+ \xc350000000000002 | -1.8014398509481992e+16 | -1.8014398509481992e+16 | \xc350000000000002 | t
+ \xc350000000002e06 | -1.8014398509529112e+16 | -1.8014398509529112e+16 | \xc350000000002e06 | t
+ \xc352000000000003 | -2.0266198323167244e+16 | -2.0266198323167244e+16 | \xc352000000000003 | t
+ \xc352000000000004 | -2.0266198323167248e+16 | -2.0266198323167248e+16 | \xc352000000000004 | t
+ \xc358000000000003 | -2.7021597764222988e+16 | -2.7021597764222988e+16 | \xc358000000000003 | t
+ \xc358000000000004 | -2.7021597764222992e+16 | -2.7021597764222992e+16 | \xc358000000000004 | t
+ \xc35f000000000020 | -3.4902897112121472e+16 | -3.4902897112121472e+16 | \xc35f000000000020 | t
+ \x42dc12218377de66 |       123456789012345.6 |       123456789012345.6 | \x42dc12218377de66 | t
+ \x42a674e79c5fe51f |       12345678901234.56 |       12345678901234.56 | \x42a674e79c5fe51f | t
+ \x4271f71fb04cb74c |       1234567890123.456 |       1234567890123.456 | \x4271f71fb04cb74c | t
+ \x423cbe991a145879 |       123456789012.3456 |       123456789012.3456 | \x423cbe991a145879 | t
+ \x4206fee0e1a9e061 |       12345678901.23456 |       12345678901.23456 | \x4206fee0e1a9e061 | t
+ \x41d26580b487e6b4 |       1234567890.123456 |       1234567890.123456 | \x41d26580b487e6b4 | t
+ \x419d6f34540ca453 |       123456789.0123456 |       123456789.0123456 | \x419d6f34540ca453 | t
+ \x41678c29dcd6e9dc |       12345678.90123456 |       12345678.90123456 | \x41678c29dcd6e9dc | t
+ \x4132d687e3df217d |       1234567.890123456 |       1234567.890123456 | \x4132d687e3df217d | t
+ \x40fe240c9fcb68c8 |       123456.7890123456 |       123456.7890123456 | \x40fe240c9fcb68c8 | t
+ \x40c81cd6e63c53d3 |       12345.67890123456 |       12345.67890123456 | \x40c81cd6e63c53d3 | t
+ \x40934a4584fd0fdc |       1234.567890123456 |       1234.567890123456 | \x40934a4584fd0fdc | t
+ \x405edd3c07fb4c93 |       123.4567890123456 |       123.4567890123456 | \x405edd3c07fb4c93 | t
+ \x4028b0fcd32f7076 |       12.34567890123456 |       12.34567890123456 | \x4028b0fcd32f7076 | t
+ \x3ff3c0ca428c59f8 |       1.234567890123456 |       1.234567890123456 | \x3ff3c0ca428c59f8 | t
+ \x3e60000000000000 |  2.9802322387695312e-08 |  2.9802322387695312e-08 | \x3e60000000000000 | t
+ \xc352bd2668e077c4 | -2.1098088986959632e+16 | -2.1098088986959632e+16 | \xc352bd2668e077c4 | t
+ \x434018601510c000 |     9.0608011534336e+15 |     9.0608011534336e+15 | \x434018601510c000 | t
+ \x43d055dc36f24000 |   4.708356024711512e+18 |   4.708356024711512e+18 | \x43d055dc36f24000 | t
+ \x43e052961c6f8000 |   9.409340012568248e+18 |   9.409340012568248e+18 | \x43e052961c6f8000 | t
+ \x3ff3c0ca2a5b1d5d |               1.2345678 |               1.2345678 | \x3ff3c0ca2a5b1d5d | t
+ \x4830f0cf064dd592 |   5.764607523034235e+39 |   5.764607523034235e+39 | \x4830f0cf064dd592 | t
+ \x4840f0cf064dd592 |   1.152921504606847e+40 |   1.152921504606847e+40 | \x4840f0cf064dd592 | t
+ \x4850f0cf064dd592 |   2.305843009213694e+40 |   2.305843009213694e+40 | \x4850f0cf064dd592 | t
+ \x3ff3333333333333 |                     1.2 |                     1.2 | \x3ff3333333333333 | t
+ \x3ff3ae147ae147ae |                    1.23 |                    1.23 | \x3ff3ae147ae147ae | t
+ \x3ff3be76c8b43958 |                   1.234 |                   1.234 | \x3ff3be76c8b43958 | t
+ \x3ff3c083126e978d |                  1.2345 |                  1.2345 | \x3ff3c083126e978d | t
+ \x3ff3c0c1fc8f3238 |                 1.23456 |                 1.23456 | \x3ff3c0c1fc8f3238 | t
+ \x3ff3c0c9539b8887 |                1.234567 |                1.234567 | \x3ff3c0c9539b8887 | t
+ \x3ff3c0ca2a5b1d5d |               1.2345678 |               1.2345678 | \x3ff3c0ca2a5b1d5d | t
+ \x3ff3c0ca4283de1b |              1.23456789 |              1.23456789 | \x3ff3c0ca4283de1b | t
+ \x3ff3c0ca43db770a |             1.234567895 |             1.234567895 | \x3ff3c0ca43db770a | t
+ \x3ff3c0ca428abd53 |            1.2345678901 |            1.2345678901 | \x3ff3c0ca428abd53 | t
+ \x3ff3c0ca428c1d2b |           1.23456789012 |           1.23456789012 | \x3ff3c0ca428c1d2b | t
+ \x3ff3c0ca428c51f2 |          1.234567890123 |          1.234567890123 | \x3ff3c0ca428c51f2 | t
+ \x3ff3c0ca428c58fc |         1.2345678901234 |         1.2345678901234 | \x3ff3c0ca428c58fc | t
+ \x3ff3c0ca428c59dd |        1.23456789012345 |        1.23456789012345 | \x3ff3c0ca428c59dd | t
+ \x3ff3c0ca428c59f8 |       1.234567890123456 |       1.234567890123456 | \x3ff3c0ca428c59f8 | t
+ \x3ff3c0ca428c59fb |      1.2345678901234567 |      1.2345678901234567 | \x3ff3c0ca428c59fb | t
+ \x40112e0be8047a7d |             4.294967294 |             4.294967294 | \x40112e0be8047a7d | t
+ \x40112e0be815a889 |             4.294967295 |             4.294967295 | \x40112e0be815a889 | t
+ \x40112e0be826d695 |             4.294967296 |             4.294967296 | \x40112e0be826d695 | t
+ \x40112e0be83804a1 |             4.294967297 |             4.294967297 | \x40112e0be83804a1 | t
+ \x40112e0be84932ad |             4.294967298 |             4.294967298 | \x40112e0be84932ad | t
+ \x0040000000000000 | 1.7800590868057611e-307 | 1.7800590868057611e-307 | \x0040000000000000 | t
+ \x007fffffffffffff | 2.8480945388892175e-306 | 2.8480945388892175e-306 | \x007fffffffffffff | t
+ \x0290000000000000 |  2.446494580089078e-296 |  2.446494580089078e-296 | \x0290000000000000 | t
+ \x029fffffffffffff | 4.8929891601781557e-296 | 4.8929891601781557e-296 | \x029fffffffffffff | t
+ \x4350000000000000 |  1.8014398509481984e+16 |  1.8014398509481984e+16 | \x4350000000000000 | t
+ \x435fffffffffffff |  3.6028797018963964e+16 |  3.6028797018963964e+16 | \x435fffffffffffff | t
+ \x1330000000000000 |  2.900835519859558e-216 |  2.900835519859558e-216 | \x1330000000000000 | t
+ \x133fffffffffffff |  5.801671039719115e-216 |  5.801671039719115e-216 | \x133fffffffffffff | t
+ \x3a6fa7161a4d6e0c |   3.196104012172126e-27 |   3.196104012172126e-27 | \x3a6fa7161a4d6e0c | t
+(209 rows)
+
+-- clean up, lest opr_sanity complain
+\set VERBOSITY terse
+drop type xfloat8 cascade;
+NOTICE:  drop cascades to 6 other objects
+\set VERBOSITY default
+--
index 75c0bf389b92f6627ff2d032f414b8063b305afd..c3a6f5331fea630cd8e08e11a701877ad49e427b 100644 (file)
@@ -24,6 +24,13 @@ SELECT '-10e-400'::float8;
 ERROR:  "-10e-400" is out of range for type double precision
 LINE 1: SELECT '-10e-400'::float8;
                ^
+-- test smallest normalized input
+SELECT float8send('2.2250738585072014E-308'::float8);
+     float8send     
+--------------------
+ \x0010000000000000
+(1 row)
+
 -- bad input
 INSERT INTO FLOAT8_TBL(f1) VALUES ('');
 ERROR:  invalid input syntax for type double precision: ""
@@ -209,7 +216,7 @@ SELECT '' AS three, f.f1, f.f1 / '-10' AS x
    WHERE f.f1 > '0.0';
  three |          f1          |           x           
 -------+----------------------+-----------------------
-       |               1004.3 |               -100.43
+       |               1004.3 |   -100.42999999999999
        | 1.2345678901234e+200 | -1.2345678901234e+199
        | 1.2345678901234e-200 | -1.2345678901234e-201
 (3 rows)
@@ -226,9 +233,9 @@ SELECT '' AS three, f.f1, f.f1 - '-10' AS x
 
 SELECT '' AS one, f.f1 ^ '2.0' AS square_f1
    FROM FLOAT8_TBL f where f.f1 = '1004.3';
- one | square_f1  
------+------------
-     | 1008618.49
+ one |     square_f1      
+-----+--------------------
+     | 1008618.4899999999
 (1 row)
 
 -- absolute value
@@ -310,6 +317,8 @@ select sign(f1) as sign_f1 from float8_tbl f;
        1
 (5 rows)
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
 -- square root
 SELECT sqrt(float8 '64') AS eight;
  eight 
@@ -445,6 +454,7 @@ SELECT '' AS five, * FROM FLOAT8_TBL;
       | -1.2345678901234e-200
 (5 rows)
 
+RESET extra_float_digits;
 -- test for over- and underflow
 INSERT INTO FLOAT8_TBL(f1) VALUES ('10e400');
 ERROR:  "10e400" is out of range for type double precision
@@ -530,7 +540,6 @@ SELECT '-9223372036854775808.5'::float8::int8;
 SELECT '-9223372036854780000'::float8::int8;
 ERROR:  bigint out of range
 -- test exact cases for trigonometric functions in degrees
-SET extra_float_digits = 3;
 SELECT x,
        sind(x),
        sind(x) IN (-1,-0.5,0,0.5,1) AS sind_exact
@@ -632,4 +641,432 @@ FROM (SELECT 10*cosd(a), 10*sind(a)
   10 |   0 |      0 | t
 (5 rows)
 
-RESET extra_float_digits;
+--
+-- test output (and round-trip safety) of various values.
+-- To ensure we're testing what we think we're testing, start with
+-- float values specified by bit patterns (as a useful side effect,
+-- this means we'll fail on non-IEEE platforms).
+create type xfloat8;
+create function xfloat8in(cstring) returns xfloat8 immutable strict
+  language internal as 'int8in';
+NOTICE:  return type xfloat8 is only a shell
+create function xfloat8out(xfloat8) returns cstring immutable strict
+  language internal as 'int8out';
+NOTICE:  argument type xfloat8 is only a shell
+create type xfloat8 (input = xfloat8in, output = xfloat8out, like = float8);
+create cast (xfloat8 as float8) without function;
+create cast (float8 as xfloat8) without function;
+create cast (xfloat8 as bigint) without function;
+create cast (bigint as xfloat8) without function;
+-- float8: seeeeeee eeeeeeee eeeeeeee mmmmmmmm mmmmmmmm(x4)
+-- we don't care to assume the platform's strtod() handles subnormals
+-- correctly; those are "use at your own risk". However we do test
+-- subnormal outputs, since those are under our control.
+with testdata(bits) as (values
+  -- small subnormals
+  (x'0000000000000001'),
+  (x'0000000000000002'), (x'0000000000000003'),
+  (x'0000000000001000'), (x'0000000100000000'),
+  (x'0000010000000000'), (x'0000010100000000'),
+  (x'0000400000000000'), (x'0000400100000000'),
+  (x'0000800000000000'), (x'0000800000000001'),
+  -- these values taken from upstream testsuite
+  (x'00000000000f4240'),
+  (x'00000000016e3600'),
+  (x'0000008cdcdea440'),
+  -- borderline between subnormal and normal
+  (x'000ffffffffffff0'), (x'000ffffffffffff1'),
+  (x'000ffffffffffffe'), (x'000fffffffffffff'))
+select float8send(flt) as ibits,
+       flt
+  from (select bits::bigint::xfloat8::float8 as flt
+          from testdata
+   offset 0) s;
+       ibits        |           flt           
+--------------------+-------------------------
+ \x0000000000000001 |                  5e-324
+ \x0000000000000002 |                  1e-323
+ \x0000000000000003 |                1.5e-323
+ \x0000000000001000 |             2.0237e-320
+ \x0000000100000000 |        2.121995791e-314
+ \x0000010000000000 |      5.43230922487e-312
+ \x0000010100000000 |      5.45352918278e-312
+ \x0000400000000000 |    3.4766779039175e-310
+ \x0000400100000000 |    3.4768901034966e-310
+ \x0000800000000000 |     6.953355807835e-310
+ \x0000800000000001 |   6.95335580783505e-310
+ \x00000000000f4240 |           4.940656e-318
+ \x00000000016e3600 |         1.18575755e-316
+ \x0000008cdcdea440 |     2.989102097996e-312
+ \x000ffffffffffff0 | 2.2250738585071935e-308
+ \x000ffffffffffff1 |  2.225073858507194e-308
+ \x000ffffffffffffe | 2.2250738585072004e-308
+ \x000fffffffffffff |  2.225073858507201e-308
+(18 rows)
+
+-- round-trip tests
+with testdata(bits) as (values
+  (x'0000000000000000'),
+  -- smallest normal values
+  (x'0010000000000000'), (x'0010000000000001'),
+  (x'0010000000000002'), (x'0018000000000000'),
+  --
+  (x'3ddb7cdfd9d7bdba'), (x'3ddb7cdfd9d7bdbb'), (x'3ddb7cdfd9d7bdbc'),
+  (x'3e112e0be826d694'), (x'3e112e0be826d695'), (x'3e112e0be826d696'),
+  (x'3e45798ee2308c39'), (x'3e45798ee2308c3a'), (x'3e45798ee2308c3b'),
+  (x'3e7ad7f29abcaf47'), (x'3e7ad7f29abcaf48'), (x'3e7ad7f29abcaf49'),
+  (x'3eb0c6f7a0b5ed8c'), (x'3eb0c6f7a0b5ed8d'), (x'3eb0c6f7a0b5ed8e'),
+  (x'3ee4f8b588e368ef'), (x'3ee4f8b588e368f0'), (x'3ee4f8b588e368f1'),
+  (x'3f1a36e2eb1c432c'), (x'3f1a36e2eb1c432d'), (x'3f1a36e2eb1c432e'),
+  (x'3f50624dd2f1a9fb'), (x'3f50624dd2f1a9fc'), (x'3f50624dd2f1a9fd'),
+  (x'3f847ae147ae147a'), (x'3f847ae147ae147b'), (x'3f847ae147ae147c'),
+  (x'3fb9999999999999'), (x'3fb999999999999a'), (x'3fb999999999999b'),
+  -- values very close to 1
+  (x'3feffffffffffff0'), (x'3feffffffffffff1'), (x'3feffffffffffff2'),
+  (x'3feffffffffffff3'), (x'3feffffffffffff4'), (x'3feffffffffffff5'),
+  (x'3feffffffffffff6'), (x'3feffffffffffff7'), (x'3feffffffffffff8'),
+  (x'3feffffffffffff9'), (x'3feffffffffffffa'), (x'3feffffffffffffb'),
+  (x'3feffffffffffffc'), (x'3feffffffffffffd'), (x'3feffffffffffffe'),
+  (x'3fefffffffffffff'),
+  (x'3ff0000000000000'),
+  (x'3ff0000000000001'), (x'3ff0000000000002'), (x'3ff0000000000003'),
+  (x'3ff0000000000004'), (x'3ff0000000000005'), (x'3ff0000000000006'),
+  (x'3ff0000000000007'), (x'3ff0000000000008'), (x'3ff0000000000009'),
+  --
+  (x'3ff921fb54442d18'),
+  (x'4005bf0a8b14576a'),
+  (x'400921fb54442d18'),
+  --
+  (x'4023ffffffffffff'), (x'4024000000000000'), (x'4024000000000001'),
+  (x'4058ffffffffffff'), (x'4059000000000000'), (x'4059000000000001'),
+  (x'408f3fffffffffff'), (x'408f400000000000'), (x'408f400000000001'),
+  (x'40c387ffffffffff'), (x'40c3880000000000'), (x'40c3880000000001'),
+  (x'40f869ffffffffff'), (x'40f86a0000000000'), (x'40f86a0000000001'),
+  (x'412e847fffffffff'), (x'412e848000000000'), (x'412e848000000001'),
+  (x'416312cfffffffff'), (x'416312d000000000'), (x'416312d000000001'),
+  (x'4197d783ffffffff'), (x'4197d78400000000'), (x'4197d78400000001'),
+  (x'41cdcd64ffffffff'), (x'41cdcd6500000000'), (x'41cdcd6500000001'),
+  (x'4202a05f1fffffff'), (x'4202a05f20000000'), (x'4202a05f20000001'),
+  (x'42374876e7ffffff'), (x'42374876e8000000'), (x'42374876e8000001'),
+  (x'426d1a94a1ffffff'), (x'426d1a94a2000000'), (x'426d1a94a2000001'),
+  (x'42a2309ce53fffff'), (x'42a2309ce5400000'), (x'42a2309ce5400001'),
+  (x'42d6bcc41e8fffff'), (x'42d6bcc41e900000'), (x'42d6bcc41e900001'),
+  (x'430c6bf52633ffff'), (x'430c6bf526340000'), (x'430c6bf526340001'),
+  (x'4341c37937e07fff'), (x'4341c37937e08000'), (x'4341c37937e08001'),
+  (x'4376345785d89fff'), (x'4376345785d8a000'), (x'4376345785d8a001'),
+  (x'43abc16d674ec7ff'), (x'43abc16d674ec800'), (x'43abc16d674ec801'),
+  (x'43e158e460913cff'), (x'43e158e460913d00'), (x'43e158e460913d01'),
+  (x'4415af1d78b58c3f'), (x'4415af1d78b58c40'), (x'4415af1d78b58c41'),
+  (x'444b1ae4d6e2ef4f'), (x'444b1ae4d6e2ef50'), (x'444b1ae4d6e2ef51'),
+  (x'4480f0cf064dd591'), (x'4480f0cf064dd592'), (x'4480f0cf064dd593'),
+  (x'44b52d02c7e14af5'), (x'44b52d02c7e14af6'), (x'44b52d02c7e14af7'),
+  (x'44ea784379d99db3'), (x'44ea784379d99db4'), (x'44ea784379d99db5'),
+  (x'45208b2a2c280290'), (x'45208b2a2c280291'), (x'45208b2a2c280292'),
+  --
+  (x'7feffffffffffffe'), (x'7fefffffffffffff'),
+  -- round to even tests (+ve)
+  (x'4350000000000002'),
+  (x'4350000000002e06'),
+  (x'4352000000000003'),
+  (x'4352000000000004'),
+  (x'4358000000000003'),
+  (x'4358000000000004'),
+  (x'435f000000000020'),
+  -- round to even tests (-ve)
+  (x'c350000000000002'),
+  (x'c350000000002e06'),
+  (x'c352000000000003'),
+  (x'c352000000000004'),
+  (x'c358000000000003'),
+  (x'c358000000000004'),
+  (x'c35f000000000020'),
+  -- exercise fixed-point memmoves
+  (x'42dc12218377de66'),
+  (x'42a674e79c5fe51f'),
+  (x'4271f71fb04cb74c'),
+  (x'423cbe991a145879'),
+  (x'4206fee0e1a9e061'),
+  (x'41d26580b487e6b4'),
+  (x'419d6f34540ca453'),
+  (x'41678c29dcd6e9dc'),
+  (x'4132d687e3df217d'),
+  (x'40fe240c9fcb68c8'),
+  (x'40c81cd6e63c53d3'),
+  (x'40934a4584fd0fdc'),
+  (x'405edd3c07fb4c93'),
+  (x'4028b0fcd32f7076'),
+  (x'3ff3c0ca428c59f8'),
+  -- these cases come from the upstream's testsuite
+  -- LotsOfTrailingZeros)
+  (x'3e60000000000000'),
+  -- Regression
+  (x'c352bd2668e077c4'),
+  (x'434018601510c000'),
+  (x'43d055dc36f24000'),
+  (x'43e052961c6f8000'),
+  (x'3ff3c0ca2a5b1d5d'),
+  -- LooksLikePow5
+  (x'4830f0cf064dd592'),
+  (x'4840f0cf064dd592'),
+  (x'4850f0cf064dd592'),
+  -- OutputLength
+  (x'3ff3333333333333'),
+  (x'3ff3ae147ae147ae'),
+  (x'3ff3be76c8b43958'),
+  (x'3ff3c083126e978d'),
+  (x'3ff3c0c1fc8f3238'),
+  (x'3ff3c0c9539b8887'),
+  (x'3ff3c0ca2a5b1d5d'),
+  (x'3ff3c0ca4283de1b'),
+  (x'3ff3c0ca43db770a'),
+  (x'3ff3c0ca428abd53'),
+  (x'3ff3c0ca428c1d2b'),
+  (x'3ff3c0ca428c51f2'),
+  (x'3ff3c0ca428c58fc'),
+  (x'3ff3c0ca428c59dd'),
+  (x'3ff3c0ca428c59f8'),
+  (x'3ff3c0ca428c59fb'),
+  -- 32-bit chunking
+  (x'40112e0be8047a7d'),
+  (x'40112e0be815a889'),
+  (x'40112e0be826d695'),
+  (x'40112e0be83804a1'),
+  (x'40112e0be84932ad'),
+  -- MinMaxShift
+  (x'0040000000000000'),
+  (x'007fffffffffffff'),
+  (x'0290000000000000'),
+  (x'029fffffffffffff'),
+  (x'4350000000000000'),
+  (x'435fffffffffffff'),
+  (x'1330000000000000'),
+  (x'133fffffffffffff'),
+  (x'3a6fa7161a4d6e0c')
+)
+select float8send(flt) as ibits,
+       flt,
+       flt::text::float8 as r_flt,
+       float8send(flt::text::float8) as obits,
+       float8send(flt::text::float8) = float8send(flt) as correct
+  from (select bits::bigint::xfloat8::float8 as flt
+          from testdata
+   offset 0) s;
+       ibits        |           flt           |          r_flt          |       obits        | correct 
+--------------------+-------------------------+-------------------------+--------------------+---------
+ \x0000000000000000 |                       0 |                       0 | \x0000000000000000 | t
+ \x0010000000000000 | 2.2250738585072014e-308 | 2.2250738585072014e-308 | \x0010000000000000 | t
+ \x0010000000000001 |  2.225073858507202e-308 |  2.225073858507202e-308 | \x0010000000000001 | t
+ \x0010000000000002 | 2.2250738585072024e-308 | 2.2250738585072024e-308 | \x0010000000000002 | t
+ \x0018000000000000 |  3.337610787760802e-308 |  3.337610787760802e-308 | \x0018000000000000 | t
+ \x3ddb7cdfd9d7bdba |   9.999999999999999e-11 |   9.999999999999999e-11 | \x3ddb7cdfd9d7bdba | t
+ \x3ddb7cdfd9d7bdbb |                   1e-10 |                   1e-10 | \x3ddb7cdfd9d7bdbb | t
+ \x3ddb7cdfd9d7bdbc |  1.0000000000000002e-10 |  1.0000000000000002e-10 | \x3ddb7cdfd9d7bdbc | t
+ \x3e112e0be826d694 |   9.999999999999999e-10 |   9.999999999999999e-10 | \x3e112e0be826d694 | t
+ \x3e112e0be826d695 |                   1e-09 |                   1e-09 | \x3e112e0be826d695 | t
+ \x3e112e0be826d696 |  1.0000000000000003e-09 |  1.0000000000000003e-09 | \x3e112e0be826d696 | t
+ \x3e45798ee2308c39 |   9.999999999999999e-09 |   9.999999999999999e-09 | \x3e45798ee2308c39 | t
+ \x3e45798ee2308c3a |                   1e-08 |                   1e-08 | \x3e45798ee2308c3a | t
+ \x3e45798ee2308c3b |  1.0000000000000002e-08 |  1.0000000000000002e-08 | \x3e45798ee2308c3b | t
+ \x3e7ad7f29abcaf47 |   9.999999999999998e-08 |   9.999999999999998e-08 | \x3e7ad7f29abcaf47 | t
+ \x3e7ad7f29abcaf48 |                   1e-07 |                   1e-07 | \x3e7ad7f29abcaf48 | t
+ \x3e7ad7f29abcaf49 |  1.0000000000000001e-07 |  1.0000000000000001e-07 | \x3e7ad7f29abcaf49 | t
+ \x3eb0c6f7a0b5ed8c |   9.999999999999997e-07 |   9.999999999999997e-07 | \x3eb0c6f7a0b5ed8c | t
+ \x3eb0c6f7a0b5ed8d |                   1e-06 |                   1e-06 | \x3eb0c6f7a0b5ed8d | t
+ \x3eb0c6f7a0b5ed8e |  1.0000000000000002e-06 |  1.0000000000000002e-06 | \x3eb0c6f7a0b5ed8e | t
+ \x3ee4f8b588e368ef |   9.999999999999997e-06 |   9.999999999999997e-06 | \x3ee4f8b588e368ef | t
+ \x3ee4f8b588e368f0 |   9.999999999999999e-06 |   9.999999999999999e-06 | \x3ee4f8b588e368f0 | t
+ \x3ee4f8b588e368f1 |                   1e-05 |                   1e-05 | \x3ee4f8b588e368f1 | t
+ \x3f1a36e2eb1c432c |   9.999999999999999e-05 |   9.999999999999999e-05 | \x3f1a36e2eb1c432c | t
+ \x3f1a36e2eb1c432d |                  0.0001 |                  0.0001 | \x3f1a36e2eb1c432d | t
+ \x3f1a36e2eb1c432e |  0.00010000000000000002 |  0.00010000000000000002 | \x3f1a36e2eb1c432e | t
+ \x3f50624dd2f1a9fb |   0.0009999999999999998 |   0.0009999999999999998 | \x3f50624dd2f1a9fb | t
+ \x3f50624dd2f1a9fc |                   0.001 |                   0.001 | \x3f50624dd2f1a9fc | t
+ \x3f50624dd2f1a9fd |   0.0010000000000000002 |   0.0010000000000000002 | \x3f50624dd2f1a9fd | t
+ \x3f847ae147ae147a |    0.009999999999999998 |    0.009999999999999998 | \x3f847ae147ae147a | t
+ \x3f847ae147ae147b |                    0.01 |                    0.01 | \x3f847ae147ae147b | t
+ \x3f847ae147ae147c |    0.010000000000000002 |    0.010000000000000002 | \x3f847ae147ae147c | t
+ \x3fb9999999999999 |     0.09999999999999999 |     0.09999999999999999 | \x3fb9999999999999 | t
+ \x3fb999999999999a |                     0.1 |                     0.1 | \x3fb999999999999a | t
+ \x3fb999999999999b |     0.10000000000000002 |     0.10000000000000002 | \x3fb999999999999b | t
+ \x3feffffffffffff0 |      0.9999999999999982 |      0.9999999999999982 | \x3feffffffffffff0 | t
+ \x3feffffffffffff1 |      0.9999999999999983 |      0.9999999999999983 | \x3feffffffffffff1 | t
+ \x3feffffffffffff2 |      0.9999999999999984 |      0.9999999999999984 | \x3feffffffffffff2 | t
+ \x3feffffffffffff3 |      0.9999999999999986 |      0.9999999999999986 | \x3feffffffffffff3 | t
+ \x3feffffffffffff4 |      0.9999999999999987 |      0.9999999999999987 | \x3feffffffffffff4 | t
+ \x3feffffffffffff5 |      0.9999999999999988 |      0.9999999999999988 | \x3feffffffffffff5 | t
+ \x3feffffffffffff6 |      0.9999999999999989 |      0.9999999999999989 | \x3feffffffffffff6 | t
+ \x3feffffffffffff7 |       0.999999999999999 |       0.999999999999999 | \x3feffffffffffff7 | t
+ \x3feffffffffffff8 |      0.9999999999999991 |      0.9999999999999991 | \x3feffffffffffff8 | t
+ \x3feffffffffffff9 |      0.9999999999999992 |      0.9999999999999992 | \x3feffffffffffff9 | t
+ \x3feffffffffffffa |      0.9999999999999993 |      0.9999999999999993 | \x3feffffffffffffa | t
+ \x3feffffffffffffb |      0.9999999999999994 |      0.9999999999999994 | \x3feffffffffffffb | t
+ \x3feffffffffffffc |      0.9999999999999996 |      0.9999999999999996 | \x3feffffffffffffc | t
+ \x3feffffffffffffd |      0.9999999999999997 |      0.9999999999999997 | \x3feffffffffffffd | t
+ \x3feffffffffffffe |      0.9999999999999998 |      0.9999999999999998 | \x3feffffffffffffe | t
+ \x3fefffffffffffff |      0.9999999999999999 |      0.9999999999999999 | \x3fefffffffffffff | t
+ \x3ff0000000000000 |                       1 |                       1 | \x3ff0000000000000 | t
+ \x3ff0000000000001 |      1.0000000000000002 |      1.0000000000000002 | \x3ff0000000000001 | t
+ \x3ff0000000000002 |      1.0000000000000004 |      1.0000000000000004 | \x3ff0000000000002 | t
+ \x3ff0000000000003 |      1.0000000000000007 |      1.0000000000000007 | \x3ff0000000000003 | t
+ \x3ff0000000000004 |      1.0000000000000009 |      1.0000000000000009 | \x3ff0000000000004 | t
+ \x3ff0000000000005 |       1.000000000000001 |       1.000000000000001 | \x3ff0000000000005 | t
+ \x3ff0000000000006 |      1.0000000000000013 |      1.0000000000000013 | \x3ff0000000000006 | t
+ \x3ff0000000000007 |      1.0000000000000016 |      1.0000000000000016 | \x3ff0000000000007 | t
+ \x3ff0000000000008 |      1.0000000000000018 |      1.0000000000000018 | \x3ff0000000000008 | t
+ \x3ff0000000000009 |       1.000000000000002 |       1.000000000000002 | \x3ff0000000000009 | t
+ \x3ff921fb54442d18 |      1.5707963267948966 |      1.5707963267948966 | \x3ff921fb54442d18 | t
+ \x4005bf0a8b14576a |      2.7182818284590455 |      2.7182818284590455 | \x4005bf0a8b14576a | t
+ \x400921fb54442d18 |       3.141592653589793 |       3.141592653589793 | \x400921fb54442d18 | t
+ \x4023ffffffffffff |       9.999999999999998 |       9.999999999999998 | \x4023ffffffffffff | t
+ \x4024000000000000 |                      10 |                      10 | \x4024000000000000 | t
+ \x4024000000000001 |      10.000000000000002 |      10.000000000000002 | \x4024000000000001 | t
+ \x4058ffffffffffff |       99.99999999999999 |       99.99999999999999 | \x4058ffffffffffff | t
+ \x4059000000000000 |                     100 |                     100 | \x4059000000000000 | t
+ \x4059000000000001 |      100.00000000000001 |      100.00000000000001 | \x4059000000000001 | t
+ \x408f3fffffffffff |       999.9999999999999 |       999.9999999999999 | \x408f3fffffffffff | t
+ \x408f400000000000 |                    1000 |                    1000 | \x408f400000000000 | t
+ \x408f400000000001 |      1000.0000000000001 |      1000.0000000000001 | \x408f400000000001 | t
+ \x40c387ffffffffff |       9999.999999999998 |       9999.999999999998 | \x40c387ffffffffff | t
+ \x40c3880000000000 |                   10000 |                   10000 | \x40c3880000000000 | t
+ \x40c3880000000001 |      10000.000000000002 |      10000.000000000002 | \x40c3880000000001 | t
+ \x40f869ffffffffff |       99999.99999999999 |       99999.99999999999 | \x40f869ffffffffff | t
+ \x40f86a0000000000 |                  100000 |                  100000 | \x40f86a0000000000 | t
+ \x40f86a0000000001 |      100000.00000000001 |      100000.00000000001 | \x40f86a0000000001 | t
+ \x412e847fffffffff |       999999.9999999999 |       999999.9999999999 | \x412e847fffffffff | t
+ \x412e848000000000 |                 1000000 |                 1000000 | \x412e848000000000 | t
+ \x412e848000000001 |      1000000.0000000001 |      1000000.0000000001 | \x412e848000000001 | t
+ \x416312cfffffffff |       9999999.999999998 |       9999999.999999998 | \x416312cfffffffff | t
+ \x416312d000000000 |                10000000 |                10000000 | \x416312d000000000 | t
+ \x416312d000000001 |      10000000.000000002 |      10000000.000000002 | \x416312d000000001 | t
+ \x4197d783ffffffff |       99999999.99999999 |       99999999.99999999 | \x4197d783ffffffff | t
+ \x4197d78400000000 |               100000000 |               100000000 | \x4197d78400000000 | t
+ \x4197d78400000001 |      100000000.00000001 |      100000000.00000001 | \x4197d78400000001 | t
+ \x41cdcd64ffffffff |       999999999.9999999 |       999999999.9999999 | \x41cdcd64ffffffff | t
+ \x41cdcd6500000000 |              1000000000 |              1000000000 | \x41cdcd6500000000 | t
+ \x41cdcd6500000001 |      1000000000.0000001 |      1000000000.0000001 | \x41cdcd6500000001 | t
+ \x4202a05f1fffffff |       9999999999.999998 |       9999999999.999998 | \x4202a05f1fffffff | t
+ \x4202a05f20000000 |             10000000000 |             10000000000 | \x4202a05f20000000 | t
+ \x4202a05f20000001 |      10000000000.000002 |      10000000000.000002 | \x4202a05f20000001 | t
+ \x42374876e7ffffff |       99999999999.99998 |       99999999999.99998 | \x42374876e7ffffff | t
+ \x42374876e8000000 |            100000000000 |            100000000000 | \x42374876e8000000 | t
+ \x42374876e8000001 |      100000000000.00002 |      100000000000.00002 | \x42374876e8000001 | t
+ \x426d1a94a1ffffff |       999999999999.9999 |       999999999999.9999 | \x426d1a94a1ffffff | t
+ \x426d1a94a2000000 |           1000000000000 |           1000000000000 | \x426d1a94a2000000 | t
+ \x426d1a94a2000001 |      1000000000000.0001 |      1000000000000.0001 | \x426d1a94a2000001 | t
+ \x42a2309ce53fffff |       9999999999999.998 |       9999999999999.998 | \x42a2309ce53fffff | t
+ \x42a2309ce5400000 |          10000000000000 |          10000000000000 | \x42a2309ce5400000 | t
+ \x42a2309ce5400001 |      10000000000000.002 |      10000000000000.002 | \x42a2309ce5400001 | t
+ \x42d6bcc41e8fffff |       99999999999999.98 |       99999999999999.98 | \x42d6bcc41e8fffff | t
+ \x42d6bcc41e900000 |         100000000000000 |         100000000000000 | \x42d6bcc41e900000 | t
+ \x42d6bcc41e900001 |      100000000000000.02 |      100000000000000.02 | \x42d6bcc41e900001 | t
+ \x430c6bf52633ffff |       999999999999999.9 |       999999999999999.9 | \x430c6bf52633ffff | t
+ \x430c6bf526340000 |                   1e+15 |                   1e+15 | \x430c6bf526340000 | t
+ \x430c6bf526340001 |  1.0000000000000001e+15 |  1.0000000000000001e+15 | \x430c6bf526340001 | t
+ \x4341c37937e07fff |   9.999999999999998e+15 |   9.999999999999998e+15 | \x4341c37937e07fff | t
+ \x4341c37937e08000 |                   1e+16 |                   1e+16 | \x4341c37937e08000 | t
+ \x4341c37937e08001 |  1.0000000000000002e+16 |  1.0000000000000002e+16 | \x4341c37937e08001 | t
+ \x4376345785d89fff |   9.999999999999998e+16 |   9.999999999999998e+16 | \x4376345785d89fff | t
+ \x4376345785d8a000 |                   1e+17 |                   1e+17 | \x4376345785d8a000 | t
+ \x4376345785d8a001 |  1.0000000000000002e+17 |  1.0000000000000002e+17 | \x4376345785d8a001 | t
+ \x43abc16d674ec7ff |   9.999999999999999e+17 |   9.999999999999999e+17 | \x43abc16d674ec7ff | t
+ \x43abc16d674ec800 |                   1e+18 |                   1e+18 | \x43abc16d674ec800 | t
+ \x43abc16d674ec801 |  1.0000000000000001e+18 |  1.0000000000000001e+18 | \x43abc16d674ec801 | t
+ \x43e158e460913cff |   9.999999999999998e+18 |   9.999999999999998e+18 | \x43e158e460913cff | t
+ \x43e158e460913d00 |                   1e+19 |                   1e+19 | \x43e158e460913d00 | t
+ \x43e158e460913d01 |  1.0000000000000002e+19 |  1.0000000000000002e+19 | \x43e158e460913d01 | t
+ \x4415af1d78b58c3f |   9.999999999999998e+19 |   9.999999999999998e+19 | \x4415af1d78b58c3f | t
+ \x4415af1d78b58c40 |                   1e+20 |                   1e+20 | \x4415af1d78b58c40 | t
+ \x4415af1d78b58c41 |  1.0000000000000002e+20 |  1.0000000000000002e+20 | \x4415af1d78b58c41 | t
+ \x444b1ae4d6e2ef4f |   9.999999999999999e+20 |   9.999999999999999e+20 | \x444b1ae4d6e2ef4f | t
+ \x444b1ae4d6e2ef50 |                   1e+21 |                   1e+21 | \x444b1ae4d6e2ef50 | t
+ \x444b1ae4d6e2ef51 |  1.0000000000000001e+21 |  1.0000000000000001e+21 | \x444b1ae4d6e2ef51 | t
+ \x4480f0cf064dd591 |   9.999999999999998e+21 |   9.999999999999998e+21 | \x4480f0cf064dd591 | t
+ \x4480f0cf064dd592 |                   1e+22 |                   1e+22 | \x4480f0cf064dd592 | t
+ \x4480f0cf064dd593 |  1.0000000000000002e+22 |  1.0000000000000002e+22 | \x4480f0cf064dd593 | t
+ \x44b52d02c7e14af5 |   9.999999999999997e+22 |   9.999999999999997e+22 | \x44b52d02c7e14af5 | t
+ \x44b52d02c7e14af6 |   9.999999999999999e+22 |   9.999999999999999e+22 | \x44b52d02c7e14af6 | t
+ \x44b52d02c7e14af7 |  1.0000000000000001e+23 |  1.0000000000000001e+23 | \x44b52d02c7e14af7 | t
+ \x44ea784379d99db3 |   9.999999999999998e+23 |   9.999999999999998e+23 | \x44ea784379d99db3 | t
+ \x44ea784379d99db4 |                   1e+24 |                   1e+24 | \x44ea784379d99db4 | t
+ \x44ea784379d99db5 |  1.0000000000000001e+24 |  1.0000000000000001e+24 | \x44ea784379d99db5 | t
+ \x45208b2a2c280290 |   9.999999999999999e+24 |   9.999999999999999e+24 | \x45208b2a2c280290 | t
+ \x45208b2a2c280291 |                   1e+25 |                   1e+25 | \x45208b2a2c280291 | t
+ \x45208b2a2c280292 |  1.0000000000000003e+25 |  1.0000000000000003e+25 | \x45208b2a2c280292 | t
+ \x7feffffffffffffe | 1.7976931348623155e+308 | 1.7976931348623155e+308 | \x7feffffffffffffe | t
+ \x7fefffffffffffff | 1.7976931348623157e+308 | 1.7976931348623157e+308 | \x7fefffffffffffff | t
+ \x4350000000000002 |  1.8014398509481992e+16 |  1.8014398509481992e+16 | \x4350000000000002 | t
+ \x4350000000002e06 |  1.8014398509529112e+16 |  1.8014398509529112e+16 | \x4350000000002e06 | t
+ \x4352000000000003 |  2.0266198323167244e+16 |  2.0266198323167244e+16 | \x4352000000000003 | t
+ \x4352000000000004 |  2.0266198323167248e+16 |  2.0266198323167248e+16 | \x4352000000000004 | t
+ \x4358000000000003 |  2.7021597764222988e+16 |  2.7021597764222988e+16 | \x4358000000000003 | t
+ \x4358000000000004 |  2.7021597764222992e+16 |  2.7021597764222992e+16 | \x4358000000000004 | t
+ \x435f000000000020 |  3.4902897112121472e+16 |  3.4902897112121472e+16 | \x435f000000000020 | t
+ \xc350000000000002 | -1.8014398509481992e+16 | -1.8014398509481992e+16 | \xc350000000000002 | t
+ \xc350000000002e06 | -1.8014398509529112e+16 | -1.8014398509529112e+16 | \xc350000000002e06 | t
+ \xc352000000000003 | -2.0266198323167244e+16 | -2.0266198323167244e+16 | \xc352000000000003 | t
+ \xc352000000000004 | -2.0266198323167248e+16 | -2.0266198323167248e+16 | \xc352000000000004 | t
+ \xc358000000000003 | -2.7021597764222988e+16 | -2.7021597764222988e+16 | \xc358000000000003 | t
+ \xc358000000000004 | -2.7021597764222992e+16 | -2.7021597764222992e+16 | \xc358000000000004 | t
+ \xc35f000000000020 | -3.4902897112121472e+16 | -3.4902897112121472e+16 | \xc35f000000000020 | t
+ \x42dc12218377de66 |       123456789012345.6 |       123456789012345.6 | \x42dc12218377de66 | t
+ \x42a674e79c5fe51f |       12345678901234.56 |       12345678901234.56 | \x42a674e79c5fe51f | t
+ \x4271f71fb04cb74c |       1234567890123.456 |       1234567890123.456 | \x4271f71fb04cb74c | t
+ \x423cbe991a145879 |       123456789012.3456 |       123456789012.3456 | \x423cbe991a145879 | t
+ \x4206fee0e1a9e061 |       12345678901.23456 |       12345678901.23456 | \x4206fee0e1a9e061 | t
+ \x41d26580b487e6b4 |       1234567890.123456 |       1234567890.123456 | \x41d26580b487e6b4 | t
+ \x419d6f34540ca453 |       123456789.0123456 |       123456789.0123456 | \x419d6f34540ca453 | t
+ \x41678c29dcd6e9dc |       12345678.90123456 |       12345678.90123456 | \x41678c29dcd6e9dc | t
+ \x4132d687e3df217d |       1234567.890123456 |       1234567.890123456 | \x4132d687e3df217d | t
+ \x40fe240c9fcb68c8 |       123456.7890123456 |       123456.7890123456 | \x40fe240c9fcb68c8 | t
+ \x40c81cd6e63c53d3 |       12345.67890123456 |       12345.67890123456 | \x40c81cd6e63c53d3 | t
+ \x40934a4584fd0fdc |       1234.567890123456 |       1234.567890123456 | \x40934a4584fd0fdc | t
+ \x405edd3c07fb4c93 |       123.4567890123456 |       123.4567890123456 | \x405edd3c07fb4c93 | t
+ \x4028b0fcd32f7076 |       12.34567890123456 |       12.34567890123456 | \x4028b0fcd32f7076 | t
+ \x3ff3c0ca428c59f8 |       1.234567890123456 |       1.234567890123456 | \x3ff3c0ca428c59f8 | t
+ \x3e60000000000000 |  2.9802322387695312e-08 |  2.9802322387695312e-08 | \x3e60000000000000 | t
+ \xc352bd2668e077c4 | -2.1098088986959632e+16 | -2.1098088986959632e+16 | \xc352bd2668e077c4 | t
+ \x434018601510c000 |     9.0608011534336e+15 |     9.0608011534336e+15 | \x434018601510c000 | t
+ \x43d055dc36f24000 |   4.708356024711512e+18 |   4.708356024711512e+18 | \x43d055dc36f24000 | t
+ \x43e052961c6f8000 |   9.409340012568248e+18 |   9.409340012568248e+18 | \x43e052961c6f8000 | t
+ \x3ff3c0ca2a5b1d5d |               1.2345678 |               1.2345678 | \x3ff3c0ca2a5b1d5d | t
+ \x4830f0cf064dd592 |   5.764607523034235e+39 |   5.764607523034235e+39 | \x4830f0cf064dd592 | t
+ \x4840f0cf064dd592 |   1.152921504606847e+40 |   1.152921504606847e+40 | \x4840f0cf064dd592 | t
+ \x4850f0cf064dd592 |   2.305843009213694e+40 |   2.305843009213694e+40 | \x4850f0cf064dd592 | t
+ \x3ff3333333333333 |                     1.2 |                     1.2 | \x3ff3333333333333 | t
+ \x3ff3ae147ae147ae |                    1.23 |                    1.23 | \x3ff3ae147ae147ae | t
+ \x3ff3be76c8b43958 |                   1.234 |                   1.234 | \x3ff3be76c8b43958 | t
+ \x3ff3c083126e978d |                  1.2345 |                  1.2345 | \x3ff3c083126e978d | t
+ \x3ff3c0c1fc8f3238 |                 1.23456 |                 1.23456 | \x3ff3c0c1fc8f3238 | t
+ \x3ff3c0c9539b8887 |                1.234567 |                1.234567 | \x3ff3c0c9539b8887 | t
+ \x3ff3c0ca2a5b1d5d |               1.2345678 |               1.2345678 | \x3ff3c0ca2a5b1d5d | t
+ \x3ff3c0ca4283de1b |              1.23456789 |              1.23456789 | \x3ff3c0ca4283de1b | t
+ \x3ff3c0ca43db770a |             1.234567895 |             1.234567895 | \x3ff3c0ca43db770a | t
+ \x3ff3c0ca428abd53 |            1.2345678901 |            1.2345678901 | \x3ff3c0ca428abd53 | t
+ \x3ff3c0ca428c1d2b |           1.23456789012 |           1.23456789012 | \x3ff3c0ca428c1d2b | t
+ \x3ff3c0ca428c51f2 |          1.234567890123 |          1.234567890123 | \x3ff3c0ca428c51f2 | t
+ \x3ff3c0ca428c58fc |         1.2345678901234 |         1.2345678901234 | \x3ff3c0ca428c58fc | t
+ \x3ff3c0ca428c59dd |        1.23456789012345 |        1.23456789012345 | \x3ff3c0ca428c59dd | t
+ \x3ff3c0ca428c59f8 |       1.234567890123456 |       1.234567890123456 | \x3ff3c0ca428c59f8 | t
+ \x3ff3c0ca428c59fb |      1.2345678901234567 |      1.2345678901234567 | \x3ff3c0ca428c59fb | t
+ \x40112e0be8047a7d |             4.294967294 |             4.294967294 | \x40112e0be8047a7d | t
+ \x40112e0be815a889 |             4.294967295 |             4.294967295 | \x40112e0be815a889 | t
+ \x40112e0be826d695 |             4.294967296 |             4.294967296 | \x40112e0be826d695 | t
+ \x40112e0be83804a1 |             4.294967297 |             4.294967297 | \x40112e0be83804a1 | t
+ \x40112e0be84932ad |             4.294967298 |             4.294967298 | \x40112e0be84932ad | t
+ \x0040000000000000 | 1.7800590868057611e-307 | 1.7800590868057611e-307 | \x0040000000000000 | t
+ \x007fffffffffffff | 2.8480945388892175e-306 | 2.8480945388892175e-306 | \x007fffffffffffff | t
+ \x0290000000000000 |  2.446494580089078e-296 |  2.446494580089078e-296 | \x0290000000000000 | t
+ \x029fffffffffffff | 4.8929891601781557e-296 | 4.8929891601781557e-296 | \x029fffffffffffff | t
+ \x4350000000000000 |  1.8014398509481984e+16 |  1.8014398509481984e+16 | \x4350000000000000 | t
+ \x435fffffffffffff |  3.6028797018963964e+16 |  3.6028797018963964e+16 | \x435fffffffffffff | t
+ \x1330000000000000 |  2.900835519859558e-216 |  2.900835519859558e-216 | \x1330000000000000 | t
+ \x133fffffffffffff |  5.801671039719115e-216 |  5.801671039719115e-216 | \x133fffffffffffff | t
+ \x3a6fa7161a4d6e0c |   3.196104012172126e-27 |   3.196104012172126e-27 | \x3a6fa7161a4d6e0c | t
+(209 rows)
+
+-- clean up, lest opr_sanity complain
+\set VERBOSITY terse
+drop type xfloat8 cascade;
+NOTICE:  drop cascades to 6 other objects
+\set VERBOSITY default
+--
index 35e3b3ff8183b5b1cccb2506cd467ed53cead1e7..8447a28c3d3c0a51664759f49c49b9e441cce9d4 100644 (file)
@@ -329,23 +329,23 @@ SELECT '' AS five, q1, q2, q1 / q2 AS divide, q1 % q2 AS mod FROM INT8_TBL;
 (5 rows)
 
 SELECT '' AS five, q1, float8(q1) FROM INT8_TBL;
- five |        q1        |        float8        
-------+------------------+----------------------
-      |              123 |                  123
-      |              123 |                  123
-      | 4567890123456789 | 4.56789012345679e+15
-      | 4567890123456789 | 4.56789012345679e+15
-      | 4567890123456789 | 4.56789012345679e+15
+ five |        q1        |        float8         
+------+------------------+-----------------------
+      |              123 |                   123
+      |              123 |                   123
+      | 4567890123456789 | 4.567890123456789e+15
+      | 4567890123456789 | 4.567890123456789e+15
+      | 4567890123456789 | 4.567890123456789e+15
 (5 rows)
 
 SELECT '' AS five, q2, float8(q2) FROM INT8_TBL;
- five |        q2         |        float8         
-------+-------------------+-----------------------
-      |               456 |                   456
-      |  4567890123456789 |  4.56789012345679e+15
-      |               123 |                   123
-      |  4567890123456789 |  4.56789012345679e+15
-      | -4567890123456789 | -4.56789012345679e+15
+ five |        q2         |         float8         
+------+-------------------+------------------------
+      |               456 |                    456
+      |  4567890123456789 |  4.567890123456789e+15
+      |               123 |                    123
+      |  4567890123456789 |  4.567890123456789e+15
+      | -4567890123456789 | -4.567890123456789e+15
 (5 rows)
 
 SELECT 37 + q1 AS plus4 FROM INT8_TBL;
@@ -726,13 +726,13 @@ SELECT CAST('42'::int2 AS int8), CAST('-37'::int2 AS int8);
 (1 row)
 
 SELECT CAST(q1 AS float4), CAST(q2 AS float8) FROM INT8_TBL;
-     q1      |          q2           
--------------+-----------------------
-         123 |                   456
-         123 |  4.56789012345679e+15
- 4.56789e+15 |                   123
- 4.56789e+15 |  4.56789012345679e+15
- 4.56789e+15 | -4.56789012345679e+15
+     q1      |           q2           
+-------------+------------------------
+         123 |                    456
+         123 |  4.567890123456789e+15
+ 4.56789e+15 |                    123
+ 4.56789e+15 |  4.567890123456789e+15
+ 4.56789e+15 | -4.567890123456789e+15
 (5 rows)
 
 SELECT CAST('36854775807.0'::float4 AS int8);
index 0ac47fcaeec3c323da2f658978877a8d8e2f094b..8dcdaf56027639903a2cb378fea49a4ade837877 100644 (file)
@@ -4376,9 +4376,9 @@ select '12345.05'::jsonb::numeric;
 (1 row)
 
 select '12345.05'::jsonb::float4;
- float4 
---------
 12345
+  float4  
+----------
12345.05
 (1 row)
 
 select '12345.05'::jsonb::float8;
index bf780daa2c1402a88130c0c6e25ca8980fde9110..fe106589c6a42b14a24a8eb014e99a63089010c0 100644 (file)
@@ -64,14 +64,14 @@ LINE 1: INSERT INTO LINE_TBL VALUES ('[(1,2),(1,2)]');
 INSERT INTO LINE_TBL VALUES (line(point '(1,0)', point '(1,0)'));
 ERROR:  invalid line specification: must be two distinct points
 select * from LINE_TBL;
-                      s                      
----------------------------------------------
+                       s                        
+------------------------------------------------
  {0,-1,5}
  {1,0,5}
  {0,3,0}
  {1,-1,0}
  {-0.4,-1,-6}
- {-0.000184615384615385,-1,15.3846153846154}
+ {-0.0001846153846153846,-1,15.384615384615387}
  {3,NaN,5}
  {NaN,NaN,NaN}
  {0,-1,3}
index c18e865370a8e1ce67172f78b81ec2b7a070a165..15e3b83b37e8b51d9dfeddf228ef99a4883cd797 100644 (file)
@@ -1,6 +1,8 @@
 --
 -- POINT
 --
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
 CREATE TABLE POINT_TBL(f1 point);
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
 INSERT INTO POINT_TBL(f1) VALUES ('(-10.0,0.0)');
index 2c8e21baa7eceff918bf26eaa29be26c4c48e236..b31594a7b55e0863098d357376a1473c0c56f8ac 100644 (file)
@@ -910,24 +910,24 @@ insert into rtest_comp values ('p4', 'cm', 15.0);
 insert into rtest_comp values ('p5', 'inch', 7.0);
 insert into rtest_comp values ('p6', 'inch', 4.4);
 select * from rtest_vcomp order by part;
- part | size_in_cm 
-------+------------
- p1   |        500
- p2   |        300
- p3   |          5
- p4   |         15
- p5   |      17.78
- p6   |     11.176
+ part |     size_in_cm     
+------+--------------------
+ p1   |                500
+ p2   |                300
+ p3   |                  5
+ p4   |                 15
+ p5   |              17.78
+ p6   | 11.176000000000002
 (6 rows)
 
 select * from rtest_vcomp where size_in_cm > 10.0 order by size_in_cm using >;
- part | size_in_cm 
-------+------------
- p1   |        500
- p2   |        300
- p5   |      17.78
- p4   |         15
- p6   |     11.176
+ part |     size_in_cm     
+------+--------------------
+ p1   |                500
+ p2   |                300
+ p5   |              17.78
+ p4   |                 15
+ p6   | 11.176000000000002
 (5 rows)
 
 --
index b088ff0d4f169fc91884ef893199bfe4515627c9..6f61acc1eda82081bbe5a93d73aecc498232dba7 100644 (file)
@@ -970,9 +970,9 @@ Water, water, every where,
   Nor any drop to drink.
 S. T. Coleridge (1772-1834)
 '), to_tsquery('english', 'breath&motion&water'));
- ts_rank_cd 
-------------
- 0.00833333
+ ts_rank_cd  
+-------------
+ 0.008333334
 (1 row)
 
 SELECT ts_rank_cd(to_tsvector('english', '
index 6272e70e09ff5736338b00755e81c8364a517273..87a36ca32988a1e60e70b3783ed045c6655bd413 100644 (file)
@@ -787,57 +787,57 @@ select to_tsvector('simple', '') @@ '!foo' AS "true";
 
 --ranking
 SELECT ts_rank(' a:1 s:2C d g'::tsvector, 'a | s');
-  ts_rank  
------------
- 0.0911891
+   ts_rank   
+-------------
+ 0.091189064
 (1 row)
 
 SELECT ts_rank(' a:1 sa:2C d g'::tsvector, 'a | s');
-  ts_rank  
------------
- 0.0303964
+   ts_rank   
+-------------
+ 0.030396355
 (1 row)
 
 SELECT ts_rank(' a:1 sa:2C d g'::tsvector, 'a | s:*');
-  ts_rank  
------------
- 0.0911891
+   ts_rank   
+-------------
+ 0.091189064
 (1 row)
 
 SELECT ts_rank(' a:1 sa:2C d g'::tsvector, 'a | sa:*');
-  ts_rank  
------------
- 0.0911891
+   ts_rank   
+-------------
+ 0.091189064
 (1 row)
 
 SELECT ts_rank(' a:1 s:2B d g'::tsvector, 'a | s');
- ts_rank  
-----------
- 0.151982
+  ts_rank   
+------------
+ 0.15198177
 (1 row)
 
 SELECT ts_rank(' a:1 s:2 d g'::tsvector, 'a | s');
-  ts_rank  
------------
- 0.0607927
+  ts_rank   
+------------
+ 0.06079271
 (1 row)
 
 SELECT ts_rank(' a:1 s:2C d g'::tsvector, 'a & s');
- ts_rank  
-----------
- 0.140153
+  ts_rank   
+------------
+ 0.14015312
 (1 row)
 
 SELECT ts_rank(' a:1 s:2B d g'::tsvector, 'a & s');
- ts_rank  
-----------
- 0.198206
+  ts_rank   
+------------
+ 0.19820644
 (1 row)
 
 SELECT ts_rank(' a:1 s:2 d g'::tsvector, 'a & s');
-  ts_rank  
------------
- 0.0991032
+  ts_rank   
+------------
+ 0.09910322
 (1 row)
 
 SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a | s');
@@ -885,7 +885,7 @@ SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a | s');
 SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a & s');
  ts_rank_cd 
 ------------
-   0.133333
+ 0.13333334
 (1 row)
 
 SELECT ts_rank_cd(' a:1 s:2B d g'::tsvector, 'a & s');
@@ -903,13 +903,13 @@ SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a & s');
 SELECT ts_rank_cd(' a:1 s:2A d g'::tsvector, 'a <-> s');
  ts_rank_cd 
 ------------
-   0.181818
+ 0.18181819
 (1 row)
 
 SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a <-> s');
  ts_rank_cd 
 ------------
-   0.133333
+ 0.13333334
 (1 row)
 
 SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a <-> s');
@@ -927,13 +927,13 @@ SELECT ts_rank_cd(' a:1 s:2 d:2A g'::tsvector, 'a <-> s');
 SELECT ts_rank_cd(' a:1 s:2,3A d:2A g'::tsvector, 'a <2> s:A');
  ts_rank_cd 
 ------------
-  0.0909091
+ 0.09090909
 (1 row)
 
 SELECT ts_rank_cd(' a:1 b:2 s:3A d:2A g'::tsvector, 'a <2> s:A');
  ts_rank_cd 
 ------------
-  0.0909091
+ 0.09090909
 (1 row)
 
 SELECT ts_rank_cd(' a:1 sa:2D sb:2A g'::tsvector, 'a <-> s:*');
index 420c5a54f2028999a5baa9f8449b6bb0dcd2e9cd..8b13ef3a091d10b3c27da78c222416fb034a8f40 100644 (file)
@@ -1,6 +1,8 @@
 --
 -- UPDATABLE VIEWS
 --
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
 -- check that non-updatable views and columns are rejected with useful error
 -- messages
 CREATE TABLE base_tbl (a int PRIMARY KEY, b text DEFAULT 'Unspecified');
index 662d34865309218137a4ac6f23a2420e40cb3084..edc93d5729b30dba90116be41c0f82294887d99f 100644 (file)
@@ -204,33 +204,33 @@ SELECT dense_rank() OVER (PARTITION BY four ORDER BY ten), ten, four FROM tenk1
 (10 rows)
 
 SELECT percent_rank() OVER (PARTITION BY four ORDER BY ten), ten, four FROM tenk1 WHERE unique2 < 10;
-   percent_rank    | ten | four 
--------------------+-----+------
-                 0 |   0 |    0
-                 0 |   0 |    0
-                 1 |   4 |    0
-                 0 |   1 |    1
-                 0 |   1 |    1
- 0.666666666666667 |   7 |    1
-                 1 |   9 |    1
-                 0 |   0 |    2
-                 0 |   1 |    3
-                 1 |   3 |    3
+    percent_rank    | ten | four 
+--------------------+-----+------
+                  0 |   0 |    0
+                  0 |   0 |    0
+                  1 |   4 |    0
+                  0 |   1 |    1
+                  0 |   1 |    1
+ 0.6666666666666666 |   7 |    1
+                  1 |   9 |    1
+                  0 |   0 |    2
+                  0 |   1 |    3
+                  1 |   3 |    3
 (10 rows)
 
 SELECT cume_dist() OVER (PARTITION BY four ORDER BY ten), ten, four FROM tenk1 WHERE unique2 < 10;
-     cume_dist     | ten | four 
--------------------+-----+------
- 0.666666666666667 |   0 |    0
- 0.666666666666667 |   0 |    0
-                 1 |   4 |    0
-               0.5 |   1 |    1
-               0.5 |   1 |    1
-              0.75 |   7 |    1
-                 1 |   9 |    1
-                 1 |   0 |    2
-               0.5 |   1 |    3
-                 1 |   3 |    3
+     cume_dist      | ten | four 
+--------------------+-----+------
+ 0.6666666666666666 |   0 |    0
+ 0.6666666666666666 |   0 |    0
+                  1 |   4 |    0
+                0.5 |   1 |    1
+                0.5 |   1 |    1
+               0.75 |   7 |    1
+                  1 |   9 |    1
+                  1 |   0 |    2
+                0.5 |   1 |    3
+                  1 |   3 |    3
 (10 rows)
 
 SELECT ntile(3) OVER (ORDER BY ten, four), ten, four FROM tenk1 WHERE unique2 < 10;
index a09fa47ae4a9eeaa4e19950080580791b83b35a6..d4fd6571886f7fd055efe9ab4607e0e2a7821b9b 100644 (file)
@@ -2,6 +2,9 @@
 -- AGGREGATES
 --
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
+
 SELECT avg(four) AS avg_1 FROM onek;
 
 SELECT avg(a) AS avg_32 FROM aggtest WHERE a < 100;
index 46c96e1400748094dd77ccb64e9ffdbe4b615458..10e51d780e69d813bd8ab5798509d12fa48f6dd9 100644 (file)
@@ -2,6 +2,9 @@
 -- CIRCLE
 --
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
+
 CREATE TABLE CIRCLE_TBL (f1 circle);
 
 INSERT INTO CIRCLE_TBL VALUES ('<(5,1),3>');
index 1fc482e146d2620df4cf53c2c8c99e9ff99a9cf7..d606e7787b87b2214734e3853f7aba067c6f5839 100644 (file)
@@ -132,3 +132,222 @@ SELECT float4send('750486563e-38'::float4);
 
 SELECT float4send('1.17549435e-38'::float4);
 SELECT float4send('1.1754944e-38'::float4);
+
+-- test output (and round-trip safety) of various values.
+-- To ensure we're testing what we think we're testing, start with
+-- float values specified by bit patterns (as a useful side effect,
+-- this means we'll fail on non-IEEE platforms).
+
+create type xfloat4;
+create function xfloat4in(cstring) returns xfloat4 immutable strict
+  language internal as 'int4in';
+create function xfloat4out(xfloat4) returns cstring immutable strict
+  language internal as 'int4out';
+create type xfloat4 (input = xfloat4in, output = xfloat4out, like = float4);
+create cast (xfloat4 as float4) without function;
+create cast (float4 as xfloat4) without function;
+create cast (xfloat4 as integer) without function;
+create cast (integer as xfloat4) without function;
+
+-- float4: seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
+
+-- we don't care to assume the platform's strtod() handles subnormals
+-- correctly; those are "use at your own risk". However we do test
+-- subnormal outputs, since those are under our control.
+
+with testdata(bits) as (values
+  -- small subnormals
+  (x'00000001'),
+  (x'00000002'), (x'00000003'),
+  (x'00000010'), (x'00000011'), (x'00000100'), (x'00000101'),
+  (x'00004000'), (x'00004001'), (x'00080000'), (x'00080001'),
+  -- stress values
+  (x'0053c4f4'),  -- 7693e-42
+  (x'006c85c4'),  -- 996622e-44
+  (x'0041ca76'),  -- 60419369e-46
+  (x'004b7678'),  -- 6930161142e-48
+  -- taken from upstream testsuite
+  (x'00000007'),
+  (x'00424fe2'),
+  -- borderline between subnormal and normal
+  (x'007ffff0'), (x'007ffff1'), (x'007ffffe'), (x'007fffff'))
+select float4send(flt) as ibits,
+       flt
+  from (select bits::integer::xfloat4::float4 as flt
+          from testdata
+   offset 0) s;
+
+with testdata(bits) as (values
+  (x'00000000'),
+  -- smallest normal values
+  (x'00800000'), (x'00800001'), (x'00800004'), (x'00800005'),
+  (x'00800006'),
+  -- small normal values chosen for short vs. long output
+  (x'008002f1'), (x'008002f2'), (x'008002f3'),
+  (x'00800e17'), (x'00800e18'), (x'00800e19'),
+  -- assorted values (random mantissae)
+  (x'01000001'), (x'01102843'), (x'01a52c98'),
+  (x'0219c229'), (x'02e4464d'), (x'037343c1'), (x'03a91b36'),
+  (x'047ada65'), (x'0496fe87'), (x'0550844f'), (x'05999da3'),
+  (x'060ea5e2'), (x'06e63c45'), (x'07f1e548'), (x'0fc5282b'),
+  (x'1f850283'), (x'2874a9d6'),
+  -- values around 5e-08
+  (x'3356bf94'), (x'3356bf95'), (x'3356bf96'),
+  -- around 1e-07
+  (x'33d6bf94'), (x'33d6bf95'), (x'33d6bf96'),
+  -- around 3e-07 .. 1e-04
+  (x'34a10faf'), (x'34a10fb0'), (x'34a10fb1'),
+  (x'350637bc'), (x'350637bd'), (x'350637be'),
+  (x'35719786'), (x'35719787'), (x'35719788'),
+  (x'358637bc'), (x'358637bd'), (x'358637be'),
+  (x'36a7c5ab'), (x'36a7c5ac'), (x'36a7c5ad'),
+  (x'3727c5ab'), (x'3727c5ac'), (x'3727c5ad'),
+  -- format crossover at 1e-04
+  (x'38d1b714'), (x'38d1b715'), (x'38d1b716'),
+  (x'38d1b717'), (x'38d1b718'), (x'38d1b719'),
+  (x'38d1b71a'), (x'38d1b71b'), (x'38d1b71c'),
+  (x'38d1b71d'),
+  --
+  (x'38dffffe'), (x'38dfffff'), (x'38e00000'),
+  (x'38efffff'), (x'38f00000'), (x'38f00001'),
+  (x'3a83126e'), (x'3a83126f'), (x'3a831270'),
+  (x'3c23d709'), (x'3c23d70a'), (x'3c23d70b'),
+  (x'3dcccccc'), (x'3dcccccd'), (x'3dccccce'),
+  -- chosen to need 9 digits for 3dcccd70
+  (x'3dcccd6f'), (x'3dcccd70'), (x'3dcccd71'),
+  --
+  (x'3effffff'), (x'3f000000'), (x'3f000001'),
+  (x'3f333332'), (x'3f333333'), (x'3f333334'),
+  -- approach 1.0 with increasing numbers of 9s
+  (x'3f666665'), (x'3f666666'), (x'3f666667'),
+  (x'3f7d70a3'), (x'3f7d70a4'), (x'3f7d70a5'),
+  (x'3f7fbe76'), (x'3f7fbe77'), (x'3f7fbe78'),
+  (x'3f7ff971'), (x'3f7ff972'), (x'3f7ff973'),
+  (x'3f7fff57'), (x'3f7fff58'), (x'3f7fff59'),
+  (x'3f7fffee'), (x'3f7fffef'),
+  -- values very close to 1
+  (x'3f7ffff0'), (x'3f7ffff1'), (x'3f7ffff2'),
+  (x'3f7ffff3'), (x'3f7ffff4'), (x'3f7ffff5'),
+  (x'3f7ffff6'), (x'3f7ffff7'), (x'3f7ffff8'),
+  (x'3f7ffff9'), (x'3f7ffffa'), (x'3f7ffffb'),
+  (x'3f7ffffc'), (x'3f7ffffd'), (x'3f7ffffe'),
+  (x'3f7fffff'),
+  (x'3f800000'),
+  (x'3f800001'), (x'3f800002'), (x'3f800003'),
+  (x'3f800004'), (x'3f800005'), (x'3f800006'),
+  (x'3f800007'), (x'3f800008'), (x'3f800009'),
+  -- values 1 to 1.1
+  (x'3f80000f'), (x'3f800010'), (x'3f800011'),
+  (x'3f800012'), (x'3f800013'), (x'3f800014'),
+  (x'3f800017'), (x'3f800018'), (x'3f800019'),
+  (x'3f80001a'), (x'3f80001b'), (x'3f80001c'),
+  (x'3f800029'), (x'3f80002a'), (x'3f80002b'),
+  (x'3f800053'), (x'3f800054'), (x'3f800055'),
+  (x'3f800346'), (x'3f800347'), (x'3f800348'),
+  (x'3f8020c4'), (x'3f8020c5'), (x'3f8020c6'),
+  (x'3f8147ad'), (x'3f8147ae'), (x'3f8147af'),
+  (x'3f8ccccc'), (x'3f8ccccd'), (x'3f8cccce'),
+  --
+  (x'3fc90fdb'), -- pi/2
+  (x'402df854'), -- e
+  (x'40490fdb'), -- pi
+  --
+  (x'409fffff'), (x'40a00000'), (x'40a00001'),
+  (x'40afffff'), (x'40b00000'), (x'40b00001'),
+  (x'411fffff'), (x'41200000'), (x'41200001'),
+  (x'42c7ffff'), (x'42c80000'), (x'42c80001'),
+  (x'4479ffff'), (x'447a0000'), (x'447a0001'),
+  (x'461c3fff'), (x'461c4000'), (x'461c4001'),
+  (x'47c34fff'), (x'47c35000'), (x'47c35001'),
+  (x'497423ff'), (x'49742400'), (x'49742401'),
+  (x'4b18967f'), (x'4b189680'), (x'4b189681'),
+  (x'4cbebc1f'), (x'4cbebc20'), (x'4cbebc21'),
+  (x'4e6e6b27'), (x'4e6e6b28'), (x'4e6e6b29'),
+  (x'501502f8'), (x'501502f9'), (x'501502fa'),
+  (x'51ba43b6'), (x'51ba43b7'), (x'51ba43b8'),
+  -- stress values
+  (x'1f6c1e4a'),  -- 5e-20
+  (x'59be6cea'),  -- 67e14
+  (x'5d5ab6c4'),  -- 985e15
+  (x'2cc4a9bd'),  -- 55895e-16
+  (x'15ae43fd'),  -- 7038531e-32
+  (x'2cf757ca'),  -- 702990899e-20
+  (x'665ba998'),  -- 25933168707e13
+  (x'743c3324'),  -- 596428896559e20
+  -- exercise fixed-point memmoves
+  (x'47f1205a'),
+  (x'4640e6ae'),
+  (x'449a5225'),
+  (x'42f6e9d5'),
+  (x'414587dd'),
+  (x'3f9e064b'),
+  -- these cases come from the upstream's testsuite
+  -- BoundaryRoundEven
+  (x'4c000004'),
+  (x'50061c46'),
+  (x'510006a8'),
+  -- ExactValueRoundEven
+  (x'48951f84'),
+  (x'45fd1840'),
+  -- LotsOfTrailingZeros
+  (x'39800000'),
+  (x'3b200000'),
+  (x'3b900000'),
+  (x'3bd00000'),
+  -- Regression
+  (x'63800000'),
+  (x'4b000000'),
+  (x'4b800000'),
+  (x'4c000001'),
+  (x'4c800b0d'),
+  (x'00d24584'),
+  (x'800000b0'),
+  (x'00d90b88'),
+  (x'45803f34'),
+  (x'4f9f24f7'),
+  (x'3a8722c3'),
+  (x'5c800041'),
+  (x'15ae43fd'),
+  (x'5d4cccfb'),
+  (x'4c800001'),
+  (x'57800ed8'),
+  (x'5f000000'),
+  (x'700000f0'),
+  (x'5f23e9ac'),
+  (x'5e9502f9'),
+  (x'5e8012b1'),
+  (x'3c000028'),
+  (x'60cde861'),
+  (x'03aa2a50'),
+  (x'43480000'),
+  (x'4c000000'),
+  -- LooksLikePow5
+  (x'5D1502F9'),
+  (x'5D9502F9'),
+  (x'5E1502F9'),
+  -- OutputLength
+  (x'3f99999a'),
+  (x'3f9d70a4'),
+  (x'3f9df3b6'),
+  (x'3f9e0419'),
+  (x'3f9e0610'),
+  (x'3f9e064b'),
+  (x'3f9e0651'),
+  (x'03d20cfe')
+)
+select float4send(flt) as ibits,
+       flt,
+       flt::text::float4 as r_flt,
+       float4send(flt::text::float4) as obits,
+       float4send(flt::text::float4) = float4send(flt) as correct
+  from (select bits::integer::xfloat4::float4 as flt
+          from testdata
+   offset 0) s;
+
+-- clean up, lest opr_sanity complain
+
+\set VERBOSITY terse
+drop type xfloat4 cascade;
+\set VERBOSITY default
+
+--
index 6595fd2b958b979443b6452d9b2ca7065656537b..a33321811d35c3886343ea90d73756a0af5c0394 100644 (file)
@@ -16,6 +16,9 @@ SELECT '-10e400'::float8;
 SELECT '10e-400'::float8;
 SELECT '-10e-400'::float8;
 
+-- test smallest normalized input
+SELECT float8send('2.2250738585072014E-308'::float8);
+
 -- bad input
 INSERT INTO FLOAT8_TBL(f1) VALUES ('');
 INSERT INTO FLOAT8_TBL(f1) VALUES ('     ');
@@ -97,6 +100,9 @@ select floor(f1) as floor_f1 from float8_tbl f;
 -- sign
 select sign(f1) as sign_f1 from float8_tbl f;
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
+
 -- square root
 SELECT sqrt(float8 '64') AS eight;
 
@@ -148,6 +154,8 @@ SELECT '' AS bad, f.f1 / '0.0' from FLOAT8_TBL f;
 
 SELECT '' AS five, * FROM FLOAT8_TBL;
 
+RESET extra_float_digits;
+
 -- test for over- and underflow
 INSERT INTO FLOAT8_TBL(f1) VALUES ('10e400');
 
@@ -189,7 +197,6 @@ SELECT '-9223372036854775808.5'::float8::int8;
 SELECT '-9223372036854780000'::float8::int8;
 
 -- test exact cases for trigonometric functions in degrees
-SET extra_float_digits = 3;
 
 SELECT x,
        sind(x),
@@ -232,4 +239,203 @@ SELECT x, y,
 FROM (SELECT 10*cosd(a), 10*sind(a)
       FROM generate_series(0, 360, 90) AS t(a)) AS t(x,y);
 
-RESET extra_float_digits;
+--
+-- test output (and round-trip safety) of various values.
+-- To ensure we're testing what we think we're testing, start with
+-- float values specified by bit patterns (as a useful side effect,
+-- this means we'll fail on non-IEEE platforms).
+
+create type xfloat8;
+create function xfloat8in(cstring) returns xfloat8 immutable strict
+  language internal as 'int8in';
+create function xfloat8out(xfloat8) returns cstring immutable strict
+  language internal as 'int8out';
+create type xfloat8 (input = xfloat8in, output = xfloat8out, like = float8);
+create cast (xfloat8 as float8) without function;
+create cast (float8 as xfloat8) without function;
+create cast (xfloat8 as bigint) without function;
+create cast (bigint as xfloat8) without function;
+
+-- float8: seeeeeee eeeeeeee eeeeeeee mmmmmmmm mmmmmmmm(x4)
+
+-- we don't care to assume the platform's strtod() handles subnormals
+-- correctly; those are "use at your own risk". However we do test
+-- subnormal outputs, since those are under our control.
+
+with testdata(bits) as (values
+  -- small subnormals
+  (x'0000000000000001'),
+  (x'0000000000000002'), (x'0000000000000003'),
+  (x'0000000000001000'), (x'0000000100000000'),
+  (x'0000010000000000'), (x'0000010100000000'),
+  (x'0000400000000000'), (x'0000400100000000'),
+  (x'0000800000000000'), (x'0000800000000001'),
+  -- these values taken from upstream testsuite
+  (x'00000000000f4240'),
+  (x'00000000016e3600'),
+  (x'0000008cdcdea440'),
+  -- borderline between subnormal and normal
+  (x'000ffffffffffff0'), (x'000ffffffffffff1'),
+  (x'000ffffffffffffe'), (x'000fffffffffffff'))
+select float8send(flt) as ibits,
+       flt
+  from (select bits::bigint::xfloat8::float8 as flt
+          from testdata
+   offset 0) s;
+
+-- round-trip tests
+
+with testdata(bits) as (values
+  (x'0000000000000000'),
+  -- smallest normal values
+  (x'0010000000000000'), (x'0010000000000001'),
+  (x'0010000000000002'), (x'0018000000000000'),
+  --
+  (x'3ddb7cdfd9d7bdba'), (x'3ddb7cdfd9d7bdbb'), (x'3ddb7cdfd9d7bdbc'),
+  (x'3e112e0be826d694'), (x'3e112e0be826d695'), (x'3e112e0be826d696'),
+  (x'3e45798ee2308c39'), (x'3e45798ee2308c3a'), (x'3e45798ee2308c3b'),
+  (x'3e7ad7f29abcaf47'), (x'3e7ad7f29abcaf48'), (x'3e7ad7f29abcaf49'),
+  (x'3eb0c6f7a0b5ed8c'), (x'3eb0c6f7a0b5ed8d'), (x'3eb0c6f7a0b5ed8e'),
+  (x'3ee4f8b588e368ef'), (x'3ee4f8b588e368f0'), (x'3ee4f8b588e368f1'),
+  (x'3f1a36e2eb1c432c'), (x'3f1a36e2eb1c432d'), (x'3f1a36e2eb1c432e'),
+  (x'3f50624dd2f1a9fb'), (x'3f50624dd2f1a9fc'), (x'3f50624dd2f1a9fd'),
+  (x'3f847ae147ae147a'), (x'3f847ae147ae147b'), (x'3f847ae147ae147c'),
+  (x'3fb9999999999999'), (x'3fb999999999999a'), (x'3fb999999999999b'),
+  -- values very close to 1
+  (x'3feffffffffffff0'), (x'3feffffffffffff1'), (x'3feffffffffffff2'),
+  (x'3feffffffffffff3'), (x'3feffffffffffff4'), (x'3feffffffffffff5'),
+  (x'3feffffffffffff6'), (x'3feffffffffffff7'), (x'3feffffffffffff8'),
+  (x'3feffffffffffff9'), (x'3feffffffffffffa'), (x'3feffffffffffffb'),
+  (x'3feffffffffffffc'), (x'3feffffffffffffd'), (x'3feffffffffffffe'),
+  (x'3fefffffffffffff'),
+  (x'3ff0000000000000'),
+  (x'3ff0000000000001'), (x'3ff0000000000002'), (x'3ff0000000000003'),
+  (x'3ff0000000000004'), (x'3ff0000000000005'), (x'3ff0000000000006'),
+  (x'3ff0000000000007'), (x'3ff0000000000008'), (x'3ff0000000000009'),
+  --
+  (x'3ff921fb54442d18'),
+  (x'4005bf0a8b14576a'),
+  (x'400921fb54442d18'),
+  --
+  (x'4023ffffffffffff'), (x'4024000000000000'), (x'4024000000000001'),
+  (x'4058ffffffffffff'), (x'4059000000000000'), (x'4059000000000001'),
+  (x'408f3fffffffffff'), (x'408f400000000000'), (x'408f400000000001'),
+  (x'40c387ffffffffff'), (x'40c3880000000000'), (x'40c3880000000001'),
+  (x'40f869ffffffffff'), (x'40f86a0000000000'), (x'40f86a0000000001'),
+  (x'412e847fffffffff'), (x'412e848000000000'), (x'412e848000000001'),
+  (x'416312cfffffffff'), (x'416312d000000000'), (x'416312d000000001'),
+  (x'4197d783ffffffff'), (x'4197d78400000000'), (x'4197d78400000001'),
+  (x'41cdcd64ffffffff'), (x'41cdcd6500000000'), (x'41cdcd6500000001'),
+  (x'4202a05f1fffffff'), (x'4202a05f20000000'), (x'4202a05f20000001'),
+  (x'42374876e7ffffff'), (x'42374876e8000000'), (x'42374876e8000001'),
+  (x'426d1a94a1ffffff'), (x'426d1a94a2000000'), (x'426d1a94a2000001'),
+  (x'42a2309ce53fffff'), (x'42a2309ce5400000'), (x'42a2309ce5400001'),
+  (x'42d6bcc41e8fffff'), (x'42d6bcc41e900000'), (x'42d6bcc41e900001'),
+  (x'430c6bf52633ffff'), (x'430c6bf526340000'), (x'430c6bf526340001'),
+  (x'4341c37937e07fff'), (x'4341c37937e08000'), (x'4341c37937e08001'),
+  (x'4376345785d89fff'), (x'4376345785d8a000'), (x'4376345785d8a001'),
+  (x'43abc16d674ec7ff'), (x'43abc16d674ec800'), (x'43abc16d674ec801'),
+  (x'43e158e460913cff'), (x'43e158e460913d00'), (x'43e158e460913d01'),
+  (x'4415af1d78b58c3f'), (x'4415af1d78b58c40'), (x'4415af1d78b58c41'),
+  (x'444b1ae4d6e2ef4f'), (x'444b1ae4d6e2ef50'), (x'444b1ae4d6e2ef51'),
+  (x'4480f0cf064dd591'), (x'4480f0cf064dd592'), (x'4480f0cf064dd593'),
+  (x'44b52d02c7e14af5'), (x'44b52d02c7e14af6'), (x'44b52d02c7e14af7'),
+  (x'44ea784379d99db3'), (x'44ea784379d99db4'), (x'44ea784379d99db5'),
+  (x'45208b2a2c280290'), (x'45208b2a2c280291'), (x'45208b2a2c280292'),
+  --
+  (x'7feffffffffffffe'), (x'7fefffffffffffff'),
+  -- round to even tests (+ve)
+  (x'4350000000000002'),
+  (x'4350000000002e06'),
+  (x'4352000000000003'),
+  (x'4352000000000004'),
+  (x'4358000000000003'),
+  (x'4358000000000004'),
+  (x'435f000000000020'),
+  -- round to even tests (-ve)
+  (x'c350000000000002'),
+  (x'c350000000002e06'),
+  (x'c352000000000003'),
+  (x'c352000000000004'),
+  (x'c358000000000003'),
+  (x'c358000000000004'),
+  (x'c35f000000000020'),
+  -- exercise fixed-point memmoves
+  (x'42dc12218377de66'),
+  (x'42a674e79c5fe51f'),
+  (x'4271f71fb04cb74c'),
+  (x'423cbe991a145879'),
+  (x'4206fee0e1a9e061'),
+  (x'41d26580b487e6b4'),
+  (x'419d6f34540ca453'),
+  (x'41678c29dcd6e9dc'),
+  (x'4132d687e3df217d'),
+  (x'40fe240c9fcb68c8'),
+  (x'40c81cd6e63c53d3'),
+  (x'40934a4584fd0fdc'),
+  (x'405edd3c07fb4c93'),
+  (x'4028b0fcd32f7076'),
+  (x'3ff3c0ca428c59f8'),
+  -- these cases come from the upstream's testsuite
+  -- LotsOfTrailingZeros)
+  (x'3e60000000000000'),
+  -- Regression
+  (x'c352bd2668e077c4'),
+  (x'434018601510c000'),
+  (x'43d055dc36f24000'),
+  (x'43e052961c6f8000'),
+  (x'3ff3c0ca2a5b1d5d'),
+  -- LooksLikePow5
+  (x'4830f0cf064dd592'),
+  (x'4840f0cf064dd592'),
+  (x'4850f0cf064dd592'),
+  -- OutputLength
+  (x'3ff3333333333333'),
+  (x'3ff3ae147ae147ae'),
+  (x'3ff3be76c8b43958'),
+  (x'3ff3c083126e978d'),
+  (x'3ff3c0c1fc8f3238'),
+  (x'3ff3c0c9539b8887'),
+  (x'3ff3c0ca2a5b1d5d'),
+  (x'3ff3c0ca4283de1b'),
+  (x'3ff3c0ca43db770a'),
+  (x'3ff3c0ca428abd53'),
+  (x'3ff3c0ca428c1d2b'),
+  (x'3ff3c0ca428c51f2'),
+  (x'3ff3c0ca428c58fc'),
+  (x'3ff3c0ca428c59dd'),
+  (x'3ff3c0ca428c59f8'),
+  (x'3ff3c0ca428c59fb'),
+  -- 32-bit chunking
+  (x'40112e0be8047a7d'),
+  (x'40112e0be815a889'),
+  (x'40112e0be826d695'),
+  (x'40112e0be83804a1'),
+  (x'40112e0be84932ad'),
+  -- MinMaxShift
+  (x'0040000000000000'),
+  (x'007fffffffffffff'),
+  (x'0290000000000000'),
+  (x'029fffffffffffff'),
+  (x'4350000000000000'),
+  (x'435fffffffffffff'),
+  (x'1330000000000000'),
+  (x'133fffffffffffff'),
+  (x'3a6fa7161a4d6e0c')
+)
+select float8send(flt) as ibits,
+       flt,
+       flt::text::float8 as r_flt,
+       float8send(flt::text::float8) as obits,
+       float8send(flt::text::float8) = float8send(flt) as correct
+  from (select bits::bigint::xfloat8::float8 as flt
+          from testdata
+   offset 0) s;
+
+-- clean up, lest opr_sanity complain
+
+\set VERBOSITY terse
+drop type xfloat8 cascade;
+\set VERBOSITY default
+
+--
index a209f3bfeb6f5a14d48160bcdbc70172b92d91a8..7f8504dbd1fb8bbfd30b1b0b2b161bc4342435ab 100644 (file)
@@ -2,6 +2,9 @@
 -- POINT
 --
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
+
 CREATE TABLE POINT_TBL(f1 point);
 
 INSERT INTO POINT_TBL(f1) VALUES ('(0.0,0.0)');
index dc6d5cbe35d2a6e70aa8c071b7a47db98281f198..2ecc3862384acd6c1f512d1a5f3223bf3df5d1b9 100644 (file)
@@ -2,6 +2,9 @@
 -- UPDATABLE VIEWS
 --
 
+-- avoid bit-exact output here because operations may not be bit-exact.
+SET extra_float_digits = 0;
+
 -- check that non-updatable views and columns are rejected with useful error
 -- messages
 
index c930eafe8902ed9fd3ebce7989e500034d08f246..5251a21d3487ab7ddf3742b865d55aadd3d8c92f 100644 (file)
@@ -119,7 +119,7 @@ sub mkvcbuild
    }
 
    our @pgcommonallfiles = qw(
-     base64.c config_info.c controldata_utils.c exec.c file_perm.c ip.c
+     base64.c config_info.c controldata_utils.c d2s.c exec.c f2s.c file_perm.c ip.c
      keywords.c kwlookup.c link-canary.c md5.c
      pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
      saslprep.c scram-common.c string.c unicode_norm.c username.c