2013-08-09 26 views
8

Tôi thỉnh thoảng nhận được ngoại lệ stackoverflow trong phương pháp này.Nguyên nhân của tràn ngăn xếp trong phương pháp này (toán học dấu phẩy động)

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); 
    } 
} 

Bất kỳ đề xuất nào về lý do tôi có thể nhận được? Bất kỳ bước nào tôi có thể thực hiện để khắc phục lỗi?

+4

tôi đã không đi sâu vào logic của bạn, nhưng những gì tôi nghi ngờ là '1.0 - norm_cdf (-x) 'là tạo ra một kết quả tiêu cực đối với một số lý do thỉnh thoảng, trong đó có thể có thể dẫn đến vô biên đệ quy – StephenTG

+0

Để xác nhận, bạn có một số đầu vào mẫu đang kích hoạt ngoại lệ SO không? – StephenTG

+2

Có thực sự không cần phải đệ quy về vấn đề này ... –

Trả lời

15

Có khả năng phương pháp này chỉ là rơm phá vỡ lưng của con lạc đà. Chức năng này sẽ chỉ gọi chính nó nhiều nhất một lần, vì vậy nó không phải là vấn đề. (Edit: Hoặc đó là vấn đề NAN khác trỏ đến, mà sẽ kết quả trong đệ quy vô hạn.)

Bạn có thể dễ dàng thực hiện các chức năng không đệ quy dù sao, mà có thể là một lựa chọn đơn giản hơn.

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

Không, hãy xem câu trả lời của Dave - 'NAN' sẽ gây ra sự đệ quy vô hạn. –

+0

Hoặc ... NAN nếu đó thực sự là những gì đang xảy ra. –

+2

+1 để loại bỏ đệ quy. –

8

Khi xNaN, việc đệ quy sẽ không bao giờ chấm dứt. Thêm séc: Hoặc là std::isnan trong C++ 11 hoặc số x != x lười biếng hoặc người dùng tài liệu và đổ lỗi. Nếu bạn chọn để xử lý NaN, tuyên truyền nó có thể là một sự lựa chọn hợp lý.

+0

Bạn có thể cho tôi biết cách x! = X sẽ giúp – Rajeshwar

+3

@Rajeshwar: Đó là một thử nghiệm bẩn cho biết số dấu phẩy động là 'NaN'. 'NaN' là giá trị dấu phẩy động duy nhất không bằng với chính nó. –

+0

Vì NaN! = NaN – StephenTG

24

Vấn đề của bạn là khi x không phải là số. NAN >= 0.0 là sai, -NAN >= 0.0 cũng sai.

Bạn có thể kiểm tra chống lại NAN đặc biệt, như những người khác đã gợi ý, nhưng tôi sẽ đề nghị điều đơn giản hóa:

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); 
    } 
} 

này có ưu điểm là trình biên dịch có thể làm cho các giả định thông minh về hành vi của nó. Lưu ý rằng tôi đã đánh dấu chức năng tĩnh "nội bộ" (sẽ giới hạn phạm vi của nó đối với đơn vị biên dịch hiện tại). Bạn cũng có thể sử dụng không gian tên không tên. (chỉnh sửa: thực sự Timothy Shields có cách đơn giản hơn để loại bỏ đệ quy, giữ mọi thứ trong một chức năng)

+0

u có thể cho tôi biết NAN là gì không? – Rajeshwar

+4

Không phải là số. Ví dụ '0.0/0.0' hoặc' sqrt (-1.0) '(trừ khi bạn đang sử dụng các số phức). Nó xuất hiện ở mọi nơi, nơi bạn không mong đợi nó, trừ khi bạn đã cố gắng tránh né nó. – Dave

+0

NAN không phải là số A. Đó là kết quả của các phép tính không hợp lệ (nhưng không đơn giản như lỗi Divide-by-zero) – abelenky