Broadcasting и точечные операции
Точка перед операцией превращает её в поэлементную — это и есть broadcasting, фирменный механизм Julia.
Broadcasting — применение операции или функции к каждому элементу массива (или к соответствующим элементам нескольких массивов) с помощью точечного синтаксиса.
Зачем нужен broadcasting
В научном коде постоянно нужно применить операцию ко всему массиву: прибавить число к каждому элементу, посчитать синус от всех значений, перемножить два вектора поэлементно. В Python для этого используют NumPy, и поэлементность подразумевается по умолчанию. В Julia векторные и матричные операторы по умолчанию математические, а для поэлементности ставят точку. Это делает намерение явным.
Точечные операторы
v = [1, 2, 3, 4]
println(v .+ 10) # прибавить 10 к каждому
println(v .^ 2) # возвести каждый в квадрат
println(v .* v) # поэлементное произведениеВывод:
[11, 12, 13, 14] [1, 4, 9, 16] [1, 4, 9, 16]
Точка для функций
Любую функцию можно применить поэлементно, поставив точку после её имени:
angles = [0.0, 1.5708, 3.14159]
println(round.(sin.(angles), digits=2))
println(uppercase.(["julia", "быстрая"]))Вывод:
[0.0, 1.0, 0.0] ["JULIA", "БЫСТРАЯ"]
Здесь sin. берёт синус каждого угла, а внешний round. округляет каждый результат. Несколько точечных вызовов в одном выражении сливаются в один проход по массиву.
Broadcasting разных форм
Broadcasting умеет «растягивать» размерности: например, прибавить вектор-строку к вектору-столбцу и получить матрицу — как в NumPy:
col = [1, 2, 3]
row = [10 20 30]
println(col .+ row)Вывод:
[11 21 31; 12 22 32; 13 23 33]
Как работает под капотом
Это ключевое преимущество Julia перед связкой Python+NumPy. В NumPy выражение вроде a + b*c над массивами создаёт временные промежуточные массивы для каждой операции. В Julia несколько точечных операций в одном выражении (a .+ b .* c) сливаются (fusion) компилятором в единственный цикл без промежуточных массивов. Это экономит память и время. Причём это работает для любых функций, в том числе ваших собственных — не нужно писать векторизованные версии, как в NumPy.
Частые ошибки
Самая частая ошибка — забыть точку и получить либо ошибку, либо неожиданный результат. Например, v ^ 2 для вектора попытается выполнить матричное возведение в степень и упадёт с ошибкой, а правильное поэлементное — v .^ 2. Если видите ошибку про несовпадение размерностей в, казалось бы, простой операции — проверьте, не пропущена ли точка.
Итоги
- Точка перед оператором (
.+,.*,.^) делает его поэлементным. - Точка после имени функции (
sin.,round.) применяет её к каждому элементу. - Несколько точечных операций сливаются в один проход без промежуточных массивов — быстрее NumPy.
- Broadcasting работает с любыми функциями, включая ваши собственные.