2013-08-09 23 views
8

Od czasu do czasu otrzymuję wyjątek stackoverflow w tej metodzie.Przyczyna przepełnienia stosu w tej metodzie (zmiennoprzecinkowa)

double norm_cdf(const double x) { 
    double k = 1.0/(1.0 + 0.2316419*x); 
    double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k)))); 

    if (x >= 0.0) { 
     return (1.0 - (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum); 
    } else { 
     return 1.0 - norm_cdf(-x); 
    } 
} 

Jakieś sugestie, dlaczego mogę je otrzymywać? Jakie kroki mogę podjąć, aby naprawić błąd?

+4

Nie sięgnął w głąb swojej logiki jeszcze, ale to, co podejrzewam, że '1.0 - norm_cdf (-x)' wytwarza negatywny wynik dla jakiegoś powodu od czasu do czasu, który mógłby doprowadzić do nieograniczonej rekursji – StephenTG

+0

Aby potwierdzić, czy masz kilka przykładowych danych wejściowych, które wyzwalają wyjątek SO? – StephenTG

+2

Naprawdę nie ma potrzeby rekursji na ten problem ... –

Odpowiedz

15

Prawdopodobnie tą metodą jest właśnie słoma, która łamie grzbiet wielbłąda. Ta funkcja wywoła się tylko raz, więc nie jest to problem. (Edit: A może to kwestia NAN inni wskazują, który będzie wynik w nieskończonej rekursji.)

Można łatwo funkcja nie rekurencyjnych zresztą, co może być prostsze rozwiązanie.

double norm_cdf(double x) { 
    bool negative = x < 0; 
    x = abs(x); 
    double k = 1.0/(1.0 + 0.2316419*x); 
    double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k)))); 

    double result = (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum; 
    if (!negative) 
     result = 1.0 - result; 
    return result; 
} 
+0

Nie, zobacz odpowiedź Dave'a - 'NAN' spowoduje nieskończoną rekursję. –

+0

Lub ... NAN, jeśli tak naprawdę to się dzieje. –

+2

+1 za usunięcie rekursji. –

8

Gdy x jest NaN, rekursja nigdy się nie zakończy. Dodaj czek: albo std::isnan w C++ 11, albo leniwy x != x, albo użytkownik-i-winien dokumentu. Jeśli zdecydujesz się obsłużyć NaN, propagowanie go może być rozsądnym wyborem.

+0

Czy możesz mi powiedzieć, jak x! = X pomoże – Rajeshwar

+3

@Rajeshwar: To jest brudny test na to, czy liczba zmiennoprzecinkowa to 'NaN'. 'NaN' to jedyna wartość zmiennoprzecinkowa, która nie jest równa sobie. –

+0

Od NaN! = NaN – StephenTG

24

Problem polega na tym, że x nie jest liczbą. NAN >= 0.0 jest fałszywe, -NAN >= 0.0 jest również fałszywe.

Można sprawdzić przed NAN specjalnie, jak inni sugerują, ale chciałbym zaproponować upraszczające rzeczy:

static double norm_cdf_positive(const double x) { 
    double k = 1.0/(1.0 + 0.2316419*x); 
    double k_sum = k*(0.319381530 + k*(-0.356563782 + k*(1.781477937 + k*(-1.821255978 + 1.330274429*k)))); 

    return (1.0 - (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x) * k_sum); 
} 

double norm_cdf(const double x) { 
    if (x >= 0.0) { 
     return norm_cdf_positive(x); 
    } else { 
     return 1.0 - norm_cdf_positive(-x); 
    } 
} 

Ma to tę zaletę, że kompilatory mogą podejmować bardziej założenia o jego zachowanie. Zauważ, że zaznaczyłem funkcję "wewnętrzną" statyczną (która ograniczy jej zasięg do aktualnej jednostki kompilacji). Możesz także użyć nienazwanych przestrzeni nazw. (edytuj: faktycznie Timothy Shields ma prostszy sposób na usunięcie rekursji, która zachowuje wszystko w jednej funkcji)

+0

czy mógłbyś mi powiedzieć, co to jest NAN? – Rajeshwar

+4

Nie numer. Na przykład '0.0/0.0' lub' sqrt (-1,0) '(chyba że używasz liczb zespolonych). Pojawia się od czasu do czasu w miejscach, w których nie spodziewałbyś się tego, chyba że starasz się go uniknąć. – Dave

+0

NAN nie jest numerem. Jest to wynikiem nieważnych obliczeń (ale nie tak prostych jak błędy dzielenia przez zero). – abelenky

Powiązane problemy