C ++为什么原始双精度数组中的赋值似乎比双变量赋值快得多?

时间:2019-05-14 10:30:47

标签: c++ arrays performance variable-assignment

我正在尝试编写Mandelbrot-set算法的简化版本。但是,通过为数组中的一个像素存储每个单个Z并使用Z [n]计算Z [n + 1]来计算Z_n + 1似乎比仅存储Z_n来容纳Z_n + 1更快。这对我来说没有多大意义。

我正在使用Qt在C ++中对此代码进行编程,并以发布模式运行。

第一版(快速):

    // inside QWidget-class
    int numberIterations = 500;
    double dw = width();
    double dh = height();
    int iw = width();
    int ih = height();
    int colors[iw][ih] = {};
    double cr = 0.0;
    double cc = 0.0;
    double zr[numberIterations] = {0.0};
    double zc[numberIterations] = {0.0};
    for (int x = 0; x < iw; x++) {
        for (int y = 0; y < ih; y++) {
            cr = ((double)x/dw)*3.0-2.0;
            cc = ((double)y/dh)*2.0-1.0;

            colors[x][y]=0;

            QTime time;
            time.start();
            for(int n=1; n<numberIterations; n++){

                zr[n] = zr[n-1]*zr[n-1] -(zc[n-1]*zc[n-1]) + cr;
                zc[n] = zr[n-1]*zc[n-1] + cc;

                if(qAbs(zr[n])>2.0 || qAbs(zc[n])>2.0){ // to simplify it
                    colors[x][y]=1;
                    break;
                }
            }
            qDebug() << time.elapsed(); // prints almost always 0 (ms)
        }
    }

如您所见,我将复数Z的实数部分和i部分分开。通过求解二项式,确实很容易以这种方式进行描述,但是在这种情况下,实际上并不重要,因为实际计算是相同的。 版本2(慢):

// ... 
    double zr = 0.0;
    double zc = 0.0;
    double zr_old = 0.0;
    for (int x = 0; x < iw; x++) {
        for (int y = 0; y < ih; y++) {
            cr = ((double)x/dw)*3.0-2.0;
            cc = ((double)y/dh)*2.0-1.0;

            colors[x][y]=0;

            QTime time;
            time.start();
            for(int n=1; n<numberIterations; n++){

                zr_old = zr;
                zr = zr*zr -(zc*zc) + cr;
                zc = zr_old*zc + cc;

                if(qAbs(zr)>2.0 || qAbs(zc)>2.0){
                    colors[x][y]=1;
                    break;
                }
            }
            qDebug() << time.elapsed(); // prints about 2 on average (0-6)
        }
    }

对于我来说,听起来很奇怪,在索引处访问double数组中的元素比使用double变量要快...实际上是这种情况,还是我缺少使内部for循环(使用n )在使用变量时会慢得多(当然还有一个额外的分配)? 也许我现在只是瞎子,但我对不起...

编辑1

Dmytro Dadyka指出,我的第二个版本是错误的。在数组中,第一个元素始终为零(约定),但是在切换到下一个像素时,我没有将变量插入像素循环,这给了我错误的时间进行有意义的计算,因为内部for循环的迭代次数为然后更大。它必须是:

    // ...
    double zr = 0.0;
    double zc = 0.0;
    for (int x = 0; x < iw; x++) {
        for (int y = 0; y < ih; y++) {
            zr = 0.0;
            zc = 0.0;
            for(int n=1; n<numberIterations; n++){
                // ...
            }
        }
    }

但是,使用此版本计算像素的所有值所需的时间仍比使用数组版本的时间长约10%。奇怪的是,如Garf365指出的那样,它应该接受更多的指令。

1 个答案:

答案 0 :(得分:2)

您提供的示例并不等效。第一种情况下的初始zrzc的值为zr[0] = 0zc[0] = 0,并且对于每个(x, y)像素都是相同的。在第二种情况下,初始zrzc值是先前像素的最终值。我认为它破坏了计算逻辑,在第二种情况下,您得到错误的迭代计数。通过在循环中初始化zrzc来修复代码:

for (int x = 0; x < iw; x++) {
    for (int y = 0; y < ih; y++) {
        cr = ((double)x/dw)*3.0-2.0;
        cc = ((double)y/dh)*2.0-1.0;
        double zr = 0.0;
        double zc = 0.0;