Использование `\` вместо `/` в Юлии

Для скаляров оператор \ (решение линейной системы) эквивалентен оператору деления /. Похоже по производительности?

Я спрашиваю, потому что сейчас в моем коде есть строка вроде

x = (1 / alpha) * averylongfunctionname(input1, input2, input3)

Визуально важно, чтобы деление на alpha происходило слева, поэтому я рассматриваю возможность замены этого на

x = alpha \ averylongfunctionname(input1, input2, input3)

Как лучше всего поступить в этой ситуации с точки зрения стиля и производительности?

Вот некоторые озадачивающие результаты тестов:

julia> using BenchmarkTools
[ Info: Precompiling BenchmarkTools [6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf]

julia> @btime x[1]\sum(x) setup=(x=rand(100))
  15.014 ns (0 allocations: 0 bytes)
56.23358979466163

julia> @btime (1/x[1]) * sum(x) setup=(x=rand(100))
  13.312 ns (0 allocations: 0 bytes)
257.4552413802698

julia> @btime sum(x)/x[1] setup=(x=rand(100))
  14.929 ns (0 allocations: 0 bytes)
46.25209548841374

Все они примерно одинаковы, но я удивлен, что подход (1 / x) * foo имеет лучшую производительность.

См. также:  Скачать с именем файла по умолчанию для даты и времени пользовательского события в приложении Vaadin Flow
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 2
  1. Max

    Скалярные / и \ действительно должны иметь одинаковое значение и производительность. Определим эти две тестовые функции:

    f(a, b) = a / b
    g(a, b) = b \ a
    

    Затем мы видим, что они производят идентичный код LLVM:

    julia> @code_llvm f(1.5, 2.5)
    ;  @ REPL[29]:1 within `f'
    define double @julia_f_380(double %0, double %1) {
    top:
    ; ┌ @ float.jl:335 within `/'
       %2 = fdiv double %0, %1
    ; └
      ret double %2
    }
    
    julia> @code_llvm g(1.5, 2.5)
    ;  @ REPL[30]:1 within `g'
    define double @julia_g_382(double %0, double %1) {
    top:
    ; ┌ @ operators.jl:579 within `\'
    ; │┌ @ float.jl:335 within `/'
        %2 = fdiv double %0, %1
    ; └└
      ret double %2
    }
    

    И тот же машинный код тоже. Я не уверен, что вызывает различия в @btime результатах, но я почти уверен, что разница между / и \ является иллюзией, а не реальностью.

    Что касается x*(1/y), он не вычисляет то же самое, что x/y: он будет потенциально менее точным, поскольку при вычислении 1/y выполняется округление, а затем это округленное значение умножается на x, которое также округляется. Например:

    julia> 17/0.7
    24.28571428571429
    
    julia> 17*(1/0.7)
    24.285714285714285
    

    Поскольку при делении с плавающей запятой гарантируется правильное округление, выполнение деления напрямую всегда будет более точным. Однако, если делитель используется во многих итерациях цикла, вы можете получить ускорение, переписав вычисление таким образом, поскольку умножение с плавающей запятой обычно быстрее, чем деление (хотя время на моем текущем компьютере этого не показывает). Однако имейте в виду, что это приводит к потере точности, и, если делитель не используется совместно, все равно будет потеря точности и никакого увеличения производительности.

    Спасибо. Есть какие-нибудь мысли по поводу стиля? person Max; 13.12.2020

    Мне нравится использовать alpha \ (longer expression), но некоторых это может сбивать с толку, поэтому это кажется немного субъективным. Я бы посоветовал использовать его, если он вам нравится, и он станет понятнее. person Max; 13.12.2020

  2. Max

    Я не знаю, но могу предложить вам попробовать использовать пакет BenchmarkTools: он может помочь вам оценить производительность двух разных операторов. Здесь вы можете найти более подробную информацию. Пока!

    Я думаю, что лучший выбор — (1/x)*foo по двум причинам:

    1. у него лучшая производительность (хотя и не намного по сравнению с другими);
    2. это более понятно для другого человека, читающего код.
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: