Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Система";
Текущий архив: 2002.09.05;
Скачать: [xml.tar.bz2];

Вниз

Вопрос   Найти похожие ветки 

 
Озадаченный   (2002-06-11 15:54) [0]

Уважаемые господа эксперты и просто умные люди!
У меня возник вопрос по типу Extended. Я пишу программу, которая должна найти корень уравнения методом половинного деления в пределах от 1e-30 до 1e30. Если поставить точность меньше чем 1e10 (например 0.1), то программа "виснет", а если точность ставить 1е10, то все работаеть нормально, но точно +-7 миллиардов меня не сильно устраивает. Программа:
...
var a,b,x,n,Fa,Fx:Extended;

...
a:=1e-30;
b:=1e29;
Fa:=формула с параметром а;
repeat
x:=(a+b)/2;
Fx:=формула с параметром х;
if Fa*Fx>0 then a:=x else b:=x;
until (ABS(Fx)<1e5) or (b-a<1e10);
n:=x;
...

Если b-a меньше ставить, то программа виснет. Помогите пожалуйста разобраться.
Спасибо!
С уважением,
Озадаченный


 
короед   (2002-06-11 20:15) [1]

ты уверен, что
if Fa*Fx>0 then a:=x else b:=x;

может
if (Fa-Fx)>0 then a:=x else b:=x;
еще
until (ABS(Fx)<1e5) or ( abs(b-a) <1e10);
вот так. может заработает...



 
MegaVolt   (2002-06-12 14:26) [2]

ИМХО if Fa*Fx>0 then a:=x else b:=x; правильно т.к. эта строка проверяет находится ли точка F(a) и точка F{x} по одну сторону от оси х.
А если прога виснет то есть вероятность что на данном участке есть несколько решений и задавать участок на которосм прога ищет решенние нужно поменьше и с условием что F(а) и F(b) лежат по разные стороны от оси х т.е. одно Ю0 а другое Б0 илши наоборот.
Вот текстик проги которая это всё решает:
function mdop;
var x1,x2,f1,f2:real;
begin
repeat
x1:=(a+b-e)/2;
x2:=(a+b+e)/2;
f1:=f(x1);
f2:=f(x2);
if f1>f2 then a:=x1 else b:=x2
until abs(a-b)<e*2;
mdop:=(a+b)/2;
end;
end.


 
Озадаченный   (2002-06-13 11:57) [3]

короед © : Да, насчет этого точно уверен, т.к. действительно функция проверяет одинаковые ли знаки получились, а модуль в условии тоже не играет особой роли, т.к. b всегда больше a
MegaVolt © : Я эту функцию и корни вроде бы вычислились, но по-моему они немного неправильные, т.к. я попробовал эту функцию на примере y=x*x-9 и у меня получился корень (в пределах от 0 до 1000) равный 7.9*10 в минус пятой

e:=0.0001;
a:=0;
b:=1000;
repeat
x1:=(a+b-e)/2;
x2:=(a+b+e)/2;
f1:=x1*x1-9;
f2:=x2*x2-9;
if f1>f2 then a:=x1 else b:=x2;
until abs(a-b)<e*2;
mdop:=(a+b)/2;
showmessage(floattostr(mdop));


а если этим методом, то все нормально:

a:=0;
b:=1000;
Fa:=a*a-9;
repeat
x:=(a+b)/2;
Fx:=x*x-9;
if Fa*Fx>0 then a:=x else b:=x;
until (ABS(Fx)<0.1) or (b-a<0.1);
showmessage(floattostr(x));


Могу дать формулу: Fx:=x+Na/(2*exp((Ea-Ec-k*T*ln(x/Nc))/(k*T))+1)-ni*ni/x-Nd/(2*exp((Ec+k*T*ln(x/Nc)-Ed)/(k*T))+1);
все переменные известные, кроме переменной x


 
ZavDim   (2002-06-13 12:52) [4]

1. А может решений вообще нет? Тогда ясно, что происходит.
2. Во- вторых мы можем промахнуться с таким диапазоном. Если у Вас будут числа порядка 1е20, то точности представления Extended просто не хватит, чтобы обеспечить Ваши 1е-много.
Вот и смотри, если 1е30, то минимальный доступный разряд 1е10, другие просто не будут присутствовать. Два числа такой величины просто неразличимы в разрядах меньше 10 миллиардов. Вот прога и крутит числа, а нужной разницы не добивается. Если корни порядка 1, то требуемая точность никогда не достигнется. Определись с порядком корней и требуй разумного. Самое лучшее - это не абсолютная, а относительная погрешность.
А про ABS(b-a) - не забывай. Хотя ты от большего отнимаешь меньшее, но все-таки.


 
MegaVolt   (2002-06-14 16:35) [5]

Попробуй пройти по шагам на примере твоей простой функции х*х-9 и посмотри где он неправильно работает но по идее всё должно быть правильно я сам проверял в молодости когда ещё в институте учился так что попробуй и напиши где он начинает неправильно считать


 
Озадаченный   (2002-06-14 18:54) [6]

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

ZavDim: корни по идее должны быть, ведь он же их находит с точностью до 1е10, а дальше не хочет искать... не понимаю. Я делал счет почти по шагам и он "валится" где-то при значении Т=300, видимо, тут для него наступает что-то критическое...
Спасибо большое Вам за ответы, постараюсь учесть все советы и попробовать еще раз.


 
Озадаченный   (2002-06-14 18:58) [7]

я еще не понимаю почему тип Extended не хочет считать до большой точности, хотя может...


 
ZavDim   (2002-06-15 07:13) [8]

Да есть у него (Extended) точность, но относительная!
Попробуй прибавлять к 1 число 1e-39 и посмотри, что будет получаться - так 1 и останется. Он же не резиновый, он хранит ограниченное количество знаков. Если у тебя величины 1e10, то требуемая точность не может быть 1e-20 - хоть лопни (прога просто зациклится).
Возьми любое Extended(sqrt(2)) и посмотри сколько тебе знаков дастся, остальные, ты в этом представлении - под пыткой не вытащищь. Я когда считал тысячу знаков Pi, так использовал другое представление - свое собственное, а иначе ничего не посчитаешь.
x^2-9 - решается, потому, что диапазон валится вниз и приходит к обыденным числам, там можно обеспечить приличную абсолютную точность - но 1e-39 - не верю. 1е-20 еще туда сюда.
Далее. <Не хочет искать...валится> - что значит не хочет: вылетает, ругается - что происходит?


 
ZavDim   (2002-06-15 07:24) [9]

Про точность 1e-39 это я перекрутил, но выложи значения констант в своих функциях - я код покручу. Может и другое что. Ноя слегка по другому ищу.

type
F1=FUNCTION(T:EXTENDED):EXTENDED; {Одноместная функция}

PROCEDURE KORFUN(A,B,EPS:EXTENDED;F:F1;VAR X:EXTENDED;VAR C:BOOLEAN);
VAR B,YA,YB,YX:EXTENDED;
BEGIN
C:=TRUE;
YA:=F(A);
YB:=F(B);
X:=(B+A)/2;
YX:=F(X);
WHILE ABS(YX)>EPS DO
BEGIN
IF ABS(B-A)<SQR(EPSILON) THEN
BEGIN
C:=FALSE;
EXIT;
END;
IF YA*YX<0 THEN
BEGIN
B:=X;
YB:=YX;
END
ELSE
BEGIN
A:=X;
YA:=YX;
END;
X:=(B+A)/2;
YX:=F(X);
END;
END;

При этом, конечно подразумевается, что корень на участке [А,В]есть. Ну, а вызов уж организуешь, я думаю.
Это голый Pascal 7.0.


 
Озадаченный   (2002-06-18 12:54) [10]

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


 
Extended   (2002-06-18 13:30) [11]

Кстати, в хелпе написано, что Extended 3.6 x 10^–4951 .. 1.1 x 10^4932 так почему же он не вмещает значения хотя бы от 1 до 10^30 с точностью до 1?


 
Shaman_Naydak   (2002-06-19 09:43) [12]

> Extended
Потому, что это не целочисленный тип, а с плавающей запятой..
И точность представления - это 19-20 знаков, а уж сколько нуликов что в одну, что в другую сторону - це дело хозяйское


 
Lord Warlock   (2002-06-19 09:57) [13]

ИМХО для решения уравнения методом деления отрезка пополам точность 1Е-30 не нужна, достаточно 1Е-6


 
Dualsoft   (2002-06-19 11:25) [14]

В данном случае желательно варьировать параметр
точности менять в зависимости от интевала поиска.
Отношение не интервала поиска к заданной точности
не должно превышать 1е19-1е20.


 
Zavdim   (2002-06-20 11:49) [15]

Вот я и говорю, что надо использовать относительную погрешность.


 
Zavdim   (2002-06-21 11:56) [16]

На самом деле надо бы выложить константы и полный текст проги.
Почему она все-таки циклилась?
Единственное существенное из вышесказанного это то, что нельзя дичиться с точностью, но в один момент abs(b-a) - должно было занулиться. Я поэсперементировал с нижеприведенным кодом, разница всегда уходила в ноль.

var a,b:extended;
procedure TForm1.FormCreate(Sender: TObject);
begin
a:=1e-30;
b:=1e+30;
l1.Caption:=FloatToStr(a);
l2.Caption:=FloatToStr(b);
l3.Caption:=FloatToStr(b-a)
end;

procedure TForm1.Button1Click(Sender: TObject);
var r:extended;
i:integer;
begin
r:=(a+b)/2;
i:=random(2);
if i=1 then a:=r else b:=r;
l1.Caption:=FloatToStr(a);
l2.Caption:=FloatToStr(b);
l3.Caption:=FloatToStr(b-a)
end;

Разобраться можно. Так что нечего дурить - давай свой код - посмотрим.


 
Озадаченный   (2002-06-21 12:45) [17]

Вот код программы:

procedure TForm1.Button1Click(Sender: TObject);
var Nc,Nv,n,ni,Ec,Ev,Ed,Ea,EgT,Fa,Fx,x:Extended;
r,a,b,k,Nd,dEd,Eg0,mdn,Na,dEa,alpha,mdp:Extended;
T:integer;
F:TextFile;
begin
k:=8.62e-5;
Nd:=1e21;
dEd:=0.044;
Eg0:=1.21;
mdn:=1.08;
Na:=0;
dEa:=0.044;
alpha:=0.00028;
mdp:=0.59;
AssignFile(F,"otchet.txt");
Rewrite(F);
for T:=1 to 1500 do begin
EgT:=Eg0-alpha*T;
Ec:=EgT/2;
Ev:=-EgT/2;
Ed:=Ec-dEd;
Ea:=Ev+dEa;
r:=T*T; // по другому почему-то нельзя возвести T в куб (T*T*T - не получается)
r:=r*T;
Nc:=4.831e21*sqrt(mdn*mdn*mdn)*sqrt(r);
Nv:=4.831e21*sqrt(mdp*mdp*mdp)*sqrt(r);
ni:=sqrt(Nc*Nv)*exp(-(EgT/(2*k*T)));
a:=1e-30; //в принципе можно и от 1 использовать, вот только значения корней немного меняются почему-то
b:=1e22;
Fa:=a+Na/(2*exp((Ea-Ec-k*T*ln(a/Nc))/(k*T))+1)-ni*ni/a-Nd/(2*exp((Ec+k*T*ln(a/Nc)-Ed)/(k*T))+1);
repeat
x:=(a+b)/2;
Fx:=x+Na/(2*exp((Ea-Ec-k*T*ln(x/Nc))/(k*T))+1)-ni*ni/x-Nd/(2*exp((Ec+k*T*ln(x/Nc)-Ed)/(k*T))+1);
if Fa*Fx>0 then a:=x else b:=x;
until (ABS(Fx)<1) or (ABS(b-a)<1e10); //ABS(b-a)<1 не получается посчитать
n:=x;
WriteLn(F,"n = "+FloatToStr(n));
end;
CloseFile(F);
end;


мне нужно найти n, но почему-то при больших T корень не ищется, хотя должен теоретически лежать в пределах от 1 до 1e21 максимум.


 
Zavdim   (2002-06-21 14:28) [18]

>r:=T*T; // по другому почему-то нельзя возвести T в куб (T*T*T - не получается)
>r:=r*T;

все просто, то что результат будет Extended он не знает заранее, а обрабатывает его как Integer, а теперь прикинь 1500^3 - это integer?


 
Zavdim   (2002-06-21 15:34) [19]

1. Ну тут штука такая, у меня в проге все к 0 сходилось и баста - хорошо, а здесь не сходилось - дествительно в последних разрядах прога висла и не меняла ни a ни b. Я ввел относительную погрешность - стала что-то делать. Но это ерунда.
2. А откуда ты уверен, что корни есть? У меня получилось что
на концах промежутка имеем одинаковые знаки. Ощущение такое, что
y=0 горизонтальная ассимптота. При b=1e22 получаются значения на пределе вычислительных возможностей Паскаля - это же чистый ноль.
3. Зачем константа Na=0, откуда Nd=1e21, при том, что к другим константам отношение более точное?
4. Возьми MathCad, Excel и построй графики этой функции.
5. Из цикла поиска мы выходим по двум причинам, в этой программе только по второй - область поиска съузилась, то что мы имеем не корни.
6. Я слегка модифицировал прогу, посмотри отчет и определись чего ты хочешь.

procedure TForm1.Button1Click(Sender: TObject);
var Nc,Nv,n,ni,Ec,Ev,Ed,Ea,EgT,Fa,Fb,Fx,x:Extended;
r,a,b,k,Nd,dEd,Eg0,mdn,Na,dEa,alpha,mdp:Extended;
T:integer;
TT:extended;
F:TextFile;
function ff(x:extended):extended;
begin
Result:=x+Na/(2*exp((Ea-Ec-k*TT*ln(x/Nc))/(k*TT))+1)-ni*ni/x-Nd/(2*exp((Ec+k*TT*ln(x/Nc)-Ed)/(k*TT))+1);
end;
begin
Button1.Enabled:=false;
k:=8.62e-5;
Nd:=1e21;
dEd:=0.044;
Eg0:=1.21;
mdn:=1.08;
Na:=0;
dEa:=0.044;
alpha:=0.00028;
mdp:=0.59;
AssignFile(F,"otchet.txt");
Rewrite(F);
for T:=1 to 1500 do begin
TT:=T;
EgT:=Eg0-alpha*TT;
Ec:=EgT/2;
Ev:=-EgT/2;
Ed:=Ec-dEd;
Ea:=Ev+dEa;
r:=exp(3*ln(TT));
Nc:=4.831e21*sqrt(mdn*mdn*mdn)*sqrt(r);
Nv:=4.831e21*sqrt(mdp*mdp*mdp)*sqrt(r);
ni:=sqrt(Nc*Nv)*exp(-(EgT/(2*k*TT)));
a:=1;
b:=1e+22;
Fa:=ff(a);
Fb:=ff(b);
repeat
x:=(a+b)/2;
Fx:=ff(x);
if Fa*Fx>0
then begin
a:=x;
Fa:=Fx;
end else
begin
b:=x;
end;
until (ABS(Fx)<1) or (ABS((b-a)/b)<1e-15);
n:=x;
WriteLn(F,"T="+IntToStr(T)+" <> n = "+FloatToStr(n)+" <> f(n)="+FloatToStr(n));
end;
CloseFile(F);
Button1.Enabled:=true;
end;

Желаю удачи. И вообще переходи на мыло, а то форум раздувается.


 
Zavdim   (2002-06-22 07:51) [20]

чтобы подвести некоторый итог:
1. Не надо пренебрегать точностью представления данных.
2. Прежде чем, что-то искать надо определиться с теорией, - ксожалению, по опыту знаю, что многие программисты плюют на математику и теорию, а это в итге порочно.
3. x^2-9=0 для приведенного приложения хороший пример, а вот, например, x^2-3x+2=0 - решений не даст, а даст огромные числа кои решениями не являются. Поэтому отделение корней не забава, а суровая необходимость.
4. Модификация должна состоять в том, что надо просто отделить корни (!!если они есть!!).

Трудно искать в темной комнате черную кошку, особенно...

Данные промахи полезны новичку, сам тонны соли на этом съел...
Но лучше самому разбираться в программе проходом по шагам, в данном случае ошибка выплывает при T=34.

Желаю удачи.


 
Озадаченный   (2002-06-24 11:59) [21]

Zavdim, Спасибо большое за помощь, попробую еще раз все перерасчитать и проверить точность



Страницы: 1 вся ветка

Форум: "Система";
Текущий архив: 2002.09.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.007 c
3-13943
S@shka
2002-07-29 21:10
2002.09.05
Доступ к базе нескольких клиентов


1-14070
ao1973
2002-08-27 11:04
2002.09.05
Разными цветами в ComboBox -е


1-13999
Roxtady
2002-08-22 16:48
2002.09.05
Как склеить два Pchar


4-14339
Марина
2002-07-05 14:44
2002.09.05
ShellExecute и ARJ.exe


8-14181
Ptushenko Denis
2002-04-25 10:02
2002.09.05
Как определить есть ли звуковая карта на компе ?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский