# Rounding to a multiple of float

**URL:** <https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295>\
**Category:** Numerics\
**Created:** [February 28, 2019, 11:25am UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295 "2019-02-28T11:25:27Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 11:25am UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/1 "2019-02-28T11:25:27Z")

</div>

I am trying to solve a simple problem - rounding a number to a nearest multiple of a given float. As an example, I would like `roundmult(3811.47123123, 0.01) = 3811.47`. However, the simplest implementation of `roundmult(val, prec) = round(val / prec) * prec` backfires by outputting `roundmult(3811.47123123, 0.01) = 3811.4700000000003`.

Is there any simple way of achieving this using some built-in functionality, or some magic of rounding the above result once more to the precision given by `prec`? Something like  
`roundmult(val, prec) = round(round(val / prec) * prec, digits=ceil(Integer, -log10(prec)+1))` would probably work, but it is so ugly.

---

<div class="post-metadata">

**Author:** ![johnh](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnh/32/3615_2.png) [@johnh](https://discourse.julialang.org/u/johnh)\
**Post date:** [February 28, 2019, 11:38am UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/2 "2019-02-28T11:38:04Z")

</div>

cheeky idea… Move everything up by two decimal places… then use integer arithmetic.

I guess that assumes that the second argument is always less that 1.0 of course.

---

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 11:42am UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/3 "2019-02-28T11:42:11Z")

</div>

Cheeky 🙂 I do not like the idea of changing the whole application due to this small issue 🙂  
Also, the precision is not fixed upfront, it changes based on the current data. So your suggestion would not really work.

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 28, 2019, 11:57am UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/4 "2019-02-28T11:57:00Z")

</div>

If you don’t mind using internal functions, try this:

```julia
julia> Base._round_invstep(3811.47123123, 1/0.01, RoundNearest)
3811.47

julia> Base._round_invstep(3811.47123123, 1/0.02, RoundNearest)
3811.48

julia> Base._round_invstep(3811.47123123, 1/0.05, RoundNearest)
3811.45

```

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2019, 11:57am UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/5 "2019-02-28T11:57:29Z")

</div>

Go through rationals:

```julia
roundmult(val::Rational, prec::Rational) = round(val / prec) * prec

function roundmult(val::T, prec::S) where {T <: AbstractFloat, S <: AbstractFloat}
    R = promote_type(T, S)
    R(roundmult(rationalize(val), rationalize(prec)))
end

julia> roundmult(3811.47123123, 0.01)
3811.47

```

It will be slower, but may be justified for pretty printing.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 28, 2019, 12:06pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/6 "2019-02-28T12:06:24Z")

</div>

What is your problem with roundmult?

E.g. `roundmult(0.3, 0.1) == 0.30000000000000004`. This is correct: `3*0.1 == 0.30000000000000004`. `0.3` is not an integer multiple of `0.1` in `Float64`.

Julia float literals are base-2 floating point. This means that `1//10` cannot be expressed (has an infinite number of nonzero digits), just like you would encounter rounding for `1//3` if you used decimal floats.

---

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 12:13pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/7 "2019-02-28T12:13:07Z")

</div>

@Tamas_Papp Thanks for the suggestion! It is definitely a cleaner approach than the one I pointed out in the original post, but I would still expect something cleaner to be around.

@foobar_lv2 I understand your point. If I would use this value just in my Julia application, it makes no sense to consider this question at all. However, I am sending the result to an external API, which will only accept numbers rounded to these given floats. If I send the result `3811.4700000000003`, my request will be simply declined. I really need to send `3811.47`, therefore my question.

---

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 12:15pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/8 "2019-02-28T12:15:04Z")

</div>

@bennedich Thanks for the suggestion, a simple wrapper around these should suffice!

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2019, 12:29pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/9 "2019-02-28T12:29:17Z")

</div>

If it is only about rounding to a certain number of digits after the decimal, then your problem is simply about _printing_ floats, which is much simpler than the on you describe (since `prec` is of the form 10^n).

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 28, 2019, 12:30pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/10 "2019-02-28T12:30:30Z")

</div>

Ultimately, I’d think that you should make the number of decimals part of your API.

Example:

```julia
julia> roundmult(val, prec, digits=6) = round(round(val / prec) * prec, digits=digits, base=10)
julia> roundmult(3811.47123123, 0.01)
3811.47

```

---

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 12:39pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/11 "2019-02-28T12:39:29Z")

</div>

> [@Tamas\_Papp](#):
>
> If it is only about rounding to a certain number of digits after the decimal, then your problem is simply about _printing_ floats, which is much simpler than the on you describe (since `prec` is of the form 10n10^n).

Not really. I am sending a JSON, where the field is actually a float. Maybe it would make more sense if it would actually accept printed floats.

> [@foobar\_lv2](#):
>
> Ultimately, I’d think that you should make the number of decimals part of your API.

The issue is that the `prec` variable does not have to be of the form 10^{-n}. As in my original post, it could easily be `0.005`. The simplest way to figure out the number of decimals is probably using the logarithm, which I also suggested in the original post.

A clean solution was already provided by bennedich - it works like charm.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2019, 12:52pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/12 "2019-02-28T12:52:50Z")

</div>

> [@cedeerwe](#):
>
> I am sending a JSON, where the field is actually a float.

JSON is a text format. You are effectively printing a number.

---

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 1:01pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/13 "2019-02-28T13:01:55Z")

</div>

True, but there still is a slight difference.

```julia
JSON.json(Dict("a"=>"12.12")) = "{\"a\":\"12.12\"}"
JSON.json(Dict("a"=>12.12)) = "{\"a\":12.12}"

```

The other side will also approach it differently based on whether it gets a printed number or an actual number.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2019, 1:13pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/14 "2019-02-28T13:13:19Z")

</div>

> [@cedeerwe](#):
>
> The other side will also approach it differently based on whether it gets a printed number or an actual number.

The question is not how the JSON.jl library accepts it, which is an implementation detail, but how _you_ can print it the way you like (since JSON is trivially easy to generate). See eg `Base.Grisu.grisu` for low-level float digits printing, which would allow you to generate either of the strings above.

---

<div class="post-metadata">

**Author:** ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)\
**Post date:** [February 28, 2019, 2:43pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/15 "2019-02-28T14:43:41Z")

</div>

Good point, I agree that rounding during the serialization would feel more natural than rounding the float. How would you round to an arbitrary step with grisu? I didn’t find any documentation about this. I.e. to accomplish this:

```julia
julia> Base._round_invstep(3.141592, 1/0.25, RoundNearest)
3.25

```

I’d advice against implementing one’s own JSON serializer, it can be hard to get all escaping, separators, etc, correct. I’ve seen bugs introduced this way before. The way to do it IMO would be to use a custom JSON serializer. Unless I’m missing something, the support for that doesn’t seem great in `JSON.jl` – I don’t think we can use `JSON.lower` for this. I guess we can do something like the below, although arguably the rounding should belong to the serializer not each individual float:

```julia
using JSON

struct MyRoundedFloat
    x::Float64
    step::Float64
end

function JSON.show_json(io::JSON.Writer.StructuralContext, s::JSON.Serializations.CommonSerialization, x::MyRoundedFloat)
    print(io, "formatting code goes here")
end

```

With result:

```julia
julia> JSON.json(Dict("a" => MyRoundedFloat(3.141592, 0.25)))
"{\"a\":formatting code goes here}"

```

All in all, this route doesn’t seem pretty, but perhaps there’s something I’m not seeing.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2019, 3:33pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/16 "2019-02-28T15:33:04Z")

</div>

> [@bennedich](#):
>
> How would you round to an arbitrary step with grisu?

It only does decimal. But `Grisu.grisu` is documented.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 28, 2019, 4:22pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/17 "2019-02-28T16:22:27Z")

</div>

> [@cedeerwe](#):
>
> Not really. I am sending a JSON, where the field is actually a float.

Oh my god. This means that you need figure out whatever the endpoint does.

Javascript has the same floating-point semantics:

```julia
s={"a": "0.1", "b":"0.3"}; 3*s.a 
0.30000000000000004

```

This means that whatever endpoint you are talking to does crazy stuff you need to figure out (if you are lucky, then by reading code; if unlucky, by looking at a disassembly; if very unlucky, then by sending a bazillion requests and black-box reversing whatever they are doing).

---

<div class="post-metadata">

**Author:** ![cedeerwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cedeerwe/32/8552_2.png) [@cedeerwe](https://discourse.julialang.org/u/cedeerwe)\
**Post date:** [February 28, 2019, 4:35pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/18 "2019-02-28T16:35:35Z")

</div>

> [@foobar\_lv2](#):
>
> This means that whatever endpoint you are talking to does crazy stuff you need to figure out (if you are lucky, then by reading code; if unlucky, by looking at a disassembly; if very unlucky, then by sending a bazillion requests and black-box reversing whatever they are doing).

I mean, isn’t it easier to just send the truncated version? In Julia we have

```julia
julia> 0.1 * 3
0.30000000000000004
julia> 0.1 * 3 == 0.3
false

```

If I would send `0.1 * 3` to the endpoint, something could go wrong, but it might work out, depending on the processing on the other side. But if I send actual `0.3`, I should be safe.

As far as I understand, the problem isn’t that Julia cannot represent `0.3`. The problem is that `0.1 * 3` does not give `0.3`, due to the representation and arithmetic on these two numbers. Am I wrong?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 28, 2019, 4:59pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/19 "2019-02-28T16:59:12Z")

</div>

> [@bennedich](#):
>
> If you don’t mind using internal functions

Wasn’t there recently a discussion about the appropriateness of recommending internal functions? At least it should come with a warning, especially to new users.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 28, 2019, 5:03pm UTC](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295/20 "2019-02-28T17:03:08Z")

</div>

> [@cedeerwe](#):
>
> As far as I understand, the problem isn’t that Julia cannot represent `0.3` . The problem is that `0.1 * 3` does not give `0.3` , due to the representation and arithmetic on these two numbers. Am I wrong?

Neither `0.1` nor `0.3` can be represented exactly in (binary-based) floating point.

Designing an interface that accepts `0.3` but not `0.30000000000000004` but otherwise works with `Float64` or similar internally is just absurd.

[Next page](https://discourse.julialang.org/t/rounding-to-a-multiple-of-float/21295.md?page=2)
