(x:y) оператор в Джулии

Я пытаюсь понять этот код:

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

Выход:

-3.0:1.0:6.0

Я понял, почему у меня есть -3 и 6. Но почему я получил это значение посередине (1.0)? Как Юля рассчитывает? Или как мне это погуглить?


person konstantin_doncov    schedule 21.10.2015    source источник


Ответы (3)


Синтаксис (first:step:last) представляет тип Range в Джулии

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

Если часть шага опущена, по умолчанию предполагается 1

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

Range - это компактный вид серии

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

Таким образом, ожидается, что тип Range и тип Vector следуют одним и тем же правилам, например, когда вы добавляете постоянное значение, подобное этому:

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

или даже добавление двух векторов даст вам тот же результат, что и добавление их представления диапазона следующим образом:

collect((1:10)+(1:10))==collect(1:10)+collect(1:10) # => true
person Reza Afzalan    schedule 21.10.2015
comment
Вероятно, это просто опечатка, но это не правда, что 1:10 === 1:1:10, только то, что 1:10 == 1:1:10. Первый - UnitRange, а второй - StepRange. Также было бы неплохо упомянуть, что isa(1:10,AbstractVector) # => true. - person Andreas Noack; 22.10.2015
comment
Спасибо @Andreas за его комментарий к 1:10 !== 1:1:10 действительно была опечатка, я редактирую это. сейчас 1:10 == 1:1:10 # => true - person Reza Afzalan; 22.10.2015

Оператор деления в 4/1 возвращает Float64. Хотя первоначальный диапазон представляет собой диапазон размера 1 с шагом Int, после добавления плавающей запятой к обеим сторонам он становится диапазоном Float64. Таким образом, размер шага 1,0 создается путем преобразования неявного целочисленного размера шага (числа с плавающей запятой распределяются неравномерно, поэтому равномерное пошаговое выполнение немного сложнее — иногда возникают проблемы с округлением).

person Dan Getz    schedule 21.10.2015

Вы можете увидеть это, применяя float к интервалу:

julia> 1:10
1:10

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

и это продвижение необходимо перед добавлением в Float64 4/1 (4.0).

Точно так же при добавлении целого числа к веществу с плавающей запятой julia «превращает» число в число с плавающей запятой перед добавлением/вычитанием:

julia> 1 + 2.0
3.0

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

см. правила продвижения:

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

Вы можете @which проследить все вызовы функций, чтобы понять, что происходит (вплоть до следующее):

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))

и, следовательно, продвижение-добавление Int64 и Float64.


Обратите внимание, что в мастере отображение интервала немного менее запутанно/двусмысленно:

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
person Andy Hayden    schedule 21.10.2015