# Rounding BigFloat to 3 significant digits

**URL:** <https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295>\
**Category:** New to Julia\
**Tags:** numbers, float, bigfloat\
**Created:** [December 6, 2022, 10:12am UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295 "2022-12-06T10:12:39Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![maxchendt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxchendt/32/42976_2.png) [@maxchendt](https://discourse.julialang.org/u/maxchendt)\
**Post date:** [December 6, 2022, 10:12am UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/1 "2022-12-06T10:12:39Z")

</div>

```julia
display(BigFloat(2)^-76)
display(round(BigFloat(2)^-76, sigdigits=3))
display(round(convert(Float64, BigFloat(2)^-76), sigdigits=3))

```

shows that

```julia
1.32348898008484427979425390731194056570529937744140625e-23
1.319999999999999999999999999999999999999999999999999999999999999999999999999999e-23
1.32e-23

```

Why `round(BigFloat(2)^-76, sigdigits=3)` not give this ugly long result? A bug?

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [December 6, 2022, 11:16am UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/2 "2022-12-06T11:16:58Z")

</div>

> [@maxchendt](#):
>
> `display(round(BigFloat(2)^-76, sigdigits=3))`

No, both prevfloat and:

```julia
julia> nextfloat(round(BigFloat(2)^-76, sigdigits=3)) # scroll to the right to see "11", i.e. it's not just zeros:
1.320000000000000000000000000000000000000000000000000000000000000000000000000011e-23

are further away, than:

julia> round(BigFloat(2)^-76, sigdigits=3)
1.319999999999999999999999999999999999999999999999999999999999999999999999999999e-23

```

and note 1.32e-23 is also farther from your true number. It may though look like the number you want to get out.

I feel like I’ve seen such an issue with also just Float64. You (or at least the round function) want the closest value to 3 digits (and infinite number of decimal zeros after) to your original number. Then Julia just shows that number in full… If you want to also show it as 3 digits that’s a different problem.

Note,

```julia
round(x, [r::RoundingMode]; sigdigits::Integer, base = 10)

```

You can round in base = 2, it’s just not the default, and then you you will have zeros after always, in that base, but in decimal, you likely will not.

---

<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:** [December 6, 2022, 12:57pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/3 "2022-12-06T12:57:20Z")

</div>

note that if you care about getting a string with 3 digits, you can use sprintf to do so reliably.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 6, 2022, 1:17pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/4 "2022-12-06T13:17:01Z")

</div>

> [@maxchendt](#):
>
> Why `round(BigFloat(2)^-76, sigdigits=3)` not give this ugly long result? A bug?

Realize that `BigFloat`, like `Float64`, is a _binary_ floating point type: what it is storing is \mbox{(integer)} \times 2^n, _not_ \mbox{(integer)} \times {10}^n as in decimal. This means that the exact value `1.32e-23` actually **does not exist** (is “not representable”) as a `BigFloat`.

So, what `round` is doing is giving you the _closest_ `BigFloat` value to `1.32e-23`, which turns out to be that weird-looking value `1.31999999999…e-23`

In `Float64`, the same thing is happening. However, when a `Float64` is printed, it uses [an interesting algorithm](https://dl.acm.org/doi/10.1145/3192366.3192369) that prints the _shortest_ decimal value that rounds to the same `Float64` value, which ends up being `1.32e-23` in this case. So that gives you the illusion that the decimal rounding was performed exactly (which is, again, _impossible_ for `Float64` because `1.32e-23` is not representable). If you want to see what `1.32e-23` _really_ is, you can use the `Printf` library to print more digits:

```julia
julia> using Printf

julia> @printf("%0.200e", 1.32e-23)
1.31999999999999993601885787144421313733909849419063708336383021089630029898387419962091371417045593261718750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-23

```

(None of this is specific to Julia. It’s inherent to how computer arithmetic works. Of course, you could [use decimal floating point](https://github.com/JuliaMath/DecFP.jl) if you need to represent decimal values and operations exactly, but this is not the default in any common programming language because it’s not supported in typical CPU hardware. Also, focusing on the errors arising in conversion to/from decimal is a bit of a red herring — it’s the first thing users notice, but it’s _not_ generally the dominant source of rounding errors in practice compared to rounding errors that occur _during_ a computation, which happen in _any_ base.)

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [December 6, 2022, 5:19pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/5 "2022-12-06T17:19:52Z")

</div>

Another issue is that `Float64` uses minimal printing: it prints the smallest number of decimal digits necessary to give the back the same value when that string is parsed as a `Float64`. This means that when you print the value `0.1 == 7205759403792794//2^56` (note this is not equal to `1//10`), it prints as `"0.1"` because that’s the shortest string that parses to the `Float64` value `0.1`. Doing this is shockingly complicated and has been the subject of very recent and ongoing research—see [Ryu](https://dl.acm.org/doi/pdf/10.1145/3296979.3192369) and [Grisu](https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf) algorithms, published in 2004 and 2018, respectively. `BigFloat`, on the other hand, does not do minimal printing, mainly because we delegate printing to the MPFR and MPFR doesn’t do minimal printing. So you already have `big"0.1"` printing as

```julia
0.1000000000000000000000000000000000000000000000000000000000000000000000000000002

```

which is clearly not minimal. I’m not sure how feasible minimal printing of BigFloats would be but it would be much nicer.

---

<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:** [December 6, 2022, 5:22pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/6 "2022-12-06T17:22:05Z")

</div>

I doubt it’s easy. Ryu is table based and the table size is proportional to the number of possible exponents

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [December 6, 2022, 5:43pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/7 "2022-12-06T17:43:41Z")

</div>

> [@Palli](#):
>
> ```julia
> julia> round(BigFloat(2)^-76, sigdigits=3)
> 1.319999999999999999999999999999999999999999999999999999999999999999999999999999e-23
> 
> ```

FYI: That is actually the minimal printing (for that number). I.e. taking one 9 off makes then number different in that precision, and 1.32 is also different.

However that value given by nextfloat seems not to be the next float value:

```julia
julia> nextfloat(round(BigFloat(2)^-76, sigdigits=3)) # scroll to the right to see "11", i.e. it's not just zeros:

julia> big"1.32e-23" < big"1.320000000000000000000000000000000000000000000000000000000000000000000000000011e-23"
true

```

That seems like a bug.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [December 6, 2022, 7:18pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/8 "2022-12-06T19:18:11Z")

</div>

Otoh you get to use whatever arbitrary precision machinery you want.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 6, 2022, 7:21pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/9 "2022-12-06T19:21:41Z")

</div>

> [@StefanKarpinski](#):
>
> I’m not sure how feasible minimal printing of BigFloats would be but it would be much nicer.

I’m not sure it’s a great idea for `BigFloat` because of the variable precision.

For example, it would mean that `big"1.32"` would _always_ print as `1.32`, even though will be a different value depending on the current precision. At least the current printing reflects some change in the underlying value:

```julia
julia> big"1.32"
1.320000000000000000000000000000000000000000000000000000000000000000000000000004

julia> setprecision(128)
128

julia> big"1.32"
1.32

julia> setprecision(1024)
1024

julia> big"1.32"
1.320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005

```

though it still prints a shorter string if the last printed digit happens to be `0` in the current precision.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [December 6, 2022, 7:22pm UTC](https://discourse.julialang.org/t/rounding-bigfloat-to-3-significant-digits/91295/10 "2022-12-06T19:22:49Z")

</div>

Ah, that’s a good point—the output format would have to capture the precision or it would be bad. Of course it’s already an issue because you can change the precision and get a different value.
