包装正态分布C ++

时间:2015-12-03 16:35:31

标签: c++ visual-c++ normal-distribution

有人知道在C ++中生成包装正态分布吗?我有一个平均和循环的标准偏差,并且想知道C ++是否有一些函数可以从包装的正态分布中生成值,类似于它们的标准正态分布。

1 个答案:

答案 0 :(得分:1)

简而言之,C++ 中没有生成包装正态分布的本机函数,但有几种简单的方法可以计算它。

1。使用提升

包裹正态分布 (WND) 与 Jacobi theta 函数 (see here) 相关。具体来说,它可以根据 Boost 中可用的“第三个”Jacobi theta 函数来表述:

    #include <boost/math/special_functions/jacobi_theta.hpp>

    /// Calculate the density function at angle given sigma and mean my.
    double wnd_density(double angle,double my,double sigma)
    {
        double a=(angle-my)/180.0*M_PI;
        double s=sigma/180.0*M_PI;
        return 1.0/(2.0*M_PI)*boost::math::jacobi_theta3tau(0.5*a,(0.5*s*s)/M_PI);
    }

2.使用迭代公式

不幸的是,Boost 没有提供一种简单的方法来实现累积 WND。尽管如此,使用第三个 Jacobi theta 函数的简单迭代来实现这个(以及 WND)是相当容易的。详细信息在 the Wikipedia entry 中给出。 可以使用相同的技巧来计算不定积分,该不定积分可以通过每次替换积分 see here 从迭代公式导出。

对于较大的 sigma 值,两次迭代都会快速收敛到机器精度(对于 20° 以上的 sigma,大约需要 30 次以下的迭代),较小的 sigma 值需要大约 800 次迭代才能达到机器精度。如果这太多了,您可以在给定的代码中明确设置更大的 eps。

    /// Calculate the indefinite integral of the third Jacobi Theta function as described in
    /// https://en.wikipedia.org/wiki/Theta_function
    /// Set eps<0 to iterate until machine precision.
    double jacobi_theta3_iterate(double z,double q,double eps=-1.0)
    {
        double th1=1.0,acc=1.0;
        int k=0;
        // This will converge depending on the value of q.
        if(eps<0.0)
        {
            while(th1+acc>th1)
            {
                k++;
                acc=2.0*pow(q,k*k); // an estimate for the accuracy
                th1+=acc*cos(2.0*z*k);
            }
        }
        else
        {
            while(fabs(acc)>=eps)
            {
                k++;
                acc=2.0*pow(q,k*k); // an estimate for the accuracy
                th1+=acc*cos(2.0*z*k);
            }
        }
        return th1;
    }

    /// Calculate the density function at angle given sigma and mean my.
    double wnd_density(double angle,double my,double sigma)
    {
        double a=(angle-my)/180.0*M_PI;
        double s=sigma/180.0*M_PI;
        return 1.0/(2.0*M_PI)*jacobi_theta3_iterate(0.5*a,exp(-0.5*s*s));
    }

    /// Calculate the indefinite integral of the third Jacobi Theta function as described in
    /// https://functions.wolfram.com/EllipticFunctions/EllipticTheta3/21/01/01/
    /// Set eps<0 to iterate until machine precision.
    double jacobi_theta3_integral(double z,double q,double eps=-1.0)
    {
        double th1=z,acc=1.0;
        int k=0;
        // This will converge depending on the value of q.
        if(eps<0.0)
        {
            while(th1+acc>th1)
            {
                k++;
                acc=pow(q,k*k)/k; // an estimate for the accuracy
                th1+=acc*sin(2.0*z*k);
            }
        }
        else
        {
            while(fabs(acc)>eps)
            {
                k++;
                acc=pow(q,k*k)/k; // an estimate for the accuracy
                th1+=acc*sin(2.0*z*k);
            }
        }
        return th1;
    }

    /// Calculate the cumulated density function at angle given sigma and mean my.
    double wnd_cumulated_density(double angle,double my,double sigma)
    {
        double a=(angle-my)/180.0*M_PI;
        double za=(0.0-my)/180.0*M_PI;
        double s=sigma/180.0*M_PI;
        double zero_v=jacobi_theta3_integral(0.5*za,exp(-0.5*s*s));
        return 1.0/M_PI*(jacobi_theta3_integral(0.5*a,exp(-0.5*s*s))-zero_v);
    }

当您使用循环来迭代评估 acc 的迭代而不是昂贵的 pow 函数时,您可以节省大量运行时间。