Б. Страуструп - Язык программирования С++. Специальное издание, 3-изд. Бином. 2004 (1160791), страница 167
Текст из файла (страница 167)
Однако можно спроектировать Ма!г!х так, чтобы для выражений соответствующего вида такая оптимизация применялась автоматически. То есть мы можем обращаться с 17=М*Уч-(У, используя один оператор с четырьмя операндами. Соответствующие обгцие приемы были продемонстрированы для манипуляторов ов!геат Я 21А,6.3). Как правило, или можно пользоваться, ьтобы комбинация л бинарных операторов работала как один (лч 1)-арный оператор. Обработка 17=М*У+(Г' требует введения двух вспомогательных классон. Однако в некоторых системах данный прием может привести к внушительному повышению быстродействия (скажем, раз в 30), благодаря тому, что становится возможна мощная техника оптимизации.
Сначала мы определим результат умножения Ма!г!х на Уес!ог. вггисгМУвьи!( соль Г Маспхй ьл, солФ Уес!огй о; МУти! (соле! Магпхй т т, соли Уесгогй оо), т (тт), о (ии) ( ) орегагог Уесгог ();,!! вычислить и вернуть реврлылат !лйлеМУти! орега!ог* (солИМаггхйтт, сопвгУесгогйьо) ( гееиглМУти!(тт, ио); Это лумножение» ничего не делает, только хранит осы.лки на свои операнды; вычисление М*У откладывается.
Объект, полученный оператором *, тесно связан с тем, что Глава 22. Численные методы 744 во многих технических сообшествах называют с7оки«е (замыкающим объектом), По- добным же образом мы можем разобраться с тем, что получится, если мы лобавим Уес7ог: кггисгМУти!УасЫ( соле!Магг)кй т; сопк! Ъесгог& о; сои к! Вес!о«& о2; МУти)Уайи' (соле! МУти)й то, сопк! Уесгогй по): т (тот), и (тип), о2 (оо) ( ) орегагог Ъесгог(); //вычислтпь и вернуть реэулыпат т)!пе МУти!Ъайй прего!ось (со пег М Ъти!й то, сопл! Уесгогй ии) ( ге!ига МУтиМаЫ (то, ио); ) Таким образом вычисление М*Уч-)Уотклацывается. Теперь нам надо гарантировать, что при присваивании этого вектору все будет вычисляться по хорошему алгоритму: с)акк Усе!о « ( О.- рио((с; Ъесгог(сопкгМУтиП~асЫ&т) ( // иниииалиэаиив результатом тот //раэмеи(ение элементов и га и.
ти! ас!й апс! акмуп (г!ик, йт, т, йт, и, йт о2); ) Уесгогй орегагог= (сопл! МУти!Уааь!й т) // присваивание *!)нк результата т ( ти! аг7г! апь! акк)уп (г!йк, йт.п, йтль Вэп.о2); ге!ига "гй!к; Теперь (/=М*У+ !У автоматически раскрывается в !торе«аког= (МУти(УасЫ(МЪти! (М, Ъ), Щ который из-за встраивания разрешается в желаемый простой вызов ти! а<И апс! аккгуп(&!!, &М, &У, й)У) Ясно, что это устраняет копирование и временные массивы. Кроме того, мы могли бы оптимизировать саму функцию ти! ачгг! апс! акк)уп (). Однако даже если мы и не будем этого делать, все равно форма кода оставит огромные возможности лля оптимизатора.
Я ввел новый класс Ъес!о«(а не воспользовался эа!а««ау), потому что мне нужно было определить присваивание (а присваивание должно быть функцией-членом). Однако, иа/аггау — это лучшая кандидатура для внутреннего представления Ъес!ог. 745 22.4. Векторная арифметика Важность этого приема заключается в том, что большинство критичных по времени вычислений с векторами и матрицами выполняются при помощи относительно простых синтаксических форм. Как правило, не ставится пели оптимизировать таким образом выражения из полдюжины операторов; для них хватает более привычных методов Я 11.6). Данный прием основывается на идее использования анализа времени компиляции и замыкающих объектов, чтобы перенести вычисление подвыражений в объект, прслставляющий составную операцию.
Такой подход можно применять к разнообразным проблемам, имеющим следующий общий признак; перед тем, как производить вычисление, информацию нужно собрать в одну функцию. Объекты, порожденные для откладывания вычислений, я называю объектами, эамыкаюшими ко илоэицию, или просто композиторами.
22.4.8. Обобщенные срезы 11ример с Ма1пх в 9 22.4.6 показывает, как два среза можно использовать для описания строк и столбцов двухмерного массива. В общем случае срез может описывать любые строки и столбцы и-мерного массива Я 22.9[71), Однако иногда нам нужно извлечь подмассив, не являющийся строкой или столбцом.
Например, нам может понадобиться матрица 2хЗ из левого верхнего угла матрицы Зх4: К сожалению, эти элементы расположены так, что их не может описать один срез: 0 1 2 00 10 20 30 01 11 21 31 02 12 22 32 4 5 6 уз11се — это «обобщенный срез», который содержит (почти) вшо информацию из л срезов: с1азззгс1::уз11се ( // вместо одного шага и одного рознера (кок дчл среза), // узггсе содерэкипг и шагов и и размеров риЬИс уз11се 0; узусе ~згее 1з, сопз1 иа1аггау<з1ге 1>с |, сопз1иа1аггау<з1ее 1>с, сй; з1ге 1 з1аг1 0 сопзй // индекс первого эле,иенпэа оа1аггау<з1ге 1>з1ге д сопзг; //число элементов в иэлиерении иагаггау<зсее 1>з1гЫе 0 сопз1; //шаг для индекса(0) индекса111, ...
Дополгительпые значения позволягот дз/1се определить соответствие между и целымн числами и индексом для адресации элементов в массиве. Например, мы можем описать размещение матрицы 2ХЗ одной парой пар (длина,шаг). Как показано в Глава 22. Численные методы ч 22.4.5, при использовании размещения в стиле гогсгап длина 2 и шаг 4 описывает два элемента строки матрицы 3Х4. Аналогично, длина 3 и сваг 1 описывает трн эле- мента столбца. Вместе они описывают все элементы подматрицы 2хЗ. Чтобы пере- числить эти элементы, мы можем написать: з!зе 1узйсе !пс(ех(сопя1уийсейз,яме 11,мхе 1!) ( ге1игп кмаг1 ()<1*з з1гЫе ()[О~+! яяггЫе ()[!), ) // (!ел[0], я!с[0]) описываепс строку // (!еп[!], згг[!)) описывает столбец исае 1!еп() =(2,8); зсее гя1гЦ=(4, 1); оа1аггау<ясее 1> !епфвя (1еп, 2); оа!аггау<я!хе Гл исгЫея (и1г, 2); ооЫ/() ( уз!Ые я (О, !епдгдз, игг!Оеи); //строка // столбец 1ог (тг ! = 0; !<з.и!хе (КО]; 1-н-) сои1 «дяйсе !пс(ех (з, Ь О) « ""; сои1 «',', /ог (!п11 = 0 1<з з!ге ()[!];1 н) сои1 «дяйсе !пс(ех (з, О, !) « " '; ооЫ/' (оа!аггау<Яоа1)Й о) ( узусе т (О, !епутли, ягг!с!еи) о[т) " О, ) // обнуление о[0], о[!), о[2], с[4), о[5).
о[б) Тнп узйсе аггау предлагает тот же набор членов, что и зйсе аггад, В частности, пользователь не может напрямую конструировать узйсе аггау, и узйсе аггау нельзя копировать Я 22А.Б). Вместо этого узйсе аггау является результатом использова- ния узйсе как индекса для массива эа1аггау (ф 22А). 22.4.9. Маски Массив спая(с аггау предоставляет еще один способ определения подмножества массива эа1аггау и прелставления результата в виде, схожем с эа1аггау. В контексте массивов оа1аггау, маска — это просто оа1аггад<Ьоо1>.
Когда маска применяется для инлексирования эа1аггад, бит 1гие обозначает, что соответствующий элемент массива эа!аггау следует включать в результат. Это позволяет нам производить операции над подмножествами эа1аггау, даже если нет простой модели (вроде среза), которая описывала бы зти подмножества. Например: , Будет выведено 0 4, 0 1 2. Таким способом узйсе с двумя парами (длина,шаг) описывает подмассив двумерного массива, узйсе с тремя парами (ллина,шаг) описывает подмассив трехмерного массива и т. д. Использование узйсе в качестве индекса для оа1аггау создаст узйсе аггау, состоящий из элементов, которые описывает узйсе.
Например: 74? 22.5. Комплексная арифметика ио!<1/ (и а (агга у <доиЫе> й и) ( Ьоо! Ь[) = ( !гиена!эеДа!эе, !гие,Хи!эе, ггие ); и1иггау<Ьоо!> тиэб (Ь, б); //элементы О, 3 и 5 ии!игга у<с(оиЫе> ии = соя (и[тояб]); // си [О]==соя (и[0]), //ии[!]==сок(и[3]), // си[2) ==сок(и[5]) таз/е аггау предлагает тот же набор членов, что и з1!се аггау. В частности, пользователь не может напрямую конструировать таей аггау, и таем аггау нельзя копировать Я 22.4.6).
Он получается в результате использования иа!аггау<боо1> как «индекса> для иа1аггад (6 22А.2). Число элементов массива иа1аггау, используемого в качестве маски, не должно превышать числа элементов массива оа1аггад, который он индексирует. 22.4.10. Косвенные массивы Массив !пйгес! аггау предоставляет способ произвольного выделения подмноже- ства из иа1аггад и переупорядочивания иа1аггау. Например: ио!д/!иа!ассад<с/оиЫе> Ьи) ( тге ! ![] = ( 3, 2, 1, 0 ); // переые четыре элемента о ооротном // порядке // элементы В, 2, 1, О (о такал~ порядке) // ии[О]== — !од(и[39, ии[!]==!од(и[2]), // си[2]==!од(и[!У, си[3]==!од(и[О]) иа!аггау<е(хе !> !пс(ех (1, 4); иа!аггау<доиЫе> ии = !од (и[!паек]), 22.5.
Комплексная арифметика Стандартная библиотека предоставляет шаблон сотр1ех в духе того класса сотр1ех, который был описан в З 11.3. Библиотечный класс сотр1ех должен быть шаблоном, чтобы комплексные числа можно было основывать на разных скалярных типах. В частности, для сотр1ех введены специализации, пользующиеся скалярными типами Яоа1, с/оиб!е н 1оггд с/оиб!е. Если индекс указан дважды, значит, мы сослались на соответствующий элемент иа1аггау дважды в одной и той же операции, Это именно тот вид альтернативных имен, который для иа1аггад зацрешен, поэтому если индекс повторяется, поведение тс((гес1 аггау не определено.
Тип 1пс/1гес! аггау предлагает тот же набор членов, что и з1лсе аггау, В частности, 1лс(!гес! аггау (пользователю) нельзя напрямую конструировать, и его нельзя копировать (э 22 А,6). Массив !пс(!гес! аггау получается в результате использования иа1аггау<ябве 1> в качестве индекса для иа1аггад Я 22А.2). Число элементов масси. ва иа1аггау, используемого в качестве индекса, не должно превышать числа элементов массива иа1аггау, который он индексирует.
748 Глава 22. Численные методы Шаблон сотр1ех определен в пространстве имен я(а(и представлен в <сотр1ех>; (етр!а(е<с(акк Т> с1акк к(дссотр!ех ( Тге, ил; рий!(с; (урсс(е/Т иа!ие (уре, сотр!ех (солз1 Тй ~7((, сопя( Тй('=ТЯ. ге (г), !т (й() 1етр1а(е<с!акз Х> сотр!вх (солк1 сотр1ех<Х>й а(; ге (аге(, (т (азт(() Т геа! () сопз1( ге1игп ге; ) Т (т ау ((сопя( ( ге 1 игл ип; ) сотр!ех<7>й орега1ог= (сопя(Тйх( // ариев аивание сотр1ех(г, 0) (етр1а1е<с1акк Х> сотр(ех<7 й орега1ог= (сопз1 сотр!ех<Х>й) //аналогично:+йь — =, "=, /= .Это представление и встроенные функции приведены для иллюстрации.