73991

Сравнение возможностей инструментария разработки программного обеспечения графических процессоров

Дипломная

Информатика, кибернетика и программирование

Обобщим основные отличия между архитектурами центрального графического процессора. CPU создан для последовательного исполнения одного потока инструкций с максимальной производительностью, а GPU спроектирован таким образом чтобы единовременно исполнять как можно большее число параллельных потоков...

Русский

2015-01-19

358 KB

2 чел.

Министерство образования и науки Российской федерации

Федеральное государственное автономное образовательное учреждение высшего профессионального образования

«Уральский федеральный университет

имени  первого Президента России Б.Н. Ельцина»

Математико-механический факультет

Кафедра высокопроизводительных компьютерных технологий

«Сравнение возможностей инструментария разработки программного обеспечения графических процессоров»

"Допущен к защите"
___________________

"__"____________2011 г.

Квалификационная работа на степень бакалавра наук
по направлению "Математика, прикладная математика" студента
Гаглоева Владимира Олеговича

Научный руководитель
Авербух Владимир Лазаревич
кандидат технических наук

Екатеринбург

2011


Оглавление

[1]
Оглавление

[2] Обобщим основные отличия между архитектурами центрального графического процессора. CPU создан для последовательного исполнения одного потока инструкций с максимальной производительностью, а GPU спроектирован таким образом чтобы единовременно исполнять как можно большее число параллельных потоков.

[3] Глава 3. Численное решение задачи Дирихле для уравнения Пуассона

[4] Глава 4. Результаты

[5] Заключение

[6]
Список литературы

[6.1] Приложение 1

[6.2]
Приложение 2


Введение

Параллельные вычисления на сегодняшний день являются одной из наиболее актуальных и приоритетных тем для исследования. Во всех ведущих IT компаниях (Microsoft, Intel, AMD, NVIDIA, Google, и т.д.) уже давно имеются подразделения и лаборатории, занимающиеся проектированием и разработкой высокопроизводительных систем основанных на алгоритмах параллельной обработки данных. Таким пристальным вниманием, параллельные вычисления обязаны стремительным ростом объемов данных, нуждающихся в обработке. Спектр исследуемых задач крайне широк. Сюда входит анализ и обработка изображений, симуляция физических процессов, прогнозирование различных процессов, анализ спутниковых данных, финансовые расчеты, электромагнитные расчеты, нейронные сети и многое другое.

В настоящее время графические процессоры (GPU) являются наиболее удобной параллельной архитектурой с общей памятью. Графические процессоры изначально проектируются таким образом, чтобы обрабатывать огромные объемы данных. На сегодняшний день они способны обеспечить производительность в сотни и даже тысячи миллиардов операций над вещественными числами в секунду (GigaFLoating point Operations Per Second, GFLOPS).

Одним из инструментов, позволяющих использовать GPU для вычислений, является CUDA (Compute Unified Device Architecture), которая представляет собой программно-аппаратное решение, предназначенное для работы с GPU, как с простым вычислителем, без необходимости использования графических API.

Целью данной работы является изучение возможностей CUDA для решения задачи Дирихле для уравнения Пуассона.

Глава 1. Сравнение центрального и графического процессора.

На сегодняшний день развитие центральных процессоров практически остановилось. Дальнейший рост вычислительной производительности CPU сопряжен с рядом сложностей технологического характера. Так, к примеру, увеличение частот универсального процессора уперлось в физическое ограничение на размер чипа и высокое энергопотребление. Тем не менее, роста производительности можно добиться за счет размещения нескольких ядер в одном чипе. Большинство современных настольных систем оснащается двуядерными и четырехядерными процессорами, что позволяет пользователю комфортно работать с подавляющим большинством прикладных пакетов. В серверных конфигурациях, где уровни нагрузок на систему существенно выше, как правило, используются более производительные чипы, оснащенные восемью и более ядрами.

Центральные процессоры являются универсальными вычислительными устройствами, способными выполнять широкий спектр задачи. Наличие нескольких ядер позволяет выполнять параллельно несколько задач, т.е. данный подход подразумевает множественный поток команд и данных (Multiple Instruction stream Multiple Data stream, MIMD). Каждое ядро работает отдельно от других, последовательно исполняя инструкции текущего процесса.

Помимо параллельного исполнения нескольких потоков, современные центральные процессоры так же поддерживают специализированные векторные вычисления. При этом преимущество в производительности достигается лишь в том случае, когда необходимо произвести одну и ту же последовательность действий над большим набором однотипных данных. SSE2 и SSE3 позволяет производить вычисления над четырехкомпонентными и двухкомпонентными векторами. В первом случае результат имеет одинарную точность, во втором – двойную.

Графические процессоры изначально нацелены на решение узкого круга задач, связанного с компьютерной обработкой графических данных. В связи с этим архитектуры GPU и CPU существенно отличаются друг от друга. Так, к примеру, в видеочипах от NVIDIA основной блок представляет собою мультипроцессор с восьмьюдесятью ядрами, и несколькими тысячами регистров. Графические процессоры от NVIDIA так же оснащены несколькими видами памяти: локальная, разделяемая общая, константная, а так же глобальная память, доступная всем мультипроцессорам на чипе

Рисунок - Устройство CPU и GPU.

Как и векторные расширения центрального процессора, графический процессор поддерживает SIMD (Single Instruction stream Multiple Data stream) метод вычислений, т.е. ядра GPU выполняют один и тот же набор инструкций для каждого экземпляра данных. Такой подход характерен для большинства графических алгоритмов и позволяет наиболее эффективно решать задачи визуализации графических сцен.  

Обобщим основные отличия между архитектурами центрального графического процессора. CPU создан для последовательного исполнения одного потока инструкций с максимальной производительностью, а GPU спроектирован таким образом чтобы единовременно исполнять как можно большее число параллельных потоков.

Для увеличения производительности центрального процессора архитекторы постарались максимизировать число инструкций исполняемых за один такт. В процессорах Intel Pentium для достижения этой цели используется суперскалярное выполнение, обеспечивающее одновременное исполнение двух инструкций. Современные процессоры так же имеют сложный механизм внеочередного (упреждающего) исполнения команд, который позволяет процессору выполнять более 100 команд, обеспечивая загруженность суперскалярных исполнительных блоков и общее повышение производительности. Но, не смотря на все модификации, поток команд, выполняемый CPU, по-прежнему является последовательным и увеличением количества ядер кратного увеличения скорости исполнения алгоритма добиться при текущей архитектуре просто невозможно.

Графический процессор является вспомогательным вычислительным устройством занимающийся обработкой графических примитивов, которая состоит в следующем: GPU принимает на вход набор вершин и инструкций для их обработки, далее происходит растеризация и генерация изображения, представляющего собою набор пикселей. При этом на каждом из шагов графического конвейера данные никак не зависят друг от друга и могут быть обработаны параллельно. Именно из-за изначально параллельной организации работы графического процессора в нем используется большое количество исполнительных блоков, которые легко загрузить, в отличие от последовательного потока инструкций для CPU.

Рисунок  - Графический конвейер.

У CPU и GPU так же имеются существенные различия в принципах организации доступа к памяти. В то время как CPU ориентирован на алгоритмы со случайным доступом к памяти, в GPU доступ осуществляется последовательно и, если в некоторый момент времени было произведено чтение из ячейки памяти, то с уверенностью можно сказать, что далее будут затребованы идущие следом данные. Аналогично обстоит дело и с записью информации в GPU. Кроме того, большинство задач решаемых на графическом процессоре предполагают интенсивную работу с большими объемами данных. В CPU проблема задержек доступа к памяти решается за счет использования технологии кэширования информации и предсказаний ветвления кода. GPU обходит эту проблему иначе: если какой-либо из параллельно исполняемых процессов остановился, ожидая доступа к памяти, видеочип попросту переключается на другой процесс, уже получивший все данные необходимые ему для продолжения работы. Кроме того, память, используемая в видеокартах, обладает куда большей пропускной способностью, нежели оперативная память.

Как уже было сказано выше, центральный процессор использует механизм кэширования данных для снижения задержек доступа к памяти. В графических процессорах так же применяется кэширование. Но в отличие от CPU, где кэш-память занимает существенную часть чипа, в GPU под кэш отводится всего 128-256 килобайт, и используется он скорее не для снижения задержек, а для увеличения полосы пропускания.

В графических процессорах так же имеется аппаратная поддержка многопоточности. Использование множества потоков на CPU не является целесообразным, так как каждое переключение между ними связано со значительными временными задержками и может занимать до нескольких сотен тактов. К тому же ядро центрального процессора способно исполнять всего 1-2 потока единовременно. В GPU разработчики смогли добиться мгновенного переключения между потоками (всего за 1 такт), а каждое из ядер графического процессора поддерживает до 1024 потоков.

В итоге можно сказать, что в отличие от современных центральных процессоров, являющихся универсальными вычислительными устройствами, одинаково эффективно справляющимися с большинством задач, графические процессоры имеют куда более узкую направленность. GPU спроектирован таким образом, чтобы максимально эффективно решать задачу обработки множественных данных. И если в CPU разработчики были вынуждены пожертвовать производительностью ради достижения максимальной унифицированности, то в GPU значительно большее число транзисторов на чипе работает по прямому назначению – обработке массивов данных. Но небольшие блоки управления исполнением и кэш-памяти, накладывают значительные ограничения на структуру алгоритмов исполняемых на GPU. Графический процессор не столь эффективен в задачах с множеством ветвлений и переходов, как центральный процессор.

Рисунок - Динамика роста пиковой производительности GPU и CPU.

Глава 2. Программная модель CUDА

CUDA - это среда разработки приложений, которая предоставляет в распоряжение программиста вычислительные мощности современных графических карт NVIDIA. В основе программной модели CUDA лежат три ключевые абстракции: иерархия групп потоков, разделяемая память и барьерная синхронизация, реализуемые в виде минимального набора расширений языка С/С++.

Приложения CUDA используют как центральный, так и графический процессоры. Фактически видеокарта является высокопроизводительным сопроцессором. Параллельные участки кода выполняются на видеокарте в виде вычислительных ядер. Ядро - это функция, которая вызывается из основной программы на CPU и выполняется на видеокарте.

Рисунок  - Ядро выполняется массивом потоков, каждый из которых имеет уникальный идентификатор

Для выполнения каждого ядра запускается большое
число одновременных потоков. Укажем два ключевых различия между программными потоками на центральном процессоре и на видеокарте. Во-первых, десятки тысяч потоков
CUDA могут быть созданы всего за несколько процессорных циклов. Благодаря этому расходы на управление потоками значительно ниже, чем на CPU, и даже легковесные ядра, состоящие всего из нескольких строчек кода, могут быть чрезвычайно эффективными. Во-вторых, переключение между контекстами потоков происходит мгновенно и используется для маскировки
задержек при обращении к памяти. При этом если один из потоков простаивает в ожидании операции чтения/записи или синхронизации, он заменяется другим потоком, выполняющим арифметические операции. Это означает, что для эффективной загрузки видеокарты число потоков должно многократно превышать число процессоров.

Итак, каждое ядро CUDA выполняется массивом параллельных потоков. Все потоки выполняют один и тот же программный код. и для того чтобы они могли обрабатывать свой участок данных, каждому из них назначается уникальный идентификатор. Этот идентификатор используется для вычисления адресов памяти и организации ветвлений. Например, на рис.2  представлено ядро, выполняемое восемью потоками. Сначала каждый из них использует свой идентификатор для считывания элемента из входного массива. Затем каждый поток передает считанное значение в функцию и записывает результат в выходной массив.

Это пример так называемой неограниченно параллельной (embarrassingly parallel) задачи, когда каждый поток может выполнять свою подзадачу независимо от соседей. В реальных задачах требуется организация межпоточного взаимодействия: потоки должны, во-первых, совместно использовать результаты, чтобы избежать лишних вычислений; во-вторых, разделять операции доступа к памяти, чтобы снизить требования программы к пропускной способности канала данных. В программной модели CUDA взаимодействие допускается только между потоками внутри небольших групп, или блоков. Каждый блок это одно-, двух- или трехмерный массив потоков фиксированного размера. При запуске ядра потоки организуются в одно- или двухмерную решетку (grid) блоков. Потоки внутри блока могут взаимодействовать посредством разделяемой памяти и выполнять барьерную синхронизацию. Организация потоков в блоки позволяет программам прозрачно масштабироваться при переходе на видеокарту с большим числом потоковых процессоров.

Поясним последнее утверждение. Благодаря тому, что блоки потоков независимы, они могут выполняться в любом порядке на любом из доступных процессоров. Допустим, ядро состоит из 8 блоков потоков. На видеокарте с двумя мультипроцессорами каждый мультипроцессор должен будет выполнить по 4 блока. А на видеокарте с 4 мультипроцессорами каждый из них должен будет выполнить по 2 блока, то есть задача будет выполнена в два раза быстрее. Такое масштабирование происходит автоматически без каких-либо изменений в программе. Поэтому
однажды написанная программа на
CUDA может выполняться на самых различных по производительности устройствах от ноутбуков до высокопроизводительных серверов.

Потоки CUDA имеют доступ к нескольким областям памяти, которые различаются областью видимости, скоростью доступа и объемом (таблица 1). Регистровая память используется для хранения локальных переменных потока. Переменные, которые не уместились в регистрах, хранятся в так называемой локальной памяти, которая, несмотря на название, находится вне чипа и потому имеет низкую скорость доступа. Разделяемая память используется для организации взаимодействия между потоками в блоке. Все потоки ядра имеют доступ чтения/записи к глобальной памяти, которая располагается в памяти видеокарты. Область видимости глобальной памяти - все приложение; ее содержимое не изменяется между запусками различных ядер. Кроме того, центральный процессор также имеет доступ к
глобальной памяти, поэтому глобальная память используется для обмена данными между
CPU и GPU.

Таблица  - Различные типы памяти, доступные программам на CUDA

Вид

Область видимости

Скорость доступа

Объем

Использование

Регистровая

Поток

Высокая

16384 регистра на МП

Локальные переменные потока

Локальная

Поток

Низкая

Ограничен объемом глобальной памяти

Локальные переменные, не уместившиеся в регистрах

Разделяемая

Блок

Высокая

16 КБ

Организация межпоточного взаимодействия

Глобальная

Программа

Низкая

До 4 ГБ

Хранение данных, обмен с CPU

Рассмотрим модель исполнения кода в CUDA. Каждый поток выполняется потоковым процессором: блок потоков выполняется одним мультипроцессором; каждый мультипроцессор может выполнять несколько блоков. Число блоков, которое может выполняться на одном мультипроцессоре, ограничено разделяемыми ресурсами, то есть объемом регистровой и разделяемой памяти.

Глава 3. Численное решение задачи Дирихле для уравнения Пуассона

Задача Дирихле для уравнения Пуассона определяется как задача нахождения функции , удовлетворяющей в области определения  уравнению

и принимающей значения  на границе  области  (и являются функциями, задаваемыми при постановке задачи). Подобная модель может применяться для описания установившегося течения жидкости, стационарных тепловых полей, процессов теплопередачи с внутренними источниками тепла и деформации упругих пластин.

Для численного решения уравнения воспользуемся методом конечных разностей (метод сеток). Следуя этому подходу, область решения  можно представить в виде дискретного набора (сетки) точек (узлов). Так, например, прямоугольная сетка в области  может быть задана в виде

 

где величина  задает количество внутренних узлов по каждой из координат области .

Обозначим оцениваемую при подобном дискретном представлении аппроксимацию функции  в точках  через . Тогда, используя пятиточечный шаблон для вычисления значений производных, мы можем представить уравнение Пуассона в конечно-разностной форме

 

Разрешив уравнение относительно  получим

 

Разностное уравнение, записанное в подобной форме, позволяет определять значение  по известным значениям функции  в соседних узлах используемого шаблона. Данный результат служит основой для построения различных итерационных схем решения задачи Дирихле, в которых в начале вычислений формируется некоторое приближение для значений , а затем эти значения последовательно уточняются в соответствии с приведенным соотношением.

Для проведения итераций воспользуемся методом Гаусса-Зейделя, который использует правило

 

по которому очередное -е приближение значения вычисляется по последнему -му приближению значений  и  и предпоследнему -му приближению значений  и .

Рисунок  - Прямоугольная сетка в области D

В качестве примера возьмем задачу Дирихле при следующих граничных условиях

 

В качестве области  возьмем единичный квадрат .

Начальное приближение величин  было получено генерированием случайных чисел из диапазона .

Глава 4. Результаты

Задача решалась на сетках размером 256x256, 512x512, 1024x1024 и 2048x2048 узлов.

Для сравнения быстродействия программа было протестирована на следующем оборудовании

  •  CPU: Intel Core 2 Duo E6600, 2.4GHz
  •  CPU: Intel Core 2 Duo P8600, 2.4GHz
  •  GPU: nVidia GeForce 450 GTS

Сравнивались значения полученные при выполнении последовательной реализации алгоритма и CUDA реализации.

Таблица 2 – Решение задачи сеточным методом (Размер сетки 1024x1024)

Устройство

Время решения, мс

Ускорение

Последовательный алгоритм

CPU Core 2 Duo P8600

40482

-

CPU Core 2 Duo E6600

42541

-

CUDA реализация

GPU nVidia GeForce 450 GTS

8011

5,3

Заключение

Стоит упомянуть, что на данный момент параллельные алгоритмы занимают все более важное место среди различных типов приложений. Легко понять, что роль параллельных вычислений с течением времени будет возрастать, а решаемые ими задачи и их структура будут усложняться. Следовательно, будут появляться новые технологии, упрощающие создание таких приложений, а их возможности будут увеличиваться.

В данной работе была разработана реализация разностной схемы для решения задачи Дирихле для уравнения Пуассона. Проведенные эксперименты показали, что CUDA реализация алгоритма показала отличные результаты и следует отдать им предпочтение перед другими решениями.


Список литературы

  1.  NVIDIA CUDA Programming guide. – NVIDIA Corporation, 2009.
  2.  Волков Е.А.. Численные методы. Москва: Наука, 1987
  3.  А.В. Боресков, А.А. Харламов. Основы работы с технологией CUDA. ДМК Пресc, 2010
  4.  В.П. Гергель. Теория и практика параллельных вычислений.
    Приложения

Приложение 1

Таблица 3 – Решение задачи сеточным методом (Размер сетки 256x256)

Устройство

Время решения

Ускорение

Последовательный алгоритм

CPU Core 2 Duo P8600

2387

-

CPU Core 2 Duo E6600

2619

-

CUDA реализация

GPU nVidia GeForce 450 GTS

1223

2,1

Таблица 4 – Решение задачи сеточным методом (Размер сетки 512x512)

Устройство

Время решения

Ускорение

Последовательный алгоритм

CPU Core 2 Duo P8600

9735

-

CPU Core 2 Duo E6600

11176

-

CUDA реализация

GPU nVidia GeForce 450 GTS

2656

4,2

Таблица 5 – Решение задачи сеточным методом (Размер сетки 2048x2048)

Устройство

Время решения

Ускорение

Последовательный алгоритм

CPU Core 2 Duo P8600

157716

-

CPU Core 2 Duo E6600

171726

-

CUDA реализация

GPU nVidia GeForce 450 GTS

29551

5,8


Приложение 2

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include <fstream>

#include <iostream>

#include <GPUSort.h>

#define BLOCK_DIM 16

const float EPS=0.1f;

const int N=2048;

void printSolution(float* u)

{

std::ofstream MyFile("Matrix.txt");

 for (int i=0; i<N*N; i++ )

{

 MyFile << u[i] << "    ";

 if((i+1)%N==0) MyFile << std::endl;

}

MyFile.close();

}

float* firstAproximation(float* u)

{

 for (int i=N; i<N*(N-1); i++ )

{

 if( ((i+1)%N!=0) && (i%N!=0) )

 u[i]=(float) (-100 + rand()%201);

}

 return u;

}

float* heterogeneity(float* f)

{

 for(int i=0;i<N*N;i++)

 f[i]=0;

 return f;

}

float* boundaryCondition(float h, float* u)

{

 int j=1;

 for(int i=1; i<N-1; i++)

 u[i] = 100 - 200* i* h;

 for(int i=N*(N-1) + 1; i<N*N-1; i++)

{

 u[i] = -100 + 200*j*h;

 j++;

}

 for(int i=0;i<N*(N-1)+1;i+=N)

 u[i]=100;

 for(int i=N-1;i<N*N;i+=N)

 u[i]=100;

 return u;

}

void randomInit (float* a)

{

 for(int i=0;i<N*N;i++)

 a[i]=0;

}

__global__ void relax(float* Matrix, float* f,float* Res, float step)

{

__shared__ float s_Matrix[BLOCK_DIM+2][BLOCK_DIM+2];

 int ix = blockIdx.x * blockDim.x + threadIdx.x;

 int iy = blockIdx.y * blockDim.y + threadIdx.y;

 int tx = threadIdx.x + 1;

 int ty = threadIdx.y + 1;

 int matrixIdx = ix + N * iy;

 

 if((ix<N) && (iy<N)) {

 s_Matrix[ty][tx] = Matrix[matrixIdx];

 if((ty==1) && (iy>0))

  s_Matrix[ty-1][tx] = Matrix[matrixIdx-N];

 if((ty==BLOCK_DIM) && (iy<N-1))

  s_Matrix[ty+1][tx] = Matrix[matrixIdx+N];

 if((tx==1) && (ix>0))

  s_Matrix[ty][tx-1] = Matrix[matrixIdx-1];

 if((tx==BLOCK_DIM) && (ix<N-1))

  s_Matrix[ty][tx+1] = Matrix[matrixIdx+1];

 if(ix==0)

  s_Matrix[ty][tx-1] = Matrix[matrixIdx+N-2];

 if(ix==N-1)

  s_Matrix[ty][tx+1] = Matrix[matrixIdx+N+2];

}

__syncthreads();

 if((ix==0)||(iy==0)||(ix==N-1)||(iy==N-1)) Res[matrixIdx]=0;

 if( (ix!=0) && (iy!=0) && (iy!=(N-1)) && (ix!=(N-1)) && (matrixIdx<N*N))

{

 Res[matrixIdx]=fabs((fabs(0.25*(s_Matrix[ty-1][tx]+s_Matrix[ty+1][tx]+s_Matrix[ty][tx-1]+s_Matrix[ty][tx+1]-f[matrixIdx]*step)))-fabs(Matrix[matrixIdx]));

 Matrix[matrixIdx]=0.25*(s_Matrix[ty-1][tx]+s_Matrix[ty+1][tx]+s_Matrix[ty][tx-1]+s_Matrix[ty][tx+1]-f[matrixIdx]*step);

}

}

float* solveEquation(float* Matrix, float step, float* f)

{

 float* devMatrix;

 float* devRes;

 float* devF;

 float* res;

res=new float[N*N];

randomInit(res);

SORT_ERROR error;

GPUSort *gpusort;

res[N*N-1]=2;

gpusort = new GPUSort(FLOAT16);

dim3 gridSize = dim3(N / BLOCK_DIM, N / BLOCK_DIM, 1);

dim3 blockSize = dim3(BLOCK_DIM, BLOCK_DIM, 1);

cudaEventCreate( &start );

cudaEventCreate( &stop );

cudaMalloc(&devMatrix, N*N*sizeof(float));

cudaMalloc(&devRes, N*N*sizeof(float));

cudaMalloc(&devF, N*N*sizeof(float));

 

cudaMemcpy(devMatrix, Matrix, N*N*sizeof(float), cudaMemcpyHostToDevice);

cudaMemcpy(devRes, Matrix, N*N*sizeof(float), cudaMemcpyHostToDevice);

cudaMemcpy(devF, f, N*N*sizeof(float), cudaMemcpyHostToDevice);

 do

{

 relax<<<gridSize, blockSize>>> (devMatrix,devF,devRes,step);

 error = gpusort->sort(devRes,N*N);

} while (res[N*N-1]>EPS);

 

cudaMemcpy(Matrix, devMatrix, N*N*sizeof(float), cudaMemcpyDeviceToHost);

cudaEventDestroy(start);

cudaEventDestroy(stop);

cudaFree(devMatrix);

cudaFree(devF);

cudaFree(devRes);

 delete res;

 return Matrix;

}

int main()

{

 float* f;

 float* Matrix;

f=new float[N*N];

Matrix=new float[N*N];

 float step;

step = (float) 1/(N+1);

f=heterogeneity(f);

randomInit(Matrix);

boundaryCondition(step, Matrix);

Matrix=firstAproximation(Matrix);

Matrix=solveEquation(Matrix, step*step,f);

printSolution(Matrix);

 

 delete f;

 delete Matrix;

 return 0;

}

Приложение 3

double** solveEquation(double h, double** u, double** f)

{

 double dmax = 0;

 double dm = 0;

 double temp = 0;

 do

{

 dmax = 0;

  for (int i=1; i<N+1; i++ )

   for (int j=1; j<N+1; j++ )

   {

    temp = u[i][j];

    u[i][j] = (u[i-1][j] + u[i+1][j] + u[i][j-1] + u[i][j+1] - h*h*f[i][j]) * 0.25;

    dm = fabs(fabs(temp) – fabs(u[i][j]));

    if ( dmax < dm ) dmax = dm;

   }

} while ( dmax > eps );

 return u;

}


 

А также другие работы, которые могут Вас заинтересовать

7325. Система управления электромуфты переключения направления намотки кабеля 180.5 KB
  ВВЕДЕНИЕ Устройство, на ряду со своей основной функцией, способно работать также и в качестве реле аварийной сигнализации. Оно выгодно отличается компактностью, небольшими массой и собственным потреблением электроэнергии. Для автомобилей новых модел...
7326. Кражи и грабежи как преступления против собственности 404 KB
  Кражи и грабежи как преступления против собственности 1. Кража Закон, касающийся кражи и относящихся к ней преступлений таких как грабеж, кража со взломом, различные преступления, включающие обман, шантаж и продажу (передачу) краденного, содержится ...
7327. Информационные технологии управления 468.5 KB
  Информационные технологии управления Информационные технологии и системы, понятие и свойства. Состав и структура экономических информационных систем. Жизненный цикл информационной системы. Классификация автоматизированных инф...
7328. Расчет силового масляного трансформатора 336 KB
  Расчет силового масляного трансформатора. Задание на расчет. Требуется рассчитать конструкцию и параметры силового трансформатора с масляным охлаждением со следующими параметрами: Мощность трансформатора SH = 1000 кВА. Число фаз m = 3. Частота f = 5...
7329. Измеритель активной энергии в однофазной сети на основе микроконтроллера ATMEL 654.5 KB
  Измеритель активной энергии в однофазной сети на основе микроконтроллера ATMEL Разработать измеритель активной энергии в однофазной сети 220 В с токовой нагрузкой 100 А на основе микроконтроллера фирмы ATMEL. Технические требования. В качестве перви...
7330. Исследование сущности и основных аспектов эффективной деятельности риэлторских фирм ООО МЕТР 225 KB
  Основой любой социально-экономической системы является собственность. Переход общества на рыночные основы вызывает ее трансформацию. Собственность от основной государственной преобразуется в многоаспектный комплекс, состоящий из федеральной...
7331. Диэлектрики в электростатическом поле 94.5 KB
  Тема: Диэлектрики в электростатическом поле. 1. Свободные и связанные заряды. Полярные и неполярные молекулы. Поляризуемость молекулы. 2. Типы диэлектриков. Деформационная и ориентационная поляризации диэлектриков. Поляризационные заряды. Поляризова...
7332. Расчет электрического поля в диэлектрике 89 KB
  Тема: Расчет электрического поля в диэлектрике. Поле в диэлектрике. Теорема Остроградского-Гаусса для электрического поля в веществе. Электрическое смещение. Диэлектрическая проницаемость вещества. Условия для E и D на границе двух диэлект...
7333. Элементы физической электроники 79 KB
  Тема: Элементы физической электроники 1. Работа выхода электрона из металла. Термоэлектронная эмиссия. 2. Электрический ток в вакууме. Законы, описывающие ток в вакууме. I=B...