VS 2017和2019运行C++非常慢

3

我最初用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";

一切都很顺利,但是网页编辑器似乎有一个内置的最大时间限制,所以我决定把它移到Visual Studio。

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

  • 网页编辑器花费0.272273秒完成了代码
  • Visual Studio花费2.446秒运行了它。

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

为什么VS运行代码需要这么长时间?如何解决这个问题?


6
你是否启用了发布版构建配置? - walnut
1
正如@walnut所说。使用不同的优化/构建标志运行可以起到巨大的作用。请参见:https://godbolt.org/z/jpgVYx,其中一个使用优化级别3,另一个使用优化级别0。对我来说,时间差异是30倍。(尽管编译器不同于msvc) - koitimes3
我已启用发布构建配置。如果没有启用,时间甚至会更长:8.701秒。 - user11454816
1
不能在Windows上使用“clock”来比较性能。 - n. m.
2
使用 sqrt(R*R - x*x) 来避免使用 pow(),确保目标为 x64。 - Hans Passant
显示剩余7条评论
2个回答

3
主要问题是VC++没有内联rint(float)调用:
    movaps  xmm0, xmm6
    call    rint
    ucomisd xmm0, xmm6

跳转至godbolt

通过使用“手动”四舍五入,您可以期望获得较好的加速:

更改

        if (rint(y) == y) {

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

在我的计算机上,使用/O2 /fp:fast编译,从0.8秒缩短到0.04秒
此外,在循环之外需要N_pairs使用,否则好的编译器会将所有内容优化掉。

1
第一条优化规则:不正确的程序性能是无关紧要的。
看起来你正在寻找整数解 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?我尝试将其更改为double,虽然对于R高达10,000的情况结果没有受到影响,但对于R高达100,000的情况结果确实受到影响。 - user11454816
@user11454816 - 我的代码不会出现误报,因为它使用整数测试来判断平方和是否等于R平方。但是,由于你提到的四舍五入问题,它可能会出现漏报;我会通过检查 y+1 的平方是否可行来解决这个问题。 - Vlad Feinstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接