Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:
// второй
Например, если объект a вначале выглядел так:
{ 1 2 3 4 5 6 7 8 }
то получим
{ 1 2 3 4 1 2 3 4 }
Обратите внимание на то, что чаще всего срезки задаются начальными и последними элементами объекта класса
Matrix
; т.е. a.slice(0,j)
— это диапазон [0:j]
, а a.slice(j)
— диапазон [j:a.size]
. В частности, приведенный выше пример можно легко переписать:
a.slice(4) = a.slice(0,4); //
присваиваем первую половину матрицы
// второй
Иначе говоря, обозначения — дело вкуса. Вы можете указать такие индексы
i
и n
, так что a.slice(i,n)
выйдет за пределы диапазона матрицы a
. Однако полученная срезка будет содержать только те элементы, которые действительно принадлежат объекту a
. Например, срезка a.slice(i,a.size)
означает диапазон [i:a.size]
, а a.slice(a.size)
и a.slice(a.size,2)
— это пустые объекты класса Matrix
. Это оказывается полезным во многих алгоритмах. Мы подсмотрели это обозначение в математических текстах. Очевидно, что срезка a.slice(i,0)
является пустым объектом класса Matrix
. Нам не следовало бы писать это намеренно, но существуют алгоритмы, которые становятся проще, если срезка a.slice(i,n)
при параметре n
, равном 0
, является пустой матрицей (это позволяет избежать ошибки).
Копирование всех элементов выполняется как обычно.
Matrix<int> a2 = a; // копирующая инициализация
a = a2; // копирующее присваивание
К каждому элементу объекта класса
Matrix
можно применять встроенные операции.
a *= 7; // пересчет: a[i]*=7 для каждого i (кроме того, +=, –=, /=
// и т.д.)
a = 7; // a[i]=7 для каждого i
Это относится к каждому оператору присваивания и каждому составному оператору присваивания (
=
, +=
, –=
, /=
, *=
, %=
, ^=
, &=
, |=
, >>=
, <<=
) при условии, что тип элемента поддерживает соответствующий оператор. Кроме того, к каждому элементу объекта класса Matrix
можно применять функции.
a.apply(f); // a[i]=f(a[i]) для каждого элемента a[i]
a.apply(f,7); // a[i]=f(a[i],7) для каждого элемента a[i]
Составные операторы присваивания и функция
apply
модифицируют свои аргументы типа Matrix
. Если же мы захотим создать новый объект класса Matrix
, то можем выполнить следующую инструкцию:
b = apply(abs,a); // создаем новый объект класса Matrix
// с условием b(i)==abs(a(i))
Функция
abs
— это стандартная функция вычисления абсолютной величины (раздел 24.8). По существу,
apply(f,x)
связана с функцией x.apply(f)
точно так же, как оператор +
связан с оператором +=
. Рассмотрим пример.
b = a*7; // b[i] = a[i]*7 для каждого i
a *= 7; // a[i] = a[i]*7 для каждого i
y = apply(f,x); // y[i] = f(x[i]) для каждого i
x.apply(f); // x[i] = f(x[i]) для каждого i
В результате
a==b
и x==y
.
В языке Fortran второй вариант функции
apply
называется функцией пересылки (“broadcast” function). В этом языке чаще пишут вызов f(x)
, а не apply(f,x)
. Для того чтобы эта возможность стала доступной для каждой функции f
(а не только для отдельных функций, как в языке Fortran), мы должны присвоить операции пересылки конкретное имя, поэтому (повторно) использовали имя apply. Кроме того, для того чтобы обеспечить соответствие с вариантом функции-члена
apply
, имеющим вид a.apply(f,x)
, мы пишем
b = apply(f,a,x); // b[i]=f(a[i],x) для каждого i
Рассмотрим пример.
double scale(double d, double s) { return d*s; }
b = apply(scale,a,7); // b[i] = a[i]*7 для каждого i
Обратите внимание на то, что “автономная” функция
apply
принимает в качестве аргумента функцию, вычисляющую результат по ее аргументам, а затем использует этот результат для инициализации итогового объекта класса Matrix
. Как правило, это не приводит к изменению объекта класса Matrix
, к которому эта функция применяется. В то же время функция-член apply
отличается тем, что принимает в качестве аргумента функцию, модифицирующую ее аргументы; иначе говоря, она модифицирует элементы объекта класса Matrix
, к которому применяется. Рассмотрим пример.
void scale_in_place(double& d, double s) { d *= s; }
b.apply(scale_in_place,7); // b[i] *= 7 для каждого i
В классе
Matrix
предусмотрено также много полезных функций из традиционных математических библиотек.
Matrix<int> a3 = scale_and_add(a,8,a2); // объединенное умножение
// и сложение
int r = dot_product(a3,a); // скалярное произведение
Операцию
scale_and_add
часто называют объединенным умножением и сложением (fused multiply-add), или просто fma; ее определение выглядит так: result(i)=arg1(i)*arg2+arg3(i)
для каждого i
в объекте класса Matrix
. Скалярное произведение также известно под именем inner_product
и описано в разделе 21.5.3; ее определение выглядит так: result+=arg1(i)*arg2(i)
для каждого i
в объекте класса Matrix
, где накопление объекта result
начинается с нуля.
Поделиться:
Популярные книги
Мимик!
1. Сбой Системы!
Фантастика:
боевая фантастика
5.40
рейтинг книги
Измена. Жизнь заново
1. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Я Гордый Часть 3
3. Стальные яйца
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я Гордый часть 2
2. Стальные яйца
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Счастливый торт Шарлотты
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Академия
2. Клан Волка
Фантастика:
боевая фантастика
5.40
рейтинг книги
Кодекс Охотника. Книга XXIII
23. Кодекс Охотника
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Поступь Империи
7. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Я все еще граф. Книга IX
9. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Неверный. Свободный роман
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Стеллар. Трибут
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Темный Лекарь 4
4. Темный Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Сердце Дракона. Предпоследний том. Часть 1
Сердце дракона
Фантастика:
фэнтези
5.00
рейтинг книги
Курсант: Назад в СССР 10
10. Курсант
Фантастика:
попаданцы
альтернативная история
5.00