2017-02-28 91 views
1

我想计算安德森达令测试发现here。我遵循维基百科上的步骤,并确保在计算我正在测试的数据的平均值和标准偏差时,使用MATLAB表示为X。另外,我使用了一个叫phi的函数来计算标准正常CDF,我也测试了这个函数以确保它是正确的。现在,当我实际计算A平方(在维基百科中表示,我在C++中将其表示为A)时,似乎出现了问题。安德森达林测试C++

这里是我的功能,我对安德森 - 达林检验进行:

void Anderson_Darling(int n, double X[]){ 
    sort(X,X + n); 
    // Find the mean of X 
    double X_avg = 0.0; 
    double sum = 0.0; 
    for(int i = 0; i < n; i++){ 
     sum += X[i]; 
    } 
    X_avg = ((double)sum)/n; 


    // Find the variance of X 
    double X_sig = 0.0; 
    for(int i = 0; i < n; i++){ 
     X_sig += (X[i] - X_avg)*(X[i] - X_avg); 
    } 
    X_sig /= n; 


    // The values X_i are standardized to create new values Y_i 
    double Y[n]; 
    for(int i = 0; i < n; i++){ 
     Y[i] = (X[i] - X_avg)/(sqrt(X_sig)); 
     //cout << Y[i] << endl; 
    } 

    // With a standard normal CDF, we calculate the Anderson_Darling Statistic 
    double A = 0.0; 
    for(int i = 0; i < n; i++){ 
     A += -n - 1/n *(2*(i) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n+1 - i]))); 
    } 
    cout << A << endl; 
} 

注意,我知道,安德森 - 达林式(A方)与i = 1开始i = n,虽然当我改变了索引使它在C++中工作,我仍然得到相同的结果而不改变索引。

我在C++中获得的价值是:

-4e+006 

我应该得到的值,在MATLAB收到的是:

0.2330 

任何建议都非常赞赏。

这里是我的全部代码:

#include <iostream> 
#include <math.h> 
#include <cmath> 
#include <random> 
#include <algorithm> 
#include <chrono> 

using namespace std; 

double *Box_Muller(int n, double u[]); 
double *Beasley_Springer_Moro(int n, double u[]); 
void Anderson_Darling(int n, double X[]); 
double phi(double x); 

int main(){ 
    int n = 2000; 
    double Mersenne[n]; 
    random_device rd; 
    mt19937 e2(1); 
    uniform_real_distribution<double> dist(0, 1); 
    for(int i = 0; i < n; i++){ 
     Mersenne[i] = dist(e2); 
    } 

    // Print Anderson Statistic for Mersenne 6a 
    double *result = new double[n]; 
    result = Box_Muller(n,Mersenne); 
    Anderson_Darling(n,result); 




    return 0; 
} 

double *Box_Muller(int n, double u[]){ 
    double *X = new double[n]; 
    double Y[n]; 
    double R_2[n]; 
    double theta[n]; 
    for(int i = 0; i < n; i++){ 
     R_2[i] = -2.0*log(u[i]); 
     theta[i] = 2.0*M_PI*u[i+1]; 
    } 
    for(int i = 0; i < n; i++){ 
     X[i] = sqrt(-2.0*log(u[i]))*cos(2.0*M_PI*u[i+1]); 
     Y[i] = sqrt(-2.0*log(u[i]))*sin(2.0*M_PI*u[i+1]); 
    } 
    return X; 
} 

double *Beasley_Springer_Moro(int n, double u[]){ 
    double y[n]; 
    double r[n+1]; 
    double *x = new double(n); 
    // Constants needed for algo 
    double a_0 = 2.50662823884;  double b_0 = -8.47351093090; 
    double a_1 = -18.61500062529; double b_1 = 23.08336743743; 
    double a_2 = 41.39119773534; double b_2 = -21.06224101826; 
    double a_3 = -25.44106049637; double b_3 = 3.13082909833; 

    double c_0 = 0.3374754822726147; double c_5 = 0.0003951896511919; 
    double c_1 = 0.9761690190917186; double c_6 = 0.0000321767881768; 
    double c_2 = 0.1607979714918209; double c_7 = 0.0000002888167364; 
    double c_3 = 0.0276438810333863; double c_8 = 0.0000003960315187; 
    double c_4 = 0.0038405729373609; 

    // Set r and x to empty for now 
    for(int i = 0; i <= n; i++){ 
     r[i] = 0.0; 
     x[i] = 0.0; 
    } 
    for(int i = 1; i <= n; i++){ 
     y[i] = u[i] - 0.5; 
     if(fabs(y[i]) < 0.42){ 
      r[i] = pow(y[i],2.0); 
      x[i] = y[i]*(((a_3*r[i] + a_2)*r[i] + a_1)*r[i] + a_0)/((((b_3*r[i] + b_2)*r[i] + b_1)*r[i] + b_0)*r[i] + 1); 
     }else{ 
      r[i] = u[i]; 
      if(y[i] > 0.0){ 
       r[i] = 1.0 - u[i]; 
       r[i] = log(-log(r[i])); 
       x[i] = c_0 + r[i]*(c_1 + r[i]*(c_2 + r[i]*(c_3 + r[i]*(c_4 + r[i]*(c_5 + r[i]*(c_6 + r[i]*(c_7 + r[i]*c_8))))))); 
      } 
      if(y[i] < 0){ 
       x[i] = -x[i]; 
      } 
     } 
    } 
    return x; 
} 

    double phi(double x){ 
    return 0.5 * erfc(-x * M_SQRT1_2); 
} 


void Anderson_Darling(int n, double X[]){ 
    sort(X,X + n); 
    // Find the mean of X 
    double X_avg = 0.0; 
    double sum = 0.0; 
    for(int i = 0; i < n; i++){ 
     sum += X[i]; 
    } 
    X_avg = ((double)sum)/n; 


    // Find the variance of X 
    double X_sig = 0.0; 
    for(int i = 0; i < n; i++){ 
     X_sig += (X[i] - X_avg)*(X[i] - X_avg); 
    } 
    X_sig /= (n-1); 


    // The values X_i are standardized to create new values Y_i 
    double Y[n]; 
    for(int i = 0; i < n; i++){ 
     Y[i] = (X[i] - X_avg)/(sqrt(X_sig)); 
     //cout << Y[i] << endl; 
    } 

    // With a standard normal CDF, we calculate the Anderson_Darling Statistic 
    double A = -n; 
    for(int i = 0; i < n; i++){ 
     A += -1.0/(double)n *(2*(i+1) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n - i]))); 
    } 
    cout << A << endl; 
} 
+2

在调试器中浏览代码并找出发生了什么。 –

+0

@AnonMail好的我正在使用Eclipse,通过确保我具有用于计算X的平均值和标准偏差的相同值进行调试。您是否建议使用Eclipse调试器? – Scooby

+0

在附注中,你为什么要重写自己的'Phi'?我在过去做过,但后来转而使用'std :: erfc'和'std :: erf',这非常准确和快速。 –

回答

3

让我猜,你的n是2000.对吗? 这里的主要问题是当你在最后一个表达式中做1/n。 1是一个int并且ao是n。当你用n除1时,它执行整数除法。现在1除以任意数字> 1在整数除法下为0(认为如果它只保留商的整数部分,那么你需要做的是通过写入1 /(double)n来将n写成双精度数n

其余的就应该可以正常

摘要从讨论 -

  1. 索引到Y []应该是我和n-1-I分别为
  2. n应不会在循环,但仅添加一次。 。

小修正像计算方差时将除数改为n而不是n-1。

+0

我看,我试过这样做,但我得到这个值-3.998e + 006和Matlab得到0.2330,所以我不知道什么是错的 – Scooby

+0

得到了你的错误。这不是一个编码错误,但是您在翻译公式时犯了一个错误。 A是 - n - S。 S是总和。你每次都添加了-n。结果你获得了巨大的负面价值。初始化A = -n并将其从循环中移除。 –

+0

对不起,你可以更具体地说明我需要做什么,我完全不理解你的评论 – Scooby

2

你有整数除法这里:

A += -n - 1/n *(2*(i) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n+1 - i]))); 
      ^^^ 

1/n为零时n > 1 - 你需要这种改变,如:1.0/n

A += -n - 1.0/n *(2*(i) - 1)*(log(phi(Y[i])) + log(1 - phi(Y[n+1 - i]))); 
      ^^^^^ 
+0

谢谢,我这样做了,但是我得到了-3.998e + 006而不是正确的值。由于A平方的公式是从i = 1开始的,我从i = 0开始,因为这就是数组如何在C++中编入索引,是否需要更改A的公式?也许让我所有的i + 1? – Scooby

+0

我对你使用的公式不熟悉,但是从你所说的听起来你需要修复索引,即使用'(i + 1)'而不是'i'。 –

+0

这很奇怪,我仍然得到相同的值-3.998e + 006,当它应该是.2330。 – Scooby