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

C++ Why does an assignment in a primitive double array seem to be much faster than a double variable assignment?

我正在尝试编写 Mandelbrot 集算法的简化版本。但是通过存储数组中一个像素的每个 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)
        }
    }

如你所见,i 将复数 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)
        }
    }

在索引处访问双精度数组中的元素比仅使用双精度变量更快,这对我来说听起来真的很奇怪......实际上是这种情况还是我遗漏了一些使内部 for 循环( with 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 指出的那样接受更多指令。

你举的例子并不等同。第一种情况下的初始 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;