Бьерн Страуструп. Язык программирования С++. Специальное издание (2011) (1004033), страница 168
Текст из файла (страница 168)
С другой стороны, можно спроектировать Магг1х таким образом, чтобы для определенного вида выражений оптимизация выполнялась бы автоматически, например, для выражений с(=М» У- 1Уможно применять единственную операцию с четырьмя операндами. Соответствующие приемы ранее были показаны на примере манипуляторов для потоков омгеагл (521.4.6.3) — ими можно пользоваться, чтобы комбинация из л бинарных операций работала как одна и-арная операция. Все это может обеспечить резкое (раз в 30) повышение производительности за счет внедрения еше более мощных приемов оптимизации.
Теперь определим результат умножения Мал гх на Уесгог: .. 1МУ сове( Маигхь т; соим Уес1огв ю МУти1(сопмМатгГхв тт, совет Уесеогв гг): т(тт), г(гг) () орегаеог солт Уесгог () )' тИпе МУти! орегагог* (соптМагг(ха тт, сопз( Уесгогв кг) ( ге!ига МУти1 ( тт, и ) ) Это «умножение» ничего не делает — лишь хранит ссылки на свои операнды; реальное же вычисление М' Уоткладывается. Объект, порождаемый операцией *, соответствует тому, что во многих других областях (и языках программирования) принято называть замыканием (с(озиге). Теперь аналогичным образом вводим сложение с вектором: Мгист МУти(Уа»Ы ( соне( Маатха т; сопли Уесгогв ю МУ(аг; 22.4.
Векторная арифметика 795 М)ти!УиЫ(сопягМЪти!а тг, сонм Усе!оса гг): т (тг.т), г(ти.г), я2(гг) () орегатг сопя! Уес(ог ( ) )' !п!те МУти!УаМ ореттг+ (солги МУти!а тя, солт Уесгога гя) ( ттгп М) титиЫ (тг, гг); ) В результате реальное вычисление М" У«)Уоткладывается «на потом», но в конце концов, нам нужно гарантировать реальное эффективное вычисление в момент присвоения этого выражения вектору: гоЫ ти! аяЫ апд аяя!дп ( Уесяог*, сопя! Мапгх*, солт Уесгог*, сапы Уес(ог*); с!ат Уесил ( риЫ!с: Уесгог(сопя! МУти!Уела т) ( //размещение элементов и т.д. гпи! а«Ы апй аияял (г!я(я, ат.т, ат.
г, ат. г2) ) Уесяога орегагог= (сопя! МУти!УаяЫа т) ( ти! аИ апя! аяя!ап (гл!я, ат.т, ат.г, ат.г2) ге!игл *ял!я! /... ); Выражение Е/= М" и+ 1Уавтоматически раскрывается в (/.орегагог= (МУти!Уайй(МУти!(М, У), )У) ) и что из-за встраивания сводится просто к желаемому вызову ти! аИ апй аяя!ап (а|/, аМ, аУ, а)У) Ясно, что тем самым устраняются копирование и создание временных объектов.
Можно, конечно, оптимизировать и саму функцию ти! аяЫ ат1 аяя1яп (), но даже в своей простой и неоптимизированной версии она оставляет массу возможностей программисту-оптимизатору. Я ввел новый тип Уесгог, а не использовал га1аггау, потому что мне нужно было определить операцию присваивания (а она должна определяться как функция-член; 911.2.2).
В то же время, га1аггау — это наилучшая кандидатура для внутреннего представления типа Уесгог. Важность рассмотренного приема заключается в том, что большая часть критически важных по производительности вычислений с матрицами и векторами выполняются с помошью немногочисленных и довольно простых синтаксических конструкций. В типичном случае не возникает нужды в сильной оптимизации дюжин операций — для них достаточно привычных методов (911.6). 796 Глава 22. Классы для математических вычислений Рассмотренный прием, основанный на опыте практической компиляции, вводит замыкающие объекты, позволяющие переместить реальные вычисления подвыражений в объект, представляющий композитную операцию.
Этот подход можно применять ко многим задачам, имеющим следующую общую черту: отдельные части информации нужно собрать в одну функцию до того момента, когда начнутся реальные вычисления. Я называю объекты, позволяющие отложить реальные вычисления, обьсктами, замыкающими композицию (согпрозг!юп с!озигв оЬ1ес(з). 22.4.8.
Обобщенные срезы Пример с Магг!х в 922.4.6 показывает, как можно использовать два среза для описания строк и столбцов двумерного массива. В общем случае срез может описывать любую строку или столбец и-мерного массива (922.9[7(). Но иногда нам требуется извлечь подмассив, который не является ни строкой, ни столбцом.
Например, нам может потребоваться матрица 2хЗ из левого верхнего угла матрицы Зх4: К сожалению, нужные нам элементы не располагаются таким образом, чтобы их можно было охарактеризовать одним срезом; О 1 2 4 5 б Класс яз!!се — это обобщенный срез (яепего!!сей з!(се), который содержит (почти) всю информацию из и срезов: с!паз згз(:: Лзбсв ( 11 дзйсе содержит и шагов и и размеров риЫ!с: аз!1се ( ); аз!!се(в!ге зз, сопИ за(аггау<з!гв 1>з 1, сопл! га1апау<з(ге !>а а); З(гс ! этан() сола; гУ индекс первого элемента ва(аггау<з!св 1> з(ге () сопи; гг число элементов измерения га(аггау<з!ге !> зОЫе() сопзг; Ушаг для !пг(ех/(Д, иЫвхГ!7, .... Дополнительные значения позволяют яз!1се определить соответствие между и целыми числами и индексом, которым адресуются элементы массива. Напри- 797 22.4. Векторная арифметика мер, мы можем описать размещение матрицы 2хЗ двумя парами (длина, шаг) целых чисел.
Как показано в 922.4.5, при расположении элементов в стиле языка Готтгап длина 2 и шаг 4 описывают два элемента строки матрицы Зх4. Аналогично, длина 3 и шаг 1 описывают три элемента столбца. В совокупности они описывают элементы подматрицы 2хЗ. Для перечисления элементов мы можем пап исат)с язе 10зйсе Ыаех (сопя Озйсеь з, з!зе 1 1, з!зе 11) ( ге1игп з.яаг1() + 1*в.зиЫе() [0) + 1*в.заЫе() [1]; ) з(зе ( 1еп [] = (2,3) 1 У(!ел[0]з(г[0]] описывают строку з!Зе 1за [) = (4,1); УУ(!еп(!]з(г(!]] описывают столбец га1аггау<з!зе 1> 1еплзпз (1еп, 2) 1 га)аггау<з!ге 1> зггЫез (ззг, 2) ! гоЫ[( ) ( Оз)ке з (О, 1епдзлз, з!гЫез); ]ог([пг 1' = О) !<вязе О [О] 1 1++) сои( «Оз1ке 1пбех(з 1 0) « " "; ](строка сои!« ", "; ]ог((п1! = 0; ]<з.з!зе() [1] 1]н) сои( «Оз!Ые таех(з, О!) « " "; ((столбец ) При этом будет выведено 04, 0 12.
Таким образом, Озйсе с двумя парами (длина, шаг) описывает подмассив двумерного массива, бзйсе с тремя парами (длина, шаг) описывает подмассив трехмерного массива, и так далее. Использование Озйсе в качестве индекса для га(аггау породит язйсе аг ау, состояший из элементов, которые описывает язйсе. Например: юЫ] (га1аггау<]гааз>З г) ( Оз!Ые т (О,!еп00)з, з1 Ыез) ! г[т] = 0; УУобнуллем г(0],г(1],к[2],к[4],г(5],г(б] ) Массив 1ийсе агз ау предоставляет тот же набор членов, что и зйсе аггау. В частности, пользователь не может напрямую конструировать Озйсе аггау, а также его нельзя копировать (922.4.6).
Обьекты лзйсе азгпу порождаются в качестве результата использования язйсе лля индексации элементов га(аггау (922.4.2). 22.4.9. Маски (тип птав]с аггау) Массив пзаз(с азгпу (маска) предоставляет еше один способ определения подмножества ю]аггау и предоставления результата в виде, похожем на га1аггау. В контексте массивов га1ап ау маски — это просто га1аггау<1юо1>. Когда маски применяются для индексации га1азтау, зНаЧеНИе тгие означает, что элемент включается в подмножество. Это позволяет нам оперировать подмножеством га!аггау даже тогда, когда нет четкой структуры (например зйсе), описывающей подмножество.
Например; 798 Глава 22. Классы для математических вычислений кои ((яа!аггоу<йоиЫе> а в) ( Ьоо! Ь (» = (тгие<(о!«е,~а!«е, тгие,(а!«е, тгие); У элементы О, 3 и 5 яо1апоу<Ьоо!> то«Ь (Ь, б) т га!аггау<т!оиЫе> гг = со«(г(та«Ь» ); Ф чч(0»=-=со«[ч(0)), эч([[==[со«(ч(ЗЦ, // чч(2! = =со«[ч(5!) ) Маски предоставляют тот же набор членов, что и тип «1!се аггау. В частности, пользователь не может напрямую конструировать та«!г аггау, а также их нельзя копировать (922.4.б).
Объекты та«!г оп ау порождаются в качестве результата использования га!аггау<Ьоо1> для индексации элементов га1аггау (922.4.2). Число элементов массива га1аггау, используемого в качестве маски, не должно превышать число . элементов индексируемого таким образом массива га1аггау. 22.4.10. Тиг) 1пс((гес1 аггау Тип 1ал(!гес! аггау предоставляет способ произвольного выделения подмножеств из га!аггау и его переупорядочения. Например: го!й ((го!оггау<ооиЫе>а г) ( Ызе ! !(» = (3,2,1,0); впервые четыре элемента в обратном порядке го!оггоу<«ае (> !плех(1,4); й элементы 32,»,0 га!оггоу<ИоиЫе> кг = !оя(г[!пдех» ); ~Учч(03==!од[э(ЗЯ, экю==!ой[э(2»), ,У и (2/= =!од[к(Ц), и (З~ = =!од[э(ОД~ ) Если индекс указан дважды, значит мы сослались на соответствующий элемент га(аггау дважды в одной операции.
Это соответствует синонимии, которую га(аггау запрещает, так что если индекс повторяется, то результирующий !пч(!гес! оггау не определен. Тип !пйгес! аггау предоставляют тот же набор членов, что и тип «1!се аггау. В частности, пользователь не может напрямую конструировать объекты 1пв(1- гес! аггау, а также их нельзя копировать (922.4.6). Объекты 1тб!гес! аггау порождаются в качестве результата использования га1аггау<«!хе !> для индексации элементов га1аггау (922.4.2).
Число элементов массива га(аггау, используемого для индексации, не должно превышать число элементов индексируемого таким образом массива га1аггау. 22.5. Комплексная арифметика Стандартная библиотека предлагает шаблон сотр1ех, реализующий комплексную арифметику в духе класса сотр1ех, рассмотренного в 811.3. Библиотечный соту(ех должен быть шаблоном, чтобы комплексные числа могли базироваться на разных скалярных типах. В частности, представлены специализации сотр1ех для 31оаг, л(оиЫе и 1опд ИоиЫе в качестве его скалярных типов.
22,5. Комплексная арифметика 799 Шаблон сотр!ех определяется в пространстве имен мй и представлен в заголовочном файле <сотр!ех>: (етр(а(е<с(азз Т> с(азз к(й:: сотр(ех ( Т ге, йп( рий!!с ( фрейе! Т га!ие суре; соп(р1ех(сопи Ть г = Т(), сопл( Ть 1= Т() ): ге(г), 1т(() () (етр1а(е<с(аккХ> сотр(ех(сот(сотр!ех<Х>ь а): ге(а.геа(() ), !т(а.!тая() ) () Тгеа1() сопз( (ге(игп ге( ) Т (таа [) сопл( ( ге(игп (т; ) сотр(ех<Т>ь ирека(ос=(сопл( Ть к); рприсвоить сотр1ех(гО) (етр1а(е<с1азз Х> сотр1ех< Т> ь прего(ог= ( сопл( сотр1ех<Х> ь ) ( раналогично; +=, =-, *=, /= )( Данное представление и встраиваемые функции приведены для иллюстрации.