Since I believe it hasn’t been stated explicitly in this thread yet, a reminder that it is generally _impossible_ to represent arbitrary float values accurately (and finitely) in decimal notation. Except for few cases, you will have to cut off and round at some point.

But that doesn’t necessarily mean that round-tripping between text and binary loses precision, as long as the rounding is precise enough for both binary-to-text and text-to-binary conversion. Though as Oleg points out, that is not an easy problem.

On 16. 6. 2022, at 08:24, Oleg <oleg@okmij.org> wrote:

In practice in our recent project, we settled on

let float : float -> float cde = fun x ->
 let str = if Float.is_integer x then string_of_float x else
           Printf.sprintf "%.17g" x

"%.17g" is what we use in the WebAssembly reference interpreter as well. Plus, we do some extra work to also preserve -0.0 and NaNs. Simplified a bit, it's something like this:

  let float_to_string x =
    let x' = abs_float x in
    (if Int64.bits_of_float x < 0L then "-" else "") ^
    if x' <> x' then
      let payload = Int64.(logand (bits_of_float x') 0x000f_ffff_ffff_ffffL) in
      "nan:0x" ^ Printf.sprintf "%Lx" payload
    else
      let s = Printf.sprintf "%.17g" x' in
      if s.[String.length s - 1] = '.' then s ^ "0" else s

Our of_string function recognises the special NaN syntax accordingly.

/Andreas