# Forcing the E or F format without losing precision

**URL:** https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837
**Category:** General Usage
**Created:** [October 3, 2024, 5:19am UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837 "2024-10-03T05:19:55Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [October 3, 2024, 5:19am UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/1 "2024-10-03T05:19:55Z")

</div>

I need a string decimal representation of a `Float64` and I’d like to specify either the E format, e.g., “3.14e-3”, or the F format, “0.00314”, without having to worry about how many digits are necessary to preserve precision. To illustrate the problem, here is a pseudo code:

```julia
a = 0.19607361594437356e-3
sprintf("%e", a) # -> "0.000196" -> would lose precision
sprintf("%f", a) # -> "1.960736e-04" -> would lose precision

```

(I obtained the above result using a shell-built-in printf command.)

Is there an “easier” solution than to explicitly specify the number of digits?

The purpose of the string representation is to feed it to Fortran, which requires a format like “3.14d-3”. Note the “d” to designate Double Precision. I’ll use `replace(s, 'e' => 'd')` to generate this string, but for that purpose I always need “e” in the original Julia string.

**Edit:** Basically what I want is a function which can use the E format and the F format and which `parse(Float64, _)` is the inverse of:

```julia
f = rand() # or any Float64 value
st = float_to_string(f, format=:E) # use the "3.14e-3" type of format.
ff = parse(Float64, st)
@assert(f == ff) # should always hold

```

---

<div class="post-metadata">

### Author: ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)
#### Post date: [October 3, 2024, 5:25am UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/2 "2024-10-03T05:25:32Z")

</div>

one answer is to use hexadecimal floats i.e. `0x1.e4fp5`. that way you know your input has no rounding since you are just writing the bits

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [October 3, 2024, 5:41am UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/3 "2024-10-03T05:41:40Z")

</div>

With Format.jl,

```julia
using Format
julia> printfmtln("{1}", sqrt(2))
1.4142135623730951

```

---

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [October 4, 2024, 7:21am UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/4 "2024-10-04T07:21:17Z")

</div>

> hexadecimal floats ` 0x1.e4fp5`

Sounds promising but I don’t quite get it. I would be doing

```julia
f = sqrt(2)
st = hexrep(f) # => hexadecimal representation of f
# use st to generate a Fortran statement like
# real(8), parameter:: f = real(Z'<hex>', kind=kind(f))

```

(I don’t know whether this is correct Fortran. All I know is that Fortran 2008 allows for some hex constants.) My question here is how can one write the function `hexrep()` above. The traditional `printf()` function does that only for integers, as far as I know. Which Julia formatter does it for floating point numbers?

---

<div class="post-metadata">

### Author: ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)
#### Post date: [October 4, 2024, 7:30am UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/5 "2024-10-04T07:30:18Z")

</div>

> [@jar1](#):
>
> `using Format`

Also sounds promising, but I haven’t been able to find how to specify the E format with “sufficient number of digits” in the documentation (quoted below). Here is my first attempt:

```julia
julia> using Format

julia> printfmtln("{1:e}", sqrt(2))
1.414214e+00

julia> printfmtln("{1:24.16e}", sqrt(2))
  1.4142135623730952e+00

```

(I’m not sure whether 16 digits is always good enough.)

[https://docs.python.org/2/library/string.html#formatspec](https://docs.python.org/2/library/string.html#formatspec)

---

<div class="post-metadata">

### Author: ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)
#### Post date: [October 4, 2024, 7:21pm UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/6 "2024-10-04T19:21:41Z")

</div>

EDIT: Well, disregard everything below. While this probably works well enough, it relies on the assumption that `string(f)` is sufficiently precise when 1 \leq f \< 10, which is a very arbitrary choice of precision. It’s better to just make this explicit in `format(f, precision=(...))` for the F format, and `format("{:.(...)e}", f)` for the E format.

(You could calculate the number of decimal digits which can represent every `Float64` exactly, but I’m clearly too tired, so I’m not going to bother :). As @Oscar_Smith highlighted, it will be more compact to stick to binary(/hexadecimal) as much as possible anyway. Additionally, while I know next to nothing about Fortran, I highly doubt it will actually use all digits if you would supply, say, a hundred of them.)

* * *

> **'Manually' formatting the exponent / zeros**
>
> > [@ryofurue](#):
> >
> > Is there an “easier” solution than to explicitly specify the number of digits?
> 
> I’d say just computing the exponent / placing the zeros is conceptually quite easy, so you could do this ‘manually’. (Here I’m starting from `string(f)` for a float in `[1,10)` assuming this is sufficiently accurate. But if you want to have fun, you could also start directly from the bits in `f` 🙂 .)
> 
> ```julia
> function float_to_string(f, format)
> exponent = floor(Int, log10(abs(f)))
> f_base_str = string(f / 10. ^ exponent) # e.g. -1.23456789
> if format === :E || format == :e
> return f_base_str * "e$exponent"
> elseif format === :F || format === :f
> if exponent == 0
> return f_base_str
> else
> digits_str = replace(f_base_str, '.' => "", '-' => "") # 123456789
> sign_str = f < 0 ? '-' : ""
> if exponent <= -1
> return sign_str * "0." * '0' ^ (-exponent - 1) * rstrip(digits_str, '0')
> # e.g. exponent == -2: -0.00123456789
> # rstrip for when f == n⋅10^exponent for some integer n, as then f_base_str == "n.0"
> else
> if length(digits_str) >= exponent + 1 # e.g. exponent == 2
> before_decimal_point = sign_str * digits_str[begin:exponent+1] # -123
> after_decimal_point = (length(digits_str) == exponent + 1) ? '0' : digits_str[exponent+2:end] # 456789
> # Make sure an integer ends with '.0' (e.g. 123.0)
> return before_decimal_point * '.' * after_decimal_point # -123.456789
> else
> return sign_str * digits_str * '0' ^ (exponent - length(digits_str) + 1) * ".0"
> # e.g. exponent == 12: -1234567890000.0
> end
> end
> end
> else
> throw("Invalid format option $format")
> end
> end
> 
> ```
> 
> But the F format is a tad annoying to get right, so just using the maximum precision in e.g. a `@sprintf` (from Printf.jl) or in Format.jl 's `format` will be easier, and probably more performant, if that’s relevant.
> 
> ```julia-repl
> julia> float_to_string(1000., :E)
> "1.0e3"
> 
> julia> float_to_string(123456789.01, :e)
> "1.2345678901000001e8"
> 
> julia> float_to_string(1.23e6, :f)
> "1230000.0"
> 
> julia> x = sqrt(2) / 1e10
> 1.414213562373095e-10
> 
> julia> s = float_to_string(x, :F)
> "0.0000000001414213562373095"
> 
> julia> parse(Float64, s) ≈ sqrt(2) / 1e10
> true
> 
> ```

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [October 4, 2024, 8:36pm UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/7 "2024-10-04T20:36:58Z")

</div>

> [@ryofurue](#):
>
> Is there an “easier” solution than to explicitly specify the number of digits?

I think that a format string like `"%.16e"` is far and away the easiest. 16 decimal digits will always be sufficient to uniquely identify every possible `Float64` value.

```julia
using Printf
float_to_string(f) = @sprintf("%.16e", f)

```

---

<div class="post-metadata">

### Author: ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)
#### Post date: [October 4, 2024, 9:33pm UTC](https://discourse.julialang.org/t/forcing-the-e-or-f-format-without-losing-precision/120837/8 "2024-10-04T21:33:35Z")

</div>

> [@ryofurue](#):
>
> Which Julia formatter does it for floating point numbers?

The printf code for hex float appears to be `"a"`:

```julia-repl
julia> using Printf

julia> @sprintf("%a", sqrt(2))
"0x1.6a09e667f3bcdp+0"

```
