Почему эта простая индексная переменная gettng Box-ed в Julia? - PullRequest
0 голосов
/ 25 апреля 2018

При решении Задачи 10 от Project Euler вручную (вместо простого using Primes) я реализовал наивное сито эратосфена в Юлии, используя BitVector.Он выдает правильный вывод, но когда я проверил его стабильность типов с помощью @code_warntype, я обнаружил, что i выделяется как Core.Box, что влияет на тип psum, и это, в свою очередь, приводит к стабильности типався функция прочьИспользуемый код:

function primesum(limit::T = 2_000_000) where T<:Integer
    #easy way: using Primes; sum(primes(limit)) 

    #hard way: 
    is_prime_num = BitVector(limit)
    is_prime_num .= true

    psum = zero(limit)
    for i in 2:limit
        if is_prime_num[i]
            psum += i
            multiples_of_i = [k*i for k in 2:(limit÷i)]
            is_prime_num[multiples_of_i] .= false
        end
    end
    psum
end

А вот часть Variables вывода code_warntype (полный вывод здесь ):

Variables:
  #self#::#primesum
  limit::Int64
  #46::##46#47
  i::Core.Box
  multiples_of_i::Any
  #temp#@_6::Int64
  is_prime_num::BitArray{1}
  psum::Any
  J::Any
  #temp#@_10::Any

В целом,многие типы в коде (включая тип возвращаемого значения функции) оставляются либо Any, либо типом where _.

Мне удалось улучшить скорость (почти в 10 раз) и память (~ 3 раза), изменив строку цикла for на for i::T in 2:limit - тогда i по-прежнему устанавливается как Core.Box, ноон получает typeassert ed для Int64 и не распространяет нестабильность на psum и другие.Но Меня больше интересует, почему Джулия не может вывести тип i, чем ускорить этот конкретный код. Я привык набирать нестабильности, что имеет смысл, по крайней мере, в ретроспективе, но этоткажется довольно ясным и простым для вывода, поэтому я хотел бы знать, где здесь присутствует неоднозначность типов.

1 Ответ

0 голосов
/ 25 апреля 2018

Временное решение состоит в том, чтобы обернуть i в let блок вокруг понимания (я также предложил несколько небольших изменений в вашем коде, которые являются незначительными исправлениями - я оставил создание multiples_of_i, так как это было ядромВаш вопрос, но на самом деле использование этой переменной также неэффективно - было бы лучше установить is_prime_num vector на false в соответствующих местах, используя цикл):

function primesum(limit::Integer = 2_000_000)
    is_prime_num = trues(limit)
    psum = zero(limit)
    for i in 2:limit
        if is_prime_num[i]
            psum += i
            let i=i
                multiples_of_i = [k*i for k in 2:(limit÷i)]
                is_prime_num[multiples_of_i] .= false
            end
        end
    end
    psum
end

Надеюсь, в долгосрочной перспективе проблема https://github.com/JuliaLang/julia/issues/15276 будет исправлено, и в этом нет необходимости.

...