Reputation: 2879
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
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
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
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