大数组c ++

时间:2016-02-20 18:09:46

标签: c++ arrays windows gcc g++

我有一个主课程的任务,涉及通过蒙特卡罗方法对概率分布进行采样。我之前想要进行一些测试,所以我用2自由度对卡方分布进行采样(可以用逆方法完成)。无论如何,我遇到了数组大小的问题,任何超过~30000个元素的元素都会导致概率分布的所有点累积为1,甚至会导致程序崩溃。

在帖子的最后,您可以看到结果的截图,包含10000点和我编写的代码。我已经使用了g ++编译器的许多版本,最高可达4.9.2,但它们都没有工作。操作系统是Windows 7.Aaaand相同的代码在朋友的gentoo计算机上完美运行。有什么建议吗?

提前致谢!

Manuel J。

Sampling with 10000 points

以下是我正在使用的代码:

I've removed it to keep the post shorter. Please see edited code

编辑:我对代码进行了一些更改,主要是从普通数组到向量的转换,问题仍然存在:超过~10000个元素的任何内容都无效。问题肯定是histograma函数:当histo.dat文件给它一个太大的向量时,它的内容是:

inf 100000
inf 0
inf 0
inf 0
...
inf 0

现在的代码如下。问题绝对是最大和最小功能,但我对问题的确切位置一点也不了解。

#include <iostream>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <vector>
#define PI 3.14159265359
#define NHISTOMAX 100
#define N 100000
#define GNUPLOT_PATH "D:\\gnuplot\\bin\\gnuplot.exe -persist"
using namespace std;
double max (vector<double> v);
double min (vector<double> v);
void histoplot (string name1);
void histograma (string name, vector<double> v, size_t num2);

vector<double> v(N);

int main (void)
{   
    srand(time(NULL));

    for(size_t i=0;i<N;i++)
    v[i]=-2*log(1.0*rand()/RAND_MAX);

    histograma("hist.dat",v,NHISTOMAX);

    histoplot("hist.dat");

    system("pause");
    return 0;
}

void histograma (string name, vector<double> v, size_t num2)
{
    ofstream fileout;
    double max1, min1, delta;
    size_t i, j, num=v.size();
    vector<int> histo(NHISTOMAX);

    if(num2>NHISTOMAX) cout << "Too many intervals. " << endl;

    else
    {
        for(i=0;i<num2;i++)
            histo[i]=0;

        max1=max(v);
        min1=min(v);
        delta=(max1-min1)/num2;

        for(i=0;i<num;i++)
        {
            j=(size_t)((v[i]-min1)/delta); 
            if(j==NHISTOMAX) j--;
            histo[j]++;
        }

        fileout.open(name.c_str());
        for(i=0;i<num2;i++)
            fileout << min1+(i+0.5)*delta << "\t" << histo[i] << endl;
        fileout.close();

        cout << "Histogram generated! Output file: " << name << endl << endl;
    }

    return;
}

void histoplot (string name1)
{
    FILE *gp1;
    gp1=popen(GNUPLOT_PATH,"w");

    if(gp1==NULL)
        cout << "Unable to open pipe. Check gnuplot.exe's path" << endl;

    else
    {
        fprintf(gp1,"unset key\n");
        fprintf(gp1,"set term wxt\n");
        fprintf(gp1,"set output\n");
        fprintf(gp1,"plot '");
        fprintf(gp1,name1.c_str());
        fprintf(gp1,"' w histeps\n");
        fflush(gp1);
        pclose(gp1);
    }

    return;
}

double max (vector<double> v)
{
    double aux=v[0];
    size_t i, num=v.size();
    for(i=1;i<num;i++)
        if(aux<v[i])
            aux=v[i];
    return aux;
}

double min (vector<double> v)
{
    double aux=v[0];
    size_t i, num=v.size();
    for(i=1;i<num;i++)
        if(aux>v[i])
            aux=v[i];
    return aux;
}

编辑2:v向量中值的典型图。所有这些都是积极的,低于25岁。

Plot of a typical vector obtained.

2 个答案:

答案 0 :(得分:1)

使用std::vector

#include <vector>
#define N 10000
int main (void)
{
    std::vector<double> v(N); 
    //...
    histograma("hist.dat",v.data(), N, NHISTOMAX);  
    // or
    // histograma("hist.dat", &v[0], N, NHISTOMAX);  

请注意,不需要更改histograma函数本身。调用的唯一区别是v.data()(或&v[0])用于返回指向存储double数组的内部缓冲区开头的指针。

此外,请使用min标题中的maxstd::min_element,而不是撰写std::max_element<algorithm>个函数:

    max1 = *std::max_element(v.begin(), v.end());
    min1  = *std::min_element(v.begin(), v.end());

或者如果使用C ++ 11,std::minmax_element来获取两者:

    auto pr = std::minmax_element(v.begin(), v.end());
    min1 = *(pr.first);
    max1 = *(pr.second);

另外,如果正如其他答案所示,并且您有内存覆盖,我建议您使用operator [ ]更改为使用vector::at()来访问您的元素。一旦进行越界访问,使用at()将抛出out_of_range异常。然后在转换回使用[ ]向量之前修复这些错误。

例如,此代码:

        j=(size_t)((v[i]-min1)/delta); 
        if(j==NHISTOMAX) j--;
        histo[j]++;

如果j是一个巨大的数字,远远超过histo向量的边界怎么办?将j递减1并不会有所帮助。要查看这是否是一个问题,可以在此处使用at()

        j=(size_t)((v[i]-min1)/delta); 
        if(j==NHISTOMAX) j--;
        histo.at(j)++;

如果运行程序,如果j超出范围,则在尝试递增histo[j]时会抛出异常。然后,您可以检查问题并修复错误。

答案 1 :(得分:0)

看起来你有一个潜在的阵列溢出:

    delta = (max1-min1)/num2;
   ...
        j = (int)((v[i]-min1)/delta);
        histo[j]++;

v[i] == max1这使得j == num2 == NHISTOMAXhisto[NHISTOMAX]超出范围时(最后一个有效元素为NHISTOMAX-1,因为数组索引从0开始)。

由于您将问题标记为C ++,我将使用std::vector<double>而不是原始数组:

#include <vector>
...
std::vector<double> v(N);
...
void histograma (string name, const std::vector<double> v, const int maxHistoSize)
{
     std::vector<double> histo(maxHistoSize + 1);
     ...
     delta = (max1 - min1) / maxHistoSize;
...    

      // There's likely a more C++ idiomatic way to get the min/max of a 
      // std::vector<> but this works fine with a few changes.
double max (const std::vector<double> v)
{
    double minValue = v[0];

    for(int i = 1; i< v.size(); i++) 
    {
         if (minValue < v[i]) minValue = v[i];
    }

    return aux;
}

// Same for min()