前言/上下文:我刚刚开始学习c ++,并决定编写一些将单个量子位门应用于量子寄存器的代码,其中该寄存器被保持在一个称为振幅的数组中,单个量子位门的四个元素是,b,c,d。我试图编写一个避免在第一次通过时出现if语句的版本,令我最初感到高兴的是,它似乎在性能上有轻微提高(〜10%)。如果我更改寄存器中的量子位数或用门指定的量子位数,我将得到类似的结果。然后,我尝试制作一个循环,对各种目标qubit进行时序比较,然后发生了一件非常奇怪的事情(至少对我而言)。我编写的替代函数避免了if语句使执行时间加倍(从〜0.23秒到0.46秒),而带有if语句的函数的执行时间不受影响(〜0.25秒)。这引出我的问题:

在任何一种情况下,如果给定相同的输入,如何在迭代这些输入的循环内花费更长的时间执行代码呢?

例如,如果我运行一个给出25个量子位和目标量子位1的测试,则“ no if”函数获胜。然后,如果我编写一个while循环,以25 qubits为起始点1的每个目标值进行比较,则“ no if”函数即使在第一次迭代中接收到与前一种情况相同的输入,也需要花费两倍的时间来执行。有趣的是,如果我仅包括while循环并通过在while语句中放入“ True”或通过注释掉增量语句target + = 1使其成为无限的while循环,则该函数将不再花费两倍的时间。这种现象需要循环和我所知道的增加。

如果这是我不那么熟悉的新语言的简单编码错误,请使用以下代码。我使用具有所有默认设置的Visual Studio 2017社区版,但我使用的是“发行版”版本,以加快代码执行速度。注释掉while语句和相应的右花括号后,“否”计时加倍。

#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <complex>

void matmulpnoif(std::complex<float> arr[], std::complex<float> out[], int numqbits, std::complex<float> a,
std::complex<float> b, std::complex<float> c, std::complex<float> d, int target)
{
    long length = 1 << (numqbits);
    long offset = 1 << (target - 1);
    long state = 0;
    while (state < length)
    {
        out[state] = arr[state] * a + arr[state + offset] * b;
        out[state + offset] = arr[state] * c + arr[state + offset] * d;
        state += 1 + offset * (((state%offset) + 1) / offset);
    }
}

void matmulpsingle(std::complex<float> arr[], std::complex<float> out[], int numqbits, std::complex<float> a,
std::complex<float> b, std::complex<float> c, std::complex<float> d, int target)
{
    long length = 1 << (numqbits);
    int shift = target - 1;
    long offset = 1 << shift;
    for (long state = 0; state < length; ++state)
    {
        if ((state >> shift) & 1)
        {
            out[state] = arr[state - offset] * c + arr[state] * d;
        }
        else
        {
            out[state] = arr[state] * a + arr[state + offset] * b;
        }
    }
}

int main()
{
    using namespace std;
    int numqbits = 25;
    long arraylength = 1 << numqbits;
    complex<float>* amplitudes = new complex<float>[arraylength];
    for (long i = 0; i < arraylength; ++i)
    {
        amplitudes[i] = complex<float>(0., 0.);
    }
    amplitudes[0] = complex<float>(1., 0.);
    complex<float> a(0., 0.);
    complex<float> b(1., 0.);
    complex<float> c(0., 0.);
    complex<float> d(1., 0.);
    int target = 1;
    int repititions = 10;
    clock_t startTime;
    //while (target <= numqbits) {
        startTime = clock();
        for (int j = 0; j < repititions; ++j) {
            complex<float>* outputs = new complex<float>[arraylength];
            matmulpsingle(amplitudes, outputs, numqbits, a, b, c, d, target);
            delete[] outputs;
        }
        cout << float(clock() - startTime) / (float)(CLOCKS_PER_SEC*repititions) << " seconds." << endl;
        startTime = clock();
        for (int k = 0; k < repititions; ++k) {
            complex<float>* outputs = new complex<float>[arraylength];
            matmulpnoif(amplitudes, outputs, numqbits, a, b, c, d, target);
            delete[] outputs;
        }
        cout << float(clock() - startTime) / (float)(CLOCKS_PER_SEC*repititions) << " seconds." << endl;
        target+=1;
    //}
    delete[] amplitudes;
    return 0;
}

最佳答案

不幸的是,我还不能发表评论,所以即使它可能不是一个完整的答案,我也会在这里发表。

通常,您提出的问题很困难。编译器执行优化,这两种情况是不同的代码,因此它们的优化方式也不同。

例如,在我的机器(Linux,GCC 7.3.1)上,仅启用-O3,matmulpnoif总是更快(4.8s vs 2.4s或4.8s vs 4.2s-这些时间不是用clock()测量的) ,具体取决于循环是否存在)。如果我不得不猜测在这种情况下会发生什么,编译器可能会意识到offset始终为1,并优化其余操作(到目前为止,除法是您所拥有的最昂贵的操作)。但是,也可能是其他因素的组合。

另外要注意的是,clock()不应用于测量时间。它计算时钟滴答的次数,例如,如果您在2个线程中并行执行代码,则该次数将是时间的两倍(假设您的代码没有在任何地方等待-在我的机器上似乎不是这种情况)。如果您想测量时间,建议您查看<chrono>high_resolution_clock应该可以解决问题。

另一个注意事项是,无需继续分配和取消分配输出数组,您可以简单地使用一个数组,这样可以减少浪费的时间。但是最重​​要的是,如果您使用的是C ++,我建议您将所有这些都放在一个类中,因为这是您将许多参数传递给每个函数,如果传递了很多参数,它会使事情变得既难于阅读又变慢。数据(复制时)。

另外要注意的是,由于您使用的是移位,因此使用无符号变量可能会更安全,因为右移>>对使用符号变量填充的内容没有严格的定义。至少要记住一点,它可能在那一侧填充1。

关于c++ - 给定看似只是因为处于循环中的相同输入,某些代码如何才能花更多时间运行?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50481430/

10-11 22:35
查看更多