19.1 Базовая векторизация ¶
В очень хорошем первом приближении цель векторизации заключается в написании кода, который избегает циклов и использует операции над целыми массивами. В качестве тривиального примера рассмотрим
for i = 1:n
for j = 1:m
c(i,j) = a(i,j) + b(i,j);
endfor
endfor по сравнению со значительно более простым
c = a + b;
Это не только проще писать; оно также намного проще для оптимизации на уровне реализации. Octave делегирует эту операцию базовой реализации, которая, помимо других оптимизаций, может использовать специальные векторные инструкции аппаратного обеспечения или, возможно, даже выполнить сложения параллельно. В общем случае, если код векторизован, у базовой реализации больше свободы в предположениях, которые она может сделать для достижения более быстрого выполнения.
Это особенно важно для циклов с «дешёвыми» телами. Часто достаточно векторизовать только внутренний цикл, чтобы получить приемлемую производительность. Общее правило — порядок векторизованного тела должен быть больше или равен порядку вложенного цикла.
В качестве менее тривиального примера, вместо
for i = 1:n-1 a(i) = b(i+1) - b(i); endfor
запишите
a = b(2:n) - b(1:n-1);
Это демонстрирует важную общую концепцию использования массивов для индексирования вместо итерации по индексной переменной. См. Индексные выражения. Также используйте булевы индексы щедро. Если необходимо проверить условие, это условие также можно записать в виде булева индекса. Например, вместо
for i = 1:n
if (a(i) > 5)
a(i) -= 20
endif
endfor запишите
a(a>5) -= 20;
что использует тот факт, что a > 5 генерирует булевый индекс.
Используйте поэлементные векторные операторы всякий раз, когда это возможно, чтобы избежать циклов (операторы, такие как .* и .^). См. Арифметические операторы.
Также используйте векторизованное расширение в этих поэлементных операторах, чтобы избежать циклов и ненужных промежуточных выделений памяти. См. Широковещательную передачу.
Используйте встроенные и библиотечные функции, если это возможно. Встроенные и скомпилированные функции очень быстрые. Даже с помощью m-файловой библиотечной функции, есть большая вероятность, что она уже оптимизирована или будет оптимизирована в будущих версиях.
Например, даже лучше, чем
a = b(2:n) - b(1:n-1);
является
a = diff (b);
Большинство функций Octave написаны с учётом векторных и массивно-ориентированных аргументов. Если вы обнаруживаете, что пишете цикл с очень простой операцией, скорее всего, такая функция уже существует. Следующие функции часто встречаются в векторизованном коде:
- Обработка индексов
- find
- sub2ind
- ind2sub
- sort
- unique
- lookup
- ifelse / merge
- Повторение
- repmat
- repelems
- Векторизованная арифметика
- sum
- prod
- cumsum
- cumprod
- sumsq
- diff
- dot
- cummax
- cummin
- Форма многомерных массивов
- reshape
- resize
- permute
- squeeze
- deal
© 1996–2023 The Octave Project Developers
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
https://docs.octave.org/v9.2.0/Basic-Vectorization.html