Страница 1 из 1
C++
Добавлено: 16 сен 2017, 17:08
Ian
Вопрос не просто детский а младенческий. Работает ли эта программа (a=0,b=1,eps=0.001)и какой дает результат?
Код: Выбрать все
#include "stdafx.h"
#include <iostream>
using namespace std;
//Функция для уравнения:
double F(double x) {
return 2 - 20 * x + 9 * pow(x, 2) - pow(x, 3);
}
//Функция поиска корня:
int main()
{
//Интервал, погрешность и корень:
double a, b, eps, x;
cin >> a;
cin >> b;
//Проверка корректности интервала:
if (F(a)*F(b) > 0) {
cout << "Wrong interval!\n";
return 0;
}
cout << "error: ";
cin >> eps;
int k = 0;
//Поиск решения:
do {
x= a-(F(a)*(b-a)) / (F(b) - F(a));
if ((F(a)*F(x)) > 0)
a = x;
else
b = x;
k++;
} while (fabs(F(b) - F(a)) > eps II fabs(a-b)>2*eps);
cout << "x = " << x << endl;
cout << "f(x)=" << F(x) << endl;
cout << "k=" << k<<endl;
system("pause");
return 0;
}
Заранее спасибо за потраченное время
C++
Добавлено: 16 сен 2017, 17:59
zykov
Так на первый взгляд у Вас есть кубический многочлен [math]2-20x+9x^2-x^3. Вы задаёте начальный интервал (a,b) и точность "eps".
Проверяете, что в "a" и "b" многочлен имеет значения с разными знаками (и значит в интервале должен быть корень).
И ищете этот корень методом хорд с точностью "eps".
На выходе сам корень (приближенно), значение многочлена в этой точке и количество итераций.
Багов вроде нет на первый взгляд.
Этот многчлен имеет ровно один корень на интервале (0,1). Так что должно сработать.
PS: В условии "while" я бы заменил "or" на "and" для безопасности. А то может войти в вечный цикл в редких случаях. (Для данных параметров не должно.)
C++
Добавлено: 16 сен 2017, 18:41
zykov
Кстати, на самом деле даже не в редких, а в самых обычных (для метода хорд), в том числе и в вашем. Вот для метода деления пополам было бы редко.
Если посмотрите на график своего многочлена в интервале от 0 до 1, то увидите, что он имеет выпуклось вниз. Значит хорды всегда будут выше графика. На каждой итерации Вы будете заменять "b" на новый (всё ближе к корню), а вот "a" так и останется нулём. Так что разность "a-b" не будет приближатся к нулю и второе условие всегда будет верным (а значит всё "или" условие будет верным и цикл никогда не закончится).
PS: Для отладки можно было бы печатать "a" и "b" на каждой итерации, тогда Вы бы сами это быстро заметили.
C++
Добавлено: 16 сен 2017, 18:46
Ian
Спасибо, я знаю. А запустите?
Более точный чем нужно x= 0.1048935 но мне интереснее какой выдаст и конечно сколько было циклов (k)
C++
Добавлено: 16 сен 2017, 19:18
zykov
Если не исправите "or" на "and", то никакой не выдаст.
Зациклится бесконечно.
C++
Добавлено: 16 сен 2017, 19:24
zykov
На самом деле у меня закончился. Но только из-за ошибок округления.
Код: Выбрать все
0
1
error: 0.001
trace: 1 0 0.166667
trace: 2 0 0.107946
trace: 3 0 0.105041
trace: 4 0 0.104901
trace: 5 0 0.104894
trace: 6 0 0.104894
trace: 7 0 0.104893
trace: 8 0 0.104893
trace: 9 0 0.104893
trace: 10 0 0.104893
trace: 11 0 0.104893
trace: 12 0 0.104893
trace: 13 0.104893 0.104893
x = 0.104893
f(x)=2.01662e-017
k=13
На 13ой итерации всё таки "a" заменил, хотя не должен был в идиале.
C++
Добавлено: 16 сен 2017, 19:32
Ian
zykov писал(а):Если не исправите "or" на "and", то никакой не выдаст.
Зациклится бесконечно.
Спасибо, исправлю. Но мне не на чем это гонять. Уже 10 лет так "программирую" -посылаю кому-то из "клубней" текст, в ответ получаю письмом результат счета. А что, я же им тоже на их вопросы отвечаю.
C++
Добавлено: 16 сен 2017, 20:26
zykov
В смысле? Нет компьютера и на форум через планшет/телефон заходите?
Всё понятно с округлением?
В данном случае цикл случайно закончился из-за ошибки округления. А так вполне мог бы крутится бесконечно.
Идеальное вещественное число "x" всегда будет справа от корня. Но здесь, в результате округления машинного числа с плавующей точкой ('double") оно оказалось слева от корня и заместило "a", в результате чего разность "b-a" оказалась близкой к нулю.
Можно сказать, случайно оказалось. Могло бы так и оставаться справа.
C++
Добавлено: 16 сен 2017, 20:38
Ian
Как помните Кнуров сказал -на столе полно а я голодный) Компа не то что нет а нет хорошего. Дистрибутива нет хорошего. И как Матроскин сказал нам ума не хватает. Вот в 1982 на любом в мире компе был файл C:\basic.exe и каждый знал запусти его и вбивай прогу. На нем бы я эту задачу за 10 минут посчитал. А прогресс видимо катится назад, у скольки профессоров уже время отнял за 10-то лет.
C++
Добавлено: 16 сен 2017, 21:43
zykov
Ну для C++ хороший компьютер и не нужен.
Под linux всегда есть GCC (если нет, то легко поставить). Там эту программу легко собрать (только заменить Микрософтовский "stdafx.h" на другое - здесь достаточно <cmath>).
Под windows я себе поставил mingw (точнее mingw-w64, чтобы 64-битные собирать). Это почти тот же GCC, только собирает виндовс-бинарники, которые под видовс запускаются. Этот пример я так под видовс и проверил. Под linux возможно другой результат был бы (хотя вряд ли).
С языком C/C++ вообще работали или только с Basic?
C++
Добавлено: 16 сен 2017, 22:31
Ian
Как-то работал, у меня жил лето гость с нотбуком, С++ это его хлеб. Он показал мне какой файл запускать и я гонял программы. И если вспомнить одного мужика которому захотелось газировки но не понял военно-морского юмора-это же самому хозяину выгодно чтобы у каждой кнопки был ясно и правдиво указан ее смысл. Как файл-то называется????
C++
Добавлено: 16 сен 2017, 22:49
zykov
В GCC две команды "gcc" и "g++" (вторая лучше для C++). В mingw тоже самое. Это все в терминале надо.
Если Вам Microsoft Visual C++ ставили, то там среду нужно запускать. (Можно в принципе и в терминале, там команда "cl".)
C++
Добавлено: 16 сен 2017, 23:58
Ian
самый простой надо дистрибутив. Установщики, пытающиеся переконфигурировать систему под себя, сработают только если аккуратно написаны и(!) если система исправна, а неисправную систему они просто грохнут, а встать под нее не смогут
На что заменять "или" (||)? на амперсенд (
)?
C++
Добавлено: 17 сен 2017, 00:16
zykov
C++
Добавлено: 17 сен 2017, 09:30
zykov
Чего-то я вчера протупил. Вот это условие "fabs(F(b) - F(a)) > eps II fabs(a-b)>2*eps" вообще не работает для метода хорд (ни с "or", ни с "and") в отличии от метода деления пополам например.
Дело в том, что для метода хорд в обычном случае "a" и "b" не приближаются друг к другу. И соответственно "F(a)" и "F(b)" не приближаются друг к другу.
Тут было бы логично условие "fabs(F(x)) > eps".
Чтобы избежать возможного зацикливания (например если eps близко к машинной точности, а функция не очень хорошая), можно по "and" добавить условие "fabs(x - x1) > eps1". Здесь "x1" - это "x" с предыдущей итерации, "eps1" - это другое эпсилон, которое фиксированно и подбирается исходя из машинной точности.
PS: Вообще метод хорд - не особо хороший метод. Деление пополам гораздо надёжнее и почти так же быстро сходится. А индустриальный стандарт - это метод Ньютона. Он гораздо быстрее сходится, если нужна высокая точность. А для многомерного случаю это по сути единственный метод.
C++
Добавлено: 17 сен 2017, 11:09
Ian
zykov писал(а):Тут было бы логично условие "fabs(F(x)) > eps"..
Спасибо, так и сделал. А для функций, производная которых больше 1 на отрезке, это и гарантия точности по х.
C++
Добавлено: 17 сен 2017, 15:11
zykov
Ian писал(а):Source of the post А для функций, производная которых больше 1 на отрезке, это и гарантия точности по х.
Да.
Но с другой стороны, если производная в корне большая, а эпсилон выбрана такой маленькой, что она близка к машинной точности, то это условие может быть никогда не достигнуто из-за ошибок округления машинных чисел. В результате - бесконечный цикл.