【问题标题】:VS 2017 & 2019 run c++ really slowVS 2017 & 2019 运行 c++ 真的很慢
【发布时间】:2020-01-12 12:47:29
【问题描述】:

我开始使用 python 中的一个小程序,但运行它需要很长时间,所以我切换到 c++。我之前没有使用这种特定语言的经验(虽然在 c# 中编写了很多代码)并且开始使用网络编辑器:https://www.onlinegdb.com/online_c++_compiler

我的 C++ 代码是:

clock_t start, end;

/* Recording the starting clock tick.*/
start = clock();

int R = 0;
int x = 0;

for (R = 6; R <= 10000; R = R + 2) {
    int X_min = ceil(0.5 * sqrt(2) * R);
    int N_pairs = 0;

    for (x = X_min; x < R; x++) {
        float y = sqrt(pow(R, 2) - pow(x, 2));

        if (rint(y) == y) {
            N_pairs = N_pairs + 1;
        }
    }

    if (N_pairs >= 4) {
        //cout << R << ", " << N_pairs;
        //cout << "\n";
    }
}

end = clock();

//Calculating total time taken by the program. 
double time_taken = double(end - start) / double(CLOCKS_PER_SEC);
cout << "Time taken by program is : " << time_taken;
cout << " sec " << endl;

//cout << "1" << "|" << "2" << "|" << "3 \n";
//cout << "4" << "|" << "5" << "|" << "6 \n";
//cout << "7" << "|" << "8" << "|" << "9 \n";

一切运行良好,但是 Web 编辑器似乎有一个内置的最大时间边界,所以此时我决定将它交给 Visual Studio。

我复制粘贴代码并运行它:

  • 网络编辑器用了 0.272273 秒完成代码
  • Visual Studio 用了 2.446 秒来运行它。

我尝试将 VS 从 2017 版更新到 2019 版,但没有效果。

为什么 VS 运行代码需要这么长时间?我该如何解决?

【问题讨论】:

  • 您是否启用了发布构建配置?
  • 正如@walnut 所说。使用不同的优化/构建标志运行可以发挥巨大的作用。请参阅:godbolt.org/z/jpgVYx,其中一个使用优化级别 3,另一个使用 0。对我来说,这是 30 倍的时间差异。 (虽然编译器与 msvc 不同)
  • 我确实启用了发布构建配置。没有它需要更长的时间:8.701 秒
  • 不能在 Windows 上使用 clock 来比较性能。
  • 使用sqrt(R*R - x*x)来避免pow(),一定要针对x64。

标签: c++ performance visual-studio-2017 visual-studio-2019


【解决方案1】:

主要问题是VC++没有内联rint(float)调用:

    movaps  xmm0, xmm6
    call    rint
    ucomisd xmm0, xmm6

link to godbolt

您可以通过将rint(y) 替换为“手动”舍入来获得良好的加速效果:

改变

        if (rint(y) == y) {

        if (int(y+0.5) == y) {

在我的机器上从 0.8 s 下降到 0.04 s(使用 /O2 /fp:fast 编译)

您还需要在循环外使用 N_pairs,否则(好的)编译器可以优化所有内容。

【讨论】:

    【解决方案2】:

    优化的第一条规则:错误程序的性能无关紧要。

    看来您正在寻找x^2 + y^2 = R^2 的整数解。但是,使用float 数据类型进行中间存储会产生很多误报。将N_pairs 移出循环(以防止完全删除该循环,正如@rustyx 已经指出的,并计算所有对)导致7886 对;与double:5681。

    最后一个数字也对应于完全整数检查,这要快得多(在我的系统上为 21 毫秒)。这是我的代码:

    #include <iostream>
    #include <chrono>
    
    int main()
    {
        auto t = std::chrono::high_resolution_clock::now();
        int N_pairs = 0;
        double d = 0.5 * sqrt(2);
        for (int R = 6; R <= 10000; R = R + 2) {
            int X_min = ceil(d * R);
    
            for (int x = X_min; x < R; x++) {
                int y = sqrtf(R * R - x * x);
                if(x*x + y*y == R*R) {
                    N_pairs = N_pairs + 1;
                }
            }
        }
        std::cout << "Time taken by program is: " 
            << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - t).count() 
            << " ms" << std::endl;
        std::cout << "N_pairs: " << N_pairs << std::endl; // with float: 7886; with double or int: 5681
    return 0;
    }
    

    【讨论】:

    • 感谢您的回复。我在循环中有 N_pairs 的原因是因为我对每个“R”的对数感兴趣,而不是对所有 R 的总对数感兴趣。也许我应该每次都将它设置为零,而不是一遍又一遍地声明它,但我还没有检查过。这是我第一次不得不优化程序。此外,您将变量 y 声明为整数这一事实是否会引入误报,因为您立即对 sqrt 进行舍入?我尝试将其更改为加倍,虽然它不会影响 R 高达 10.000 的结果,但它对 R 高达 100.000 的结果有影响
    • @user11454816 - 我的代码不能有误报,因为要查看平方和是否等于 R 平方的整数测试。由于您提到的四舍五入,它可能有误报;我会通过检查y+1-squared 是否有效来解决这个问题。
    猜你喜欢
    • 2013-04-12
    • 2017-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-10
    • 2010-12-28
    • 2013-01-25
    相关资源
    最近更新 更多