<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Блоги &#187; Intel Software Network</title>
	<atom:link href="http://software.intel.com/ru-ru/blogs/category/isn/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/ru-ru/blogs</link>
	<description></description>
	<lastBuildDate>Tue, 07 Feb 2012 14:18:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>Конкурс футболок для участников ISN</title>
		<link>http://software.intel.com/ru-ru/blogs/2012/02/07/isn-8/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2012/02/07/isn-8/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 14:15:42 +0000</pubDate>
		<dc:creator>Boris Rozenshteyn (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Конкурсы и мероприятия]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2012/02/07/isn-8/</guid>
		<description><![CDATA[На ISN объявляется конкурс на дизайн футболок для блогеров ISN.]]></description>
			<content:encoded><![CDATA[<p>Всем привет!</p>
<p><img align=right src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/tShirt2012_logo.png"/></p>
<p>В эти холодные дни, когда студенты спокойно отдыхают от сессии, а не-студенты два раза в день мерзнут по дороге на работу и с работы, мы опять решаем, как оформить новые блог(г)ерские футболки для участников Intel Software Network.<br/><br />
В далеком 2008 году мои коллеги <a href="http://software.intel.com/ru-ru/blogs/2008/08/22/2000112/">уже обращались</a> к авторам сообщества с призывом придумать надпись для футболок, но чем закончилось дело я не знаю.</p>
<p>Итак, в этот раз всё серьезно и более свободно.</p>
<p>Наверняка, у вас есть <strong>идея для клёвой футболки блогера/участника ISN</strong>. Мы можем воплотить ее в жизнь!</p>
<p>Каждый, кому не безразлична ISN-мода этого сезона, может перейти в <a href="http://software.intel.com/ru-ru/forums/showthread.php?t=102890">специальную тему на форуме</a> и опубликовать там картинку или текстовое описание «футболки мечты». </p>
<p>Если же вы не готовы проявить креативность, можете комментировать уже опубликованные идеи и голосовать за них.</p>
<p>Самую лучшую идею мы воплотим в жизнь (а это значит, что более 50 человек будут носить на себе ваше творение), а автору идеи, а также самому активному на наш взгляд участнику, отправим свежеиспеченные футболки, как только они приедут к нам из типографии.</p>
<p><strong>Таймлайн</strong>: обсуждение лучшей футболки не закончится никогда, но выбирать лучший вариант мы будем 9 марта, сразу после праздников (чтобы веселее было <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  )</p>
<p>До встречи <a href="http://software.intel.com/ru-ru/forums/showthread.php?t=102890">в форуме</a>!</p>
<p><strong>P.S.</strong>: Тому, кто догадается, почему мы не предлагаем публиковать картинку в комментариях к этой записи, плюс в карму <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>P.P.S.</strong>: Не воспринимайте последний вопрос серьезно, ответ лежит на поверхности и не отличается уникальностью <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2012/02/07/isn-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Качество обслуживания: Computer Networks vs. Network on Chip</title>
		<link>http://software.intel.com/ru-ru/blogs/2012/01/31/computer-networks-vs-network-on-chip/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2012/01/31/computer-networks-vs-network-on-chip/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 13:35:49 +0000</pubDate>
		<dc:creator>Yuriy Viktorov (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[communication fabrics]]></category>
		<category><![CDATA[Computer Networks]]></category>
		<category><![CDATA[Network on Chip]]></category>
		<category><![CDATA[QoS]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2012/01/31/computer-networks-vs-network-on-chip/</guid>
		<description><![CDATA[Традиционно устройства внутри микропроцессора коммутировались с помощью общей шины. С течением времени росла степень интеграции, что сопровождалось увеличением числа блоков внутри микропроцессора. При числе блоков порядка десятков и сотен, шинная архитектура соединений становится непригодной из-за ограниченной пропускной способности и масштабируемости. Современные системы межсоединений, архитектуры которых сильно зависят от области применения, объединяют под общим названием коммуникационных [...]]]></description>
			<content:encoded><![CDATA[<p>Традиционно устройства внутри микропроцессора коммутировались с помощью общей шины. С течением времени росла степень интеграции, что сопровождалось увеличением числа блоков внутри микропроцессора. При числе блоков порядка десятков и сотен, шинная архитектура соединений становится непригодной из-за ограниченной пропускной способности и масштабируемости.<br />
Современные системы межсоединений, архитектуры которых сильно зависят от области применения, объединяют под общим названием коммуникационных фабрик (<em>communication fabrics</em>). При этом для северного кластера микросхем потребительской электроники характерна централизованная структура, являющаяся дальнейшим развитием идей общей шины в сторону конвейеризации и параллельной обработки запросов. Южный кластер традиционно имеет древовидную иерархическую структуру. Для серверов применяют распределенные архитектуры типа «сеть на кристалле» (<em>Network on Chip, NoC</em>), такие как кольца и решетки. </p>
<p>Если проводить аналогии, то сети на кристалле (<em>NoC</em>) являются прямым аналогом вычислительных (компьютерных) сетей, которые исторически возникли намного раньше. Вопросы  их проектирования, в том числе и в области качества обслуживания, достаточно подробно исследованы в литературе и отражены в технических стандартах. Для компьютерных сетей существуют методы анализа и обеспечения требований к пропускной способности, задержке и её вариации, надежности и т.д. Пришло время разобраться, в чем же отличия компьютерных сетей от сетей на кристалле, которые препятствуют использованию существующих подходов к обеспечению качества обслуживания и вынуждают разрабатывать новые.</p>
<p>Первое отличие, которое должно быть очевидно каждому, это расстояние, на которое передаются данные. Поскольку скорость распространения сигнала величина конечная, то и задержка передачи на большее расстояние превосходит задержку передачи на меньшее. Хоть задержка передачи по физической линии связи это лишь одна из составляющих общей задержки и не всегда существенная, но она есть.</p>
<p>Другое, менее очевидное отличие это то, что для буферизации трафика в сетях на кристалле используется регистровая память небольшого объема, и широко применяются сложные схемы разделения ресурсов с блокировкой каналов. Память, используемая для буферизации в компьютерных сетях, обладает большим объемом и гораздо дешевле, чем регистровая память. Так как прежде чем начать передачу пакета данных он должен быть сформирован и помещен в буферную память, то дефицит буферной памяти делает сети на кристалле более чувствительными к неравномерному характеру поступления данных и разнообразным задержкам передачи.</p>
<p>Аргумент в пользу сетей на кристалле: в глобальных сетях, поток данных может проходить через участки, построенные по различным технологиям, отличающимся способами коммутации, разделения среды, маршрутизации и т.д. Например, при звонке с IP-телефона на сотовый телефон, голосовой трафик может сначала проходить через локальную сеть с коммутацией пакетов, затем через сеть ATM с коммутацией соединений и, наконец, через мобильную сеть построенную по третьей технологии (например, UMTS). Чтобы обеспечить выполнение требований качества обслуживания на всем пути от источника к получателю, необходимо учитывать отличия механизмов качества обслуживания в этих типах сетей. Для сетей на кристалле архитектура заранее  известна и проблемы связанные с передачей данных между разными типами сетей не актуальны.</p>
<p>Число агентов подключенных к сети на кристалле и их поведение в процессе эксплуатации остается неизменным, в то время как для компьютерных сетей оно может меняться. Это приводит к тому, что в компьютерных сетях гораздо выше «запас прочности». В частности линии связи большую часть времени функционируют не на пределе своей пропускной способности, а между двумя узлами может существовать несколько маршрутов. Последнее позволяет использовать для передачи критичных к параметрам качества обслуживания данных другой маршрут, нежели для остальных данных. В сетях на кристалле, как правило, маршрутизация носит детерминированный характер, а линии связи работают под нагрузкой близкой к предельной.<br />
Можно приводить еще множество отличий, например, что компьютерные сети в случае выхода линии связи из строя могут провести реконфигурацию и продолжить работу, а для сетей на кристалле выход линии связи из строя, как правило, фатален. Но какое же отличие является главным?</p>
<p>Принципиальным отличием компьютерных сетей от сетей на кристалле является масштаб времени. Для компьютерных сетей время обработки пакетов измеряется микросекундами или миллисекундами, тогда как для сетей на кристалле время обработки и доставки пакетов измеряется наносекундами и долями наносекунд. При этом требования к пропускной способности в сетях на кристалле сопоставимы или превосходят требования для компьютерных сетей. Это накладывает дополнительные ограничения на используемые алгоритмы маршрутизации, планирования и арбитража. Для компьютерной сети анализ одного пакета данных может предполагать  выполнение целой подпрограммы, в то время как в сетях на кристалле большинство решений должно приниматься за 1-2 периода тактового сигнала или  и вовсе комбинационно. Это делает неприменимыми для сетей на кристалле практически все алгоритмы обеспечения качества обслуживания, используемые в компьютерных сетях.</p>
<p>За последнее десятилетие были предложены подходы к проектированию коммуникационных фабрик, призванные обеспечить гарантии качества обслуживания “по построению”. Их можно условно разделить на две категории. Подходы на основе дифференциации трафика (<em>traffic differentiation</em>) решают проблему конкурирующих запросов введением уровней приоритета, соответствующих разным классам трафика.  Однако для сложной системы затруднительно определить необходимое количество уровней приоритетов и избежать таких проблем, как инверсии приоритета и истощения ресурсов (<em>starvation</em>).<br />
Проблема инверсии приоритетов заключается в следующем: если в одной из очередей пакетов высокоприоритетному пакету предшествует низкоприоритетный, то продвижение пакета с высоким приоритетом блокируется до тех пор, пока не будет обработан низкоприоритетный пакет. Такая ситуация потенциально приводит к нарушению требований качества обслуживания для высокоприоритетного трафика. Фактически приоритет обслуживания блокирующего пакета повышается по сравнению с тем классом трафика, к которому он принадлежит. Избежать этого можно, например, повсеместным использованием раздельных очередей для буферизации различных классов трафика.</p>
<p>Передача без конкуренции (<em>contention-free transmisson</em>) основывается на той или иной схеме резервирования ресурсов перед началом передачи.  Разделение времени обработки, использование мест в очередях, порядок передачи по разделяемым линиям связи, планируются заранее. Если тот или иной ресурс оказывается невостребованным тем, кому он предназначался согласно плану, то он не используется даже при наличии других запросов на этот ресурс.<br />
Используя статическое резервирование, несложно добиться определенных гарантий производительности. Такой подход позволяет оптимизировать архитектуру под конкретное приложение и пригоден для встраиваемых систем, но приводит к низкой утилизация ресурсов в системах на кристалле широкого спектра применения. Это объясняется опять же тем, что поведение узлов сети может сильно изменяться с течением времени. При динамическом резервировании ресурсов, после того как ресурсы уже зарезервированы, удается добиться и гарантий производительности и хорошей утилизации ресурсов. Но сам процесс резервирования может занять длительное время и задержки на стадии резервирования по-прежнему трудно оценить.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2012/01/31/computer-networks-vs-network-on-chip/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ННГУ + МГУ = хорошее образование в области параллельного программирования</title>
		<link>http://software.intel.com/ru-ru/blogs/2012/01/31/2006799/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2012/01/31/2006799/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 12:40:20 +0000</pubDate>
		<dc:creator>Boris Rozenshteyn (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Академическое сообщество]]></category>
		<category><![CDATA[Параллельное программирование]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2012/01/31/2006799/</guid>
		<description><![CDATA[В ноябре объединенный коллектив НИВЦ МГУ и ВМК ННГУ получили награду Informatics Europe Curriculum Best Practices Award в международном конкурсе по разработке учебных материалов по параллельному программированию Informatics Europe Curriculum Best Practices Award.
]]></description>
			<content:encoded><![CDATA[<style>
blockquote, blockquote *{
	font-family:Arial, sans-serif !important;
}
</style>
<p>Как известно, Intel поддерживает студентов по всему миру, а в российских вузах <a href="http://software.intel.com/ru-ru/blogs/2010/04/08/2003468/">есть несколько лабораторий</a>, которым Intel выделяет деньги на обучение и оборудование.</p>
<p>В ноябре прошлого года сотрудники двух лабораторий (<a href="http://www.srcc.msu.su">НИВЦ МГУ</a> и <a href="http://itlab.unn.ru/">ВМК ННГУ</a>) разработали совместный курс по параллельному программированию и победили в международном конкурсе, организованном компанией Informatics Europe.</p>
<p align="center"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/ItLab_award.jpg"/></p>
<p>Конкурсная заявка коллектива МГУ–ННГУ <strong><a href="http://www.informatics-europe.org/images/ECSS/ECSS2011/slides/ECSS2011-Voevodin.pdf">Parallelism &amp; Concurrency: Changing the Landscape of IT-Education</a></strong> получила признание представительного международного жюри конкурса, что подтверждает высокий уровень образования и исследований в Московском и Нижегородском университетах и свидетельствует о качестве образования в России в целом в области суперкомпьютерных технологий.</p>
<blockquote>
<p><a href="http://www.informatics-europe.org">Informatics Europe</a> – известная международная ассоциация факультетов и исследовательских лабораторий в области Computer Science в Европе и соседних регионах. Основное направление деятельности ассоциации – способствование повышению качества образования и исследований в области информатики и Computer Science.</p>
</blockquote>
<blockquote>
<p>Награда в конкурсе <strong>Informatics Europe Curriculum Best Practices Award</strong> присуждается за выдающиеся достижения, способствующие повышению качества образования и привлекательности дисциплины. Отмечается возможность использования образовательных материалов за пределами создавшей их организации. В 2011 году конкурс был направлен на тематику, связанную с параллельными вычислениями (Parallelism and Concurrency), и поддержан грантом компании Intel.</p>
</blockquote>
<blockquote>
<p>Вручение награды состоялось в рамках ежегодного международного форума <a href="http://www.informatics-europe.org/ecss.html">European Computer Science Summit</a>. В саммите принимали участие деканы, заведующие кафедрами и ключевые сотрудники ведущих европейских университетов, факультетов, исследовательских институтов в области информатики и Computer Science, а также представители индустрии. В 2011 году форум <a href="http://www.ecss2011.polimi.it">был проведен в Милане</a> (Италия) с 7 по 9 ноября.</p>
</blockquote>
<p>Кстати, часть выигравшего курса была опубликована ранее на ISN: <a href="http://software.intel.com/ru-ru/articles/courseware_parallel_computation_numerical_methods/">Учебный курс "Параллельные численные методы"</a>, поэтому если вам интересно, как сейчас учат студентов, <a href="http://software.intel.com/ru-ru/articles/courseware_parallel_computation_numerical_methods/">можете ознакомиться</a> с материалами курса и выложенными лабораторными работами. Надеемся, что скоро на <span style="text-decoration: line-through;">экранах</span> ISN мы увидим "Параллельные численные методы: продолжение" ну или хотя бы "Параллельные численные методы возвращаются" <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>С презентацией курса, который получил эту почетную награду можно ознакомиться по ссылке <a href="http://www.informatics-europe.org/images/ECSS/ECSS2011/slides/ECSS2011-Voevodin.pdf">Parallelism &amp; Concurrency: Changing the Landscape of IT-Education</a> (pdf).</p>
<blockquote><p>Авторы курса:</p>
<p>ННГУ:</p>
<ul>
<li><strong>В.П. Гергель</strong>, д.т.н., профессор, декан факультета ВМК ННГУ, соруководитель коллектива</li>
<li><strong>И.Б. Мееров</strong>, к.т.н., доцент</li>
<li><strong>К.А. Баркалов</strong>, к.ф.-м.н., старший преподаватель</li>
<li><strong>А.В. Сысоев</strong>, ассистент</li>
</ul>
<p>МГУ:</p>
<ul>
<li><strong>В.В. Воеводин</strong>, член-корреспондент РАН, д.ф.-м.н., профессор, заместитель директора НИВЦ ВМК, соруководитель коллектива</li>
<li><strong>Н.Н. Попова</strong>, к.ф.-м.н., доцент</li>
<li><strong>А.С. Антонов</strong>, к.ф.-м.н., старший научный сотрудник</li>
<li><strong>С.А. Жуматий</strong>, к.ф.-м.н., старший научный сотрудник</li>
<li><strong>О.В. Джосан</strong>, к.ф.-м.н., ассистент</li>
</ul>
</blockquote>
<p>Я сам уже почти 3 года участвую в жизни лаборатории <a href="http://itlab.unn.ru/">ITLab ННГУ</a> и очень рад за преподавателей и коллег.</p>
<p>Еще раз поздравляем!</p>
<p><strong>Вопрос читателям</strong>: а как <strong>вас</strong> учили параллельному программированию в университете? <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> <br/><br />
Хотели бы вы учиться, например, по такому курсу, как <a href="http://software.intel.com/ru-ru/articles/courseware_parallel_computation_numerical_methods/">Параллельные численные методы</a>?</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2012/01/31/2006799/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Шаблонные параметры: typename и class. Есть ли разница?</title>
		<link>http://software.intel.com/ru-ru/blogs/2012/01/03/typename-class-2/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2012/01/03/typename-class-2/#comments</comments>
		<pubDate>Tue, 03 Jan 2012 12:22:00 +0000</pubDate>
		<dc:creator>smel</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[Си++]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2012/01/03/typename-class-2/</guid>
		<description><![CDATA[Эпиграф: Не все йогурты одинаково полезны. Преамбула: При написании шаблонных параметров обычно принято использовать ключевое слово class, чтобы подчеркнуть, что шаблонный параметр является классом (структурой). Стандарт C++ говорит следующее [п.14.1.2]: There is no semantic difference between class and typename in a template-parameter. Из чего можно сделать вывод, что никакой разницы в ключевых словах typename и [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Эпиграф:</strong></p>
<blockquote><p>Не все йогурты одинаково полезны.</p></blockquote>
<p />
<p><strong>Преамбула:</strong><br />
При написании шаблонных параметров обычно принято использовать ключевое слово class, чтобы подчеркнуть, что шаблонный параметр является классом (структурой). Стандарт C++ говорит следующее [п.14.1.2]:</p>
<blockquote><p>There is no semantic difference between class and typename in a template-parameter.</p></blockquote>
<p>Из чего можно сделать вывод, что никакой разницы в ключевых словах typename и class при объявлении шаблонных параметров нет.</p>
<p />
<strong>Амбула:</strong><br />
Намедни необходимо было написать шаблонный класс, параметризованный другим шаблонным классом. Было написано:</p>
<pre name="code" class="cpp">
template &lt;template  &lt;typename T&gt; typename Cl &gt;
</pre>
<p>Вот тут и возникла проблема - компилятор VC++ 2010 гордо рапортовал об ошибке:</p>
<blockquote><p>error C2988: unrecognizable template declaration/definition</p></blockquote>
<p>Компилятор Intel C++ Compiler 12.0 и также возвращал сообщение об ошибке:</p>
<blockquote><p>error : expected "class"<br />
template &lt;template  &lt;typename T&gt; typename Cl &gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;^</p></blockquote>
<p>После повторного чтения стандарта, была выяснена причина. Если подробнее рассмотреть синтаксис шаблонных параметров, то можно заметить, что для параметризации шаблонных параметров можно использовать только ключевое слово class [п.14.1.1]:</p>
<blockquote><p>template &lt; template-parameter-list &gt; class ...[opt] identifier[opt]<br />
template &lt; template-parameter-list &gt; class identifier[opt] = id-expression</p></blockquote>
<p>Вобщем, проблема локализована и после корректировки исходного кода до:</p>
<pre name="code" class="cpp">
template &lt;template  &lt;typename T&gt; class Cl &gt;
</pre>
<p>компиляция проходит успешно в VC++ 2010 и Intel C++ 12.0.</p>
<p />
<strong>Мораль: </strong><br />
Не всегда ключевые слова typename и class являются синонимами. <u>При объявлении шаблонного параметра другого шаблонного параметра необходимо использовать только ключевое слово class, вместо typename.</u><br />
И... проглядывайте стандарт C++;)</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2012/01/03/typename-class-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Развлечения ради: OpenMP для построения фракталов</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/12/30/openmp-4/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/12/30/openmp-4/#comments</comments>
		<pubDate>Fri, 30 Dec 2011 08:44:59 +0000</pubDate>
		<dc:creator>atercattus</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Графика]]></category>
		<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[c++ parallel programming]]></category>
		<category><![CDATA[openmp]]></category>
		<category><![CDATA[картинки]]></category>
		<category><![CDATA[фрактал]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/12/30/openmp-4/</guid>
		<description><![CDATA[<p>Данный пост будет первым из, надеюсь, серии небольших очерков о применении различных библиотек распараллеливания вычислений. В качестве прикладной задачи выбрано графическое построение всем хорошо знакомого <a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE_%D0%9C%D0%B0%D0%BD%D0%B4%D0%B5%D0%BB%D1%8C%D0%B1%D1%80%D0%BE%D1%82%D0%B0">множества Мандельброта</a>. В качестве библиотеки реализации вычислений в этот раз возьму OpenMP, а для унификации работы с разными оконными подсистемами - GLUT/OpenGL.</p>]]></description>
			<content:encoded><![CDATA[<p>Данный пост будет первым из, надеюсь, серии небольших очерков о применении различных библиотек распараллеливания вычислений. В качестве прикладной задачи выбрано графическое построение всем хорошо знакомого <a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE_%D0%9C%D0%B0%D0%BD%D0%B4%D0%B5%D0%BB%D1%8C%D0%B1%D1%80%D0%BE%D1%82%D0%B0">множества Мандельброта</a>. В качестве библиотеки реализации вычислений в этот раз возьму OpenMP, а для унификации работы с разными оконными подсистемами - GLUT/OpenGL.</p>
<p><span id="more-2006700"></span></p>
<p>В качестве пиксельной матрицы возьмем массив 32-битных целых, рассматривая его как ARGB-плоскость. 4 байта на тексель не сильно экономят память <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> , но избавляют от необходимости следить за выравниваем при заполнении буфера. Альфа-канал использоваться не будет.</p>
<p>После заполнения его каким-либо способом (зависит от библиотеки распараллеливания), загружаем данные в память видеокарты вызовом glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA...), а затем отрисовываем одним блоком GL_QUADS на весь экран (выводим прямоугольник).</p>
<blockquote><p>Вариант с glDrawPixels и так не советуют к использованию, так еще и по результатам эксперимента применение данной функции приводит к падению скорости отрисовки на порядок. Не пойдет. А применение VBO (Vertex Buffer Objects) в данном случае не обосновано - у нас всего 4 вершины и одна текстура.</p>
</blockquote>
<p>На выбор OpenGL+GLUT прежде всего повлияло желание собрать и запустить приложение как под Linux, так и под Windows и сравнить результаты на одинаковом "железе".</p>
<p>Распараллеливание будем выполнять, разделив текстуру на горизонтальные блоки по числу используемых потоков/ядер. В SLI/CrossFire конфигурациях видеокарт используется подобный режим Split Frame/Scissor (изображение взято с <a href="http://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Scissor.png">википедии</a>):</p>
<p><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Scissor1.png" alt="" class="alignnone size-thumbnail wp-image-2006709" /></p>
<p>Заменим видеокарты на процессорные ядра - и получим вариант распараллеливания.</p>
<p>Просто выводить множество целиком не столь интересно, как рассматривать его фрагменты в приближении. Для этого сразу введем координаты ограничивающего окна, в пределах которого строится изображение и данные самой текстуры:</p>
<pre name="code" class="cpp">
typedef struct {
    double x1, y1,
           x2, y2;
} Bounds;

typedef unsigned char byte;

typedef struct {
    int  width,     // ширина в пикселях
         height,    // высота в пикселях
         size;      // размер в пикселях == width*height
    byte *buff;     // кусок памяти с пиксельными данными
} Buffer;
</pre>
<p>Само множество на комплексной плоскости находится в пределах (-2,-1) x (1,1), так что можно начать с вывода с запасом (-2,-1.5) x (1,1.5) - вариант квадратной области.</p>
<p>Текстура хранится также квадратная, размерами 2^n (текстуры размерами не кратными степени 2 будут работать далеко не на всех видеокартах). Размер текстуры (T), равно как и предельное число итераций  проверки сходимости (n) выражают общую сложность построения как O(T^2*n).</p>
<p>При распараллеливании каждому из потоков на вход нужно подать ограничивающий объем в координатах комплексной плоскости, а также две V-координаты текстуры (высота/ось Y), обозначающие первую и последнюю строки, в которых следует отобразить результаты.</p>
<p>Сразу картинку возможного вывода:</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-12_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-12_cut-300x222.png" alt="" width="300" height="222" class="alignnone size-medium wp-image-2006717" /></a></p>
<p>Итого имеем:</p>
<pre name="code" class="cpp">
// координаты "окна" в комплексной плоскости
Bounds screen;

// текущие координаты центра "окна" в комплексной плоскости
double cX=0, cY=0;

// размер клиентской области окна в системе
int window_width  = 800,
    window_height = 800;

// текущий шаг приближения
int STEP = 0;

// предел числа итераций проверки сходимости
int ITERS = MIN_ITERS;
</pre>
<p>Собственно рендер фрактала в текстуру выполняется обычным распараллеленым циклом:</p>
<pre name="code" class="cpp">
void fractal() {
    int parts = omp_get_max_threads();
    if ( parts &lt;= 0 ) parts = 1;

    omp_set_dynamic( 0 );
    omp_set_num_threads( parts );

    int p, y=0, dy;
    double sy = (screen.y2-screen.y1) / parts;
    dy = buffer.height / parts;

    #pragma omp parallel for firstprivate(y) ordered
    for ( p=0; p&lt;parts; ++p ) {
        Bounds bounds;
        bounds.x1 = screen.x1;
        bounds.x2 = screen.x2;

        bounds.y1 = screen.y1 + p*sy;
        bounds.y2 = bounds.y1 + sy;

        y = p*dy;

        //fractal_block( bounds, y, y+dy-1, (p+1)*6 );
        fractal_block( bounds, y, y+dy-1, 3 );
    }
}
</pre>
<p>Т.к. координата верхней строки каждого блока (y) используется внутри тела цикла, при этом меняясь, то ее следует передавать через firstprivate.</p>
<p>Функция fractal_block принимает координаты окна комплексной плоскости (bounds), верхнюю и нижнюю границы в текстуре (y, y+dy-1) и множитель "яркости" (о нем ниже):</p>
<pre name="code" class="cpp">
void fractal_block( Bounds block, int y1, int y2, int f ) {
    int *ptr = (int*)( buffer.buff + y1*buffer.width*4 );

    double x, y, sx, sy, z, zi;

    x = block.x1;
    y = block.y1;
    // приращения по комплексным осям между соседними текселями текстуры
    sx = (block.x2 - block.x1) / buffer.width;
    sy = (block.y2 - block.y1) / (y2-y1+1);

    int width = buffer.width;

    // раскидываю значение множителя по трем младшим байтам
    f = f%256;
    f = (f&lt;&lt;16) | (f&lt;&lt;8) | f;

    for ( ; y1&lt;=y2; ++y1 ) {
        int _x;
        for ( _x=0; _x&lt;width; ++_x ) {
            z = zi = 0.0;
            int steps = 0;
            for ( ; steps&lt;ITERS; ++steps ) {
                double tmp = (z*z) - (zi*zi) + x;
                zi = 2*z*zi + y;
                z = tmp;

                if ( z*z + zi*zi &gt; 4.0 ) break;
            }

            *ptr++ = f * steps2RGBA( steps&lt;ITERS ? steps : 0 );

            x += sx;
        }

        y += sy;
        x  = block.x1;
    }
}
</pre>
<p>Что же дает "множитель яркости" f? Благодаря ему можно визуально разделять блоки, которые рассчитывались разными ядрами. Достаточно использовать при генерации значение, зависящее от номера текущего блока/ядра, например так: <b>fractal_block( bounds, y, y+dy-1, (p+1)*6 );</b></p>
<p>При этом будет наблюдаться картина вроде такой:</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-10_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-10_cut-e1325188428659-300x221.png" alt="" width="300" height="221" class="alignnone size-medium wp-image-2006721" /></a></p>
<p>Хорошо заметны 5 блоков, из которых состыкована текстура.</p>
<p>Технические подробности инициализации GLUT, OpenGL, рендеринга текстуры, масштабирования вокруг точки, подстройки предела проверки сходимости оставлю за кадром. Это все есть в прилагаемом исходнике для желающих.</p>
<p>Реализация выполнена с подстройкой предела сходимости с целью снять ненужную нагрузку (на общем плане что 50 итераций, что 100 - визуально не заметно, а нагрузка ощущается). Соотвественно идет подстройка предела при масштабировании (также ее можно менять кнопками Up/Down). </p>
<p>Непосредственно по распараллеливанию. На машине с Core i5 750 в 2 потока отрисовка дает честный двухкратный прирост, на 4х потоках прирост порядка 3.5 раз. На приближении 2^40 и пределе итераций в 250 время работы 4х ядер 1.01сек против 3.64сек на одном. <i>Была бы машина с иксами с большим числом ядер - было бы конечно интересней. Не раз встречал мнение, что распараллеливание особо проявляется не менее, чем на 8ми ядрах. Если у кого есть возможность и желание - запустите, интересен коэффициент прироста скорости в сравнении с одним и двумя ядрами.</i></p>
<p>Приближение 2^40 выбрано с целью предотвращения величин ошибок округления, влияющих на результат. Примерно на 42-43 итерации приближения размер окна в комплексной плоскости становится менее 6.82e-13 и начинают проявляться ошибки округления (underflow):</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/fractal_underflow_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/fractal_underflow_cut-e1325190159240-300x213.png" alt="" width="300" height="213" class="alignnone size-medium wp-image-2006725" /></a></p>
<p>В итоге получаем достаточно неплохой результат ценой практически одной только строчки pragma <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>На очереди ArBB, TBB и что еще подвернется.</p>
<p>И еще немного картинок:</p>
<p><a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot_cut-300x222.png" alt="" width="300" height="222" class="alignnone size-medium wp-image-2006727" /></a> <a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-15_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-15_cut-300x222.png" alt="" width="300" height="222" class="alignnone size-medium wp-image-2006728" /></a> <a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-1_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-1_cut-300x300.png" alt="" width="300" height="300" class="alignnone size-medium wp-image-2006731" /></a> <a href="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-14_cut.png"><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/Screenshot-14_cut-300x222.png" alt="" width="300" height="222" class="alignnone size-medium wp-image-2006729" /></a></p>
<p><a href='http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/fractal_isn.tar.gz'>Исходники (tar.gz)</a></p>
<p><b>И всех с Наступающим!</b></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/12/30/openmp-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Несколько слов о диспетчеризации</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/12/29/2006663/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/12/29/2006663/#comments</comments>
		<pubDate>Thu, 29 Dec 2011 10:42:59 +0000</pubDate>
		<dc:creator>Alexey Kryukov (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Параллельное программирование]]></category>
		<category><![CDATA[Разработка софта]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/12/29/2006663/</guid>
		<description><![CDATA[В этом посте я хотел бы поговорить об оптимизации кода сразу под несколько семейств процессоров. Данная задача актуальна, если мы заранее не знаем, на каком "железе" код будет исполняться. А это довольно типовой случай. В предыдущем посте я немного рассказал об одном из возможных решений - динамической генерации кода. Это реализовано в Intel Array Building [...]]]></description>
			<content:encoded><![CDATA[<p>В этом посте я хотел бы поговорить об оптимизации кода сразу под несколько семейств процессоров. Данная задача актуальна, если мы заранее не знаем, на каком "железе" код будет исполняться. А это довольно типовой случай.</p>
<p>В предыдущем посте я немного <a href="http://software.intel.com/ru-ru/blogs/2011/09/22/array-building-blocks-2/">рассказал</a> об одном из возможных решений - динамической генерации кода. Это реализовано в <a href="http://software.intel.com/en-us/articles/intel-array-building-blocks/">Intel Array Building Blocks</a>. У этого подхода свои плюсы и минусы. К плюсам следует отнести универсальность и гибкость, к минусам внутреннюю сложность и значительные накладные расходы (ведь сначала код надо сгенерировать).</p>
<p>Вопрос: какие еще существуют решения для оптимизации кода под различные платформы? Попытаемся разобраться в способе, который называется диспетчеризацией (Dispatching).</p>
<p>Для начала уточним задачу: код должен быть оптимизирован не под все железо, а только под определенный набор. Это нормально, ведь продукты поддерживают ограниченное число процессоров. Преемлемым решением для остальных процессоров выглядит запуск неоптимизированного кода на них. Кроме того, не всегда имеет смысл оптимизировать код под каждый процессор. Многие могут быть объединены в классы эквивалентности. Например, много процессоров поддерживают одинаковый набор SIMD инструкций.</p>
<p>Исходя из того, что простое лучше, чем сложное, можно сделать несколько вариантов кода, каждый из которых функционально идентичен остальным, но оптимизирован под свой набор процессоров. Очевиден и основной недостаток: на каждом CPU необходимо выбрать, какой процесс запустить или какую библиотеку вызвать. Этот минус можно обойти, если использовать дополнительный модуль. Он вызывается в run-time, автоматически определяет тип процессора и предлагает выбрать ветку кода, которая подойдет под текущее "железо" наилучшим образом. Этот модуль называется диспетчером (Dispatcher).</p>
<p>Процесс диспетчеризации представляет собой определение типа и возможностей CPU во время исполнения приложения. Вызов диспетчера обычно происходит в первую очередь еще до начала использования функциональности. На основании данных от диспетчера происходит выбор ветки кода, соответствующего текущему процессору.</p>
<p>Существуют различные реализации диспетчеров. По <a href="http://software.intel.com/en-us/articles/intel-integrated-performance-primitives-intel-ipp-understanding-cpu-optimized-code-used-in-intel-ipp/">одной</a> из них (в библиотеке <a href="http://www.intel.com/software/products/ipp/">Intel IPP</a>) диспетчер идентифицирует CPU один раз - во время инициализации библиотеки, после чего задает набор внутренних переменных. В соответствии с этим набором библиотечные вызовы из приложения перенаправляются в соответствующие внутренние функции библиотеки. Например, при запуске приложения на Core 2 Duo в 32-битной операционной системе вызов функции <em>ippsCopy_8u()</em> перенаправляется на <em>p8_ippsCopy_8u()</em> - одну из множества реализаций функциональности <em>ippsCopy_8u()</em>, имеющихся в библиотеке.</p>
<p>К недостаткам такой системы следует отнести громоздкость. Размер библиотеки увеличивается вместе с ростом поддерживаемого железа. Рост размеров библиотеки означает и рост объемов приложений, которые ее используют. Справедливости ради стоит сказать, что есть способы борьбы и против этого эффекта.</p>
<p>Преимущества данного подхода следующие. Простота и модульность: если необходимо что-то исправить в одной ветке, нет необходимости менять остальные. Низкие накладные расходы (по сравнению с подходом, где осуществляется динамическая генерация кода), которые определяются временем работы диспетчера. </p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/12/29/2006663/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Интервальное кодирование (Range encoding), как частный случай кодирования арифметического</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/12/28/range-encoding/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/12/28/range-encoding/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 07:10:55 +0000</pubDate>
		<dc:creator>atercattus</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Разработка софта]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[decoding]]></category>
		<category><![CDATA[range coding]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/12/28/range-encoding/</guid>
		<description><![CDATA[<p>При помощи <a href="http://software.intel.com/ru-ru/blogs/2011/12/20/2006336/">арифметического кодирования</a> <i>в теории</i> можно сжать любой объем данных до одного вещественного числа. Однако на практике все упирается в конечную точность вычислений чисел с плавающей точкой, ограничивая объем обрабатываемого за раз блока. Требуется следить за ситуацией потери точности (underflow),а также за алгоритмом округления (на x86 задается битами регистра CWR) на случай работы с сжатыми данными на разных платформах.</p>

<p>В качестве альтернативы можно использовать целочисленные операции, основанные на работе не с одним значением внутри интервала, а с текущими границами...</p>]]></description>
			<content:encoded><![CDATA[<p>При помощи <a href="http://software.intel.com/ru-ru/blogs/2011/12/20/2006336/">арифметического кодирования</a> <i>в теории</i> можно сжать любой объем данных до одного вещественного числа. Однако на практике все упирается в конечную точность вычислений чисел с плавающей точкой, ограничивая объем обрабатываемого за раз блока. Требуется следить за ситуацией потери точности (underflow),а также за алгоритмом округления (на x86 задается битами регистра CWR) на случай работы с сжатыми данными на разных платформах.</p>
<p>В качестве альтернативы можно использовать целочисленные операции, основанные на работе не с одним значением внутри интервала, а с текущими границами. Если арифметический кодер работает в пределах интервала [0,1), то интервальный кодер начинает с интервала [0,N), где N - произвольный верхний предел, от которого и зависит максимальный размер обрабатываемого блока. Логично брать N, основываясь на аппаратных возможностях архитектуры, например 2^32.</p>
<p>Каждый обрабатываемый символ сужает интервал, приводя его в итоге к [x,x+1), что является предельным значением точности и размера обрабатываемого блока. Подинтервалы, в которые сужается исходный [0,1), как и в случае с арифметическим кодированием берутся исходя из вероятности появления данных символов во входном потоке. Учет вероятностей позволяет оптимально использовать выделенный интервал, предоставляя "чаще используемым" символам больший диапазон значений.</p>
<blockquote><p>Эксперимента ради, попробуйте разделить интервал [0,20) на 10 частей, а потом на столько же частей интервал [0,5), сохраняя при этом целочисленную точность. И почувствуйте разницу <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p></blockquote>
<p>Рассмотрим пример сжатия строки "abraha#" (сократил "abrahadabra") с вероятностями:</p>
<table border="1" style="border:1px solid #000;border-collapse:collapse">
<tr>
<th style="padding: 2px;">Символ</th>
<th style="padding: 2px;">Вероятность</th>
</tr>
<tr>
<td style="padding: 2px;">a</td>
<td style="padding: 2px;">40%</td>
</tr>
<tr>
<td style="padding: 2px;">b</td>
<td style="padding: 2px;">20%</td>
</tr>
<tr>
<td style="padding: 2px;">h</td>
<td style="padding: 2px;">10%</td>
</tr>
<tr>
<td style="padding: 2px;">r</td>
<td style="padding: 2px;">25%</td>
</tr>
<tr>
<td style="padding: 2px;">#</td>
<td style="padding: 2px;">5%</td>
</tr>
</table>
<p>&nbsp;</p>
<p>Символ "#" является служебным терминальным и нужен на случай, если после сжатия в потоке вывода <u>не</u> передается исходная длина строки. В таком случае появление данного символа при декодировании будет служить сигналом завершения работы (аналогично EOF, EOL, etc).</p>
<p>В качестве максимального значения возьмем N=100.000.000 (100 миллионов).<br />
Преобразуем вероятности появления символов в отрезки на интервале [0,N):</p>
<ul>
<li>a = 40% = 0.4 =&gt; 0.4*N - верхняя граница интервала</li>
<li>b = 20% = 0.2 =&gt; 0.2+0.4 = 0.6*N - верхняя граница интервала, а нижняя - 0.4*N</li>
<li>...</li>
</ul>
<p>Получаем:</p>
<table border="1" style="border:1px solid #000;border-collapse:collapse">
<tr>
<th style="padding: 2px;">Символ</th>
<th style="padding: 2px;">Интервал</th>
<th style="padding: 2px;">Значения интервала (*10^6)</th>
</tr>
<tr>
<td style="padding: 2px;">a</td>
<td style="padding: 2px;">
<pre>[     0,  0.4*N)</pre>
</td>
<td style="padding: 2px;">[ 0,  40)</td>
</tr>
<tr>
<td style="padding: 2px;">b</td>
<td style="padding: 2px;">
<pre>[ 0.4*N,  0.6*N)</pre>
</td>
<td style="padding: 2px;">[40,  60)</td>
</tr>
<tr>
<td style="padding: 2px;">h</td>
<td style="padding: 2px;">
<pre>[ 0.6*N,  0.7*N)</pre>
</td>
<td style="padding: 2px;">[60,  70)</td>
</tr>
<tr>
<td style="padding: 2px;">r</td>
<td style="padding: 2px;">
<pre>[ 0.7*N, 0.95*N)</pre>
</td>
<td style="padding: 2px;">[70,  95)</td>
</tr>
<tr>
<td style="padding: 2px;">#</td>
<td style="padding: 2px;">
<pre>[0.95*N,      N)</pre>
</td>
<td style="padding: 2px;">[95, 100)</td>
</tr>
</table>
<p></p>
<p>Кодирование строки по шагам:</p>
<table border="1" style="border:1px solid #000;border-collapse:collapse">
<tr>
<th style="padding: 2px;">Шаг</th>
<th style="padding: 2px;">Рабочий интервал</th>
<th style="padding: 2px;">Вход</th>
<th style="padding: 2px;">Интервал символа (*10^6)</th>
<th style="padding: 2px;">Новый интервал</th>
</tr>
<tr>
<td style="padding: 2px;">0</td>
<td style="padding: 2px;">[0,000,000 ... 100,000,000)</td>
<td style="padding: 2px;"><u>a</u>braha#</td>
<td style="padding: 2px;">[0 ... 40)</td>
<td style="padding: 2px;">[0,000,000 ... 40,000,000)</td>
</tr>
<tr>
<td style="padding: 2px;">1</td>
<td style="padding: 2px;">[0,000,000 ... 40,000,000)</td>
<td style="padding: 2px;">a<u>b</u>raha#</td>
<td style="padding: 2px;">[40 ... 60)</td>
<td style="padding: 2px;">[16,000,000 ... 24,000,000)</td>
</tr>
<tr>
<td style="padding: 2px;">2</td>
<td style="padding: 2px;">[16,000,000 ... 24,000,000)</td>
<td style="padding: 2px;">ab<u>r</u>aha#</td>
<td style="padding: 2px;">[70 ... 95)</td>
<td style="padding: 2px;">[21,600,000 ... 23,600,000)</td>
</tr>
<tr>
<td style="padding: 2px;">3</td>
<td style="padding: 2px;">[21,600,000 ... 23,600,000)</td>
<td style="padding: 2px;">abr<u>a</u>ha#</td>
<td style="padding: 2px;">[0 ... 40)</td>
<td style="padding: 2px;">[21,600,000 ... 22,400,000)</td>
</tr>
<tr>
<td style="padding: 2px;">4</td>
<td style="padding: 2px;">[21,600,000 ... 22,400,000)</td>
<td style="padding: 2px;">abra<u>h</u>a#</td>
<td style="padding: 2px;">[60 ... 70)</td>
<td style="padding: 2px;">[22,080,000 ... 22,160,000)</td>
</tr>
<tr>
<td style="padding: 2px;">5</td>
<td style="padding: 2px;">[22,080,000 ... 22,160,000)</td>
<td style="padding: 2px;">abrah<u>a</u>#</td>
<td style="padding: 2px;">[0 ... 40)</td>
<td style="padding: 2px;">[22,080,000 ... 22,112,000)</td>
</tr>
<tr>
<td style="padding: 2px;">6</td>
<td style="padding: 2px;">[22,080,000 ... 22,112,000)</td>
<td style="padding: 2px;">abraha<u>#</u></td>
<td style="padding: 2px;">[95 ... 100)</td>
<td style="padding: 2px;">[22,110,400 ... 22,112,000)</td>
</tr>
</table>
<p>&nbsp;</p>
<p>В результате имеем интервал [22,110,400 ... 22,112,000). Любое значение из этого интервала даст нам результат кодирования.<br />
Для выбора оптимального значения можно выбрать то, в котором будем максимальное число нулевых младших бит среди всех возможных. Если имеем интервал [f,t), то искомой величиной будет:</p>
<p><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/x_f_xor_t.png" alt="x = f xor t" width="84" height="21" class="alignnone size-full wp-image-2006627" /><br />
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/xl.png" alt="xl=ceil(log2x)" width="113" height="23" class="alignnone size-full wp-image-2006629" /><br />
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/result2-300x38.png" alt="result = ( f &amp; !( 2^xl - 1 ) ) or ( 2^(xl-1) )" width="300" height="38" class="alignnone size-medium wp-image-2006633" /></p>
<p>Сначала XOR'ом получаем различающиеся младшие биты, затем из двоичного логарифма получаем число различающихся бит. А результирующее оптимальное значение получаем, добавляя к неизменяющейся части нижней границы единицу в старшем разряде меняющейся части.</p>
<p>Если брать просто среднее значение интервала, то в качестве ответа будет 22,111,200. Если взять оптимальное значение, то получим 22,111,232. Для сравнения, их бинарное представление:</p>
<blockquote><p>22,111,200 = 10101000101100<b>01111100000</b><br />
22,111,232 = 10101000101100<b>10000000000</b></p></blockquote>
<p>Декодирование выполняется еще более похоже на арифметическое кодирование:</p>
<ol>
<li>имея значение <b>cur</b> из текущего интервала <b>[f,t)</b>, получаем соответствующий символ <b>c</b>;</li>
<li>нормализуем интервал до <b>[0,N)</b>, получая новое значение <b>new</b> по формуле:<br /><img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/new1.png" alt="new" width="161" height="51" class="alignnone size-full wp-image-2006636" /></li>
<li>повторяем шаги 1 и 2 до встречи терминального символа, либо до достижения исходной длины строки (если известно).</li>
</ol>
<p>Декодирование строки по шагам:</p>
<table border="1" style="border:1px solid #000;border-collapse:collapse">
<tr>
<th style="padding: 2px;">Шаг</th>
<th style="padding: 2px;">Текущее значение</th>
<th style="padding: 2px;">Интервал</th>
<th style="padding: 2px;">Выход</th>
<th style="padding: 2px;">Новое значение</th>
</tr>
<tr>
<td style="padding: 2px;">0</td>
<td style="padding: 2px;">22,111,232</td>
<td style="padding: 2px;">[0,000,000 ... 40,000,000)</td>
<td style="padding: 2px;">a</td>
<td style="padding: 2px;">55,278,080</td>
</tr>
<tr>
<td style="padding: 2px;">1</td>
<td style="padding: 2px;">55,278,080</td>
<td style="padding: 2px;">[40,000,000 ... 60,000,000)</td>
<td style="padding: 2px;">b</td>
<td style="padding: 2px;">76,390,400</td>
</tr>
<tr>
<td style="padding: 2px;">2</td>
<td style="padding: 2px;">76,390,400</td>
<td style="padding: 2px;">[70,000,000 ... 95,000,000)</td>
<td style="padding: 2px;">r</td>
<td style="padding: 2px;">25,561,600</td>
</tr>
<tr>
<td style="padding: 2px;">3</td>
<td style="padding: 2px;">25,561,600</td>
<td style="padding: 2px;">[0,000,000 ... 40,000,000)</td>
<td style="padding: 2px;">a</td>
<td style="padding: 2px;">63,904,000</td>
</tr>
<tr>
<td style="padding: 2px;">4</td>
<td style="padding: 2px;">63,904,000</td>
<td style="padding: 2px;">[60,000,000 ... 70,000,000)</td>
<td style="padding: 2px;">h</td>
<td style="padding: 2px;">39,040,000</td>
</tr>
<tr>
<td style="padding: 2px;">5</td>
<td style="padding: 2px;">39,040,000</td>
<td style="padding: 2px;">[0,000,000 ... 40,000,000)</td>
<td style="padding: 2px;">a</td>
<td style="padding: 2px;">55,278,080</td>
</tr>
<tr>
<td style="padding: 2px;">6</td>
<td style="padding: 2px;">55,278,080</td>
<td style="padding: 2px;">[95,000,000 ... 100,000,000)</td>
<td style="padding: 2px;">#</td>
<td style="padding: 2px;">52,000,000</td>
</tr>
</table>
<p>&nbsp;</p>
<p>Ну и пример реализации на Python:</p>
<pre name="code" class="python">
#!/usr/bin/env python
#-*- coding: utf8 -*-

from math import floor, log, ceil

class Arithmetic:

    def __init__(self, freqs_tuples, MAX):
        # верхняя граница интервала
        self.max = MAX
        # подготовка словаря с интервалами вероятностей символов
        self.__freqs2dict( freqs_tuples )

    def encode(self, s):
        u"""
            Кодирование строки s на основе вероятностей в self.freqs
            Возвращает число из итогового диапазона
        """
        # начинает с полного интервала [0,1)
        (f, t) = (0, self.max)
        for c in s:
            # координаты нового интервала
            (cf, ct) = self.freqs[c]
            # длина базового интервала
            t_f = t-f
            # Получение нового интервала.
            # Важно: т.к. в вычислении фигурирует f, то его
            # изменение выполняется только после вычисления t.
            # Т.е. не надо менять строки местами : )
            t = int( floor( ct*t_f / self.max + f ) )
            f = int( floor( cf*t_f / self.max + f ) )
        return self.__optimize( f, t )

    def decode(self, i):
        u"""
            Декодирование числа в строку на основе вероятностей в self.freqs
        """
        res = []
        c = None
        while c != '#':
            c = self.__find_interval( i )
            res.append( c )
            (f,t) = self.freqs[c]
            i = int( ( i-f ) * self.max / ( t-f ) )
        return ''.join(res)

    def __freqs2dict(self, freqs_tuples):
        u"""
            Преобразование кортежа вероятностей символов строки в
              словарь интервалов с учетом self.max
        """
        self.freqs = {}
        left = 0
        for (k,v) in freqs:
            self.freqs[k] = ( int(left*self.max), int((left+v)*self.max) )
            left += v

    def __optimize(self, f, t):
        u"""
            Подбор числа из диапазона [f, t) такого, чтобы в нем
            было максимально возможное на интервале число нулевых младших бит
        """
        #return int( (t-f)/2 + f )
        f = int(f)
        t = int(t)
        x = f ^ t
        if not x: return f

        xl = int( ceil( log(x, 2) ) )
        if not xl: return f

        mask_and = ~((1&lt;&lt;xl)-1)
        mask_or  = 1&lt;&lt;(xl-1)

        r = (f &#038; mask_and) | mask_or

        return r

    def __find_interval(self, v):
        u"""
            Ищем интервал, которому принадлежит значение v
        """
        for ( c, (cf, ct) ) in self.freqs.items():
            if v&gt;=cf and v&lt;ct:
                return c

freqs = ( ('a',0.4), ('b',0.2), ('h',0.1), ('r',0.25), ('#',0.05) )
src = 'abraha#'
MAX = 100000000

coder = Arithmetic( freqs, MAX )

print 'SOURCE:  ', src

enc = coder.encode( src )
print 'ENCODED: ', enc

dec = coder.decode( enc )
print 'DECODED: ', dec
</pre>
<p>Несмотря на хранение промежуточных значений в целом виде, выполняется много операций деления и умножения. Существуют реализации интервального кодирования, исключающие эти медленные операции. Кроме того, при кодировании старшие разряды, которые уже не меняются, можно сразу отдавать в выходной поток. Но про это все уже не сейчас.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/12/28/range-encoding/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Непростая арифметика: декодирование</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/12/27/2006586/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/12/27/2006586/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 08:11:53 +0000</pubDate>
		<dc:creator>Dmitry Serkin (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Графика]]></category>
		<category><![CDATA[arithmetic coding]]></category>
		<category><![CDATA[entropy coding]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/12/27/2006586/</guid>
		<description><![CDATA[Небольшая заметка-продолжение темы арифметического кодирования, на сей раз речь пойдет о декодировании.]]></description>
			<content:encoded><![CDATA[<p>Небольшая заметка-продолжение темы арифметического кодирования. Но на сей раз речь пойдет о декодировании. <a href="http://software.intel.com/ru-ru/blogs/2011/12/20/2006336/">Вспомним</a>, что с помощью техники вложенных интервалов мы получили некоторый код, который однозначно определяет всю входную последовательность. Декодирование же восстанавливает оригинальные символы, тем самым образуя множество элементов:</p>
<div style="text-align:center;padding: 5 5 5 5">
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/114.png" />
</div>
<p>Процесс декодирования восстанавливает последовательность в том же порядке в каком она кодировалась. Определим множество нормализованных кодов (нормализация на целый интервал):</p>
<div style="text-align:center;padding: 5 5 5 5">
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/211.png" />
</div>
<p>Естественно предположить, что рекурсия, применяемая для кодирования, действует и в обратную сторону. Начиная с исходного кода алгоритм шаг за шагом находит закодированный символ:</p>
<div style="text-align:center;padding: 5 5 5 5">
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/310.png" />
</div>
<p>Если до этого момента понятно так и не стало, то нас спасет только пример. <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Следуя примеру из <a href="http://software.intel.com/ru-ru/blogs/2011/12/20/2006336/">предыдущей заметки</a>, входная последовательность символов: a2a1a0a0a1a3. Распределение вероятностей: p = [0.2, 0.5, 0.2, 0.1]. Код: 0.74267578125.</p>
<div style="text-align:center;padding: 5 5 5 5">
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/48.png" />
</div>
<p>В таком ключе находим все 6 символов. Но так как мы работаем с интервалами действительных чисел, то есть риск не закончить эту работу никогда. Поэтому для завершения декодеру необходимо знать либо количество символов, либо иметь некоторый маркер конца.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/12/27/2006586/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Движемся к началу: MTF (Move To Front) в помощь энтропийному кодированию</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/12/26/mtf-move-to-front/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/12/26/mtf-move-to-front/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 12:59:16 +0000</pubDate>
		<dc:creator>atercattus</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[Графика]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[decoding]]></category>
		<category><![CDATA[move-to-front]]></category>
		<category><![CDATA[mtf]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/12/26/mtf-move-to-front/</guid>
		<description><![CDATA[<p>Решил написать небольшую статейку в дополнение к серии статей <a href="http://software.intel.com/ru-ru/blogs/author/dmitry-serkin/">Dmitry Serkin</a> по сжатию (в частности изображений).</p>

<p>Как-то все непосредственно само сжатие, да итоговое досжатие тем же арифметическим кодером.</p>

<p>Здесь же решил описать опциональную стадию предобработки сжатых основными шагами конвейера бинарных данных, но до подачи их энтропийному кодеру (ЭК).</p>]]></description>
			<content:encoded><![CDATA[<p>Решил написать небольшую статейку в дополнение к серии статей <a href="http://software.intel.com/ru-ru/blogs/author/dmitry-serkin/">Dmitry Serkin</a> по сжатию (в частности изображений).</p>
<p>Как-то все непосредственно само сжатие, да итоговое досжатие тем же арифметическим кодером.</p>
<p>Здесь же решил описать опциональную стадию предобработки сжатых основными шагами конвейера бинарных данных, но до подачи их энтропийному кодеру (ЭК).</p>
<p>Что лучше сожмет ЭК? Конечно можно подать на вход 100500 нулей, но с такой вырожденной задачей отлично справится RLE. Тут важна предсказуемость и монотонность данных в потоке: было бы хорошо, если бы одинаковые значения (байт, бит) шли последовательно.</p>
<p>Можно рассматривать два наиболее популярных алгоритма: BWT и MTF.</p>
<p><i>В этот раз напишу про второй, т.к. первый (Burrows–Wheeler transform, преобразование Барроуза-Уиллера) прекрасно описан на Википедии, и смысла рассказывать тоже самое своими словами мало. Но если только кому-то будет интересно... <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </i></p>
<p>Итак, MTF (Move-To-Front, Движение к началу, Стопка книг, Сортировка стопки книг) является обратимым преобразованием над сжимаемым потоком, выполняемым с целью улучшения результатов последующего ЭК.</p>
<p>Алгоритм работает над блоками байт (машинных слов, etc), подменяя их соответствующими позициями в некотором словаре. При этом при обработке каждого символа словарь модифицируется, что приводит к выдаче различных позиций для одного и того же символа в процессе работы алгоритма.</p>
<p>Первоначально словарь заполняется всеми возможными значениями обрабатываемого блока (потока). Это заполнение идентично выполняется и на стороне архиватора, так и на стороне распаковщика.</p>
<p>Кодирование заключается в последовательном обходе всех символов входной последовательности. Символ ищется в словаре, а в выходной поток записывается его <u>текущая</u> позиция. После этого символ удаляется из своей позиции в словаре (сдвиг вправо значений словаря с 0 до позиции символа-1), и вставляется в начало словаря (присвоение нулевому элементу).</p>
<p>Для примера возьмем блок "20112012" и словарь из цифр "0".."9". Если сразу сжимать RLE, то будет найдено только "11" и ничего хорошего не выйдет. Если сжимать, Хаффманом или PPM с окном на все 8 байт, то будет найдено слово "201", что уже хорошо.</p>
<p>А теперь попробуем сначала преобразовать по MTF:</p>
<table border="1"  style="border:1px solid #888;cellpadding: 5">
<tr>
<th>Шаг</th>
<th>Вход</th>
<th>Выход</th>
<th>Словарь</th>
</tr>
<tr>
<td style="padding: 2px;">0</td>
<td style="padding: 2px;"><u>2</u>0112012</td>
<td style="padding: 2px;"><i>Пустой список</i></td>
<td style="padding: 2px;">0123456789</td>
</tr>
<tr>
<td style="padding: 2px;">1</td>
<td style="padding: 2px;"><u>2</u>0112012</td>
<td style="padding: 2px;">2</td>
<td style="padding: 2px;">2013456789</td>
</tr>
<tr>
<td style="padding: 2px;">2</td>
<td style="padding: 2px;">2<u>0</u>112012</td>
<td style="padding: 2px;">2,1</td>
<td style="padding: 2px;">0213456789</td>
</tr>
<tr>
<td style="padding: 2px;">3</td>
<td style="padding: 2px;">20<u>1</u>12012</td>
<td style="padding: 2px;">2,1,2</td>
<td style="padding: 2px;">1023456789</td>
</tr>
<tr>
<td style="padding: 2px;">4</td>
<td style="padding: 2px;">201<u>1</u>2012</td>
<td style="padding: 2px;">2,1,2,0</td>
<td style="padding: 2px;">1023456789</td>
</tr>
<tr>
<td style="padding: 2px;">5</td>
<td style="padding: 2px;">2011<u>2</u>012</td>
<td style="padding: 2px;">2,1,2,0,2</td>
<td style="padding: 2px;">2103456789</td>
</tr>
<tr>
<td style="padding: 2px;">6</td>
<td style="padding: 2px;">20112<u>0</u>12</td>
<td style="padding: 2px;">2,1,2,0,2,2</td>
<td style="padding: 2px;">0213456789</td>
</tr>
<tr>
<td style="padding: 2px;">7</td>
<td style="padding: 2px;">201120<u>1</u>2</td>
<td style="padding: 2px;">2,1,2,0,2,2,2</td>
<td style="padding: 2px;">1023456789</td>
</tr>
<tr>
<td style="padding: 2px;">8</td>
<td style="padding: 2px;">2011201<u>2</u></td>
<td style="padding: 2px;">2,1,2,0,2,2,2,2</td>
<td style="padding: 2px;">2103456789</td>
</tr>
</table>
<p>И по шагам:</p>
<ol start="0">
<li>Во входном буфере смотрим на первый символ, результирующий список позиций пуст, словарь с исходном виде;</li>
<li>Текущий символ "2" имеет позицию 2 в словаре. Добавляем 2 в результат, а "2" в словаре переносим в начало, получая "20134...";</li>
<li>Следущий символ "0" имеет позицию 1 в текущем словаре. Добавляем 1 в результат, а "0" в словаре переносим в начало, получая "02134..."</li>
<li>Аналогично повторяем для всего блока;</li>
<li>В результате получаем последовательность позиций символов в меняющемся словаре.</li>
</ol>
<p>В итоге получаем последовательность "21202222". Которая в некоторых случаях будет сжата компактнее исходного варианта <img src='http://software.intel.com/ru-ru/blogs/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </p>
<p>Однако толку мало, если обратно раскодировать нельзя. А делается это просто: выполняем все в обратную сторону (но с исходным словарем):</p>
<table border="1" style="border:1px solid #888;border-collapse:collapse">
<tr>
<th>Шаг</th>
<th>Вход</th>
<th>Выход</th>
<th>Словарь</th>
</tr>
<tr>
<td style="padding: 2px;">0</td>
<td style="padding: 2px;"><u>2</u>1202222</td>
<td style="padding: 2px;"><i>Пусто</i></td>
<td style="padding: 2px;">0123456789</td>
</tr>
<tr>
<td style="padding: 2px;">1</td>
<td style="padding: 2px;"><u>2</u>1202222</td>
<td style="padding: 2px;">2</td>
<td style="padding: 2px;">2013456789</td>
</tr>
<tr>
<td style="padding: 2px;">2</td>
<td style="padding: 2px;">2<u>1</u>202222</td>
<td style="padding: 2px;">2,0</td>
<td style="padding: 2px;">0213456789</td>
</tr>
<tr>
<td style="padding: 2px;">3</td>
<td style="padding: 2px;">21<u>2</u>02222</td>
<td style="padding: 2px;">2,0,1</td>
<td style="padding: 2px;">1023456789</td>
</tr>
<tr>
<td style="padding: 2px;">4</td>
<td style="padding: 2px;">212<u>0</u>2222</td>
<td style="padding: 2px;">2,0,1,1</td>
<td style="padding: 2px;">1023456789</td>
</tr>
<tr>
<td style="padding: 2px;">5</td>
<td style="padding: 2px;">2120<u>2</u>222</td>
<td style="padding: 2px;">2,0,1,1,2</td>
<td style="padding: 2px;">2103456789</td>
</tr>
<tr>
<td style="padding: 2px;">6</td>
<td style="padding: 2px;">21202<u>2</u>22</td>
<td style="padding: 2px;">2,0,1,1,2,0</td>
<td style="padding: 2px;">0213456789</td>
</tr>
<tr>
<td style="padding: 2px;">7</td>
<td style="padding: 2px;">212022<u>2</u>2</td>
<td style="padding: 2px;">2,0,1,1,2,0,1</td>
<td style="padding: 2px;">1023456789</td>
</tr>
<tr>
<td style="padding: 2px;">8</td>
<td style="padding: 2px;">2120222<u>2</u></td>
<td style="padding: 2px;">2,0,1,1,2,0,1,2</td>
<td style="padding: 2px;">2103456789</td>
</tr>
</table>
<p>
И по шагам:</p>
<ol start="0">
<li>Во входном буфере смотрим на первый символ (позицию в словаре), результирующий список позиций пуст, словарь с исходном виде;</li>
<li>Текущий символ 2, а по позиции 2 в словаре символ "2". Добавляем "2" в результат, а "2" в словаре переносим в начало, получая "20134...";</li>
<li>Следущий символ 1, с этой позицией у нас символ "0". Добавляем "0" в результат, а "0" в словаре переносим в начало, получая "02134..."</li>
<li>Аналогично повторяем для всего блока;</li>
<li>В результате получаем исходную строку байт "20112012".</li>
</ol>
<p>Как можно заметить, итоговый словарь совпадает в обоих случаях.</p>
<p>Пример реализации на Python:</p>
<pre name="code" class="python">
#!/usr/bin/env python
#-*- coding: utf8 -*-

# создаем исходный словарь
DICT = [chr(i) for i in range(ord('0'),ord('9')+1)]

src = '20112012'

def encode(s,d):
    seq = []
    for c in s:
        i = d.index(c)
        seq.append(i)
        d.pop(i)
        d.insert(0,c)
    return seq

def decode(seq,d):
    s = []
    for i in seq:
        c = d[i]
        s.append(c)
        d.pop(i)
        d.insert(0,c)
    return ''.join(s)

print 'SOURCE:  ', src

enc=encode( src, DICT[:] )  # передаем копию словаря
print 'ENCODED: ', enc

dec=decode(enc,DICT[:])  # передаем копию словаря
print 'DECODED: ', dec
</pre>
<p>Стоит заметить, что битовые длины значений выходной последовательности не превышают длины значений во входном потоке (т.к. позиции не превышают размер словаря, который содержит все возможные значения в потоке).</p>
<p>Это позволяет сохранять результирующую последовательность индексов в туже область памяти, откуда читаются входные данные.</p>
<p>Само собой, если нет требования к сохранению исходных данных.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/12/26/mtf-move-to-front/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Непростая арифметика: ода индукции</title>
		<link>http://software.intel.com/ru-ru/blogs/2011/12/26/2006581/</link>
		<comments>http://software.intel.com/ru-ru/blogs/2011/12/26/2006581/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 07:57:07 +0000</pubDate>
		<dc:creator>Dmitry Serkin (Intel)</dc:creator>
				<category><![CDATA[Intel Software Network]]></category>
		<category><![CDATA[arithmetic coding]]></category>
		<category><![CDATA[entropy coding]]></category>

		<guid isPermaLink="false">http://software.intel.com/ru-ru/blogs/2011/12/26/2006581/</guid>
		<description><![CDATA[Ода математической индукции на примере арифметического кодирования]]></description>
			<content:encoded><![CDATA[<p><a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D0%B8%D0%BD%D0%B4%D1%83%D0%BA%D1%86%D0%B8%D1%8F">Математическая индукция</a> один из самых известных методов доказательства. Помню, что меня впечатлила простота и количество проблем, которые решает цепная реакция метода.</p>
<p>Вспомнил я о индукции не просто так, а в продолжении темы арифметического кодирования. В <a href="http://software.intel.com/ru-ru/blogs/2011/12/20/2006336/">прошлый раз</a> мы остановились на том, что определили рекурсивный метод нахождения конечного интервала из которого, в результате, получили код входной последовательности символов. Вот он в двоичной системе счисления: 0.10111110001(2)</p>
<p>Выбрали мы его не просто так, а руководствуясь некоторым предположением оптимальности, согласно которому из финального интервала  необходимо выбрать такое действительное число для передачи, которое потребует минимальное количество бит. Существует ли какая-то оценка числа бит? Конечно.</p>
<p>Процесс нахождения «лучшего» бинарного представления довольно прост и нагляден на примере математической индукции. Центральная идея состоит в том, что для довольно длинных интервалов мы можем найти оптимальное значение путем тестирования нескольких бинарных представлений. Далее, уполовинивая длину интервала, количество бинарных значений удваивается, тем самым, на единицу инкрементируется количество бит на их представления. Процесс строится следующим образом:</p>
<div style="text-align:center;padding: 5 5 5 5">
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/113.png" />
</div>
<p>Дальнейшие индукционные переходы повторяют явный логарифмический паттерн, который гласит, что необходимое минимальное количество бит для представления кода в конечном интервале известной длины равно:</p>
<div style="text-align:center;padding: 5 5 5 5">
<img src="http://software.intel.com/ru-ru/blogs/wordpress/wp-content/uploads/210.png" />
</div>
<p>Вспомним пример из <a href="http://software.intel.com/ru-ru/blogs/2011/12/20/2006336/">предыдущей заметки</a>. Длина конечного интервала составила 0.0002. Тогда полученная выше оценка составит 13 бит. Но, итоговое представление заняло только 11 бит. Источником этой несостыковки является тот факт, что мы всегда можем выбрать представление удовлетворяющее обозначенной оценке, но завершающееся непрерывной последовательностью нулей, которые в итоге и обрезаются. Однако, доказано, что среднее количество бит, которые можно сэкономить подобным образом, равно единице, то есть на практике редко удасться сэкономить более одного бита.</p>
<p>Вот такая вот ода математике.</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/ru-ru/blogs/2011/12/26/2006581/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

