File 2461-add-option-short-to-float_to_-2-bifs.patch of Package erlang

From c4d9b08daf154fae13239fe627b8db33997c9d56 Mon Sep 17 00:00:00 2001
From: Thomas Depierre <depierre.thomas@gmail.com>
Date: Thu, 8 Apr 2021 17:03:54 +0200
Subject: [PATCH] add option short to float_to_*/2 bifs

This bring the Ryu algorithm, vendored in /erts/emulator/ryu from
https://github.com/ulfjack/ryu. We use this algorithm to add a
new formatting option to float_to_list/2 and float_to_binary/2.

This new formatting option implement an exact shortest round-trip
format, giving us the shortest format possible with no loss of
precision. It also is faster than any other formatting option
available in OTP and less memory intensive.

io_lib_format:fwrite_g/1 is changed to use this BIF, which
should be a transaparent change.
---
 erts/doc/src/erlang.xml                       |  23 +-
 erts/emulator/Makefile.in                     |  16 +-
 erts/emulator/beam/atom.names                 |   1 +
 erts/emulator/beam/bif.c                      |  14 +-
 erts/emulator/ryu/README.ryu_update.md        |  20 +
 erts/emulator/ryu/common.h                    | 115 +++
 erts/emulator/ryu/d2s.c                       | 712 ++++++++++++++++++
 erts/emulator/ryu/d2s_full_table.h            | 367 +++++++++
 erts/emulator/ryu/d2s_intrinsics.h            | 358 +++++++++
 erts/emulator/ryu/digit_table.h               |  35 +
 erts/emulator/ryu/ryu.h                       |  36 +
 erts/emulator/ryu/ryu.mk                      |  57 ++
 erts/emulator/test/num_bif_SUITE.erl          |  60 ++
 erts/preloaded/ebin/atomics.beam              | Bin 4616 -> 4624 bytes
 erts/preloaded/ebin/counters.beam             | Bin 4856 -> 4868 bytes
 erts/preloaded/ebin/erl_init.beam             | Bin 2824 -> 2832 bytes
 erts/preloaded/ebin/erl_prim_loader.beam      | Bin 60372 -> 59696 bytes
 erts/preloaded/ebin/erl_tracer.beam           | Bin 2436 -> 2452 bytes
 erts/preloaded/ebin/erlang.beam               | Bin 130932 -> 130980 bytes
 erts/preloaded/ebin/erts_code_purger.beam     | Bin 12560 -> 12584 bytes
 .../erts_dirty_process_signal_handler.beam    | Bin 3020 -> 3032 bytes
 erts/preloaded/ebin/erts_internal.beam        | Bin 26432 -> 26440 bytes
 .../ebin/erts_literal_area_collector.beam     | Bin 3968 -> 3988 bytes
 erts/preloaded/ebin/init.beam                 | Bin 60272 -> 60280 bytes
 erts/preloaded/ebin/persistent_term.beam      | Bin 1992 -> 2000 bytes
 erts/preloaded/ebin/prim_buffer.beam          | Bin 4052 -> 4064 bytes
 erts/preloaded/ebin/prim_eval.beam            | Bin 1648 -> 1656 bytes
 erts/preloaded/ebin/prim_file.beam            | Bin 32848 -> 32852 bytes
 erts/preloaded/ebin/prim_inet.beam            | Bin 91892 -> 91836 bytes
 erts/preloaded/ebin/prim_net.beam             | Bin 6200 -> 6208 bytes
 erts/preloaded/ebin/prim_socket.beam          | Bin 31544 -> 31552 bytes
 erts/preloaded/ebin/prim_zip.beam             | Bin 25904 -> 25860 bytes
 erts/preloaded/ebin/socket_registry.beam      | Bin 19824 -> 19832 bytes
 erts/preloaded/ebin/zlib.beam                 | Bin 22544 -> 22536 bytes
 erts/preloaded/src/erlang.erl                 |   6 +-
 lib/stdlib/scripts/generate_ryu_table.escript | 108 ---
 lib/stdlib/src/Makefile                       |   1 -
 lib/stdlib/src/io_lib_format.erl              | 260 +------
 lib/stdlib/src/io_lib_format_ryu_table.erl    | 686 -----------------
 lib/stdlib/src/stdlib.app.src                 |   1 -
 lib/stdlib/test/stdlib_bench_SUITE.erl        |  46 +-
 41 files changed, 1849 insertions(+), 1073 deletions(-)
 create mode 100644 erts/emulator/ryu/README.ryu_update.md
 create mode 100644 erts/emulator/ryu/common.h
 create mode 100644 erts/emulator/ryu/d2s.c
 create mode 100644 erts/emulator/ryu/d2s_full_table.h
 create mode 100644 erts/emulator/ryu/d2s_intrinsics.h
 create mode 100644 erts/emulator/ryu/digit_table.h
 create mode 100644 erts/emulator/ryu/ryu.h
 create mode 100644 erts/emulator/ryu/ryu.mk
 delete mode 100755 lib/stdlib/scripts/generate_ryu_table.escript
 delete mode 100644 lib/stdlib/src/io_lib_format_ryu_table.erl

diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 7e4e521f5b..010aae971c 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -2064,7 +2064,14 @@ true</pre>
 > <input>float_to_binary(7.12, [{decimals, 4}, compact]).</input>
 &lt;&lt;"7.12">>
 > <input>float_to_binary(7.12, [{scientific, 3}]).</input>
-&lt;&lt;"7.120e+00">></pre>
+&lt;&lt;"7.120e+00">>
+> <input>float_to_binary(7.12, [short]).</input>
+&lt;&lt;"7.12">>
+> <input>float_to_binary(0.1+0.2, [short]).</input>
+&lt;&lt;"0.30000000000000004">>
+> <input>float_to_binary(0.1+0.2)</input>
+&lt;&lt;"3.00000000000000044409e-01">>
+</pre>
       </desc>
     </func>
 
@@ -2099,6 +2106,16 @@ true</pre>
             formatted using scientific notation with <c>Decimals</c>
             digits of precision.</p>
           </item>
+          <item><p>If option <c>short</c> is specified, the float is formatted
+          with the smallest number of digits that still guarantees that
+          <c>F =:= list_to_float(float_to_list(F, [short]))</c>. When the float
+          is inside the range (-2⁵³, 2⁵³), the notation
+          that yields the smallest number of characters is used (scientific
+          notation or normal decimal notation). Floats outside the range
+          (-2⁵³, 2⁵³) are always formatted using
+          scientific notation to avoid confusing results when doing arithmetic
+          operations.</p>
+          </item>
           <item><p>If <c>Options</c> is <c>[]</c>, the function behaves as
             <seemfa marker="#float_to_list/1">
             <c>float_to_list/1</c></seemfa>.</p>
@@ -2112,6 +2129,10 @@ true</pre>
 "7.12"
 > <input>float_to_list(7.12, [{scientific, 3}]).</input>
 "7.120e+00"
+> <input>float_to_list(7.12, [short]).</input>
+"7.12"
+> <input>float_to_list(0.1+0.2, [short]).</input>
+"0.30000000000000004"
 > <input>float_to_list(0.1+0.2)</input>
 "3.00000000000000044409e-01"
 </pre>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index ef70d345ec..4a973f8ba2 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -371,6 +371,14 @@ endif
 LIBS += $(OPENSSL_LIB)
 endif
 
+DEPLIBS += $(RYU_LIBRARY)
+ifeq ($(TARGET),win32)
+LIBS += -L$(RYU_OBJDIR) -lryu
+else
+# Build on darwin fails if -lryu is used
+LIBS += $(RYU_LIBRARY)
+endif
+
 LIBSCTP = @LIBSCTP@
 
 ORG_THR_LIBS=@EMU_THR_LIBS@
@@ -412,6 +420,7 @@ OBJDIR = obj/$(TTF_DIR)
 CREATE_DIRS += $(OBJDIR) \
 	pcre/obj/$(TARGET)/$(TYPE) \
 	$(ZLIB_OBJDIR) \
+	$(RYU_OBJDIR) \
 	$(OPENSSL_OBJDIR)
 
 ifeq ($(FLAVOR),jit)
@@ -478,6 +487,7 @@ endif
 
 include zlib/zlib.mk
 include pcre/pcre.mk
+include ryu/ryu.mk
 include openssl/openssl.mk
 
 $(ERTS_LIB):
@@ -490,6 +500,7 @@ clean:
 	$(RM) -r obj/$(TARGET)
 	$(RM) -r pcre/obj/$(TARGET) $(PCRE_GENINC)
 	$(RM) -r zlib/obj/$(TARGET)
+	$(RM) -r ryu/obj/$(TARGET)
 	$(RM) -r openssl/obj/$(TARGET)
 	$(RM) -r bin/$(TARGET)
 	cd $(ERTS_LIB_DIR) && $(MAKE) clean
@@ -774,6 +785,7 @@ ifndef Z_LIB
 COMMON_INCLUDES += -Izlib 
 endif
 COMMON_INCLUDES += -Ipcre
+COMMON_INCLUDES += -Iryu
 COMMON_INCLUDES += -Iopenssl/include
 COMMON_INCLUDES += -I../include -I../include/$(TARGET)
 COMMON_INCLUDES += -I../include/internal -I../include/internal/$(TARGET)
@@ -1391,6 +1403,8 @@ $(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC)
 		| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
 	$(V_at)$(DEP_CC) $(DEP_FLAGS) $(ZLIB_SRC) \
 		| $(SED_DEPEND_ZLIB) >> $(TTF_DIR)/depend.mk
+	$(V_at)$(DEP_CC) $(DEP_FLAGS) $(RYU_SRC) \
+		| $(SED_DEPEND_ZLIB) >> $(TTF_DIR)/depend.mk
 ifeq ($(JIT_ENABLED),yes)
 	$(V_at)$(DEP_CXX) $(DEP_CXXFLAGS) $(BEAM_CPP_SRC) \
 		| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 08634f52e6..600508051d 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -629,6 +629,7 @@ atom set_on_spawn
 atom set_seq_token
 atom set_tcw
 atom set_tcw_fake
+atom short
 atom shutdown
 atom sighup
 atom sigterm
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 024d8f8436..a38aa6d022 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -45,6 +45,7 @@
 #include "erl_map.h"
 #include "erl_msacc.h"
 #include "erl_proc_sig_queue.h"
+#include "ryu.h"
 #include "jit/beam_asm.h"
 #include "beam_load.h"
 #include "dtrace-wrapper.h"
@@ -3412,6 +3413,7 @@ static int do_float_to_charbuf(Process *p, Eterm efloat, Eterm list,
     int compact = 0;
     enum fmt_type_ {
         FMT_LEGACY,
+        FMT_SHORT,
         FMT_FIXED,
         FMT_SCIENTIFIC
     } fmt_type = FMT_LEGACY;
@@ -3440,16 +3442,26 @@ static int do_float_to_charbuf(Process *p, Eterm efloat, Eterm list,
                         continue;
                 }
             }
+        } else if (arg == am_short) {
+            fmt_type = FMT_SHORT;
+            continue;
         }
         goto badarg;
     }
+
     if (is_not_nil(list)) {
         goto badarg;
     }
 
     GET_DOUBLE(efloat, f);
 
-    if (fmt_type == FMT_FIXED) {
+    if (fmt_type == FMT_SHORT) {
+        const int index = d2s_buffered_n(f.fd, fbuf);
+
+        /* Terminate the string. */
+        fbuf[index] = '\0';
+        return index;
+    } else if (fmt_type == FMT_FIXED) {
         return sys_double_to_chars_fast(f.fd, fbuf, sizeof_fbuf,
                 decimals, compact);
     } else {
diff --git a/erts/emulator/ryu/README.ryu_update.md b/erts/emulator/ryu/README.ryu_update.md
new file mode 100644
index 0000000000..cc60ea1690
--- /dev/null
+++ b/erts/emulator/ryu/README.ryu_update.md
@@ -0,0 +1,20 @@
+# How to update the Ryu version used by Erlang
+
+Last commit taken : 844864ac213bdbf1fb57e6f51c653b3d90af0937
+
+## The basic changes to the Ryu library
+
+To work with the Erlang VM, Ryu has been changed in three important ways. These
+changes have been marked with a `//CHANGE_FOR_ERLANG` comment explaining them in
+the code.
+
+1. We only kept the bare minimum files needed to generate a double to string with the shortest algorithm, with the widest lookup table
+2. We deleted the code producing the final string, this is handled using a modified version of to_chars from the MS STL. <https://github.com/microsoft/STL/blob/8f4c8163775d665d80642044ce27c4bc696127ce/stl/inc/xcharconv_ryu.h#L1302>
+3. All other unneeded code has been deleted
+
+This is build with our own makefile.
+
+Some of the more minor difference:
+
+- the Zero case in common.h is changed to correspond to erlang fixed point version
+- the MS STL pointer check are not here. Erlang generate a 256 bytes buffer, we only need 30 maximum. Beware what this mean when refactoring.
diff --git a/erts/emulator/ryu/common.h b/erts/emulator/ryu/common.h
new file mode 100644
index 0000000000..7048e90974
--- /dev/null
+++ b/erts/emulator/ryu/common.h
@@ -0,0 +1,115 @@
+// 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
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#if defined(_M_IX86) || defined(_M_ARM)
+#define RYU_32_BIT_PLATFORM
+#endif
+
+// Returns the number of decimal digits in v, which must not contain more than 9 digits.
+static inline uint32_t decimalLength9(const uint32_t v) {
+  // Function precondition: v is not a 10-digit number.
+  // (f2s: 9 digits are sufficient for round-tripping.)
+  // (d2fixed: We print 9-digit blocks.)
+  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;
+}
+
+// Returns e == 0 ? 1 : [log_2(5^e)]; requires 0 <= e <= 3528.
+static inline int32_t log2pow5(const int32_t 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 (int32_t) ((((uint32_t) e) * 1217359) >> 19);
+}
+
+// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528.
+static inline int32_t pow5bits(const int32_t 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 (int32_t) (((((uint32_t) e) * 1217359) >> 19) + 1);
+}
+
+// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528.
+static inline int32_t ceil_log2pow5(const int32_t e) {
+  return log2pow5(e) + 1;
+}
+
+// Returns floor(log_10(2^e)); requires 0 <= e <= 1650.
+static inline uint32_t log10Pow2(const int32_t 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 (((uint32_t) e) * 78913) >> 18;
+}
+
+// Returns floor(log_10(5^e)); requires 0 <= e <= 2620.
+static inline uint32_t log10Pow5(const int32_t 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 (((uint32_t) 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;
+  }
+  // CHANGE_FOR_ERLANG we use "0.0" as the 0 and not "0E0"
+  memcpy(result + sign, "0.0", 3);
+  return sign + 3;
+}
+
+static inline uint32_t float_to_bits(const float f) {
+  uint32_t bits = 0;
+  memcpy(&bits, &f, sizeof(float));
+  return bits;
+}
+
+static inline uint64_t double_to_bits(const double d) {
+  uint64_t bits = 0;
+  memcpy(&bits, &d, sizeof(double));
+  return bits;
+}
+
+#endif // RYU_COMMON_H
diff --git a/erts/emulator/ryu/d2s.c b/erts/emulator/ryu/d2s.c
new file mode 100644
index 0000000000..643e41ce02
--- /dev/null
+++ b/erts/emulator/ryu/d2s.c
@@ -0,0 +1,712 @@
+// 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_DEBUG Generate verbose debugging output to stdout.
+//
+// -DRYU_ONLY_64_BIT_OPS Avoid using uint128_t or 64-bit intrinsics. Slower,
+//     depending on your compiler.
+//
+
+// CHANGE_FOR_ERLANG: "ryu/ryu.h" -> "ryu.h"
+#include "ryu.h"
+// END CHANGE_FOR_ERLANG
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef RYU_DEBUG
+#include <inttypes.h>
+#include <stdio.h>
+#endif
+
+// CHANGE_FOR_ERLANG: "ryu/*.h" -> "*.h"
+#include "common.h"
+#include "digit_table.h"
+#include "d2s_intrinsics.h"
+// END CHANGE_FOR_ERLANG
+
+// CHANGE_FOR_ERLANG we got rid of the small_table. Also namespace as above
+#include "d2s_full_table.h"
+// END CHANGE_FOR_ERLANG
+
+#define DOUBLE_MANTISSA_BITS 52
+#define DOUBLE_EXPONENT_BITS 11
+#define DOUBLE_BIAS 1023
+
+static inline uint32_t decimalLength17(const uint64_t 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_t mantissa;
+  // Decimal exponent's range is -324 to 308
+  // inclusive, and can fit in a short if needed.
+  int32_t exponent;
+} floating_decimal_64;
+
+static inline floating_decimal_64 d2d(const uint64_t ieeeMantissa, const uint32_t ieeeExponent) {
+  int32_t e2;
+  uint64_t 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 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
+    m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
+  }
+  const bool even = (m2 & 1) == 0;
+  const bool acceptBounds = even;
+
+#ifdef RYU_DEBUG
+  printf("-> %" PRIu64 " * 2^%d\n", m2, e2 + 2);
+#endif
+
+  // Step 2: Determine the interval of valid decimal representations.
+  const uint64_t mv = 4 * m2;
+  // Implicit bool -> int conversion. True is 1, false is 0.
+  const uint32_t mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
+  // We would compute mp and mm like this:
+  // uint64_t mp = 4 * m2 + 2;
+  // uint64_t mm = mv - 1 - mmShift;
+
+  // Step 3: Convert to a decimal power base using 128-bit arithmetic.
+  uint64_t vr, vp, vm;
+  int32_t e10;
+  bool vmIsTrailingZeros = false;
+  bool vrIsTrailingZeros = false;
+  if (e2 >= 0) {
+    // I tried special-casing q == 0, but there was no effect on performance.
+    // This expression is slightly faster than max(0, log10Pow2(e2) - 1).
+    const uint32_t q = log10Pow2(e2) - (e2 > 3);
+    e10 = (int32_t) q;
+    const int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t) q) - 1;
+    const int32_t i = -e2 + (int32_t) q + k;
+    vr = mulShiftAll64(m2, DOUBLE_POW5_INV_SPLIT[q], i, &vp, &vm, mmShift);
+#ifdef RYU_DEBUG
+    printf("%" PRIu64 " * 2^%d / 10^%u\n", mv, e2, q);
+    printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
+#endif
+    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_t mvMod5 = ((uint32_t) mv) - 5 * ((uint32_t) 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_t q = log10Pow5(-e2) - (-e2 > 1);
+    e10 = (int32_t) q + e2;
+    const int32_t i = -e2 - (int32_t) q;
+    const int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
+    const int32_t j = (int32_t) q - k;
+    vr = mulShiftAll64(m2, DOUBLE_POW5_SPLIT[i], j, &vp, &vm, mmShift);
+#ifdef RYU_DEBUG
+    printf("%" PRIu64 " * 5^%d / 10^%u\n", mv, -e2, q);
+    printf("%u %d %d %d\n", q, i, k, j);
+    printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
+#endif
+    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 want to know if the full product has at least q trailing zeros.
+      // We need to compute min(p2(mv), p5(mv) - e2) >= q
+      // <=> p2(mv) >= q && p5(mv) - e2 >= q
+      // <=> p2(mv) >= q (because -e2 >= q)
+      vrIsTrailingZeros = multipleOfPowerOf2(mv, q);
+#ifdef RYU_DEBUG
+      printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
+#endif
+    }
+  }
+#ifdef RYU_DEBUG
+  printf("e10=%d\n", e10);
+  printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
+  printf("vm is trailing zeros=%s\n", vmIsTrailingZeros ? "true" : "false");
+  printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
+#endif
+
+  // Step 4: Find the shortest decimal representation in the interval of valid representations.
+  int32_t removed = 0;
+  uint8_t lastRemovedDigit = 0;
+  uint64_t output;
+  // On average, we remove ~2 digits.
+  if (vmIsTrailingZeros || vrIsTrailingZeros) {
+    // General case, which happens rarely (~0.7%).
+    for (;;) {
+      const uint64_t vpDiv10 = div10(vp);
+      const uint64_t vmDiv10 = div10(vm);
+      if (vpDiv10 <= vmDiv10) {
+        break;
+      }
+      const uint32_t vmMod10 = ((uint32_t) vm) - 10 * ((uint32_t) vmDiv10);
+      const uint64_t vrDiv10 = div10(vr);
+      const uint32_t vrMod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrDiv10);
+      vmIsTrailingZeros &= vmMod10 == 0;
+      vrIsTrailingZeros &= lastRemovedDigit == 0;
+      lastRemovedDigit = (uint8_t) vrMod10;
+      vr = vrDiv10;
+      vp = vpDiv10;
+      vm = vmDiv10;
+      ++removed;
+    }
+#ifdef RYU_DEBUG
+    printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
+    printf("d-10=%s\n", vmIsTrailingZeros ? "true" : "false");
+#endif
+    if (vmIsTrailingZeros) {
+      for (;;) {
+        const uint64_t vmDiv10 = div10(vm);
+        const uint32_t vmMod10 = ((uint32_t) vm) - 10 * ((uint32_t) vmDiv10);
+        if (vmMod10 != 0) {
+          break;
+        }
+        const uint64_t vpDiv10 = div10(vp);
+        const uint64_t vrDiv10 = div10(vr);
+        const uint32_t vrMod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrDiv10);
+        vrIsTrailingZeros &= lastRemovedDigit == 0;
+        lastRemovedDigit = (uint8_t) vrMod10;
+        vr = vrDiv10;
+        vp = vpDiv10;
+        vm = vmDiv10;
+        ++removed;
+      }
+    }
+#ifdef RYU_DEBUG
+    printf("%" PRIu64 " %d\n", vr, lastRemovedDigit);
+    printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
+#endif
+    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_t vpDiv100 = div100(vp);
+    const uint64_t vmDiv100 = div100(vm);
+    if (vpDiv100 > vmDiv100) { // Optimization: remove two digits at a time (~86.2%).
+      const uint64_t vrDiv100 = div100(vr);
+      const uint32_t vrMod100 = ((uint32_t) vr) - 100 * ((uint32_t) 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_t vpDiv10 = div10(vp);
+      const uint64_t vmDiv10 = div10(vm);
+      if (vpDiv10 <= vmDiv10) {
+        break;
+      }
+      const uint64_t vrDiv10 = div10(vr);
+      const uint32_t vrMod10 = ((uint32_t) vr) - 10 * ((uint32_t) vrDiv10);
+      roundUp = vrMod10 >= 5;
+      vr = vrDiv10;
+      vp = vpDiv10;
+      vm = vmDiv10;
+      ++removed;
+    }
+#ifdef RYU_DEBUG
+    printf("%" PRIu64 " roundUp=%s\n", vr, roundUp ? "true" : "false");
+    printf("vr is trailing zeros=%s\n", vrIsTrailingZeros ? "true" : "false");
+#endif
+    // We need to take vr + 1 if vr is outside bounds or we need to round up.
+    output = vr + (vr == vm || roundUp);
+  }
+  const int32_t exp = e10 + removed;
+
+#ifdef RYU_DEBUG
+  printf("V+=%" PRIu64 "\nV =%" PRIu64 "\nV-=%" PRIu64 "\n", vp, vr, vm);
+  printf("O=%" PRIu64 "\n", output);
+  printf("EXP=%d\n", exp);
+#endif
+
+  floating_decimal_64 fd;
+  fd.exponent = exp;
+  fd.mantissa = output;
+  return fd;
+}
+
+//CHANGE_FOR_ERLANG: This format is new, it is here to handle the different format switch used in the STL code
+enum chars_format {
+    FMT_SCIENTIFIC,
+    FMT_FIXED,
+    FMT_GENERAL
+};
+
+// This is inspired from the MS STL Charconv, under Apache with LLVM exception licence
+// see https://github.com/microsoft/STL/blob/main/LICENSE.txt
+// The inspiration is at https://github.com/microsoft/STL/blob/e745bad3b1d05b5b19ec652d68abb37865ffa454/stl/inc/xcharconv_ryu.h#L1926
+// CHANGE_FOR_ERLANG all the types and typecast have been adapted to C types from Cpp.
+// I have also kept the Ryu original function head as it allows to not impact the rest of the code
+// __v and __mantissa and __exponent have lost their double underscore over the whole function
+// all the test on the lenght of the buffer have been dropped too. This could need change, but
+// we always pass a 256 bytes buffer when we only need 26 bytes maximum.
+static inline int to_chars(const floating_decimal_64 v, const bool sign, char* const result) {
+  // Step 5: Print the decimal representation.
+  uint64_t __output = v.mantissa;
+  int32_t _Ryu_exponent = v.exponent;
+  const uint32_t __olength = decimalLength17(__output);
+  int32_t _Scientific_exponent = _Ryu_exponent + ((int32_t) __olength) - 1;
+
+  // CHANGE_FOR_ERLANG: we use our chars_format instead of the STL one
+  enum chars_format _Fmt;
+
+  int32_t _Lower;
+  int32_t _Upper;
+
+  if (__olength == 1) {
+    // CHANGE_FOR_ERLANG the format and examples have been adapted to the erlang format
+    // as the original would have not shown a change in format
+    // (erlang always add ".0" to scientific format) and omit the + in the exponent
+    // Value | Fixed    | Scientific
+    // 1e-4  | "0.0001" | "1.0e-4"
+    // 1e2   | "100.0"  | "1.0e2"
+    // CHANGE_FOR_ERLANG the values for a switch, as seen in the example above, for erlang
+    // are different than for STL format.
+    _Lower = -4;
+    _Upper = 2;
+  } else if (_Scientific_exponent >= 10) {
+    // CHANGE_FOR_ERLANG This case does not exist for the STL and is due to the 
+    // negative sign in the exponent.
+    // Value        | Fixed           | Scientific
+    // 123456789e1  | "1234567890.0"  | "1.23456789e9"
+    // 123456789e2  | "12345678900.0" | "1.23456789e10"
+
+    _Lower = - (int32_t) (__olength + 2);
+    _Upper = 2;
+  } else {
+    // CHANGE_FOR_ERLANG the format and examples have been adapted to the erlang format
+    // as the original would have not shown a change in format
+    // (erlang always add ".0" to scientific format) and omit the + in the exponent
+    // Value   | Fixed      | Scientific
+    // 1234e-6 | "0.001234" | "1.234e-4"
+    // 1234e1  | "12340.0"  | "1.234e4"
+    // CHANGE_FOR_ERLANG the values for a switch, as seen in the example above, for erlang
+    // are different than for STL format.
+    _Lower = - (int32_t) (__olength + 2);
+    _Upper = 1;
+  }
+
+  if (_Lower <= _Ryu_exponent && _Ryu_exponent <= _Upper) {
+    // CHANGE_FOR_ERLANG this is added to handle the -2**53, 2**53 range special case
+    // These are edge cases not captured above, all the other are naturally handled
+    // by _Lower nad _Upper
+    if ((__output >= (1ull << 53) && _Ryu_exponent == 0) 
+          || (__output > ((1ull << 52) / 5) && _Ryu_exponent == 1)
+          || (__output > ((1ull << 51) / 25) && _Ryu_exponent == 2)) {
+      _Fmt = FMT_SCIENTIFIC;
+    } else {
+      _Fmt = FMT_FIXED;
+    }
+  } else {
+    // CHANGE_FOR_ERLANG we do not need to handle the %g case here.
+    _Fmt = FMT_SCIENTIFIC;
+  }
+
+  // CHANGE_FOR_ERLANG we handle the sign here as it is handled outside of this in the STL case
+  // and we need it to compute the start of the buffer for the characters after
+  if (sign) {
+    result[0] = '-';
+  }
+
+  // CHANGE_FOR_ERLANG we compute the start of the usable buffer. It is done here
+  // in order to be fixed for both branches of formatting.
+  char* const __result = result + sign;
+
+  if (_Fmt == FMT_FIXED) {
+    // CHANGE_FOR_ERLANG this whole table has been adapted to erlang examples to help
+    // debug and evolve the edge cases
+    // Example: __output == 1729, __olength == 4
+
+    // _Ryu_exponent | Printed  | _Whole_digits | _Total_fixed_length  | Notes
+    // --------------|----------|---------------|----------------------|---------------------------------------
+    //             1 | 17290.0  |  5            |  _Whole_digits + 2   | Unified length cases.
+    //             0 | 1729.0   |  4            |                      |
+    // --------------|----------|---------------|----------------------|---------------------------------------
+    //            -1 | 172.9    |  3            | __olength + 1        | This case can't happen for
+    //            -2 | 17.29    |  2            |                      | __olength == 1, but no additional
+    //            -3 | 1.729    |  1            |                      | code is needed to avoid it.
+    // --------------|----------|---------------|----------------------|---------------------------------------
+    //            -4 | 0.1729   |  0            | 2 - _Ryu_exponent    | If the decimal point appears, we need
+    //            -5 | 0.01729  | -1            |                      | to put the "0" in front
+    //            -6 | 0.001729 | -2            |                      |
+
+    const int32_t _Whole_digits = (int32_t) (__olength) + _Ryu_exponent;
+
+    uint32_t _Total_fixed_length;
+    if (_Ryu_exponent >= 0) { 
+      // CHANGE_FOR_ERLANG the examples and values have been adapted to erlang format one
+      // CHANGE_FOR_ERLANG we also dropped the whole adjustement, as it is only of value
+      // for %f which we do not handle
+      // cases "17290.0" and "1729.0"
+      _Total_fixed_length = (uint32_t) (_Whole_digits) + 2;
+    } else if (_Whole_digits > 0) { // case "17.29"
+      _Total_fixed_length = __olength + 1;
+    } else { // case "0.001729"
+      _Total_fixed_length = (uint32_t) (2 - _Ryu_exponent);
+    }
+
+    char* _Mid;
+    if (_Ryu_exponent >= 0) { // case "172900.0"
+      // CHANGE_FOR_ERLANG we do not need the can_use_ryu, as we are not doing %f
+      // but always shortest round_trip. The whole complexity here is dropped
+      // Print the decimal digits, left-aligned within [result, result + _Total_fixed_length).
+      _Mid = __result + __olength;
+    } else { // cases "1729.0", "17.29", and "0.001729"
+      // Print the decimal digits, right-aligned within [result, result + _Total_fixed_length).
+      _Mid = __result + _Total_fixed_length;
+    }
+
+    // We prefer 32-bit operations, even on 64-bit platforms.
+    // We have at most 17 digits, and uint32_t can store 9 digits.
+    // If __output doesn't fit into uint32_t, we cut off 8 digits,
+    // so the rest will fit into uint32_t.
+    // CHANGE_FOR_ERLANG we consider in this whole thing that memcopy use the same
+    // char has defined in the DIGIT_TABLE
+    // CHANGE_FOR_ERLANG __DIGIT_TABLE became DIGIT_TABLE
+    if ((__output >> 32) != 0) {
+      // Expensive 64-bit division.
+      const uint64_t __q = div1e8(__output);
+      uint32_t __output2 = (uint32_t) (__output - 100000000 * __q);
+      __output = __q;
+
+      const uint32_t __c = __output2 % 10000;
+      __output2 /= 10000;
+      const uint32_t __d = __output2 % 10000;
+      const uint32_t __c0 = (__c % 100) << 1;
+      const uint32_t __c1 = (__c / 100) << 1;
+      const uint32_t __d0 = (__d % 100) << 1;
+      const uint32_t __d1 = (__d / 100) << 1;
+
+      memcpy(_Mid -= 2, DIGIT_TABLE + __c0, 2);
+      memcpy(_Mid -= 2, DIGIT_TABLE + __c1, 2);
+      memcpy(_Mid -= 2, DIGIT_TABLE + __d0, 2);
+      memcpy(_Mid -= 2, DIGIT_TABLE + __d1, 2);
+    }
+    uint32_t __output2 = (uint32_t) __output;
+    while (__output2 >= 10000) {
+#ifdef __clang__ // TRANSITION, LLVM-38217
+      const uint32_t __c = __output2 - 10000 * (__output2 / 10000);
+#else
+      const uint32_t __c = __output2 % 10000;
+#endif
+      __output2 /= 10000;
+      const uint32_t __c0 = (__c % 100) << 1;
+      const uint32_t __c1 = (__c / 100) << 1;
+      memcpy(_Mid -= 2, DIGIT_TABLE + __c0, 2);
+      memcpy(_Mid -= 2, DIGIT_TABLE + __c1, 2);
+    }
+    if (__output2 >= 100) {
+      const uint32_t __c = (__output2 % 100) << 1;
+      __output2 /= 100;
+      memcpy(_Mid -= 2, DIGIT_TABLE + __c, 2);
+    }
+    if (__output2 >= 10) {
+      const uint32_t __c = __output2 << 1;
+      memcpy(_Mid -= 2, DIGIT_TABLE + __c, 2);
+    } else {
+      *--_Mid = (char) ('0' + __output2);
+    }
+
+    if (_Ryu_exponent > 0) { // case "172900.0"
+      // Performance note: it might be more efficient to do this immediately after setting _Mid.
+      // CHANGE_FOR_ERLANG we have different case here, so we have to add the ".0" here
+      // we use memset as we do not have access to fill_n
+      memset(__result + __olength, '0', (size_t) _Ryu_exponent);
+      __result[__olength + (size_t) _Ryu_exponent] = '.';
+      __result[__olength + (size_t) _Ryu_exponent + 1] = '0';
+    } else if (_Ryu_exponent == 0) { // case "1729.0"
+      // CHANGE_FOR_ERLANG we have different case here, so we have to add the ".0" here
+      __result[__olength] = '.';
+      __result[__olength + 1] = '0';
+    } else if (_Whole_digits > 0) { // case "17.29"
+      // Performance note: moving digits might not be optimal.
+      memmove(__result, __result + 1, (size_t) _Whole_digits);
+      __result[_Whole_digits] = '.';
+    } else { // case "0.001729"
+      // CHANGE_FOR_ERLANG we use the memset here as we do not have access to fill_n
+      // Performance note: a larger memset() followed by overwriting '.' might be more efficient.
+      __result[0] = '0';
+      __result[1] = '.';
+      memset(__result + 2, '0', (size_t) (-_Whole_digits));
+    }
+
+    // CHANGE_FOR_ERLANG we do not need the errc and we are only interested in
+    // returning the length, as it is what Ryu and erlang expect. We do add the
+    // sign as we did it here instead of adding it by default as in the STL
+    return _Total_fixed_length + sign;
+  }
+
+  uint32_t _Scientific_exponent_length;
+  // CHANGE_FOR_ERLANG we have to do a little bit more complex logic here because we do not always
+  // print the exponent sign, only if it is negative
+  if (_Scientific_exponent <= -100) { // "e-100"
+    _Scientific_exponent_length = 5;
+  } else if (_Scientific_exponent <= -10 || _Scientific_exponent >= 100) { // "e-10" or "e100"
+    _Scientific_exponent_length = 4;
+  } else if ((_Scientific_exponent > -10 && _Scientific_exponent < 0) || _Scientific_exponent >= 10) { // "e-9" or "e10"
+    _Scientific_exponent_length = 3;
+  } else { // "e1"
+    _Scientific_exponent_length = 2;
+  }
+
+  // CHANGE_FOR_ERLANG we do not need the ternary as we did all the logic above
+  const uint32_t _Total_scientific_length = __olength + 1 +(__olength == 1) // digits + decimal point + possible 0 after decimal point
+    + _Scientific_exponent_length; // + scientific exponent
+
+  // Print the decimal digits.
+  uint32_t __i = 0;
+  // We prefer 32-bit operations, even on 64-bit platforms.
+  // We have at most 17 digits, and uint32_t can store 9 digits.
+  // If __output doesn't fit into uint32_t, we cut off 8 digits,
+  // so the rest will fit into uint32_t.
+    // CHANGE_FOR_ERLANG we consider in this whole thing that memcopy use the same
+    // char has defined in the DIGIT_TABLE
+    // CHANGE_FOR_ERLANG __DIGIT_TABLE became DIGIT_TABLE
+  if ((__output >> 32) != 0) {
+    // Expensive 64-bit division.
+    const uint64_t __q = div1e8(__output);
+    uint32_t __output2 = (uint32_t) (__output) - 100000000 * (uint32_t) (__q);
+    __output = __q;
+
+    const uint32_t __c = __output2 % 10000;
+    __output2 /= 10000;
+    const uint32_t __d = __output2 % 10000;
+    const uint32_t __c0 = (__c % 100) << 1;
+    const uint32_t __c1 = (__c / 100) << 1;
+    const uint32_t __d0 = (__d % 100) << 1;
+    const uint32_t __d1 = (__d / 100) << 1;
+    memcpy(__result + __olength - __i - 1, DIGIT_TABLE + __c0, 2);
+    memcpy(__result + __olength - __i - 3, DIGIT_TABLE + __c1, 2);
+    memcpy(__result + __olength - __i - 5, DIGIT_TABLE + __d0, 2);
+    memcpy(__result + __olength - __i - 7, DIGIT_TABLE + __d1, 2);
+    __i += 8;
+  }
+  uint32_t __output2 = (uint32_t) (__output);
+  while (__output2 >= 10000) {
+#ifdef __clang__ // TRANSITION, LLVM-38217
+    const uint32_t __c = __output2 - 10000 * (__output2 / 10000);
+#else
+    const uint32_t __c = __output2 % 10000;
+#endif
+    __output2 /= 10000;
+    const uint32_t __c0 = (__c % 100) << 1;
+    const uint32_t __c1 = (__c / 100) << 1;
+    memcpy(__result + __olength - __i - 1, DIGIT_TABLE + __c0, 2);
+    memcpy(__result + __olength - __i - 3, DIGIT_TABLE + __c1, 2);
+    __i += 4;
+  }
+  if (__output2 >= 100) {
+    const uint32_t __c = (__output2 % 100) << 1;
+    __output2 /= 100;
+    memcpy(__result + __olength - __i - 1, DIGIT_TABLE + __c, 2);
+    __i += 2;
+  }
+  if (__output2 >= 10) {
+    const uint32_t __c = __output2 << 1;
+    // We can't use memcpy here: the decimal dot goes between these two digits.
+    __result[2] = DIGIT_TABLE[__c + 1];
+    __result[0] = DIGIT_TABLE[__c];
+  } else {
+    __result[0] = (char) ('0' + __output2);
+  }
+
+  // Print decimal point if needed.
+  uint32_t __index;
+  if (__olength > 1) {
+    __result[1] = '.';
+    __index = __olength + 1;
+  } else {
+    // In erlang we _have_ to print the ".0" in the case this is an integer
+    __result[1] = '.';
+    __result[2] = '0';
+    __index = __olength + 2;
+  }
+
+  // Print the exponent.
+  __result[__index++] = 'e';
+  if (_Scientific_exponent < 0) {
+    __result[__index++] = '-';
+    _Scientific_exponent = -_Scientific_exponent;
+  }
+  // CHANGE_FOR_ERLANG no else, as we do not print the positive sign on the exponent
+
+  if (_Scientific_exponent >= 100) {
+    const int32_t __c = _Scientific_exponent % 10;
+    memcpy(__result + __index, DIGIT_TABLE + 2 * (_Scientific_exponent / 10), 2);
+    __result[__index + 2] = (char) ('0' + __c);
+    __index += 3;
+  } else if (_Scientific_exponent >= 10) {
+    // CHANGE_FOR_ERLANG we have to do this only if the exponent is larger than 10
+    memcpy(__result + __index, DIGIT_TABLE + 2 * _Scientific_exponent, 2);
+    __index += 2;
+  } else { 
+  // CHANGE_FOR_ERLANG we can have an exponent under 10, which is not handled by the table
+  // so we handle it here
+    __result[__index++] = (char) ('0' + _Scientific_exponent);
+  }
+
+    // CHANGE_FOR_ERLANG we do not need the errc and we are only interested in
+    // returning the length, as it is what Ryu and erlang expect. We do add the
+    // sign as we did it here instead of adding it by default as in the STL
+  return _Total_scientific_length + sign;
+}
+// end of STL code, back to ryu
+
+static inline bool d2d_small_int(const uint64_t ieeeMantissa, const uint32_t ieeeExponent,
+  floating_decimal_64* const v) {
+  const uint64_t m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
+  const int32_t e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;
+
+  if (e2 > 0) {
+    // f = m2 * 2^e2 >= 2^53 is an integer.
+    // Ignore this case for now.
+    return false;
+  }
+
+  if (e2 < -52) {
+    // f < 1.
+    return false;
+  }
+
+  // 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.
+  const uint64_t mask = (1ull << -e2) - 1;
+  const uint64_t fraction = m2 & mask;
+  if (fraction != 0) {
+    return false;
+  }
+
+  // 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 decimalLength17().
+  v->mantissa = m2 >> -e2;
+  v->exponent = 0;
+  return true;
+}
+
+int d2s_buffered_n(double f, char* result) {
+  // Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
+  const uint64_t bits = double_to_bits(f);
+
+#ifdef RYU_DEBUG
+  printf("IN=");
+  for (int32_t bit = 63; bit >= 0; --bit) {
+    printf("%d", (int) ((bits >> bit) & 1));
+  }
+  printf("\n");
+#endif
+
+  // Decode bits into sign, mantissa, and exponent.
+  const bool ieeeSign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
+  const uint64_t ieeeMantissa = bits & ((1ull << DOUBLE_MANTISSA_BITS) - 1);
+  const uint32_t ieeeExponent = (uint32_t) ((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) {
+    // For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros.
+    // For scientific notation we need to move these zeros into the exponent.
+    // (This is not needed for fixed-point notation, so it might be beneficial to trim
+    // trailing zeros in to_chars only if needed - once fixed-point notation output is implemented.)
+    for (;;) {
+      const uint64_t q = div10(v.mantissa);
+      const uint32_t r = ((uint32_t) v.mantissa) - 10 * ((uint32_t) q);
+      if (r != 0) {
+        break;
+      }
+      v.mantissa = q;
+      ++v.exponent;
+    }
+  } else {
+    v = d2d(ieeeMantissa, ieeeExponent);
+  }
+
+  return to_chars(v, ieeeSign, result);
+}
+
+void d2s_buffered(double f, char* result) {
+  const int index = d2s_buffered_n(f, result);
+
+  // Terminate the string.
+  result[index] = '\0';
+}
+
+char* d2s(double f) {
+  char* const result = (char*) malloc(25);
+  d2s_buffered(f, result);
+  return result;
+}
diff --git a/erts/emulator/ryu/d2s_full_table.h b/erts/emulator/ryu/d2s_full_table.h
new file mode 100644
index 0000000000..c8629eef1b
--- /dev/null
+++ b/erts/emulator/ryu/d2s_full_table.h
@@ -0,0 +1,367 @@
+// 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 PrintDoubleLookupTable.
+#define DOUBLE_POW5_INV_BITCOUNT 125
+#define DOUBLE_POW5_BITCOUNT 125
+
+#define DOUBLE_POW5_INV_TABLE_SIZE 342
+#define DOUBLE_POW5_TABLE_SIZE 326
+
+static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
+  {                    1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
+  {  5165088340638674453u, 1475739525896764129u }, {  7821419487252849886u, 1180591620717411303u },
+  {  8824922364862649494u, 1888946593147858085u }, {  7059937891890119595u, 1511157274518286468u },
+  { 13026647942995916322u, 1208925819614629174u }, {  9774590264567735146u, 1934281311383406679u },
+  { 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
+  { 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
+  {  9162556910162266299u, 1267650600228229401u }, {  7281393426775805432u, 2028240960365167042u },
+  { 16893161185646375315u, 1622592768292133633u }, {  2446482504291369283u, 1298074214633706907u },
+  {  7603720821608101175u, 2076918743413931051u }, {  2393627842544570617u, 1661534994731144841u },
+  { 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
+  {  5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
+  {  3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
+  {  6382248639981364905u, 1393796574908163946u }, {  2832900194486363201u, 2230074519853062314u },
+  {  5955668970331000884u, 1784059615882449851u }, {  1075186361522890384u, 1427247692705959881u },
+  { 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
+  {  3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
+  {  5547241898389809503u, 1870722095783555735u }, {  4437793518711847602u, 1496577676626844588u },
+  { 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
+  {  6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
+  { 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
+  { 14151565162110759939u, 1255420347077336152u }, {  7885109000409574610u, 2008672555323737844u },
+  {  9997436015069570011u, 1606938044258990275u }, {  7997948812055656009u, 1285550435407192220u },
+  { 12796718099289049614u, 2056880696651507552u }, {  2858676849947419045u, 1645504557321206042u },
+  { 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
+  {  3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
+  { 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
+  {  8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
+  { 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
+  { 15986332124095098083u, 2261564242916331941u }, {  9099716884534168143u, 1809251394333065553u },
+  { 14658471137111155161u, 1447401115466452442u }, {  4348079280205103483u, 1157920892373161954u },
+  { 14335624477811986218u, 1852673427797059126u }, {  7779150767507678651u, 1482138742237647301u },
+  {  2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
+  { 12097921058438802501u, 1517710072051350836u }, {  5988988032009131678u, 1214168057641080669u },
+  { 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
+  {  7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
+  { 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
+  {  4951948911778577463u, 2037035976334486086u }, {   272210314680951647u, 1629628781067588869u },
+  {  3907117066486671641u, 1303703024854071095u }, {  6251387306378674625u, 2085924839766513752u },
+  { 16069156289328670670u, 1668739871813211001u }, {  9165976216721026213u, 1334991897450568801u },
+  {  7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
+  { 13518030318433270404u, 1367031702989382452u }, {  6871453250525591353u, 2187250724783011924u },
+  {  9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
+  { 10282995085511086630u, 2239744742177804210u }, {  8226396068408869304u, 1791795793742243368u },
+  { 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
+  {  5324776569667477496u, 1834798892792057209u }, {  7949170070475892320u, 1467839114233645767u },
+  { 17427382500606444826u, 1174271291386916613u }, {  5747719112518849781u, 1878834066219066582u },
+  { 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
+  {  5295368560860596524u, 1923926083808324180u }, {  4236294848688477220u, 1539140867046659344u },
+  {  7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
+  {  9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
+  { 12335095245094488799u, 2017382717255397335u }, {  9868076196075591040u, 1613906173804317868u },
+  { 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
+  {  7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
+  { 11918976037903224966u, 2115379100128795516u }, {  5845832015580669650u, 1692303280103036413u },
+  { 12055363241948356366u, 1353842624082429130u }, {   841837113407818570u, 2166148198531886609u },
+  {  4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
+  { 12225235553534690011u, 2218135755296651887u }, {  2401490813343931363u, 1774508604237321510u },
+  {  1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
+  {  6886345170554478103u, 1817096810739017226u }, {  1819727321701672159u, 1453677448591213781u },
+  { 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
+  { 15587778368262418694u, 1488565707357402911u }, {  8780873879868024632u, 1190852565885922329u },
+  {  2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
+  {  7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
+  { 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
+  {  1553625868034358140u, 1997919072202235028u }, {  8621598323911307159u, 1598335257761788022u },
+  { 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
+  {   121653480894270168u, 1636695303948070935u }, {    97322784715416134u, 1309356243158456748u },
+  { 14913111714512307107u, 2094969989053530796u }, {  8241140556867935363u, 1675975991242824637u },
+  { 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
+  { 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
+  { 14650556434236701088u, 2196735251241795108u }, {   652398703163629901u, 1757388200993436087u },
+  { 11589965406756634890u, 1405910560794748869u }, {  7475898206584884855u, 2249456897271598191u },
+  {  2291369750525997561u, 1799565517817278553u }, {  9211793429904618695u, 1439652414253822842u },
+  { 18428218302589300235u, 2303443862806116547u }, {  7363877012587619542u, 1842755090244893238u },
+  { 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
+  {  2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
+  { 13231802778477390823u, 1207667975942893232u }, {  6413489186596184024u, 1932268761508629172u },
+  { 16198837793502678189u, 1545815009206903337u }, {  5580372605318321905u, 1236652007365522670u },
+  {  8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
+  {  7190041073742725760u, 1266331655542295214u }, {   436019273762630246u, 2026130648867672343u },
+  {  7727513048493924843u, 1620904519094137874u }, {  9871359253537050198u, 1296723615275310299u },
+  {  4726128361433549347u, 2074757784440496479u }, {  7470251503888749801u, 1659806227552397183u },
+  { 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
+  { 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
+  {  4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
+  {  3483374466074094362u, 1392346379889585943u }, {  1884050330976640656u, 2227754207823337509u },
+  {  5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
+  {  5913764258841343181u, 2281220308811097609u }, {  8420360221814984868u, 1824976247048878087u },
+  { 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
+  { 10245762345624985047u, 1868775676978051161u }, {  4507261061758077715u, 1495020541582440929u },
+  {  7295157664148372495u, 1196016433265952743u }, {  7982903447895485668u, 1913626293225524389u },
+  { 10075671573058298858u, 1530901034580419511u }, {  4371188443704728763u, 1224720827664335609u },
+  { 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
+  { 15839291315758726049u, 1254114127528279663u }, {  3206773216762499739u, 2006582604045247462u },
+  { 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
+  {  4907049252451240275u, 2054740586542333401u }, {   236290587219081897u, 1643792469233866721u },
+  { 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
+  {  5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
+  { 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
+  { 12584037722297574282u, 1378913065775496824u }, {  9066413911450387881u, 2206260905240794919u },
+  { 10942479943902220628u, 1765008724192635935u }, {  8753983955121776503u, 1412006979354108748u },
+  { 10317025513452932081u, 2259211166966573997u }, {   874922781278525018u, 1807368933573259198u },
+  {  8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
+  { 14767872471458792434u, 1850745787979017418u }, {   746251532941302978u, 1480596630383213935u },
+  {   597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
+  {  8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
+  { 17270291175157100626u, 1940647615375886168u }, {  2748186495899949531u, 1552518092300708935u },
+  {  2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
+  { 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
+  {  8826220925580526867u, 2034916513940385215u }, {  7060976740464421494u, 1627933211152308172u },
+  { 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
+  {  9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
+  { 13015147745246481542u, 2133764618521553367u }, {  3033420566713364587u, 1707011694817242694u },
+  {  6116085268112601993u, 1365609355853794155u }, {  9785736428980163188u, 2184974969366070648u },
+  { 15207286772667951197u, 1747979975492856518u }, {  1097782973908629988u, 1398383980394285215u },
+  {  1756452758253807981u, 2237414368630856344u }, {  5094511021344956708u, 1789931494904685075u },
+  {  4075608817075965366u, 1431945195923748060u }, {  6520974107321544586u, 2291112313477996896u },
+  {  1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
+  { 17210690286378213644u, 1173049504500734410u }, {  9090360384495590213u, 1876879207201175057u },
+  { 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
+  { 16096930852848599373u, 1921924308174003258u }, {  1809498238053148529u, 1537539446539202607u },
+  { 12515645034668249793u, 1230031557231362085u }, {  1578287981759648052u, 1968050491570179337u },
+  { 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
+  {  3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
+  {  6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
+  { 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
+  {  7551343283653851484u, 2113178124542660985u }, {  6041074626923081187u, 1690542499634128788u },
+  { 12211557331022285596u, 1352433999707303030u }, {  1091747655926105338u, 2163894399531684849u },
+  {  4562746939482794594u, 1731115519625347879u }, {  7339546366328145998u, 1384892415700278303u },
+  {  8053925371383123274u, 2215827865120445285u }, {  6443140297106498619u, 1772662292096356228u },
+  { 12533209867169019542u, 1418129833677084982u }, {  5295740528502789974u, 2269007733883335972u },
+  { 15304638867027962949u, 1815206187106668777u }, {  4865013464138549713u, 1452164949685335022u },
+  { 14960057215536570740u, 1161731959748268017u }, {  9178696285890871890u, 1858771135597228828u },
+  { 14721654658196518159u, 1487016908477783062u }, {  4398626097073393881u, 1189613526782226450u },
+  {  7037801755317430209u, 1903381642851562320u }, {  5630241404253944167u, 1522705314281249856u },
+  {   814844308661245011u, 1218164251424999885u }, {  1303750893857992017u, 1949062802279999816u },
+  { 15800395974054034906u, 1559250241823999852u }, {  5261619149759407279u, 1247400193459199882u },
+  { 12107939454356961969u, 1995840309534719811u }, {  5997002748743659252u, 1596672247627775849u },
+  {  8486951013736837725u, 1277337798102220679u }, {  2511075177753209390u, 2043740476963553087u },
+  { 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
+  {  4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
+  {  3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
+  {  9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
+  {  5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
+  { 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
+  { 13453306206113055875u, 1797693134862315907u }, {  3383947335406624054u, 1438154507889852726u },
+  { 16482362180876329456u, 2301047212623764361u }, {  9496540929959153242u, 1840837770099011489u },
+  { 11286581558709232917u, 1472670216079209191u }, {  5339916432225476010u, 1178136172863367353u },
+  {  4854517476818851293u, 1885017876581387765u }, {  3883613981455081034u, 1508014301265110212u },
+  { 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
+  {  5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
+  {  6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
+  { 12969830440044306787u, 1265014083170691364u }, {  9683682259845159889u, 2024022533073106183u },
+  { 15125643437359948558u, 1619218026458484946u }, {  8411165935146048523u, 1295374421166787957u },
+  { 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
+  {  8022738107230848036u, 1326463407274790868u }, {  9147032156827446534u, 2122341451639665389u },
+  { 11006974540203867551u, 1697873161311732311u }, {  5116230817421183718u, 1358298529049385849u },
+  { 15564666937357714594u, 2173277646479017358u }, {  1383687105660440706u, 1738622117183213887u },
+  { 12174996128754083534u, 1390897693746571109u }, {  8411947361780802685u, 2225436309994513775u },
+  {  6729557889424642148u, 1780349047995611020u }, {  5383646311539713719u, 1424279238396488816u },
+  {  1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
+  { 16285752362063044992u, 1458461940118004547u }, {  5649904260166615347u, 1166769552094403638u },
+  {  5350498001524674232u, 1866831283351045821u }, {   591049586477829062u, 1493465026680836657u },
+  { 11540886113407994219u, 1194772021344669325u }, {    18673707743239135u, 1911635234151470921u },
+  { 14772334225162232601u, 1529308187321176736u }, {  8128518565387875758u, 1223446549856941389u },
+  {  1937583260394870242u, 1957514479771106223u }, {  8928764237799716840u, 1566011583816884978u },
+  { 14521709019723594119u, 1252809267053507982u }, {  8477339172590109297u, 2004494827285612772u },
+  { 17849917782297818407u, 1603595861828490217u }, {  6901236596354434079u, 1282876689462792174u },
+  { 18420676183650915173u, 2052602703140467478u }, {  3668494502695001169u, 1642082162512373983u },
+  { 10313493231639821582u, 1313665730009899186u }, {  9122891541139893884u, 2101865168015838698u },
+  { 14677010862395735754u, 1681492134412670958u }, {   673562245690857633u, 1345193707530136767u }
+};
+
+static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
+  {                    0u, 1152921504606846976u }, {                    0u, 1441151880758558720u },
+  {                    0u, 1801439850948198400u }, {                    0u, 2251799813685248000u },
+  {                    0u, 1407374883553280000u }, {                    0u, 1759218604441600000u },
+  {                    0u, 2199023255552000000u }, {                    0u, 1374389534720000000u },
+  {                    0u, 1717986918400000000u }, {                    0u, 2147483648000000000u },
+  {                    0u, 1342177280000000000u }, {                    0u, 1677721600000000000u },
+  {                    0u, 2097152000000000000u }, {                    0u, 1310720000000000000u },
+  {                    0u, 1638400000000000000u }, {                    0u, 2048000000000000000u },
+  {                    0u, 1280000000000000000u }, {                    0u, 1600000000000000000u },
+  {                    0u, 2000000000000000000u }, {                    0u, 1250000000000000000u },
+  {                    0u, 1562500000000000000u }, {                    0u, 1953125000000000000u },
+  {                    0u, 1220703125000000000u }, {                    0u, 1525878906250000000u },
+  {                    0u, 1907348632812500000u }, {                    0u, 1192092895507812500u },
+  {                    0u, 1490116119384765625u }, {  4611686018427387904u, 1862645149230957031u },
+  {  9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
+  { 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
+  { 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
+  { 15629249925580062720u, 2220446049250313080u }, {  9768281203487539200u, 1387778780781445675u },
+  {  7598665485932036096u, 1734723475976807094u }, {   274959820560269312u, 2168404344971008868u },
+  {  9395221924704944128u, 1355252715606880542u }, {  2520655369026404352u, 1694065894508600678u },
+  { 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
+  { 13702562178731606016u, 1654361225106055349u }, {  3293144668132343808u, 2067951531382569187u },
+  { 18199116482078572544u, 1292469707114105741u }, {  8913837547316051968u, 1615587133892632177u },
+  { 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
+  { 15190102943214346240u, 1577721810442023610u }, {  9764256642163156992u, 1972152263052529513u },
+  { 17631875447420442880u, 1232595164407830945u }, {  8204786253993389888u, 1540743955509788682u },
+  {  1032610780636961552u, 1925929944387235853u }, {  2951224747111794922u, 1203706215242022408u },
+  {  3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
+  { 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
+  {  3710578054803671186u, 1836709923159824231u }, {    26536550077201078u, 2295887403949780289u },
+  { 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
+  {  8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
+  { 12076381983474541759u, 1751623080406021338u }, {  5872105442488401391u, 2189528850507526673u },
+  { 15199280947623720629u, 1368455531567204170u }, {  9775729147674874978u, 1710569414459005213u },
+  { 16831347453020981627u, 2138211768073756516u }, {  1296220121283337709u, 1336382355046097823u },
+  { 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
+  {  6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
+  { 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
+  {   532749306367912313u, 1593091911132452277u }, {  5277622651387278295u, 1991364888915565346u },
+  {  7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
+  {  8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
+  { 10989071563364309441u, 1519290839321567799u }, {  9124653435777998898u, 1899113549151959749u },
+  {  8008751406574943263u, 1186945968219974843u }, {  5399253239791291175u, 1483682460274968554u },
+  { 15972438586593889776u, 1854603075343710692u }, {   759402079766405302u, 1159126922089819183u },
+  { 14784310654990170340u, 1448908652612273978u }, {  9257016281882937117u, 1811135815765342473u },
+  { 16182956370781059300u, 2263919769706678091u }, {  7808504722524468110u, 1414949856066673807u },
+  {  5148944884728197234u, 1768687320083342259u }, {  1824495087482858639u, 2210859150104177824u },
+  {  1140309429676786649u, 1381786968815111140u }, {  1425386787095983311u, 1727233711018888925u },
+  {  6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
+  { 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
+  {   803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
+  {  4714634887749086344u, 2059023035787211567u }, {  9864175832484260821u, 1286889397367007229u },
+  { 16941905809032713930u, 1608611746708759036u }, {  2730638187581340797u, 2010764683385948796u },
+  { 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
+  {  4396021111970173586u, 1963637386119090621u }, {  5053356204195052443u, 1227273366324431638u },
+  { 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
+  { 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
+  { 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
+  {  4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
+  {  7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
+  { 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
+  { 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
+  { 10956397575869330579u, 2180075438084173168u }, {  6847748484918331612u, 1362547148802608230u },
+  { 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
+  { 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
+  { 13024893955298202172u, 2079081953128979843u }, {  5834715712847682405u, 1299426220705612402u },
+  { 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
+  { 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
+  { 12596021324643517422u, 1982767060402850955u }, {  5566670318688504437u, 1239229412751781847u },
+  {  2346651879933242642u, 1549036765939727309u }, {  7545000868343941206u, 1936295957424659136u },
+  {  4715625542714963254u, 1210184973390411960u }, {  5894531928393704067u, 1512731216738014950u },
+  { 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
+  { 16997363506238734644u, 1477276578845717724u }, {  2799960309088866689u, 1846595723557147156u },
+  { 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
+  { 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
+  { 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
+  {  3447025083132431277u, 2201313642927583642u }, {  6766076695385157452u, 1375821026829739776u },
+  {  8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
+  {  6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
+  { 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
+  {  5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
+  { 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
+  {  7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
+  {  3885132398186337741u, 1564127418111797597u }, {  9468101516160310080u, 1955159272639746996u },
+  { 15140935484454969608u, 1221974545399841872u }, {   479425281859160394u, 1527468181749802341u },
+  {  5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
+  { 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
+  { 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
+  {  8047776328842869663u, 1820883967578175474u }, {   836348374198811271u, 2276104959472719343u },
+  {  7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
+  {  8166621051047176104u, 2222758749485077483u }, {  2798295147690791113u, 1389224218428173427u },
+  { 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
+  {  8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
+  {  3828506775840797949u, 2119787930951192363u }, {    86973725686804766u, 1324867456844495227u },
+  { 13943775212390669669u, 1656084321055619033u }, {  3594660960206173375u, 2070105401319523792u },
+  {  2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
+  {  5816254103165035138u, 2021587305976097453u }, {  5941001823691840913u, 1263492066235060908u },
+  {  7426252279614801142u, 1579365082793826135u }, {  4671129331091113523u, 1974206353492282669u },
+  {  5225298841145639904u, 1233878970932676668u }, {  6531623551432049880u, 1542348713665845835u },
+  {  3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
+  { 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
+  { 11355826773077190286u, 1176718684132267635u }, {  9583097447919099954u, 1470898355165334544u },
+  { 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
+  {  2440964573842414192u, 1436424174966147016u }, {  3051205717303017741u, 1795530218707683770u },
+  { 13037379183483547984u, 2244412773384604712u }, {  8148361989677217490u, 1402757983365377945u },
+  { 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
+  { 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
+  {  9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
+  {  3292878744173340370u, 1672217826086733276u }, {  4116098430216675462u, 2090272282608416595u },
+  {   266718509671728212u, 1306420176630260372u }, {   333398137089660265u, 1633025220787825465u },
+  {  5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
+  { 12575375104699370472u, 1594751192175610805u }, {  1884160825592049379u, 1993438990219513507u },
+  { 17318501580490888525u, 1245899368887195941u }, {  7813068920331446945u, 1557374211108994927u },
+  {  5154650131986920777u, 1946717763886243659u }, {   915813323278131534u, 1216698602428902287u },
+  { 14979824709379828129u, 1520873253036127858u }, {  9501408849870009354u, 1901091566295159823u },
+  { 12855909558809837702u, 1188182228934474889u }, {  2234828893230133415u, 1485227786168093612u },
+  {  2793536116537666769u, 1856534732710117015u }, {  8663489100477123587u, 1160334207943823134u },
+  {  1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
+  {  9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
+  { 16011667041914537212u, 1770529492101780905u }, {  6179525747111007803u, 2213161865127226132u },
+  { 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
+  { 15834525901571292854u, 2161290883913306769u }, {  2979049660840976177u, 1350806802445816731u },
+  { 17558870131333383934u, 1688508503057270913u }, {  8113529608884566205u, 2110635628821588642u },
+  {  9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
+  { 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
+  {  1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
+  {  4853210475701136017u, 1258036869061940099u }, {  1454827076199032118u, 1572546086327425124u },
+  {  1818533845248790147u, 1965682607909281405u }, {  3442426662494187794u, 1228551629943300878u },
+  { 13526405364972510550u, 1535689537429126097u }, {  3072948650933474476u, 1919611921786407622u },
+  { 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
+  {  9630225068416591280u, 1874621017369538693u }, {  8324733676974063502u, 1171638135855961683u },
+  {  5794231077790191473u, 1464547669819952104u }, {  7242788847237739342u, 1830684587274940130u },
+  { 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
+  {  1596658836748081690u, 1787777917260683721u }, {  6607509564362490017u, 2234722396575854651u },
+  {  1823850468512862308u, 1396701497859909157u }, {  6891499104068465790u, 1745876872324886446u },
+  { 17837745916940358045u, 2182346090406108057u }, {  4231062170446641922u, 1363966306503817536u },
+  {  5288827713058302403u, 1704957883129771920u }, {  6611034641322878003u, 2131197353912214900u },
+  { 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
+  { 11644235287647684442u, 2081247415929897363u }, {  4971804045566108824u, 1300779634956185852u },
+  {  6214755056957636030u, 1625974543695232315u }, {  3156757802769657134u, 2032468179619040394u },
+  {  6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
+  { 17206059723201118751u, 1984832206659219134u }, {  6142101308573311315u, 1240520129162011959u },
+  {  3065940617289251240u, 1550650161452514949u }, {  8444111790038951954u, 1938312701815643686u },
+  {   665883850346957067u, 1211445438634777304u }, {   832354812933696334u, 1514306798293471630u },
+  { 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
+  { 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
+  { 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
+  {  1277659885424598868u, 1805194375864829576u }, {  1597074856780748586u, 2256492969831036970u },
+  {  5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
+  {  1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
+  { 11243484188358716120u, 1721567512383298469u }, {   219297180166231438u, 2151959390479123087u },
+  {  7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
+  { 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
+  { 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
+  { 16925056528170176201u, 1282667750405742577u }, {  7321262604930556539u, 1603334688007178222u },
+  { 18374950293017971482u, 2004168360008972777u }, {  4566814905495150320u, 1252605225005607986u },
+  { 14931890668723713708u, 1565756531257009982u }, {  9441491299049866327u, 1957195664071262478u },
+  {  1289246043478778550u, 1223247290044539049u }, {  6223243572775861092u, 1529059112555673811u },
+  {  3167368447542438461u, 1911323890694592264u }, {  1979605279714024038u, 1194577431684120165u },
+  {  7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
+  { 13606538515115052232u, 1166579523129023598u }, {  7784801107039039482u, 1458224403911279498u },
+  {   507629346944023544u, 1822780504889099373u }, {  5246222702107417334u, 2278475631111374216u },
+  {  3278889188817135834u, 1424047269444608885u }, {  8710297504448807696u, 1780059086805761106u }
+};
+
+#endif // RYU_D2S_FULL_TABLE_H
diff --git a/erts/emulator/ryu/d2s_intrinsics.h b/erts/emulator/ryu/d2s_intrinsics.h
new file mode 100644
index 0000000000..77388b3088
--- /dev/null
+++ b/erts/emulator/ryu/d2s_intrinsics.h
@@ -0,0 +1,358 @@
+// 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
+
+#include <assert.h>
+#include <stdint.h>
+
+// Defines RYU_32_BIT_PLATFORM if applicable.
+#include "common.h"
+
+// ABSL avoids uint128_t on Win32 even if __SIZEOF_INT128__ is defined.
+// Let's do the same for now.
+#if defined(__SIZEOF_INT128__) && !defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS)
+#define HAS_UINT128
+#elif defined(_MSC_VER) && !defined(RYU_ONLY_64_BIT_OPS) && defined(_M_X64)
+#define HAS_64_BIT_INTRINSICS
+#endif
+
+#if defined(HAS_UINT128)
+typedef __uint128_t uint128_t;
+#endif
+
+#if defined(HAS_64_BIT_INTRINSICS)
+
+#include <intrin.h>
+
+static inline uint64_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
+  return _umul128(a, b, productHi);
+}
+
+// Returns the lower 64 bits of (hi*2^64 + lo) >> dist, with 0 < dist < 64.
+static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t 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].)
+  // However, this function is now also called by s2d, which requires supporting
+  // the larger shift range (TODO: what is the actual range?).
+  // 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_t umul128(const uint64_t a, const uint64_t b, uint64_t* const productHi) {
+  // The casts here help MSVC to avoid calls to the __allmul library function.
+  const uint32_t aLo = (uint32_t)a;
+  const uint32_t aHi = (uint32_t)(a >> 32);
+  const uint32_t bLo = (uint32_t)b;
+  const uint32_t bHi = (uint32_t)(b >> 32);
+
+  const uint64_t b00 = (uint64_t)aLo * bLo;
+  const uint64_t b01 = (uint64_t)aLo * bHi;
+  const uint64_t b10 = (uint64_t)aHi * bLo;
+  const uint64_t b11 = (uint64_t)aHi * bHi;
+
+  const uint32_t b00Lo = (uint32_t)b00;
+  const uint32_t b00Hi = (uint32_t)(b00 >> 32);
+
+  const uint64_t mid1 = b10 + b00Hi;
+  const uint32_t mid1Lo = (uint32_t)(mid1);
+  const uint32_t mid1Hi = (uint32_t)(mid1 >> 32);
+
+  const uint64_t mid2 = b01 + mid1Lo;
+  const uint32_t mid2Lo = (uint32_t)(mid2);
+  const uint32_t mid2Hi = (uint32_t)(mid2 >> 32);
+
+  const uint64_t pHi = b11 + mid1Hi + mid2Hi;
+  const uint64_t pLo = ((uint64_t)mid2Lo << 32) | b00Lo;
+
+  *productHi = pHi;
+  return pLo;
+}
+
+static inline uint64_t shiftright128(const uint64_t lo, const uint64_t hi, const uint32_t dist) {
+  // We don't need to handle the case dist >= 64 here (see above).
+  assert(dist < 64);
+  assert(dist > 0);
+  return (hi << (64 - dist)) | (lo >> dist);
+}
+
+#endif // defined(HAS_64_BIT_INTRINSICS)
+
+#if defined(RYU_32_BIT_PLATFORM)
+
+// Returns the high 64 bits of the 128-bit product of a and b.
+static inline uint64_t umulh(const uint64_t a, const uint64_t b) {
+  // Reuse the umul128 implementation.
+  // Optimizers will likely eliminate the instructions used to compute the
+  // low part of the product.
+  uint64_t 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_t div5(const uint64_t x) {
+  return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 2;
+}
+
+static inline uint64_t div10(const uint64_t x) {
+  return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 3;
+}
+
+static inline uint64_t div100(const uint64_t x) {
+  return umulh(x >> 2, 0x28F5C28F5C28F5C3u) >> 2;
+}
+
+static inline uint64_t div1e8(const uint64_t x) {
+  return umulh(x, 0xABCC77118461CEFDu) >> 26;
+}
+
+static inline uint64_t div1e9(const uint64_t x) {
+  return umulh(x >> 9, 0x44B82FA09B5A53u) >> 11;
+}
+
+static inline uint32_t mod1e9(const uint64_t x) {
+  // Avoid 64-bit math as much as possible.
+  // Returning (uint32_t) (x - 1000000000 * div1e9(x)) would
+  // perform 32x64-bit multiplication and 64-bit subtraction.
+  // x and 1000000000 * div1e9(x) are guaranteed to differ by
+  // less than 10^9, so their highest 32 bits must be identical,
+  // so we can truncate both sides to uint32_t before subtracting.
+  // We can also simplify (uint32_t) (1000000000 * div1e9(x)).
+  // We can truncate before multiplying instead of after, as multiplying
+  // the highest 32 bits of div1e9(x) can't affect the lowest 32 bits.
+  return ((uint32_t) x) - 1000000000 * ((uint32_t) div1e9(x));
+}
+
+#else // defined(RYU_32_BIT_PLATFORM)
+
+static inline uint64_t div5(const uint64_t x) {
+  return x / 5;
+}
+
+static inline uint64_t div10(const uint64_t x) {
+  return x / 10;
+}
+
+static inline uint64_t div100(const uint64_t x) {
+  return x / 100;
+}
+
+static inline uint64_t div1e8(const uint64_t x) {
+  return x / 100000000;
+}
+
+static inline uint64_t div1e9(const uint64_t x) {
+  return x / 1000000000;
+}
+
+static inline uint32_t mod1e9(const uint64_t x) {
+  return (uint32_t) (x - 1000000000 * div1e9(x));
+}
+
+#endif // defined(RYU_32_BIT_PLATFORM)
+
+static inline uint32_t pow5Factor(uint64_t value) {
+  uint32_t count = 0;
+  for (;;) {
+    assert(value != 0);
+    const uint64_t q = div5(value);
+    const uint32_t r = ((uint32_t) value) - 5 * ((uint32_t) 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_t value, const uint32_t 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_t value, const uint32_t p) {
+  assert(value != 0);
+  assert(p < 64);
+  // __builtin_ctzll doesn't appear to be faster here.
+  return (value & ((1ull << 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.
+//    x64 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 x64 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(HAS_UINT128)
+
+// Best case: use 128-bit type.
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+  const uint128_t b0 = ((uint128_t) m) * mul[0];
+  const uint128_t b2 = ((uint128_t) m) * mul[1];
+  return (uint64_t) (((b0 >> 64) + b2) >> (j - 64));
+}
+
+static inline uint64_t mulShiftAll64(const uint64_t m, const uint64_t* const mul, const int32_t j,
+  uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) {
+//  m <<= 2;
+//  uint128_t b0 = ((uint128_t) m) * mul[0]; // 0
+//  uint128_t b2 = ((uint128_t) m) * mul[1]; // 64
+//
+//  uint128_t hi = (b0 >> 64) + b2;
+//  uint128_t lo = b0 & 0xffffffffffffffffull;
+//  uint128_t factor = (((uint128_t) mul[1]) << 64) + mul[0];
+//  uint128_t vpLo = lo + (factor << 1);
+//  *vp = (uint64_t) ((hi + (vpLo >> 64)) >> (j - 64));
+//  uint128_t vmLo = lo - (factor << mmShift);
+//  *vm = (uint64_t) ((hi + (vmLo >> 64) - (((uint128_t) 1ull) << 64)) >> (j - 64));
+//  return (uint64_t) (hi >> (j - 64));
+  *vp = mulShift64(4 * m + 2, mul, j);
+  *vm = mulShift64(4 * m - 1 - mmShift, mul, j);
+  return mulShift64(4 * m, mul, j);
+}
+
+#elif defined(HAS_64_BIT_INTRINSICS)
+
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+  // m is maximum 55 bits
+  uint64_t high1;                                   // 128
+  const uint64_t low1 = umul128(m, mul[1], &high1); // 64
+  uint64_t high0;                                   // 64
+  umul128(m, mul[0], &high0);                       // 0
+  const uint64_t sum = high0 + low1;
+  if (sum < high0) {
+    ++high1; // overflow into high1
+  }
+  return shiftright128(sum, high1, j - 64);
+}
+
+static inline uint64_t mulShiftAll64(const uint64_t m, const uint64_t* const mul, const int32_t j,
+  uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) {
+  *vp = mulShift64(4 * m + 2, mul, j);
+  *vm = mulShift64(4 * m - 1 - mmShift, mul, j);
+  return mulShift64(4 * m, mul, j);
+}
+
+#else // !defined(HAS_UINT128) && !defined(HAS_64_BIT_INTRINSICS)
+
+static inline uint64_t mulShift64(const uint64_t m, const uint64_t* const mul, const int32_t j) {
+  // m is maximum 55 bits
+  uint64_t high1;                                   // 128
+  const uint64_t low1 = umul128(m, mul[1], &high1); // 64
+  uint64_t high0;                                   // 64
+  umul128(m, mul[0], &high0);                       // 0
+  const uint64_t sum = high0 + low1;
+  if (sum < high0) {
+    ++high1; // overflow into high1
+  }
+  return shiftright128(sum, high1, j - 64);
+}
+
+// This is faster if we don't have a 64x64->128-bit multiplication.
+static inline uint64_t mulShiftAll64(uint64_t m, const uint64_t* const mul, const int32_t j,
+  uint64_t* const vp, uint64_t* const vm, const uint32_t mmShift) {
+  m <<= 1;
+  // m is maximum 55 bits
+  uint64_t tmp;
+  const uint64_t lo = umul128(m, mul[0], &tmp);
+  uint64_t hi;
+  const uint64_t mid = tmp + umul128(m, mul[1], &hi);
+  hi += mid < tmp; // overflow into hi
+
+  const uint64_t lo2 = lo + mul[0];
+  const uint64_t mid2 = mid + mul[1] + (lo2 < lo);
+  const uint64_t hi2 = hi + (mid2 < mid);
+  *vp = shiftright128(mid2, hi2, (uint32_t) (j - 64 - 1));
+
+  if (mmShift == 1) {
+    const uint64_t lo3 = lo - mul[0];
+    const uint64_t mid3 = mid - mul[1] - (lo3 > lo);
+    const uint64_t hi3 = hi - (mid3 > mid);
+    *vm = shiftright128(mid3, hi3, (uint32_t) (j - 64 - 1));
+  } else {
+    const uint64_t lo3 = lo + lo;
+    const uint64_t mid3 = mid + mid + (lo3 < lo);
+    const uint64_t hi3 = hi + hi + (mid3 < mid);
+    const uint64_t lo4 = lo3 - mul[0];
+    const uint64_t mid4 = mid3 - mul[1] - (lo4 > lo3);
+    const uint64_t hi4 = hi3 - (mid4 > mid3);
+    *vm = shiftright128(mid4, hi4, (uint32_t) (j - 64));
+  }
+
+  return shiftright128(mid, hi, (uint32_t) (j - 64 - 1));
+}
+
+#endif // HAS_64_BIT_INTRINSICS
+
+#endif // RYU_D2S_INTRINSICS_H
diff --git a/erts/emulator/ryu/digit_table.h b/erts/emulator/ryu/digit_table.h
new file mode 100644
index 0000000000..02219bc6d5
--- /dev/null
+++ b/erts/emulator/ryu/digit_table.h
@@ -0,0 +1,35 @@
+// 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_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/erts/emulator/ryu/ryu.h b/erts/emulator/ryu/ryu.h
new file mode 100644
index 0000000000..9439ada7cc
--- /dev/null
+++ b/erts/emulator/ryu/ryu.h
@@ -0,0 +1,36 @@
+// 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_H
+#define RYU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+int d2s_buffered_n(double f, char* result);
+void d2s_buffered(double f, char* result);
+char* d2s(double f);
+
+//CHANGE_FOR_ERLANG we dropped all the other functions as not used by us
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // RYU_H
diff --git a/erts/emulator/ryu/ryu.mk b/erts/emulator/ryu/ryu.mk
new file mode 100644
index 0000000000..524618f446
--- /dev/null
+++ b/erts/emulator/ryu/ryu.mk
@@ -0,0 +1,57 @@
+#-*-makefile-*-   ; force emacs to enter makefile-mode
+# ----------------------------------------------------
+# Make include file for Ryu
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2011-2021. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+# ----------------------------------------------------
+
+RYU_FILES = d2s
+
+RYU_OBJDIR = $(ERL_TOP)/erts/emulator/ryu/obj/$(TARGET)/$(TYPE)
+RYU_OBJS = $(RYU_FILES:%=$(RYU_OBJDIR)/%.o)
+RYU_DIR =  $(ERL_TOP)/erts/emulator/ryu
+
+RYU_SRC = $(RYU_FILES:%=ryu/%.c)
+
+ifeq ($(TARGET), win32)
+RYU_LIBRARY = $(RYU_OBJDIR)/ryu.lib
+else
+RYU_LIBRARY = $(RYU_OBJDIR)/libryu.a
+endif
+
+ifeq ($(TARGET), win32)
+RYU_CFLAGS = $(CFLAGS)
+else
+RYU_CFLAGS = $(filter-out -Wdeclaration-after-statement,$(CFLAGS))
+endif
+
+ifeq ($(TARGET), win32)
+$(RYU_LIBRARY): $(RYU_OBJS)
+	$(V_AR) -out:$@ $(RYU_OBJS)
+else
+$(RYU_LIBRARY): $(RYU_OBJS)
+	$(V_AR) $(ARFLAGS) $@ $(RYU_OBJS)
+	-@ ($(RANLIB) $@ || true) 2>/dev/null
+endif
+
+
+
+$(RYU_OBJDIR)/%.o: ryu/%.c
+	$(V_CC) -c $(RYU_CFLAGS) -o $@ $<
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index d509699eef..facb2dc7ba 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -191,15 +191,75 @@ t_float_to_string(Config) when is_list(Config) ->
     <<NegZero/float>> = <<16#8000000000000000:64>>,
     "-0.0" = float_to_list(NegZero, [{decimals, 1}, compact]),
     "-0.0" = float_to_list(NegZero, [{decimals, 1}]),
+    "-0.0" = float_to_list(NegZero, [short]),
     "-0.0e+00" = float_to_list(NegZero, [{scientific, 1}]),
     "-0.0e+00" = float_to_list(NegZero, [{scientific, 1}, compact]),
     <<"-0.0">> = float_to_binary(NegZero, [{decimals, 1}, compact]),
     <<"-0.0">> = float_to_binary(NegZero, [{decimals, 1}]),
+    <<"-0.0">> = float_to_binary(NegZero, [short]),
     <<"-0.0e+00">> = float_to_binary(NegZero, [{scientific, 1}]),
     <<"-0.0e+00">> = float_to_binary(NegZero, [{scientific, 1}, compact]),
 
     fts_rand_float_decimals(1000),
 
+    % test short option
+
+    % test switch for big integers
+    test_fts("-9007199254740991.0", -float((1 bsl 53) -1), [short]),
+    test_fts("-9.007199254740992e15", -float(1 bsl 53), [short]),
+    test_fts("-9.007199254740992e15", -float((1 bsl 53) +1), [short]),
+    test_fts("9007199254740991.0", float((1 bsl 53) -1), [short]),
+    test_fts("9.007199254740992e15", float(1 bsl 53), [short]),
+    test_fts("9.007199254740992e15", float((1 bsl 53) +1), [short]),
+
+    % test basic
+    test_fts("2.018", 2.018, [short]),
+    test_fts("-2.018", -2.018, [short]),
+
+    % test switching logic between decimal and scientific
+    test_fts("1.0e-6", 1.0e-6, [short]),
+    test_fts("1.0e-5", 1.0e-5, [short]),
+    test_fts("0.0001", 1.0e-4, [short]),
+    test_fts("0.001", 1.0e-3, [short]),
+    test_fts("0.01", 1.0e-2, [short]),
+    test_fts("0.1", 1.0e-1, [short]),
+    test_fts("1.0", 1.0e0, [short]),
+    test_fts("10.0", 1.0e1, [short]),
+    test_fts("100.0", 1.0e2, [short]),
+    test_fts("1.0e3", 1.0e3, [short]),
+    test_fts("1.0e4", 1.0e4, [short]),
+    test_fts("1.0e5", 1.0e5, [short]),
+    test_fts("1.0e6", 1.0e6, [short]),
+    test_fts("1.0e7", 1.0e7, [short]),
+    test_fts("1.234e-6", 1.234e-6, [short]),
+    test_fts("1.234e-5", 1.234e-5, [short]),
+    test_fts("1.234e-4", 1.234e-4, [short]),
+    test_fts("0.001234", 1.234e-3, [short]),
+    test_fts("0.01234", 1.234e-2, [short]),
+    test_fts("0.1234", 1.234e-1, [short]),
+    test_fts("1.234", 1.234e0, [short]),
+    test_fts("12.34", 1.234e1, [short]),
+    test_fts("123.4", 1.234e2, [short]),
+    test_fts("1234.0", 1.234e3, [short]),
+    test_fts("12340.0", 1.234e4, [short]),
+    test_fts("1.234e5", 1.234e5, [short]),
+    test_fts("1.234e6", 1.234e6, [short]),
+
+    % test the switch to subnormals
+    test_fts("2.2250738585072014e-308", 2.2250738585072014e-308, [short]),
+
+    % test lots of trailing zeroes
+    test_fts("2.9802322387695312e-8", 2.98023223876953125e-8, [short]),
+
+    % test some ryu regressions
+    test_fts("-2.109808898695963e16", -2.109808898695963e16, [short]),
+    test_fts("4.940656e-318", 4.940656e-318, [short]),
+    test_fts("1.18575755e-316", 1.18575755e-316, [short]),
+    test_fts("2.989102097996e-312", 2.989102097996e-312, [short]),
+    test_fts("9.0608011534336e15", 9.0608011534336e15, [short]),
+    test_fts("4.708356024711512e18", 4.708356024711512e18, [short]),
+    test_fts("9.409340012568248e18", 9.409340012568248e18, [short]),
+    test_fts("1.2345678", 1.2345678, [short]),
     ok.
 
 test_fts(Expect, Float) ->
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 7f23c21d45..8a1f01ac8c 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -946,7 +946,8 @@ float_to_binary(_Float) ->
       Options :: [Option],
       Option  :: {decimals, Decimals :: 0..253} |
                  {scientific, Decimals :: 0..249} |
-                 compact.
+                 compact |
+                 short.
 float_to_binary(_Float, _Options) ->
     erlang:nif_error(undefined).
 
@@ -962,7 +963,8 @@ float_to_list(_Float) ->
       Options :: [Option],
       Option  :: {decimals, Decimals :: 0..253} |
                  {scientific, Decimals :: 0..249} |
-                 compact.
+                 compact |
+                 short.
 float_to_list(_Float, _Options) ->
     erlang:nif_error(undefined).
 
diff --git a/lib/stdlib/scripts/generate_ryu_table.escript b/lib/stdlib/scripts/generate_ryu_table.escript
deleted file mode 100755
index 7191b64cd3..0000000000
--- a/lib/stdlib/scripts/generate_ryu_table.escript
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/usr/bin/env escript
-%% -*- erlang -*-
-%%! +A0
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2017-2021. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%%     http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--mode(compile).
-
--define(MOD, "io_lib_format_ryu_table").
-
--define(TABLE_SIZE, 326).
--define(INV_TABLE_SIZE, 342).
-
--define(POW5_BITCOUNT, 125).
--define(POW5_INV_BITCOUNT, 125).
-
-main(_) ->
-    Values = [ values(X) || X <- lists:seq(0, ?TABLE_SIZE - 1)],
-    InvValues = [ inv_values(X) || X <- lists:seq(0, ?INV_TABLE_SIZE - 1)],
-
-    %% Make module
-    {ok, Out} = file:open("../src/" ++ ?MOD ++ ".erl", [write]),
-    gen_file(Out, Values, InvValues),
-    ok = file:close(Out),
-    ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-inv_values(X) ->
-  Pow = pow5(X),
-  Pow5len = log2floor(Pow),
-  J = Pow5len + ?POW5_INV_BITCOUNT - 1,
-  Inv = ((1 bsl J) div Pow) + 1,
-  {X, Inv}.
-
-values(X) ->
-  Pow = pow5(X),
-  Pow5len = log2floor(Pow),
-  Pow5 = Pow bsr (Pow5len - ?POW5_BITCOUNT),
-  {X, Pow5}.
-
-pow5(0) ->
-  1;
-pow5(1) ->
-  5;
-pow5(X) ->
-  5 * pow5(X - 1).
-
-log2floor(Int) when is_integer(Int), Int > 0 ->
-    log2floor(Int, 0).
-
-log2floor(0, N) ->
-    N;
-log2floor(Int, N) ->
-    log2floor(Int bsr 1, 1 + N).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-gen_file(Fd, Values, InvValues) ->
-    gen_header(Fd),
-    gen_pow5_static(Fd),
-    gen_table(Fd, Values),
-    gen_inv_table(Fd, InvValues),
-    ok.
-
-gen_header(Fd) ->
-    io:put_chars(Fd, "%%\n%% this file is generated do not modify\n"),
-    io:put_chars(Fd, "%% see ../script/generate_ryu_table.escript\n\n"),
-    io:put_chars(Fd, "-module(" ++ ?MOD ++").\n"),
-    io:put_chars(Fd, "-export([pow5_bitcount/0, pow5_inv_bitcount/0, value/1, inv_value/1]).\n\n"),
-    ok.
-
-gen_pow5_static(Fd) ->
-    io:put_chars(Fd, "-spec pow5_bitcount() -> integer().\n"),
-    io:format(Fd, "pow5_bitcount() -> ~p.~n~n", [?POW5_BITCOUNT]),
-    io:put_chars(Fd, "-spec pow5_inv_bitcount() -> integer().\n"),
-    io:format(Fd, "pow5_inv_bitcount() -> ~p.~n~n", [?POW5_INV_BITCOUNT]),
-    ok.
-
-gen_table(Fd, Values) ->
-    io:put_chars(Fd, "-spec value(integer()) -> integer().\n"),
-    [io:format(Fd, "value(~p) -> ~p;~n", [Key, Val]) || {Key,Val} <- Values],
-    io:put_chars(Fd, "value(_) -> error(function_clause).\n\n"),
-    ok.
-
-gen_inv_table(Fd, Values) ->
-    io:put_chars(Fd, "-spec inv_value(integer()) -> integer().\n"),
-    [io:format(Fd, "inv_value(~p) -> ~p;~n", [Key, Val]) || {Key,Val} <- Values],
-    io:put_chars(Fd, "inv_value(_) -> error(function_clause).\n"),
-    ok.
-
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 509648cb2b..8a45b8e249 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -91,7 +91,6 @@ MODULES= \
 	io \
 	io_lib \
 	io_lib_format \
-	io_lib_format_ryu_table \
 	io_lib_fread \
 	io_lib_pretty \
 	lists \
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 597ff4c2c5..58ed3b31f7 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -539,268 +539,10 @@ float_data([_|Cs], Ds) ->
 
 %%  Returns a correctly rounded string that converts to Float when
 %%  read back with list_to_float/1.
-%%
-%%  When abs(Float) < float(1 bsl 53) the shortest such string is
-%%  returned, and otherwise the shortest such string using scientific
-%%  notation is returned. That is, scientific notation is used if and
-%%  only if scientific notation results in a shorter string than
-%%  normal notation when abs(Float) < float(1 bsl 53), and scientific
-%%  notation is used unconditionally if abs(Float) >= float(1 bsl
-%%  53). See comment in insert_decimal/2 for an explanation for why
-%%  float(1 bsl 53) is chosen as cutoff point.
-%%
-%%  The algorithm that is used to find the decimal number that is
-%%  represented by the returned String is described in "Ryu: Fast
-%%  Float-to-String Conversion" in Proceedings of 39th ACM SIGPLAN
-%%  Conference on Programming Language Design and Implementation.
-%%  https://dl.acm.org/doi/pdf/10.1145/3192366.3192369
 
 -spec fwrite_g(float()) -> string().
 fwrite_g(Float) ->
-    case sign_mantissa_exponent(Float) of
-        {0, 0, 0} -> "0.0";
-        {1, 0, 0} -> "-0.0";
-        {S, M, E} when E < 2047 ->
-            {Place, Digits} = 
-                case is_small_int(M, E) of
-                    {int, M1, E1} ->
-                        compute_shortest_int(M1, E1);
-                    not_int ->
-                        fwrite_g_1(M, E)
-                end,
-            DigitList = insert_decimal(Place, Digits, Float),
-            insert_minus(S, DigitList)
-    end.
-
--define(BIG_POW, (1 bsl 52)).
--define(DECODE_CORRECTION, 1075).
-
-sign_mantissa_exponent(F) ->
-    <<S:1, BE:11, M:52>> = <<F:64/float>>,
-    {S, M , BE}.
-
-is_small_int(M, E) ->
-    M2 = ?BIG_POW bor M,
-    E2 = E - ?DECODE_CORRECTION,
-    case E2 > 0 orelse E2 < -52 of
-        true ->
-            %% f = m2 * 2^e2 >= 2^53 is an integer.
-            %% Ignore this case for now.
-            %% or f < 1
-            not_int;
-        _ -> 
-            %% 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.
-            Mask = (1 bsl -E2) - 1,
-            Fraction = M2 band Mask,
-            case Fraction of
-                0 ->
-                %% f is an integer in the range [1, 2^53).
-                %% Note: mantissa might contain trailing (decimal) 0's.
-                    {int, M2 bsr -E2, 0};
-                _ ->
-                    not_int
-            end
-    end.
-
-%%  For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros.
-compute_shortest_int(M, E) when M rem 10 =:= 0 ->
-    Q = M div 10,
-    compute_shortest_int(Q, E + 1);
-compute_shortest_int(M, E) ->
-    {E, integer_to_list(M)}.
-
-fwrite_g_1(M, E) ->
-    {Mf, Ef} = decode(M, E),
-    Shift = mmshift(M, E),
-    Mv = 4 * Mf,
-    {Q, Vm, Vr, Vp, E10} = convert_to_decimal(Ef, Mv, Shift),
-    Accept = M rem 2 == 0,
-    {VmIsTrailingZero, VrIsTrailingZero, Vp1} = bounds(Mv, Q, Vp, Accept, Ef, Shift),
-    {D1, E1} = compute_shortest(Vm, Vr, Vp1, VmIsTrailingZero, VrIsTrailingZero, Accept),
-    {E1 + E10, integer_to_list(D1)}.
-
-decode(Mantissa, 0) ->
-    {Mantissa, 1 - ?DECODE_CORRECTION - 2};
-decode(Mantissa, Exponent) ->
-    {Mantissa + ?BIG_POW, Exponent - ?DECODE_CORRECTION - 2}.
-
-mmshift(0, E) when E > 1 ->
-    0;
-mmshift(_M, _E) ->
-    1.
-
-convert_to_decimal(E2, Mv, Shift) when E2 >= 0 ->
-    Q = max(0, ((E2 * 78913) bsr 18) - 1),
-    Mul = io_lib_format_ryu_table:inv_value(Q),
-    K = io_lib_format_ryu_table:pow5_inv_bitcount() + pow5bits(Q) - 1,
-    I = -E2 + Q + K,
-    {Vm, Vr, Vp} = mulShiftAll(Mv, Shift, I, Mul),
-    {Q, Vm, Vr, Vp, Q};
-
-convert_to_decimal(E2, Mv, Shift) when E2 < 0 ->
-    Q = max(0, ((-E2 * 732923) bsr 20) - 1),
-    I = -E2 - Q,
-    K = pow5bits(I) - io_lib_format_ryu_table:pow5_bitcount(),
-    From_file = io_lib_format_ryu_table:value(I),
-    J = Q - K,
-    {Vm, Vr, Vp} = mulShiftAll(Mv, Shift, J, From_file),
-    E10 = E2 + Q,
-    {Q, Vm, Vr, Vp, E10}.
-
-pow5bits(E) ->
-    ((E * 1217359) bsr 19) + 1.
-
-mulShiftAll(Mv, Shift, J, Mul) ->
-    A = mulShift64(Mv - 1 - Shift, Mul, J),
-    B = mulShift64(Mv, Mul, J),
-    C = mulShift64(Mv + 2,Mul, J),
-    {A, B, C}.
-
-mulShift64(M, Mul, J) ->
-    (M * Mul) bsr J.
-
-bounds(Mv, Q, Vp, _Accept, E2, _Shift) when E2 >= 0, Q =< 21, Mv rem 5 =:= 0 ->
-    {false, multipleOfPowerOf5(Mv, Q) , Vp};
-bounds(Mv, Q, Vp, true, E2, Shift) when E2 >= 0, Q =< 21 ->
-    {multipleOfPowerOf5(Mv - 1 - Shift, Q), false , Vp};
-bounds(Mv, Q, Vp, _Accept, E2, _Shift) when E2 >= 0, Q =< 21 ->
-    {false, false , Vp - vpmodifier(multipleOfPowerOf5(Mv + 2, Q))};
-bounds(_Mv, Q, Vp, true, E2, Shift) when E2 < 0, Q =< 1 ->
-    {Shift =:= 1, true, Vp};
-bounds(_Mv, Q, Vp, false, E2, _Shift) when E2 < 0, Q =< 1 ->
-    {false, true, Vp - 1};
-bounds(Mv, Q, Vp, _Accept, E2, _Shift) when E2 < 0, Q < 63 ->
-    {false, (Mv band ((1 bsl Q) -1 )) =:= 0, Vp};
-bounds(_Mv, _Q, Vp, _Accept, _E2, _Shift) ->
-    {false, false, Vp}.
-
-multipleOfPowerOf5(Value, Q) ->
-    pow5factor(Value) >= Q.
-
-pow5factor(Val) ->
-    pow5factor(Val div 5, 0).
-
-pow5factor(Val, Count) when (Val rem 5) /= 0->
-    Count;
-pow5factor(Val, Count) ->
-    pow5factor(Val div 5, Count + 1).
-
-vpmodifier(true) ->
-    1;
-vpmodifier(false) ->
-    0.
-
-compute_shortest(Vm, Vr, Vp, false, false, _Accept) ->
-    {Vm1, Vr1, Removed, RoundUp} =
-        general_case(Vm, Vr, Vp, 0, false),
-    Output = Vr1 + handle_normal_output_mod(Vr1, Vm1, RoundUp),
-    {Output, Removed};
-compute_shortest(Vm, Vr, Vp, VmIsTrailingZero, VrIsTrailingZero, Accept) ->
-    {Vm1, Vr1, Removed, LastRemovedDigit} = 
-        handle_trailing_zeros(Vm, Vr, Vp, VmIsTrailingZero, VrIsTrailingZero, 0, 0),
-    Output = Vr1 + handle_zero_output_mod(Vr1, Vm1, Accept, VmIsTrailingZero, LastRemovedDigit),
-    {Output, Removed}.
-
-general_case(Vm, Vr, Vp, Removed, RoundUp) when (Vp div 100) =< (Vm div 100)->
-    general_case_10(Vm, Vr, Vp, Removed, RoundUp);
-general_case(Vm, Vr, Vp, Removed, _RU) ->
-    VmD100 = Vm div 100,
-    VrD100 = Vr div 100,
-    VpD100 = Vp div 100,
-    RoundUp = ((Vr rem 100) >= 50),
-    general_case_10(VmD100, VrD100, VpD100, 2 + Removed, RoundUp).
-
-general_case_10(Vm, Vr, Vp, Removed, RoundUp) 
-    when (Vp div 10) =< (Vm div 10)->
-    {Vm, Vr, Removed, RoundUp};
-general_case_10(Vm, Vr, Vp, Removed, _RU) ->
-    VmD10 = Vm div 10,
-    VrD10 = Vr div 10,
-    VpD10 = Vp div 10,
-    RoundUp = ((Vr rem 10) >= 5),
-    general_case_10(VmD10, VrD10, VpD10, 1 + Removed, RoundUp).
-
-handle_normal_output_mod(Vr, Vm, RoundUp) when (Vm =:= Vr) or RoundUp ->
-    1;
-handle_normal_output_mod(_Vr, _Vm, _RoundUp) ->
-    0.
-
-handle_trailing_zeros(Vm, Vr, Vp, VmTZ, VrTZ, Removed, LastRemovedDigit)
-    when (Vp div 10) =< (Vm div 10)->
-    vmIsTrailingZero(Vm, Vr, Vp, VmTZ, VrTZ, Removed, LastRemovedDigit);
-handle_trailing_zeros(Vm, Vr, Vp, VmIsTrailingZero, VrIsTrailingZero, Removed, LastRemovedDigit) ->
-    VmTZ = VmIsTrailingZero and ((Vm rem 10) =:= 0),
-    VrTZ = VrIsTrailingZero and (LastRemovedDigit =:= 0),
-    handle_trailing_zeros(Vm div 10, Vr div 10, Vp div 10, VmTZ, VrTZ, 1 + Removed, Vr rem 10).
-
-vmIsTrailingZero(Vm, Vr, _Vp, false = _VmTZ, VrTZ, Removed, LastRemovedDigit) ->
-    handle_50_dotdot_0(Vm, Vr, VrTZ, Removed, LastRemovedDigit);
-vmIsTrailingZero(Vm, Vr, _Vp, _VmTZ, VrTZ, Removed, LastRemovedDigit) when (Vm rem 10) /= 0 ->
-    handle_50_dotdot_0(Vm, Vr, VrTZ, Removed, LastRemovedDigit);
-vmIsTrailingZero(Vm, Vr, Vp, VmTZ, VrTZ, Removed, LastRemovedDigit) ->
-    vmIsTrailingZero(Vm div 10, Vr div 10, Vp div 10, VmTZ, LastRemovedDigit == 0 andalso VrTZ, 1 + Removed, Vr rem 10).
-
-handle_50_dotdot_0(Vm, Vr, true, Removed, 5) when (Vr rem 2) =:= 0 ->
-    {Vm, Vr, Removed, 4};
-handle_50_dotdot_0(Vm, Vr, _VrTZ, Removed, LastRemovedDigit) ->
-    {Vm, Vr, Removed, LastRemovedDigit}.
-
-handle_zero_output_mod(_Vr, _Vm, _Accept, _VmTZ, LastRemovedDigit) when LastRemovedDigit >= 5 ->
-    1;
-handle_zero_output_mod(Vr, Vm, Accept, VmTZ, _LastRemovedDigit) when Vr =:= Vm, ((not Accept) or (not VmTZ)) ->
-    1;
-handle_zero_output_mod(_Vr, _Vm, _Accept, _VmTZ, _LastRemovedDigit) ->
-    0.
-
-insert_decimal(Place, S, Float) ->
-    L = length(S),
-    Exp = Place + L - 1,
-    ExpL = integer_to_list(Exp),
-    ExpCost = length(ExpL) + 2,
-    if
-        Place < 0 ->
-            if
-                Exp >= 0 ->
-                    {S0, S1} = lists:split(L + Place, S),
-                    S0 ++ "." ++ S1;
-                2 - Place - L =< ExpCost ->
-                    "0." ++ lists:duplicate(-Place - L, $0) ++ S;
-                true ->
-                    insert_exp(ExpL, S)
-            end;
-        true ->
-            Dot = if L =:= 1 -> 1; true -> 0 end,
-            if
-                %% All integers in the range [-2^53, 2^53] can
-                %% be stored without loss of precision in an
-                %% IEEE 754 64-bit double but 2^53+1 cannot be
-                %% stored in an IEEE 754 64-bit double without
-                %% loss of precision (float((1 bsl 53)+1) =:=
-                %% float(1 bsl 53)). It thus makes sense to
-                %% show floats that are >= 2^53 or <= -2^53 in
-                %% scientific notation to indicate that the
-                %% number is so large that there could be loss
-                %% in precion when adding or subtracting 1.
-                %%
-                %% https://stackoverflow.com/questions/1848700/biggest-integer-that-can-be-stored-in-a-double?answertab=votes#tab-top
-                ExpCost + Dot >= Place + 2 andalso abs(Float) < float(1 bsl 53) ->
-                    S ++ lists:duplicate(Place, $0) ++ ".0";
-                true ->
-                    insert_exp(ExpL, S)
-            end
-    end.
-
-
-insert_exp(ExpL, [C]) ->
-    [C] ++ ".0e" ++ ExpL;
-insert_exp(ExpL, [C | S]) ->
-    [C] ++ "." ++ S ++ "e" ++ ExpL.
-
-insert_minus(0, Digits) ->
-    Digits;
-insert_minus(1, Digits) ->
-    [$-] ++ Digits.
+    float_to_list(Float, [short]).
 
 %% fwrite_g(Float, Field, Adjust, Precision, PadChar)
 %%  Use the f form if Float is >= 0.1 and < 1.0e4, 
diff --git a/lib/stdlib/src/io_lib_format_ryu_table.erl b/lib/stdlib/src/io_lib_format_ryu_table.erl
deleted file mode 100644
index b20268a939..0000000000
--- a/lib/stdlib/src/io_lib_format_ryu_table.erl
+++ /dev/null
@@ -1,686 +0,0 @@
-%%
-%% this file is generated do not modify
-%% see ../script/generate_ryu_table.escript
-
--module(io_lib_format_ryu_table).
--export([pow5_bitcount/0, pow5_inv_bitcount/0, value/1, inv_value/1]).
-
--spec pow5_bitcount() -> integer().
-pow5_bitcount() -> 125.
-
--spec pow5_inv_bitcount() -> integer().
-pow5_inv_bitcount() -> 125.
-
--spec value(integer()) -> integer().
-value(0) -> 21267647932558653966460912964485513216;
-value(1) -> 26584559915698317458076141205606891520;
-value(2) -> 33230699894622896822595176507008614400;
-value(3) -> 41538374868278621028243970633760768000;
-value(4) -> 25961484292674138142652481646100480000;
-value(5) -> 32451855365842672678315602057625600000;
-value(6) -> 40564819207303340847894502572032000000;
-value(7) -> 25353012004564588029934064107520000000;
-value(8) -> 31691265005705735037417580134400000000;
-value(9) -> 39614081257132168796771975168000000000;
-value(10) -> 24758800785707605497982484480000000000;
-value(11) -> 30948500982134506872478105600000000000;
-value(12) -> 38685626227668133590597632000000000000;
-value(13) -> 24178516392292583494123520000000000000;
-value(14) -> 30223145490365729367654400000000000000;
-value(15) -> 37778931862957161709568000000000000000;
-value(16) -> 23611832414348226068480000000000000000;
-value(17) -> 29514790517935282585600000000000000000;
-value(18) -> 36893488147419103232000000000000000000;
-value(19) -> 23058430092136939520000000000000000000;
-value(20) -> 28823037615171174400000000000000000000;
-value(21) -> 36028797018963968000000000000000000000;
-value(22) -> 22517998136852480000000000000000000000;
-value(23) -> 28147497671065600000000000000000000000;
-value(24) -> 35184372088832000000000000000000000000;
-value(25) -> 21990232555520000000000000000000000000;
-value(26) -> 27487790694400000000000000000000000000;
-value(27) -> 34359738368000000000000000000000000000;
-value(28) -> 21474836480000000000000000000000000000;
-value(29) -> 26843545600000000000000000000000000000;
-value(30) -> 33554432000000000000000000000000000000;
-value(31) -> 41943040000000000000000000000000000000;
-value(32) -> 26214400000000000000000000000000000000;
-value(33) -> 32768000000000000000000000000000000000;
-value(34) -> 40960000000000000000000000000000000000;
-value(35) -> 25600000000000000000000000000000000000;
-value(36) -> 32000000000000000000000000000000000000;
-value(37) -> 40000000000000000000000000000000000000;
-value(38) -> 25000000000000000000000000000000000000;
-value(39) -> 31250000000000000000000000000000000000;
-value(40) -> 39062500000000000000000000000000000000;
-value(41) -> 24414062500000000000000000000000000000;
-value(42) -> 30517578125000000000000000000000000000;
-value(43) -> 38146972656250000000000000000000000000;
-value(44) -> 23841857910156250000000000000000000000;
-value(45) -> 29802322387695312500000000000000000000;
-value(46) -> 37252902984619140625000000000000000000;
-value(47) -> 23283064365386962890625000000000000000;
-value(48) -> 29103830456733703613281250000000000000;
-value(49) -> 36379788070917129516601562500000000000;
-value(50) -> 22737367544323205947875976562500000000;
-value(51) -> 28421709430404007434844970703125000000;
-value(52) -> 35527136788005009293556213378906250000;
-value(53) -> 22204460492503130808472633361816406250;
-value(54) -> 27755575615628913510590791702270507812;
-value(55) -> 34694469519536141888238489627838134765;
-value(56) -> 21684043449710088680149056017398834228;
-value(57) -> 27105054312137610850186320021748542785;
-value(58) -> 33881317890172013562732900027185678482;
-value(59) -> 42351647362715016953416125033982098102;
-value(60) -> 26469779601696885595885078146238811314;
-value(61) -> 33087224502121106994856347682798514142;
-value(62) -> 41359030627651383743570434603498142678;
-value(63) -> 25849394142282114839731521627186339173;
-value(64) -> 32311742677852643549664402033982923967;
-value(65) -> 40389678347315804437080502542478654959;
-value(66) -> 25243548967072377773175314089049159349;
-value(67) -> 31554436208840472216469142611311449186;
-value(68) -> 39443045261050590270586428264139311483;
-value(69) -> 24651903288156618919116517665087069677;
-value(70) -> 30814879110195773648895647081358837096;
-value(71) -> 38518598887744717061119558851698546370;
-value(72) -> 24074124304840448163199724282311591481;
-value(73) -> 30092655381050560203999655352889489352;
-value(74) -> 37615819226313200254999569191111861690;
-value(75) -> 23509887016445750159374730744444913556;
-value(76) -> 29387358770557187699218413430556141945;
-value(77) -> 36734198463196484624023016788195177431;
-value(78) -> 22958874039497802890014385492621985894;
-value(79) -> 28698592549372253612517981865777482368;
-value(80) -> 35873240686715317015647477332221852960;
-value(81) -> 22420775429197073134779673332638658100;
-value(82) -> 28025969286496341418474591665798322625;
-value(83) -> 35032461608120426773093239582247903282;
-value(84) -> 21895288505075266733183274738904939551;
-value(85) -> 27369110631344083416479093423631174439;
-value(86) -> 34211388289180104270598866779538968048;
-value(87) -> 21382117680737565169124291737211855030;
-value(88) -> 26727647100921956461405364671514818788;
-value(89) -> 33409558876152445576756705839393523485;
-value(90) -> 41761948595190556970945882299241904356;
-value(91) -> 26101217871994098106841176437026190222;
-value(92) -> 32626522339992622633551470546282737778;
-value(93) -> 40783152924990778291939338182853422223;
-value(94) -> 25489470578119236432462086364283388889;
-value(95) -> 31861838222649045540577607955354236111;
-value(96) -> 39827297778311306925722009944192795139;
-value(97) -> 24892061111444566828576256215120496962;
-value(98) -> 31115076389305708535720320268900621202;
-value(99) -> 38893845486632135669650400336125776503;
-value(100) -> 24308653429145084793531500210078610314;
-value(101) -> 30385816786431355991914375262598262893;
-value(102) -> 37982270983039194989892969078247828616;
-value(103) -> 23738919364399496868683105673904892885;
-value(104) -> 29673649205499371085853882092381116106;
-value(105) -> 37092061506874213857317352615476395133;
-value(106) -> 23182538441796383660823345384672746958;
-value(107) -> 28978173052245479576029181730840933698;
-value(108) -> 36222716315306849470036477163551167122;
-value(109) -> 22639197697066780918772798227219479451;
-value(110) -> 28298997121333476148465997784024349314;
-value(111) -> 35373746401666845185582497230030436643;
-value(112) -> 22108591501041778240989060768769022902;
-value(113) -> 27635739376302222801236325960961278627;
-value(114) -> 34544674220377778501545407451201598284;
-value(115) -> 21590421387736111563465879657000998927;
-value(116) -> 26988026734670139454332349571251248659;
-value(117) -> 33735033418337674317915436964064060824;
-value(118) -> 42168791772922092897394296205080076030;
-value(119) -> 26355494858076308060871435128175047519;
-value(120) -> 32944368572595385076089293910218809399;
-value(121) -> 41180460715744231345111617387773511748;
-value(122) -> 25737787947340144590694760867358444843;
-value(123) -> 32172234934175180738368451084198056053;
-value(124) -> 40215293667718975922960563855247570067;
-value(125) -> 25134558542324359951850352409529731292;
-value(126) -> 31418198177905449939812940511912164115;
-value(127) -> 39272747722381812424766175639890205143;
-value(128) -> 24545467326488632765478859774931378214;
-value(129) -> 30681834158110790956848574718664222768;
-value(130) -> 38352292697638488696060718398330278460;
-value(131) -> 23970182936024055435037948998956424037;
-value(132) -> 29962728670030069293797436248695530047;
-value(133) -> 37453410837537586617246795310869412559;
-value(134) -> 23408381773460991635779247069293382849;
-value(135) -> 29260477216826239544724058836616728561;
-value(136) -> 36575596521032799430905073545770910702;
-value(137) -> 22859747825645499644315670966106819189;
-value(138) -> 28574684782056874555394588707633523986;
-value(139) -> 35718355977571093194243235884541904982;
-value(140) -> 22323972485981933246402022427838690614;
-value(141) -> 27904965607477416558002528034798363267;
-value(142) -> 34881207009346770697503160043497954084;
-value(143) -> 21800754380841731685939475027186221303;
-value(144) -> 27250942976052164607424343783982776628;
-value(145) -> 34063678720065205759280429729978470785;
-value(146) -> 21289799200040753599550268581236544241;
-value(147) -> 26612249000050941999437835726545680301;
-value(148) -> 33265311250063677499297294658182100376;
-value(149) -> 41581639062579596874121618322727625471;
-value(150) -> 25988524414112248046326011451704765919;
-value(151) -> 32485655517640310057907514314630957399;
-value(152) -> 40607069397050387572384392893288696749;
-value(153) -> 25379418373156492232740245558305435468;
-value(154) -> 31724272966445615290925306947881794335;
-value(155) -> 39655341208057019113656633684852242919;
-value(156) -> 24784588255035636946035396053032651824;
-value(157) -> 30980735318794546182544245066290814780;
-value(158) -> 38725919148493182728180306332863518475;
-value(159) -> 24203699467808239205112691458039699047;
-value(160) -> 30254624334760299006390864322549623809;
-value(161) -> 37818280418450373757988580403187029761;
-value(162) -> 23636425261531483598742862751991893600;
-value(163) -> 29545531576914354498428578439989867001;
-value(164) -> 36931914471142943123035723049987333751;
-value(165) -> 23082446544464339451897326906242083594;
-value(166) -> 28853058180580424314871658632802604493;
-value(167) -> 36066322725725530393589573291003255616;
-value(168) -> 22541451703578456495993483306877034760;
-value(169) -> 28176814629473070619991854133596293450;
-value(170) -> 35221018286841338274989817666995366813;
-value(171) -> 22013136429275836421868636041872104258;
-value(172) -> 27516420536594795527335795052340130322;
-value(173) -> 34395525670743494409169743815425162903;
-value(174) -> 21497203544214684005731089884640726814;
-value(175) -> 26871504430268355007163862355800908518;
-value(176) -> 33589380537835443758954827944751135647;
-value(177) -> 41986725672294304698693534930938919559;
-value(178) -> 26241703545183940436683459331836824724;
-value(179) -> 32802129431479925545854324164796030906;
-value(180) -> 41002661789349906932317905205995038632;
-value(181) -> 25626663618343691832698690753746899145;
-value(182) -> 32033329522929614790873363442183623931;
-value(183) -> 40041661903662018488591704302729529914;
-value(184) -> 25026038689788761555369815189205956196;
-value(185) -> 31282548362235951944212268986507445245;
-value(186) -> 39103185452794939930265336233134306557;
-value(187) -> 24439490907996837456415835145708941598;
-value(188) -> 30549363634996046820519793932136176997;
-value(189) -> 38186704543745058525649742415170221247;
-value(190) -> 23866690339840661578531089009481388279;
-value(191) -> 29833362924800826973163861261851735349;
-value(192) -> 37291703656001033716454826577314669186;
-value(193) -> 23307314785000646072784266610821668241;
-value(194) -> 29134143481250807590980333263527085302;
-value(195) -> 36417679351563509488725416579408856627;
-value(196) -> 22761049594727193430453385362130535392;
-value(197) -> 28451311993408991788066731702663169240;
-value(198) -> 35564139991761239735083414628328961550;
-value(199) -> 22227587494850774834427134142705600969;
-value(200) -> 27784484368563468543033917678382001211;
-value(201) -> 34730605460704335678792397097977501514;
-value(202) -> 21706628412940209799245248186235938446;
-value(203) -> 27133285516175262249056560232794923058;
-value(204) -> 33916606895219077811320700290993653822;
-value(205) -> 42395758619023847264150875363742067278;
-value(206) -> 26497349136889904540094297102338792048;
-value(207) -> 33121686421112380675117871377923490061;
-value(208) -> 41402108026390475843897339222404362576;
-value(209) -> 25876317516494047402435837014002726610;
-value(210) -> 32345396895617559253044796267503408262;
-value(211) -> 40431746119521949066305995334379260328;
-value(212) -> 25269841324701218166441247083987037705;
-value(213) -> 31587301655876522708051558854983797131;
-value(214) -> 39484127069845653385064448568729746414;
-value(215) -> 24677579418653533365665280355456091509;
-value(216) -> 30846974273316916707081600444320114386;
-value(217) -> 38558717841646145883852000555400142982;
-value(218) -> 24099198651028841177407500347125089364;
-value(219) -> 30123998313786051471759375433906361705;
-value(220) -> 37654997892232564339699219292382952131;
-value(221) -> 23534373682645352712312012057739345082;
-value(222) -> 29417967103306690890390015072174181352;
-value(223) -> 36772458879133363612987518840217726691;
-value(224) -> 22982786799458352258117199275136079181;
-value(225) -> 28728483499322940322646499093920098977;
-value(226) -> 35910604374153675403308123867400123721;
-value(227) -> 22444127733846047127067577417125077326;
-value(228) -> 28055159667307558908834471771406346657;
-value(229) -> 35068949584134448636043089714257933322;
-value(230) -> 21918093490084030397526931071411208326;
-value(231) -> 27397616862605037996908663839264010407;
-value(232) -> 34247021078256297496135829799080013009;
-value(233) -> 21404388173910185935084893624425008131;
-value(234) -> 26755485217387732418856117030531260163;
-value(235) -> 33444356521734665523570146288164075204;
-value(236) -> 41805445652168331904462682860205094006;
-value(237) -> 26128403532605207440289176787628183753;
-value(238) -> 32660504415756509300361470984535229692;
-value(239) -> 40825630519695636625451838730669037115;
-value(240) -> 25516019074809772890907399206668148197;
-value(241) -> 31895023843512216113634249008335185246;
-value(242) -> 39868779804390270142042811260418981558;
-value(243) -> 24917987377743918838776757037761863473;
-value(244) -> 31147484222179898548470946297202329342;
-value(245) -> 38934355277724873185588682871502911677;
-value(246) -> 24333972048578045740992926794689319798;
-value(247) -> 30417465060722557176241158493361649748;
-value(248) -> 38021831325903196470301448116702062185;
-value(249) -> 23763644578689497793938405072938788865;
-value(250) -> 29704555723361872242423006341173486082;
-value(251) -> 37130694654202340303028757926466857602;
-value(252) -> 23206684158876462689392973704041786001;
-value(253) -> 29008355198595578361741217130052232502;
-value(254) -> 36260443998244472952176521412565290627;
-value(255) -> 22662777498902795595110325882853306642;
-value(256) -> 28328471873628494493887907353566633302;
-value(257) -> 35410589842035618117359884191958291628;
-value(258) -> 22131618651272261323349927619973932267;
-value(259) -> 27664523314090326654187409524967415334;
-value(260) -> 34580654142612908317734261906209269168;
-value(261) -> 21612908839133067698583913691380793230;
-value(262) -> 27016136048916334623229892114225991537;
-value(263) -> 33770170061145418279037365142782489422;
-value(264) -> 42212712576431772848796706428478111778;
-value(265) -> 26382945360269858030497941517798819861;
-value(266) -> 32978681700337322538122426897248524826;
-value(267) -> 41223352125421653172653033621560656033;
-value(268) -> 25764595078388533232908146013475410020;
-value(269) -> 32205743847985666541135182516844262526;
-value(270) -> 40257179809982083176418978146055328157;
-value(271) -> 25160737381238801985261861341284580098;
-value(272) -> 31450921726548502481577326676605725123;
-value(273) -> 39313652158185628101971658345757156403;
-value(274) -> 24571032598866017563732286466098222752;
-value(275) -> 30713790748582521954665358082622778440;
-value(276) -> 38392238435728152443331697603278473050;
-value(277) -> 23995149022330095277082311002049045656;
-value(278) -> 29993936277912619096352888752561307070;
-value(279) -> 37492420347390773870441110940701633838;
-value(280) -> 23432762717119233669025694337938521149;
-value(281) -> 29290953396399042086282117922423151436;
-value(282) -> 36613691745498802607852647403028939295;
-value(283) -> 22883557340936751629907904626893087059;
-value(284) -> 28604446676170939537384880783616358824;
-value(285) -> 35755558345213674421731100979520448530;
-value(286) -> 22347223965758546513581938112200280331;
-value(287) -> 27934029957198183141977422640250350414;
-value(288) -> 34917537446497728927471778300312938018;
-value(289) -> 21823460904061080579669861437695586261;
-value(290) -> 27279326130076350724587326797119482826;
-value(291) -> 34099157662595438405734158496399353533;
-value(292) -> 21311973539122149003583849060249595958;
-value(293) -> 26639966923902686254479811325311994947;
-value(294) -> 33299958654878357818099764156639993684;
-value(295) -> 41624948318597947272624705195799992106;
-value(296) -> 26015592699123717045390440747374995066;
-value(297) -> 32519490873904646306738050934218743833;
-value(298) -> 40649363592380807883422563667773429791;
-value(299) -> 25405852245238004927139102292358393619;
-value(300) -> 31757315306547506158923877865447992024;
-value(301) -> 39696644133184382698654847331809990030;
-value(302) -> 24810402583240239186659279582381243769;
-value(303) -> 31013003229050298983324099477976554711;
-value(304) -> 38766254036312873729155124347470693389;
-value(305) -> 24228908772695546080721952717169183368;
-value(306) -> 30286135965869432600902440896461479210;
-value(307) -> 37857669957336790751128051120576849012;
-value(308) -> 23661043723335494219455031950360530633;
-value(309) -> 29576304654169367774318789937950663291;
-value(310) -> 36970380817711709717898487422438329114;
-value(311) -> 23106488011069818573686554639023955696;
-value(312) -> 28883110013837273217108193298779944620;
-value(313) -> 36103887517296591521385241623474930775;
-value(314) -> 22564929698310369700865776014671831734;
-value(315) -> 28206162122887962126082220018339789668;
-value(316) -> 35257702653609952657602775022924737085;
-value(317) -> 22036064158506220411001734389327960678;
-value(318) -> 27545080198132775513752167986659950848;
-value(319) -> 34431350247665969392190209983324938560;
-value(320) -> 21519593904791230870118881239578086600;
-value(321) -> 26899492380989038587648601549472608250;
-value(322) -> 33624365476236298234560751936840760312;
-value(323) -> 42030456845295372793200939921050950390;
-value(324) -> 26269035528309607995750587450656843994;
-value(325) -> 32836294410387009994688234313321054992;
-value(_) -> error(function_clause).
-
--spec inv_value(integer()) -> integer().
-inv_value(0) -> 42535295865117307932921825928971026433;
-inv_value(1) -> 34028236692093846346337460743176821146;
-inv_value(2) -> 27222589353675077077069968594541456917;
-inv_value(3) -> 21778071482940061661655974875633165534;
-inv_value(4) -> 34844914372704098658649559801013064854;
-inv_value(5) -> 27875931498163278926919647840810451883;
-inv_value(6) -> 22300745198530623141535718272648361506;
-inv_value(7) -> 35681192317648997026457149236237378410;
-inv_value(8) -> 28544953854119197621165719388989902728;
-inv_value(9) -> 22835963083295358096932575511191922183;
-inv_value(10) -> 36537540933272572955092120817907075492;
-inv_value(11) -> 29230032746618058364073696654325660394;
-inv_value(12) -> 23384026197294446691258957323460528315;
-inv_value(13) -> 37414441915671114706014331717536845304;
-inv_value(14) -> 29931553532536891764811465374029476243;
-inv_value(15) -> 23945242826029513411849172299223580995;
-inv_value(16) -> 38312388521647221458958675678757729591;
-inv_value(17) -> 30649910817317777167166940543006183673;
-inv_value(18) -> 24519928653854221733733552434404946938;
-inv_value(19) -> 39231885846166754773973683895047915101;
-inv_value(20) -> 31385508676933403819178947116038332081;
-inv_value(21) -> 25108406941546723055343157692830665665;
-inv_value(22) -> 40173451106474756888549052308529065064;
-inv_value(23) -> 32138760885179805510839241846823252051;
-inv_value(24) -> 25711008708143844408671393477458601641;
-inv_value(25) -> 41137613933030151053874229563933762625;
-inv_value(26) -> 32910091146424120843099383651147010100;
-inv_value(27) -> 26328072917139296674479506920917608080;
-inv_value(28) -> 42124916667422874679167211073468172928;
-inv_value(29) -> 33699933333938299743333768858774538343;
-inv_value(30) -> 26959946667150639794667015087019630674;
-inv_value(31) -> 21567957333720511835733612069615704539;
-inv_value(32) -> 34508731733952818937173779311385127263;
-inv_value(33) -> 27606985387162255149739023449108101810;
-inv_value(34) -> 22085588309729804119791218759286481448;
-inv_value(35) -> 35336941295567686591665950014858370317;
-inv_value(36) -> 28269553036454149273332760011886696254;
-inv_value(37) -> 22615642429163319418666208009509357003;
-inv_value(38) -> 36185027886661311069865932815214971205;
-inv_value(39) -> 28948022309329048855892746252171976964;
-inv_value(40) -> 23158417847463239084714197001737581571;
-inv_value(41) -> 37053468555941182535542715202780130514;
-inv_value(42) -> 29642774844752946028434172162224104411;
-inv_value(43) -> 23714219875802356822747337729779283529;
-inv_value(44) -> 37942751801283770916395740367646853646;
-inv_value(45) -> 30354201441027016733116592294117482917;
-inv_value(46) -> 24283361152821613386493273835293986334;
-inv_value(47) -> 38853377844514581418389238136470378133;
-inv_value(48) -> 31082702275611665134711390509176302507;
-inv_value(49) -> 24866161820489332107769112407341042006;
-inv_value(50) -> 39785858912782931372430579851745667209;
-inv_value(51) -> 31828687130226345097944463881396533767;
-inv_value(52) -> 25462949704181076078355571105117227014;
-inv_value(53) -> 40740719526689721725368913768187563222;
-inv_value(54) -> 32592575621351777380295131014550050577;
-inv_value(55) -> 26074060497081421904236104811640040462;
-inv_value(56) -> 41718496795330275046777767698624064739;
-inv_value(57) -> 33374797436264220037422214158899251791;
-inv_value(58) -> 26699837949011376029937771327119401433;
-inv_value(59) -> 21359870359209100823950217061695521147;
-inv_value(60) -> 34175792574734561318320347298712833834;
-inv_value(61) -> 27340634059787649054656277838970267067;
-inv_value(62) -> 21872507247830119243725022271176213654;
-inv_value(63) -> 34996011596528190789960035633881941846;
-inv_value(64) -> 27996809277222552631968028507105553477;
-inv_value(65) -> 22397447421778042105574422805684442782;
-inv_value(66) -> 35835915874844867368919076489095108450;
-inv_value(67) -> 28668732699875893895135261191276086760;
-inv_value(68) -> 22934986159900715116108208953020869408;
-inv_value(69) -> 36695977855841144185773134324833391053;
-inv_value(70) -> 29356782284672915348618507459866712843;
-inv_value(71) -> 23485425827738332278894805967893370274;
-inv_value(72) -> 37576681324381331646231689548629392439;
-inv_value(73) -> 30061345059505065316985351638903513951;
-inv_value(74) -> 24049076047604052253588281311122811161;
-inv_value(75) -> 38478521676166483605741250097796497857;
-inv_value(76) -> 30782817340933186884593000078237198286;
-inv_value(77) -> 24626253872746549507674400062589758629;
-inv_value(78) -> 39402006196394479212279040100143613806;
-inv_value(79) -> 31521604957115583369823232080114891045;
-inv_value(80) -> 25217283965692466695858585664091912836;
-inv_value(81) -> 40347654345107946713373737062547060537;
-inv_value(82) -> 32278123476086357370698989650037648430;
-inv_value(83) -> 25822498780869085896559191720030118744;
-inv_value(84) -> 41315998049390537434494706752048189990;
-inv_value(85) -> 33052798439512429947595765401638551992;
-inv_value(86) -> 26442238751609943958076612321310841594;
-inv_value(87) -> 42307582002575910332922579714097346550;
-inv_value(88) -> 33846065602060728266338063771277877240;
-inv_value(89) -> 27076852481648582613070451017022301792;
-inv_value(90) -> 21661481985318866090456360813617841434;
-inv_value(91) -> 34658371176510185744730177301788546293;
-inv_value(92) -> 27726696941208148595784141841430837035;
-inv_value(93) -> 22181357552966518876627313473144669628;
-inv_value(94) -> 35490172084746430202603701557031471404;
-inv_value(95) -> 28392137667797144162082961245625177124;
-inv_value(96) -> 22713710134237715329666368996500141699;
-inv_value(97) -> 36341936214780344527466190394400226718;
-inv_value(98) -> 29073548971824275621972952315520181375;
-inv_value(99) -> 23258839177459420497578361852416145100;
-inv_value(100) -> 37214142683935072796125378963865832159;
-inv_value(101) -> 29771314147148058236900303171092665728;
-inv_value(102) -> 23817051317718446589520242536874132582;
-inv_value(103) -> 38107282108349514543232388058998612131;
-inv_value(104) -> 30485825686679611634585910447198889705;
-inv_value(105) -> 24388660549343689307668728357759111764;
-inv_value(106) -> 39021856878949902892269965372414578822;
-inv_value(107) -> 31217485503159922313815972297931663058;
-inv_value(108) -> 24973988402527937851052777838345330446;
-inv_value(109) -> 39958381444044700561684444541352528714;
-inv_value(110) -> 31966705155235760449347555633082022971;
-inv_value(111) -> 25573364124188608359478044506465618377;
-inv_value(112) -> 40917382598701773375164871210344989403;
-inv_value(113) -> 32733906078961418700131896968275991523;
-inv_value(114) -> 26187124863169134960105517574620793218;
-inv_value(115) -> 41899399781070615936168828119393269149;
-inv_value(116) -> 33519519824856492748935062495514615319;
-inv_value(117) -> 26815615859885194199148049996411692255;
-inv_value(118) -> 21452492687908155359318439997129353804;
-inv_value(119) -> 34323988300653048574909503995406966087;
-inv_value(120) -> 27459190640522438859927603196325572870;
-inv_value(121) -> 21967352512417951087942082557060458296;
-inv_value(122) -> 35147764019868721740707332091296733273;
-inv_value(123) -> 28118211215894977392565865673037386618;
-inv_value(124) -> 22494568972715981914052692538429909295;
-inv_value(125) -> 35991310356345571062484308061487854871;
-inv_value(126) -> 28793048285076456849987446449190283897;
-inv_value(127) -> 23034438628061165479989957159352227118;
-inv_value(128) -> 36855101804897864767983931454963563388;
-inv_value(129) -> 29484081443918291814387145163970850711;
-inv_value(130) -> 23587265155134633451509716131176680569;
-inv_value(131) -> 37739624248215413522415545809882688910;
-inv_value(132) -> 30191699398572330817932436647906151128;
-inv_value(133) -> 24153359518857864654345949318324920902;
-inv_value(134) -> 38645375230172583446953518909319873443;
-inv_value(135) -> 30916300184138066757562815127455898755;
-inv_value(136) -> 24733040147310453406050252101964719004;
-inv_value(137) -> 39572864235696725449680403363143550406;
-inv_value(138) -> 31658291388557380359744322690514840325;
-inv_value(139) -> 25326633110845904287795458152411872260;
-inv_value(140) -> 40522612977353446860472733043858995616;
-inv_value(141) -> 32418090381882757488378186435087196493;
-inv_value(142) -> 25934472305506205990702549148069757194;
-inv_value(143) -> 41495155688809929585124078636911611511;
-inv_value(144) -> 33196124551047943668099262909529289209;
-inv_value(145) -> 26556899640838354934479410327623431367;
-inv_value(146) -> 42491039425341367895167056524197490187;
-inv_value(147) -> 33992831540273094316133645219357992150;
-inv_value(148) -> 27194265232218475452906916175486393720;
-inv_value(149) -> 21755412185774780362325532940389114976;
-inv_value(150) -> 34808659497239648579720852704622583961;
-inv_value(151) -> 27846927597791718863776682163698067169;
-inv_value(152) -> 22277542078233375091021345730958453735;
-inv_value(153) -> 35644067325173400145634153169533525976;
-inv_value(154) -> 28515253860138720116507322535626820781;
-inv_value(155) -> 22812203088110976093205858028501456625;
-inv_value(156) -> 36499524940977561749129372845602330600;
-inv_value(157) -> 29199619952782049399303498276481864480;
-inv_value(158) -> 23359695962225639519442798621185491584;
-inv_value(159) -> 37375513539561023231108477793896786534;
-inv_value(160) -> 29900410831648818584886782235117429227;
-inv_value(161) -> 23920328665319054867909425788093943382;
-inv_value(162) -> 38272525864510487788655081260950309411;
-inv_value(163) -> 30618020691608390230924065008760247529;
-inv_value(164) -> 24494416553286712184739252007008198023;
-inv_value(165) -> 39191066485258739495582803211213116837;
-inv_value(166) -> 31352853188206991596466242568970493469;
-inv_value(167) -> 25082282550565593277172994055176394776;
-inv_value(168) -> 40131652080904949243476790488282231641;
-inv_value(169) -> 32105321664723959394781432390625785313;
-inv_value(170) -> 25684257331779167515825145912500628250;
-inv_value(171) -> 41094811730846668025320233460001005200;
-inv_value(172) -> 32875849384677334420256186768000804160;
-inv_value(173) -> 26300679507741867536204949414400643328;
-inv_value(174) -> 42081087212386988057927919063041029325;
-inv_value(175) -> 33664869769909590446342335250432823460;
-inv_value(176) -> 26931895815927672357073868200346258768;
-inv_value(177) -> 21545516652742137885659094560277007015;
-inv_value(178) -> 34472826644387420617054551296443211223;
-inv_value(179) -> 27578261315509936493643641037154568979;
-inv_value(180) -> 22062609052407949194914912829723655183;
-inv_value(181) -> 35300174483852718711863860527557848292;
-inv_value(182) -> 28240139587082174969491088422046278634;
-inv_value(183) -> 22592111669665739975592870737637022907;
-inv_value(184) -> 36147378671465183960948593180219236651;
-inv_value(185) -> 28917902937172147168758874544175389321;
-inv_value(186) -> 23134322349737717735007099635340311457;
-inv_value(187) -> 37014915759580348376011359416544498331;
-inv_value(188) -> 29611932607664278700809087533235598665;
-inv_value(189) -> 23689546086131422960647270026588478932;
-inv_value(190) -> 37903273737810276737035632042541566291;
-inv_value(191) -> 30322618990248221389628505634033253033;
-inv_value(192) -> 24258095192198577111702804507226602426;
-inv_value(193) -> 38812952307517723378724487211562563882;
-inv_value(194) -> 31050361846014178702979589769250051106;
-inv_value(195) -> 24840289476811342962383671815400040885;
-inv_value(196) -> 39744463162898148739813874904640065415;
-inv_value(197) -> 31795570530318518991851099923712052332;
-inv_value(198) -> 25436456424254815193480879938969641866;
-inv_value(199) -> 40698330278807704309569407902351426985;
-inv_value(200) -> 32558664223046163447655526321881141588;
-inv_value(201) -> 26046931378436930758124421057504913271;
-inv_value(202) -> 41675090205499089212999073692007861233;
-inv_value(203) -> 33340072164399271370399258953606288986;
-inv_value(204) -> 26672057731519417096319407162885031189;
-inv_value(205) -> 21337646185215533677055525730308024951;
-inv_value(206) -> 34140233896344853883288841168492839922;
-inv_value(207) -> 27312187117075883106631072934794271938;
-inv_value(208) -> 21849749693660706485304858347835417550;
-inv_value(209) -> 34959599509857130376487773356536668080;
-inv_value(210) -> 27967679607885704301190218685229334464;
-inv_value(211) -> 22374143686308563440952174948183467571;
-inv_value(212) -> 35798629898093701505523479917093548114;
-inv_value(213) -> 28638903918474961204418783933674838491;
-inv_value(214) -> 22911123134779968963535027146939870793;
-inv_value(215) -> 36657797015647950341656043435103793269;
-inv_value(216) -> 29326237612518360273324834748083034615;
-inv_value(217) -> 23460990090014688218659867798466427692;
-inv_value(218) -> 37537584144023501149855788477546284307;
-inv_value(219) -> 30030067315218800919884630782037027446;
-inv_value(220) -> 24024053852175040735907704625629621957;
-inv_value(221) -> 38438486163480065177452327401007395130;
-inv_value(222) -> 30750788930784052141961861920805916104;
-inv_value(223) -> 24600631144627241713569489536644732884;
-inv_value(224) -> 39361009831403586741711183258631572614;
-inv_value(225) -> 31488807865122869393368946606905258091;
-inv_value(226) -> 25191046292098295514695157285524206473;
-inv_value(227) -> 40305674067357272823512251656838730356;
-inv_value(228) -> 32244539253885818258809801325470984285;
-inv_value(229) -> 25795631403108654607047841060376787428;
-inv_value(230) -> 41273010244973847371276545696602859885;
-inv_value(231) -> 33018408195979077897021236557282287908;
-inv_value(232) -> 26414726556783262317616989245825830326;
-inv_value(233) -> 42263562490853219708187182793321328522;
-inv_value(234) -> 33810849992682575766549746234657062818;
-inv_value(235) -> 27048679994146060613239796987725650254;
-inv_value(236) -> 21638943995316848490591837590180520204;
-inv_value(237) -> 34622310392506957584946940144288832325;
-inv_value(238) -> 27697848314005566067957552115431065860;
-inv_value(239) -> 22158278651204452854366041692344852688;
-inv_value(240) -> 35453245841927124566985666707751764301;
-inv_value(241) -> 28362596673541699653588533366201411441;
-inv_value(242) -> 22690077338833359722870826692961129153;
-inv_value(243) -> 36304123742133375556593322708737806644;
-inv_value(244) -> 29043298993706700445274658166990245316;
-inv_value(245) -> 23234639194965360356219726533592196253;
-inv_value(246) -> 37175422711944576569951562453747514004;
-inv_value(247) -> 29740338169555661255961249962998011203;
-inv_value(248) -> 23792270535644529004768999970398408963;
-inv_value(249) -> 38067632857031246407630399952637454340;
-inv_value(250) -> 30454106285624997126104319962109963472;
-inv_value(251) -> 24363285028499997700883455969687970778;
-inv_value(252) -> 38981256045599996321413529551500753244;
-inv_value(253) -> 31185004836479997057130823641200602595;
-inv_value(254) -> 24948003869183997645704658912960482076;
-inv_value(255) -> 39916806190694396233127454260736771322;
-inv_value(256) -> 31933444952555516986501963408589417058;
-inv_value(257) -> 25546755962044413589201570726871533646;
-inv_value(258) -> 40874809539271061742722513162994453834;
-inv_value(259) -> 32699847631416849394178010530395563067;
-inv_value(260) -> 26159878105133479515342408424316450454;
-inv_value(261) -> 41855804968213567224547853478906320726;
-inv_value(262) -> 33484643974570853779638282783125056581;
-inv_value(263) -> 26787715179656683023710626226500045265;
-inv_value(264) -> 21430172143725346418968500981200036212;
-inv_value(265) -> 34288275429960554270349601569920057938;
-inv_value(266) -> 27430620343968443416279681255936046351;
-inv_value(267) -> 21944496275174754733023745004748837081;
-inv_value(268) -> 35111194040279607572837992007598139329;
-inv_value(269) -> 28088955232223686058270393606078511463;
-inv_value(270) -> 22471164185778948846616314884862809171;
-inv_value(271) -> 35953862697246318154586103815780494673;
-inv_value(272) -> 28763090157797054523668883052624395738;
-inv_value(273) -> 23010472126237643618935106442099516591;
-inv_value(274) -> 36816755401980229790296170307359226545;
-inv_value(275) -> 29453404321584183832236936245887381236;
-inv_value(276) -> 23562723457267347065789548996709904989;
-inv_value(277) -> 37700357531627755305263278394735847982;
-inv_value(278) -> 30160286025302204244210622715788678386;
-inv_value(279) -> 24128228820241763395368498172630942709;
-inv_value(280) -> 38605166112386821432589597076209508334;
-inv_value(281) -> 30884132889909457146071677660967606667;
-inv_value(282) -> 24707306311927565716857342128774085334;
-inv_value(283) -> 39531690099084105146971747406038536534;
-inv_value(284) -> 31625352079267284117577397924830829227;
-inv_value(285) -> 25300281663413827294061918339864663382;
-inv_value(286) -> 40480450661462123670499069343783461410;
-inv_value(287) -> 32384360529169698936399255475026769128;
-inv_value(288) -> 25907488423335759149119404380021415303;
-inv_value(289) -> 41451981477337214638591047008034264484;
-inv_value(290) -> 33161585181869771710872837606427411587;
-inv_value(291) -> 26529268145495817368698270085141929270;
-inv_value(292) -> 42446829032793307789917232136227086832;
-inv_value(293) -> 33957463226234646231933785708981669466;
-inv_value(294) -> 27165970580987716985547028567185335573;
-inv_value(295) -> 21732776464790173588437622853748268458;
-inv_value(296) -> 34772442343664277741500196565997229533;
-inv_value(297) -> 27817953874931422193200157252797783626;
-inv_value(298) -> 22254363099945137754560125802238226901;
-inv_value(299) -> 35606980959912220407296201283581163042;
-inv_value(300) -> 28485584767929776325836961026864930433;
-inv_value(301) -> 22788467814343821060669568821491944347;
-inv_value(302) -> 36461548502950113697071310114387110955;
-inv_value(303) -> 29169238802360090957657048091509688764;
-inv_value(304) -> 23335391041888072766125638473207751011;
-inv_value(305) -> 37336625667020916425801021557132401617;
-inv_value(306) -> 29869300533616733140640817245705921294;
-inv_value(307) -> 23895440426893386512512653796564737035;
-inv_value(308) -> 38232704683029418420020246074503579256;
-inv_value(309) -> 30586163746423534736016196859602863405;
-inv_value(310) -> 24468930997138827788812957487682290724;
-inv_value(311) -> 39150289595422124462100731980291665158;
-inv_value(312) -> 31320231676337699569680585584233332127;
-inv_value(313) -> 25056185341070159655744468467386665702;
-inv_value(314) -> 40089896545712255449191149547818665122;
-inv_value(315) -> 32071917236569804359352919638254932098;
-inv_value(316) -> 25657533789255843487482335710603945678;
-inv_value(317) -> 41052054062809349579971737136966313085;
-inv_value(318) -> 32841643250247479663977389709573050468;
-inv_value(319) -> 26273314600197983731181911767658440375;
-inv_value(320) -> 42037303360316773969891058828253504599;
-inv_value(321) -> 33629842688253419175912847062602803679;
-inv_value(322) -> 26903874150602735340730277650082242944;
-inv_value(323) -> 21523099320482188272584222120065794355;
-inv_value(324) -> 34436958912771501236134755392105270968;
-inv_value(325) -> 27549567130217200988907804313684216774;
-inv_value(326) -> 22039653704173760791126243450947373419;
-inv_value(327) -> 35263445926678017265801989521515797471;
-inv_value(328) -> 28210756741342413812641591617212637977;
-inv_value(329) -> 22568605393073931050113273293770110382;
-inv_value(330) -> 36109768628918289680181237270032176610;
-inv_value(331) -> 28887814903134631744144989816025741288;
-inv_value(332) -> 23110251922507705395315991852820593031;
-inv_value(333) -> 36976403076012328632505586964512948849;
-inv_value(334) -> 29581122460809862906004469571610359079;
-inv_value(335) -> 23664897968647890324803575657288287263;
-inv_value(336) -> 37863836749836624519685721051661259621;
-inv_value(337) -> 30291069399869299615748576841329007697;
-inv_value(338) -> 24232855519895439692598861473063206158;
-inv_value(339) -> 38772568831832703508158178356901129852;
-inv_value(340) -> 31018055065466162806526542685520903882;
-inv_value(341) -> 24814444052372930245221234148416723105;
-inv_value(_) -> error(function_clause).
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index f03aab50b6..7d6d70ad87 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -71,7 +71,6 @@
 	     io,
 	     io_lib,
 	     io_lib_format,
-	     io_lib_format_ryu_table,
 	     io_lib_fread,
 	     io_lib_pretty,
 	     lists,
diff --git a/lib/stdlib/test/stdlib_bench_SUITE.erl b/lib/stdlib/test/stdlib_bench_SUITE.erl
index 81764a5913..4ccbdb9b57 100644
--- a/lib/stdlib/test/stdlib_bench_SUITE.erl
+++ b/lib/stdlib/test/stdlib_bench_SUITE.erl
@@ -52,7 +52,7 @@ groups() ->
        encode_list, encode_list_to_string,
        mime_binary_decode, mime_binary_decode_to_string,
        mime_list_decode, mime_list_decode_to_string]},
-     {io, [{repeat, 5}], [double_random_to_list]},
+     {io, [{repeat, 5}], [double_random_to_list, double_random_to_list_array]},
      {gen_server, [{repeat,5}], cases(gen_server)},
      {gen_statem, [{repeat,3}], cases(gen_statem)},
      {gen_server_comparison, [],
@@ -283,14 +283,17 @@ mbb(N, Acc) ->
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 -define(MAX_DOUBLE, (1 bsl 62) - 1).
--define(DOUBLE_SAMPLE, 10000).
+-define(DOUBLE_SAMPLE, 100000).
 -define(SMALL_DIGITS, 6).
 
 double_random_to_list(_Config) ->
-    comment(test_double(io_lib_format, fwrite_g, 0)).
+    comment(test_double(0)).
+
+double_random_to_list_array(_Config) ->
+    comment(test_double_array(0)).
 
 double_small_digit_to_list(_Config) ->
-    comment(test_double(io_lib_format, fwrite_g, ?SMALL_DIGITS)).
+    comment(test_double(?SMALL_DIGITS)).
 
 double(0) ->
     Int = rand:uniform(?MAX_DOUBLE),
@@ -319,17 +322,34 @@ exp10(Acc, 0) ->
 exp10(Acc, X) ->
     exp10(Acc, X - 1).
 
-test_double(Mod, Fun, SmallDigits) ->
-    test_double(?DOUBLE_SAMPLE, Mod, Fun, SmallDigits).
-test_double(Iter, Mod, Fun, SmallDigits) ->
-    F = fun() -> loop_double(Iter, Mod, Fun, SmallDigits) end,
+test_double(Samples) when is_list(Samples) ->
+    F = fun() -> loop_double(Samples) end,
     {Time, ok} = timer:tc(fun() -> lspawn(F) end),
-    report_mfa(Iter, Time, Mod).
+    report_mfa(?DOUBLE_SAMPLE, Time, io_lib_format);
+test_double(SmallDigits) when is_integer(SmallDigits) ->
+    rand:seed(exsplus, {1201,855653,380975}),
+    Samples = [double(SmallDigits) || _ <- lists:seq(1, ?DOUBLE_SAMPLE)],
+    test_double(Samples).
+
+loop_double([]) -> garbage_collect(), ok;
+loop_double([Sample | Rest]) ->
+    _ = io_lib_format:fwrite_g(Sample),
+    loop_double(Rest).
+
+test_double_array(SmallDigits) when is_integer(SmallDigits) ->
+    rand:seed(exsplus, {1201,855653,380975}),
+    Samples = [double(SmallDigits) || _ <- lists:seq(1, ?DOUBLE_SAMPLE)],
+    Samples_array = array:from_list(Samples),
+    test_double_array(?DOUBLE_SAMPLE - 1, Samples_array).
+test_double_array(Iter, Samples_array) ->
+    F = fun() -> loop_double_array(Iter, Samples_array) end,
+    {Time, ok} = timer:tc(fun() -> lspawn(F) end),
+    report_mfa(?DOUBLE_SAMPLE, Time, io_lib_format).
 
-loop_double(0, _M, _F, _SmallDigits) -> garbage_collect(), ok;
-loop_double(N, M, F, SmallDigits) ->
-    _ = apply(M, F, [double(SmallDigits)]),
-    loop_double(N - 1, M, F, SmallDigits).
+loop_double_array(0, _Samples_array) -> garbage_collect(), ok;
+loop_double_array(Iter, Samples_array) ->
+    _ = io_lib_format:fwrite_g(array:get(Iter, Samples_array)),
+    loop_double_array(Iter - 1, Samples_array).
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-- 
2.31.1

openSUSE Build Service is sponsored by