# Wrap2pi: what should it do?

**URL:** <https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441>\
**Category:** General Usage\
**Tags:** question\
**Created:** [September 15, 2024, 5:54pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441 "2024-09-15T17:54:16Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [September 15, 2024, 7:31pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/21 "2024-09-15T19:31:58Z")

</div>

Fell free not to follow my suggestions but

1. with floating point numbers you should really use `isapprox`, not `==`
2. with your definition `wra2pi` is type-unstable
3. you get that because for all `Irrational` the equality `==` with `Real` is defined to be always `false`: [julia/base/irrationals.jl at 4633607ce9b9f077f32f89f09a136e04389bbac2 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/4633607ce9b9f077f32f89f09a136e04389bbac2/base/irrationals.jl#L91-L93). Which brings you again to point 1

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 16, 2024, 11:49am UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/22 "2024-09-16T11:49:01Z")

</div>

Any specific reason you define a dedicated function for this?

```julia
julia> using IntervalSets

julia> mod(10, -π..π)
-2.5663706143591725

# can choose between open and closed intervals easily:
julia> mod(3π, iv"[-π, π]")
-3.141592653589793

julia> mod(3π, iv"[-π, π)")
-3.141592653589793

julia> mod(3π, iv"(-π, π]")
3.141592653589793

```

is both more general and less error-prone.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [September 16, 2024, 1:21pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/23 "2024-09-16T13:21:34Z")

</div>

Well, I do not want to add packages to my project unless really needed. I use now:

```julia
"""
    wrap2pi(angle)

Limit the angle to the range -π .. π .
"""
wrap2pi(::typeof(pi)) = π
function wrap2pi(angle)
    y = rem(angle, 2π)
    abs(y) > π && (y -= 2π * sign(y))
    return y
end

```

which passes my tests:

```julia
    @test wrap2pi(0.0) == 0.0
    @test wrap2pi(2π) == 0.0
    @test wrap2pi(3π) == float(π)
    @test wrap2pi(-2π) == 0.0
    @test wrap2pi(-3π) == float(-π)
    @test wrap2pi(π) == π
    @test wrap2pi(3.14) == 3.14
    @test wrap2pi(3.15) < 0.0
    @test wrap2pi(-3.15) > 0.0
    @test wrap2pi(-3.14) == -3.14
    @test wrap2pi(-π) == -π

```

I prefer to use `==` instead of `isapprox` if it works. And here it works just fine. The code is also simple and fast, about the same performance as `sin()`.

---

<div class="post-metadata">

**Author:** ![barucden](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/barucden/32/26154_2.png) [@barucden](https://discourse.julialang.org/u/barucden)\
**Post date:** [September 16, 2024, 1:47pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/24 "2024-09-16T13:47:55Z")

</div>

Beware of false expectations though. Since ` wrap2pi(-π) == -π` holds, then `-wrap2pi(-π) == π` holds too, right? (Warning: it does not.) Also, from your nine test cases, only one uses the `Irrational` method.

If I may take the liberty of interpreting giordano, he’s saying that you should embrace that you are, in fact, working with floating-point numbers and be explicit about what tolerances are acceptable for you. For example, the following passes:

```julia
wrap2pi(x::typeof(π)) = rem2pi(float(x), RoundNearest)
wrap2pi(x) = rem2pi(x, RoundNearest)

@test wrap2pi(0.0) ≈ 0.0 atol=1e-7
@test wrap2pi(2π) ≈ 0.0 atol=1e-7
@test wrap2pi(3π) ≈ float(π) atol=1e-7
@test wrap2pi(-2π) ≈ 0.0 atol=1e-7
@test wrap2pi(-3π) ≈ float(-π) atol=1e-7
@test wrap2pi(π) ≈ π atol=1e-7
@test wrap2pi(3.14) ≈ 3.14 atol=1e-7
@test wrap2pi(-3.14) ≈ -3.14 atol=1e-7
@test wrap2pi(-π) ≈ -π atol=1e-7
# And this passes too:
@test -wrap2pi(-π) ≈ π atol=1e-7

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [September 16, 2024, 3:06pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/25 "2024-09-16T15:06:20Z")

</div>

> [@ufechner7](#):
>
> do not want to add packages to my project unless really needed

Is this not an example of a “really needed” situation?

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [September 16, 2024, 3:14pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/26 "2024-09-16T15:14:31Z")

</div>

> [@nsajko](#):
>
> Is this not an example of a “really needed” situation?

No. I have this function (written slightly differently) since years in my code, and it works well. I decided to move it to a common package, `KiteUtils.jl`, added some tests and improved it a little bit. No reason whatsoever to add another package (my project already depends on 500 packages).

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [September 16, 2024, 3:18pm UTC](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441/27 "2024-09-16T15:18:58Z")

</div>

> [@ufechner7](#):
>
> ```julia
> @test wrap2pi(3π) == float(π)
> @test wrap2pi(-3π) == float(-π)
> 
> ```

Is there any particular reason why you expect the signs of the odd multiples to be conserved, or is this just a regression test of the signs you have observed?

[Previous page](https://discourse.julialang.org/t/wrap2pi-what-should-it-do/119441.md?page=1)
