konstantin_doncov
konstantin_doncov

Reputation: 2879

(x:y) operator in Julia

I am trying to understand this code:

  r = (1:10) - (4/1)
    println(r)

Output:

-3.0:1.0:6.0

I understood why I got -3 and 6. But why I got that value in the middle (1.0)? How does Julia calculate it? Or how I can google it?

Upvotes: 8

Views: 367

Answers (3)

Reza Afzalan
Reza Afzalan

Reputation: 5756

(first:step:last) syntax represent a Range type in Julia

typeof(1:10) # => UnitRange{Int32}

If step part is omitted, by default it is assumed 1

1:10 == 1:1:10 # => true

A Range is a compact view of a series

collect(1:10) # => 10-element Array{Int32,1}:
#  1
#  2
#  3
#  4
#  5
#  6
#  7
#  8
#  9
# 10

So it's expected that a Range type and a Vector follow the same rules e.g when you add a constant value like this:

collect(1+(1:10))==collect(1:10)+1 # => true

or even adding two vectors give you the same result of adding their range representation like this:

collect((1:10)+(1:10))==collect(1:10)+collect(1:10) # => true

Upvotes: 12

Andy Hayden
Andy Hayden

Reputation: 375675

You can see this when applying float to an interval:

julia> 1:10
1:10

julia> float(1:10)
1.0:1.0:10.0

and this promotion is required before adding to the Float64 4/1 (4.0).

Similarly, when adding an integer to a float julia "promotes" the integer to a float before adding/subtracting:

julia> 1 + 2.0
3.0

julia> @which 1 + 2.0
+(x::Number, y::Number) at promotion.jl:172

see the promotion rules:

+(x::Number, y::Number) = +(promote(x,y)...)

You can @which follow the function calls all the way down to understand what's going on (all the way to the following):

julia> @which +(1:10, 2.0)
+(A::AbstractArray{T,N}, x::Number) at arraymath.jl

julia> @which .+(1:10, 2.0)
.+(r::Range{T}, x::Real) at range.jl

julia> @which .+(2.0, 1:10)
.+(x::Real, r::UnitRange{T<:Real}) at range.jl

# which is defined as
.+(x::Real, r::UnitRange)  = range(x + r.start, length(r))

and hence promotion-addition of Int64 and Float64.


Note in master the display of interval is slightly less confusing/ambiguous:

julia> float(1:10)
10-element FloatRange{Float64}:
 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0

julia> 1:10
10-element UnitRange{Int64}:
 1,2,3,4,5,6,7,8,9,10

Upvotes: 2

Dan Getz
Dan Getz

Reputation: 18217

The division operator in 4/1 returns a Float64. Although the original Range is a size 1 Int step Range, after adding a floating point to both sides it becomes a Float64 Range. As such, a step size of 1.0 is created by converting the implicit integer step size (floating point numbers are non-uniformly distributed, so uniform stepping is a little tricky - sometimes there are rounding issues).

Upvotes: 3

Related Questions