# What's up with UnitRange?

**URL:** <https://discourse.julialang.org/t/whats-up-with-unitrange/22321>\
**Category:** General Usage\
**Tags:** question\
**Created:** [March 25, 2019, 8:42pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321 "2019-03-25T20:42:17Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![mosiman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mosiman/32/6959_2.png) [@mosiman](https://discourse.julialang.org/u/mosiman)\
**Post date:** [March 25, 2019, 8:42pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/1 "2019-03-25T20:42:18Z")

</div>

Consider in matlab:

```julia
>> 1.12*100:0.02*100:1.2*100

ans =

          112 114 116 118 120

```

In julia I get

```julia
julia> 1.12*100:0.02*100:1.2*100
112.00000000000001:2.0:118.00000000000001

```

which when I collect is definitely not what I expected

```julia
julia> collect(1.12*100:0.02*100:1.2*100)
4-element Array{Float64,1}:
 112.00000000000001
 114.00000000000001
 116.00000000000001
 118.00000000000001

```

---

<div class="post-metadata">

**Author:** ![spaceLem](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/spacelem/32/217628_2.png) [@spaceLem](https://discourse.julialang.org/u/spaceLem)\
**Post date:** [March 25, 2019, 8:45pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/2 "2019-03-25T20:45:39Z")

</div>

In Matlab everything is a Complex Float, but it rounds the answer when possible. In Julia you explicitly asked for a Float, and so you got one.

---

<div class="post-metadata">

**Author:** ![mosiman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mosiman/32/6959_2.png) [@mosiman](https://discourse.julialang.org/u/mosiman)\
**Post date:** [March 25, 2019, 8:51pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/3 "2019-03-25T20:51:16Z")

</div>

Makes sense, but I still find it very unintuitive. Is there anything I can do to match the functionality of matlab in this case?

---

<div class="post-metadata">

**Author:** ![pkofod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pkofod/32/2179_2.png) [@pkofod](https://discourse.julialang.org/u/pkofod)\
**Post date:** [March 25, 2019, 8:54pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/4 "2019-03-25T20:54:48Z")

</div>

Is this not just printing though? Matlab just truncates it to avoid that question.

---

<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:** [March 25, 2019, 9:01pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/5 "2019-03-25T21:01:33Z")

</div>

Yes, Matlab may be lying to you and truncating its display. It’s also returning a floating point number — it’s just formatted like Julia formats integers. I no longer have a Matlab installed, but try

```julia
r = 1.12*100:0.02*100:1.2*100
fprintf('%.17f\n',r(1)) 

```

I do know that Matlab also does some “snapping” to integral endpoints within its colon syntax, so that may (also) be happening here.

Floating point arithmetic doesn’t behave how you might expect — across all languages. Indeed, just check out the result of `1.12*100` in both Matlab and Julia. Again, Matlab will likely obscure the “real” answer via its printing.

---

<div class="post-metadata">

**Author:** ![spaceLem](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/spacelem/32/217628_2.png) [@spaceLem](https://discourse.julialang.org/u/spaceLem)\
**Post date:** [March 25, 2019, 9:04pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/6 "2019-03-25T21:04:27Z")

</div>

`collect(round(Int, 1.12*100):round(Int, 0.02*100):round(Int, 1.2*100))` would work.

---

<div class="post-metadata">

**Author:** ![mosiman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mosiman/32/6959_2.png) [@mosiman](https://discourse.julialang.org/u/mosiman)\
**Post date:** [March 25, 2019, 9:04pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/7 "2019-03-25T21:04:37Z")

</div>

I tried the snippet you wrote, and yeah Matlab is just hiding the ugly in the print statements. But what I’m more concerned about is properly computing the number of elements in the range (the “snapping” as you say). `112.00000000000001421` is pretty much `112`, but a range with 4 elements where it’s supposed to have 5 is a much bigger problem.

---

<div class="post-metadata">

**Author:** ![mosiman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mosiman/32/6959_2.png) [@mosiman](https://discourse.julialang.org/u/mosiman)\
**Post date:** [March 25, 2019, 9:07pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/8 "2019-03-25T21:07:55Z")

</div>

That would work if I expected all the elements in the UnitRange to be integers, but I don’t. For example, if I do this in matlab, I get what I expect:

```julia
>> 1.12*87:0.02*87:1.2*87

ans =

        97.44 99.18 100.92 102.66 104.4

```

But in Julia, I’m still losing an element because of the small +ϵ tacked on

```julia
julia> collect(1.12*87:0.02*87:1.2*87)
4-element Array{Float64,1}:
  97.44000000000001
  99.18
 100.92000000000002
 102.66000000000001

```

---

<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:** [March 25, 2019, 9:13pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/9 "2019-03-25T21:13:10Z")

</div>

Ah, I missed that. That’s the other part of my answer — the slop for snapping. We don’t do slop, but it’s still something we try very hard to get right. It’s a challenge because of floating point issues like this. In general, if you write the values directly as floating point literals (instead of an multiplication) we’ll get them almost always right.

As such, a nice workaround is to do the multiplication outside the range. It also hits your intended values much more accurately.

```julia
julia> (1.12:0.02:1.2) .* 87
97.44:1.74:104.4

julia> collect(ans)
5-element Array{Float64,1}:
  97.44
  99.18
 100.92
 102.66
 104.4

```

---

<div class="post-metadata">

**Author:** ![aharoun](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aharoun/32/6887_2.png) [@aharoun](https://discourse.julialang.org/u/aharoun)\
**Post date:** [March 25, 2019, 9:21pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/10 "2019-03-25T21:21:22Z")

</div>

You can use `range` with keyword `length`:

```julia
julia> collect(range(1.12*100,1.20*100, length=5))
5-element Array{Float64,1}:
 112.00000000000001
 114.00000000000001
 116.0
 118.0
 120.0

```

Here the step size is implicit, which might be inconvenient in some cases, but this always guarantees the end point to be included.

---

<div class="post-metadata">

**Author:** ![mosiman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mosiman/32/6959_2.png) [@mosiman](https://discourse.julialang.org/u/mosiman)\
**Post date:** [March 25, 2019, 9:26pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/11 "2019-03-25T21:26:31Z")

</div>

Thanks, I appreciate the lack of slop with Julia but it can be frustrating at times. This is a simple fix that’ll work for me.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [March 25, 2019, 9:40pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/12 "2019-03-25T21:40:30Z")

</div>

How does Julia calculate ` (1.12:0.02:1.2)*87` to get the crisp values?

---

<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:** [March 25, 2019, 9:47pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/13 "2019-03-25T21:47:21Z")

</div>

It infers more precision than `1.12` and `1.2` specify since taken at face value, those end-points and a length of 5 are incompatible since `1.12 + 4*0.02 != 1.2`. If you call `dump` on the range object, you can see the higher precision values that are inferred upon construction:

```nohighlight
julia> dump((1.12:0.02:1.2))
StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}
  ref: Base.TwicePrecision{Float64}
    hi: Float64 1.12
    lo: Float64 -1.0658141036401502e-16
  step: Base.TwicePrecision{Float64}
    hi: Float64 0.01999999999999999
    lo: Float64 9.992007221626408e-18
  len: Int64 5
  offset: Int64 1

```

Indeed, the true value 1.12 is about 1.0658141036401502e-16 smaller than the floating-point value `1.12`.

---

<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:** [March 25, 2019, 9:51pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/14 "2019-03-25T21:51:12Z")

</div>

The end-point is always included but it may not be what you wanted. In this case, `1.12*100 == 112.00000000000001 != 112` whereas:

```julia
julia> collect((1.12:0.02:1.2)*100)
5-element Array{Float64,1}:
 112.0
 114.0
 116.0
 118.0
 120.0

```

The values are all exact integer values.

---

<div class="post-metadata">

**Author:** ![aharoun](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aharoun/32/6887_2.png) [@aharoun](https://discourse.julialang.org/u/aharoun)\
**Post date:** [March 25, 2019, 10:48pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/15 "2019-03-25T22:48:43Z")

</div>

So range object triggers high precision multiplication. Very neat!

---

<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:** [March 26, 2019, 10:34pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/16 "2019-03-26T22:34:19Z")

</div>

Julia is doing two things: it first realizes that the floating point value `0.02` — that is, `0.0200000000000000004163336342344337026588618755340576171875` — is the closest representable value to `1//50`. And that the start and stop can also be expressed in terms of a common denominator with the step. Then, secondly, it finds the closest twice-precision (128-bit) floating point representation for this exact fraction:

```julia
julia> big(0.02)
0.0200000000000000004163336342344337026588618755340576171875

julia> big((1.12:0.02:1.2).step)
0.019999999999999999999999999999999630221450677650716213252235023693954840684483542645466513931751251220703125

```

It’s not just high precision; it’s also a rationalization of the number you gave it. I should note that we _are_ snapping, but we’re only changing the exact values by less than `eps(x)/2`. In other words, if you converted this value back to a normal Float64, you’d get the same number you started with. This is why I talked about writing the floating point literals yourself. If you write them out, you’re writing some decimal fraction — something divisible by a power of 10 — that is able to be rationalized in this manner. If you instead do `0.02*87`, then you’re also multiply that trailing `...00004163336...` in the full expansion of `0.2` 87 times, and that adds up to the point that you’re more than a half-step away from the rational number you really wanted. Matlab, on the other hand, seems to have some “closeness” heuristics that are much more forgiving.

A really awesome side-effect of the high precision arithmetic backing this is that the intermediate values are also much more frequently what you intended. The classic example is the third value in `0.1:0.1:0.9` — it’s 0.3 in Julia, but 0.30000000000000004 in most other languages.

---

<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:** [March 26, 2019, 11:16pm UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/17 "2019-03-26T23:16:27Z")

</div>

> [@mbauman](#):
>
> The classic example is the third value in `0.1:0.1:0.9` — it’s 0.3 in Julia, but 0.30000000000000004 in most other languages.

Actually, it’s `0.29999999999999998889776975…` in Julia; it just _prints_ as `0.3` because that is the shortest literal that parses to the same value. The fraction `3/10` is not representable in binary floating point.

---

<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:** [March 27, 2019, 3:01am UTC](https://discourse.julialang.org/t/whats-up-with-unitrange/22321/18 "2019-03-27T03:01:57Z")

</div>

Right, it’s `0.3` but not 0.3 if you see what I’m saying.
