- •Соглашения
- •Общие замечания
- •Порядок выполнения первого задания
- •Общий порядок выполнения очередного (не первого) задания
- •Признак успешности выполнения алгоритма
- •Практическое задание №1. Метод половинного деления
- •Методические указания
- •Порядок выполнения задания
- •Варианты решаемых функций
- •Практическое задание №2. Метод простых итераций
- •Методические указания
- •Порядок выполнения задания
- •Варианты решаемых функций
- •Практическое задание №3. Метод Ньютона
- •Методические указания
- •Порядок выполнения задания
- •Варианты решаемых функций
Практическое задание №1. Метод половинного деления
Краткое описание задания: задана решаемая функция вида f(x) = 0. Методом деления отрезка пополам найти её решение с заданной точностью ε.
Методические указания
1.Программа ничего не принимает с клавиатуры. Все исходные данные задаются в коде программы, как правило, в основном модуле, во время вызова функции метода (внутри функции main).
2.Программа решает задачу двумя способами в двух функциях метода: а) вычислительный цикл завершается, когда будет достигнута заданная
точность вычисления.
б) число циклов рассчитывается перед вычислительным циклом, исходя из заданной точности;
3.Название модуля (файла типа .h) для функции метода — mhalfint.
4.Название функции метода — halfint.
5.Сигнатура (прототип) функции метода имеет следующий вид:
double halfintN(pef ef, double X1, double X2, double eps, int* success);
Здесь:
-N — цифра 1 или 2 для первого и второго способов решения;
-pef — тип решаемой функции;
-X1 — левая граница начального отрезка;
-X2 — правая граница начального отрезка;
-eps — заданная точность решения;
-success — возвращаемый признак успешного выполнения алгоритма.
-возвращаемое значение функции метода — результат вычисления аргумента x решаемой функции, при котором решаемая функция равна нулю
сзаданной точностью eps.
6. Тип решаемой функции задается следующим описанием:
typedef double (*pef)(double);
7. Решаемая функция описывается в основном модуле следующим образом:
// Решаемая функция для метода деления отрезка пополам double f1(double x) {
/* код функции */
}
6
8. Функция метода вызывается в основной функции.
После вызова выводятся три строчки результата, например:
SUCCESS=9
EPSILON=0.001
RESULT1=1.254
Здесь:
SUCCESS — успешность выполнения алгоритма (значение success); EPSILON — заданная точность вычисления (значение EPS); RESULT1 — результат вычислений способом 1, вывод должен соот-
ветствовать заданной точности.
Порядок выполнения задания
1.Сначала выполните действия 1-11, описанные выше в разделе «Порядок выполнения первого задания».
2.Добавьте в решение новый модуль:
-выберите в меню Project — Add New Item;
-в списке Categories выберите Code;
-в списке Templates выберите Header File (.h);
-в поле Name введите название модуля mhalfint;
-нажмите кнопку Add.
В проекте появится новый модуль.
Добавьте в новый модуль файловый комментарий согласно ТПМ, например, так:
/* Файл mhalfint.h |
*/ |
/* ОТИ НИЯУ МИФИ |
*/ |
/* 1ПО-XXД |
*/ |
/* Пономарев Владимир Вадимович |
*/ |
/* Вычислительная математика |
*/ |
/* Программа VM1 |
*/ |
/* |
Модуль метода деления отрезка пополам */ |
|
/* |
20.02.2013 |
*/ |
3. Добавьте в модуль описание типа решаемой функции:
typedef double (*pef)(double);
4. Добавьте в модуль определение функции метода:
/* Метод деления отрезка пополам, способ 1 */
double halfint1(pef ef, double X1, double X2, double eps, int* success) {
}
Здесь первая строка определения функции не умещается в одной строке документа, поэтому она размещена на двух строчках, однако вы напишите заголовок функции в одной строке.
7
5.Поскольку функция метода должна возвращать результат, впишите
внее следующий код для предварительной отладки:
double halfint1(pef ef, double X1, double X2, double eps, int* success) {
*success = 0; return ef(X1);
}
Здесь функция метода возвращает значение решаемой функции от X1.
6. Перейдите в основной модуль. В основной модуль включите библио-
теку математических функций math и модуль функции метода:
#include |
"stdafx.h" |
#include |
<math.h> |
/* Метод |
деления отрезка пополам */ |
#include |
"mhalfint.h" |
7. Опишите константу, задающую заданную точность вычислений, например, так:
#include |
"stdafx.h" |
#include |
<math.h> |
/* Метод |
деления отрезка пополам */ |
#include |
"mhalfint.h" |
/* Заданная точность вычислений */ #define EPS 0.001
8. Опишите решаемую функцию перед основной функцией, например:
/* Решаемая функция для метода деления отрезка пополам */ double f1(double x) {
return (x);
}
Название функции читается «эф один». На данном этапе разработки программы функция просто возвращает аргумент. Где-то далее по ходу выполнения работы вы замените код этой функции на нужный.
9. Перейдите в основную функцию (в основной модуль). Объявите в основной функции переменную для возвращаемого признака успешности алгоритма и переменную для возвращаемого результата, например, так:
/* Основная функция */ void _tmain() {
int success = 0; double result = 0.0;
}
10. Скомпилируйте проект, нажав, например, сочетание Ctrl+Shift+B. В случае возникновения ошибок устраните их.
8
11. Добавьте в основную функцию вызов функции метода для предварительной отладки, например, так:
void _tmain() {
int success = 0; double result = 0.0;
result = halfint1(f1, -1.0, 2.0, EPS, &success);
}
Заметим, что здесь "f1" — имя решаемой функции, "–1" — левая граница отрезка, "2" — правая граница отрезка, "EPS" — предполагаемая точность вычислений, "&success" — адрес переменной, указывающей на признак успешности выполнения алгоритма.
12. В основной функции добавьте код, который выводит результат вычислений, например, так:
void _tmain() {
int success = 0; double result = 0.0;
result = halfint1(f1, -1.0, 2.0, 0.001, &success); printf("SUCCESS=%d\n", success); printf("EPSILON=%0.3f\n", EPS); printf("RESULT1=%0.3f\n", result);
}
Заметим, что значения EPS и result следует выводить с необходимой точностью, поэтому при изменении точности EPS соответственно следует изменить также и спецификации вывода значений "%0.3f".
13.Скомпилируйте проект, нажав, например, сочетание Ctrl+Shift+B. В случае возникновения ошибок устраните их.
14.Запустите проект на выполнение, нажав сочетание клавиш Ctrl+F5. Убедитесь, что на консоль выводится:
ITERATION=0
EPSILON=0.001
RESULT1=-1.000
15.Основной модуль. Напишите код вычисления решаемой функции f1
всоответствии с заданием. Например, если решаемая функция задана следующим образом:
x + 1 = 0,
скорректируйте код решаемой функции так:
double f1(double x) { return (x + 1);
}
9
Определите границы начального отрезка и задайте их в вызове функции метода в основной функции. Например, если задана решаемая функция, приведенная в предыдущем пункте, то можно задать левую границу начального отрезка X1 = –2, правую границу X2 = 3 (решение равно –1):
result = halfint1(f1, -2.0, 3.0, EPS, &success);
Заметим, что желательно задать границы отрезка так, чтобы решение не лежало в центре начального отрезка, потому что в этом случае решение будет найдено в первой итерации, а это не интересно. В практических случаях, кстати, не всегда можно определить такие границы, чтобы решение находилось в центре. Дайте алгоритму возможность проявить себя! Пусть расстояние между границами и решением будет в соотношении, например, 1:4, 1:3, 1:2, 1:1.5. Кроме того, если функция не определена в некоторой точке x = a, то задайте отрезок, в который эта точка не входит.
16.Подготовительная работа завершена. Теперь ваша задача заключается в том, чтобы правильно организовать вычислительный процесс внут-
ри функций метода halfint1 и halfint2.
17.Организация вычислений, способ 1 (цикл завершается при обнаружении заданной точности).
Суть метода заключается в последовательном сокращении наполовину ширины текущего отрезка, внутри которого находится точное решение.
Пусть точное решение находится между границами X1 и X2.
а) определим значение X, находящееся в середине отрезка [X1, X2]. б) вычислим значение решаемой функции g в точке X.
в) если значение g по абсолютной величине равно или не превышает заданную точность вычислений eps, то алгоритм достиг результата и завершается, при этом возвращается значение X.
г) вычислим значения решаемой функции g1 и g2 в точках X1 и X2. Заметим, что значения g1 и g2 должны иметь противоположные знаки.
Если это не так, отрезок [X1, X2] задан неверно, это ошибка.
д) Если произведение g×g1 меньше нуля (то есть значения g и g1 имеют разные знаки), то точное решение находится в отрезке [X1, X], и в этом случае границу X2 нужно заменить значением середины отрезка X (то есть присвоить границе X2 значение X). Если произведение g×g2 меньше нуля, то точное решение находится в отрезке [X, X2], и в этом случае границу X1 нужно заменить значением середины отрезка X.
В случае, если и g×g1 больше нуля, и g×g2 больше нуля, то алгоритм выполняется неверно, и его следует завершить с признаком ошибки.
е) перейти к следующей итерации, то есть к п.п. а).
Внутри функции, естественно, должны быть описаны локальные переменные X, g, g1, g2 типа double. Цикл реализуется оператором while (1).
10