Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Ада и другие языки _ [С++ Builder 6] pow: domain error

Автор: 18192123 18.10.2009 20:03

Здравствуйте!

Столкнулась вот с такой проблемой:
В программе генерируются случайные числа, распределённые по нормальному з-ну. Но суть не совсем в этом.
Когда требуется сгенерировать 500-1000 значений - всё нормально, когда же я захотела получить 10 000 значений - ошибка pow: DOMAIN error..


double xi = 0, xiStar = 0, yi = 0;
float sigma1 = 1, sigma3 = 1;
float m1 = 5, m3 = 3;
..............
double GaussLow(int var)
{
randomize;
xi = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
xiStar = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
switch (var)
{
case 1:
yi = sigma1 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1/2) + m1;
break;
case 2:
yi = sigma3 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1/2) + m3;
}
return yi;
}
............
void __fastcall TForm2MS::ButGenClick(TObject *Sender)
{
double tempG = 0;
int test = 10000;
StrGrGen->RowCount = test+1;
StrGrGen->Visible = true;
StrGrGen->Cells[1][0] = "Íîðìàëüíûé ç-í";
StrGrGen->Cells[2][0] = "Íîðìàëüíûé ç-í";
for (int i=0;i<test;i++)
{
StrGrGen->Cells[0][i+1] = i+1;
tempG = GaussLow(1);
StrGrGen->Cells[1][i+1] = FloatToStrF(tempG,ffFixed,8,5);
tempG = 0;
tempG = GaussLow(2);
StrGrGen->Cells[2][i+1] = FloatToStrF(tempG,ffFixed,8,5);
}
}


Объясните пожалуйста, в чём тут дело? Как избежать ошибки..?
Подозреваю, что проблема можеть быть связана с областями определения (значения) pow или log10..

Автор: volvo 18.10.2009 20:35

Во-первых, randomize()... Во-вторых, этот самый randomize() в цикле запускать нельзя, только перед началом вычислений, однократно. В третьих, желательно переменную yi сделать ЛОКАЛЬНОЙ:

double xi = 0., xiStar = 0.;
double sigma1 = 1., sigma3 = 1.;
double m1 = 5., m3 = 3.;

double GaussLow(int var)
{
double yi; // Три
xi = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
xiStar = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
switch (var)
{
case 1:
yi = sigma1 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1/2) + m1;
break;
case 2:
yi = sigma3 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1/2) + m3;
}
return yi;
}
void __fastcall TForm2MS::ButGenClick(TObject *Sender)
{
// раз, два
randomize();

double tempG = 0;
int test = 10000;

StrGrGen->RowCount = test+1;
StrGrGen->Visible = true;
StrGrGen->Cells[1][0] = "Íîðìàëüíûé ç-í";
StrGrGen->Cells[2][0] = "Íîðìàëüíûé ç-í";
for (int i=0;i<test;i++)
{
StrGrGen->Cells[0][i+1] = i+1;
tempG = GaussLow(1);
StrGrGen->Cells[1][i+1] = FloatToStrF(tempG,ffFixed,8,5);
tempG = 0;
tempG = GaussLow(2);
StrGrGen->Cells[2][i+1] = FloatToStrF(tempG,ffFixed,8,5);
}
}
и куда делся domain error? smile.gif

Автор: 18192123 18.10.2009 21:17

Цитата(volvo @ 18.10.2009 17:35) *

и куда делся domain error? smile.gif


я добавила ещё одну ф-ю EXpLow для генерации чисел, распределённых по экспоненциальному з-ну..
внесла изменения относительно randomize..
Запустила - отработало без ошибок!
Запустила снова - тут вам кроме pow: DOMAIN error, и log10: SING error, и pow: OVERFLOW error..

Вот как-то так.. blink.gif

//---------------------------------------------------------------------------

#include <vcl.h>
#include <math.h>
#pragma hdrstop

#include <utilcls.h>
#include <sysvari.h>
#include <ComObj.hpp>

#include "UnitMain.h"
#include "Unit_Stochastic_variables.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2MS *Form2MS;

//my description
double xi = 0., xiStar = 0.;
double sigma1 = 1., sigma3 = 1.;
double m1 = 5., m3 = 3.;
double lambda2 = 0.16;
//---------------------------------------------------------------------------
__fastcall TForm2MS::TForm2MS(TComponent* Owner)
: TForm(Owner)
{

}
//---------------------------------------------------------------------------
double GaussLow(int var)
{
double yi;
xi = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
xiStar = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
switch (var)
{
case 1:
yi = sigma1 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1/2) + m1;
break;
case 2:
yi = sigma3 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1/2) + m3;
}
return yi;
}
//---------------------------------------------------------------------------
double ExpLow()
{
double yi;
xi = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
yi = (-1/lambda2) * log10(xi);
return yi;
}

void __fastcall TForm2MS::ButGenClick(TObject *Sender)
{
randomize();
double tempG = 0, tempE = 0;
int test = 10000;
StrGrGen->RowCount = test+1;
StrGrGen->Visible = true;
StrGrGen->Cells[1][0] = "Нормальный з-н";
StrGrGen->Cells[2][0] = "Нормальный з-н";
StrGrGen->Cells[3][0] = "Показательный з-н";
for (int i=0;i<test;i++)
{
StrGrGen->Cells[0][i+1] = i+1;
tempG = GaussLow(1);
StrGrGen->Cells[1][i+1] = FloatToStrF(tempG,ffFixed,8,5);
tempG = 0;
tempG = GaussLow(2);
StrGrGen->Cells[2][i+1] = FloatToStrF(tempG,ffFixed,8,5);
tempE = ExpLow();
StrGrGen->Cells[3][i+1] = FloatToStrF(tempE,ffFixed,8,5);
}
}




Автор: volvo 18.10.2009 21:47

case 1:
yi = sigma1 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1./2.) + m1; // <-- 1/2 в Сях = 0, тебе надо 1.0/2.0
break;
case 2:
yi = sigma3 * cos(2*M_PI*xi) * pow(-2*log10(xiStar),1./2.) + m3; // <-- Здесь - то же самое
Внимательнее с этими вещами...

Автор: 18192123 20.10.2009 0:45

Ну просто напасть какая-то...Я снова увеличиваю размер генерируемой последовательности (до 60 000 элементов) - и вновь лезут ошибки log10:sign error... И в чём же теперь причина - для меня непостижимо(
Может рандом выдаёт какое-то недопустимое значение аргумента...?

Автор: volvo 20.10.2009 1:58

Цитата
Может рандом выдаёт какое-то недопустимое значение аргумента...?
Вполне возможно... Я тебе даже скажу какое значение должно выдаваться, чтобы ты получала то, что получаешь: НОЛЬ... Если rand() вернул 0, то xiStar (естественно) тоже будет = 0, а это некорректные входные данные, это оговорено в описании функции. Так что придется тебе гарантировать, что аргумент log10 не будет нулевым. Ну, например, так:
int sure_rand()
{
int rnd = rand();

if(!rnd) rnd += 1;
return rnd;
}
...
xiStar = static_cast<double>(sure_rand()) / static_cast<double>(RAND_MAX);


Если сделать просто:
xiStar = static_cast<double>(rand() + 1) / static_cast<double>(RAND_MAX);
, то получишь сбой, когда rand() вернет RAND_MAX... Тогда xiStar примет значение > 1, следовательно log10(xiStar) станет больше 0, и ты попытаешься вычислить квадратный корень из отрицательного числа. Поверь, ни к чему хорошему это не приведет...