c++ - 64 位模运算的奇怪性能行为

标签 c++ performance 64-bit numeric

这些方法调用中的最后三个需要大约。时间比前四个多一倍。

唯一的区别是它们的参数不再适合整数。但这应该重要吗?参数声明为long,所以无论如何都应该使用long来计算。模运算是否对数字使用另一种算法>maxint?

我正在使用 amd athlon64 3200+、winxp sp3 和 vs2008。

       Stopwatch sw = new Stopwatch();
       TestLong(sw, int.MaxValue - 3l);
       TestLong(sw, int.MaxValue - 2l);
       TestLong(sw, int.MaxValue - 1l);
       TestLong(sw, int.MaxValue);
       TestLong(sw, int.MaxValue + 1l);
       TestLong(sw, int.MaxValue + 2l);
       TestLong(sw, int.MaxValue + 3l);
       Console.ReadLine();

    static void TestLong(Stopwatch sw, long num)
    {
        long n = 0;
        sw.Reset();
        sw.Start();
        for (long i = 3; i < 20000000; i++)
        {
            n += num % i;
        }
        sw.Stop();
        Console.WriteLine(sw.Elapsed);            
    }

编辑: 我现在尝试用 C 做同样的事情,这里没有出现问题,所有模运算都花费相同的时间,在发布和 Debug模式下打开和不打开优化:

#include "stdafx.h"
#include "time.h"
#include "limits.h"

static void TestLong(long long num)
{
    long long n = 0;

    clock_t t = clock();
    for (long long i = 3; i < 20000000LL*100; i++)
    {
        n += num % i;
    }

    printf("%d - %lld\n", clock()-t, n);  
}

int main()
{
    printf("%i %i %i %i\n\n", sizeof (int), sizeof(long), sizeof(long long), sizeof(void*));

    TestLong(3);
    TestLong(10);
    TestLong(131);
    TestLong(INT_MAX - 1L);
    TestLong(UINT_MAX +1LL);
    TestLong(INT_MAX + 1LL);
    TestLong(LLONG_MAX-1LL);

    getchar();
    return 0;
}

编辑 2:

感谢您的宝贵建议。我发现 .net 和 c(在调试和 Release模式下)都没有使用原子 cpu 指令来计算余数,但它们调用了一个函数来计算余数。

在 c 程序中,我可以得到它的名称,即“_allrem”。它还显示了该文件的完整源代码注释,因此我发现了该算法特殊情况下的 32 位除数而不是 .net 应用程序中的股息的信息。

我还发现 c 程序的性能实际上只受除数的值影响,而不受被除数的影响。另一项测试表明,.net 程序中求余函数的性能取决于被除数和除数。

顺便说一句:即使是 long long 值的简单加法也是通过连续的 add 和 adc 指令计算的。所以即使我的处理器自称为 64 位,它也确实不是 :(

编辑 3:

我现在在 windows 7 x64 版本上运行 c 应用程序,使用 visual studio 2010 编译。有趣的是,性能行为保持不变,尽管现在(我检查了汇编源)使用了真正的 64 位指令。

最佳答案

多么奇怪的观察。您可以做一些事情来进一步调查此问题:在程序的开头添加一个“暂停”,例如 Console.ReadLine,但在第一次调用您的方法之后。然后以“发布”模式构建程序。然后启动程序不在调试器中。然后,在暂停时附加调试器。通过它调试并查看为有问题的方法编译的代码。找到循环体应该很容易。

了解生成的循环体与您的 C 程序中的循环体有何不同会很有趣。

跳过所有这些环的原因是因为抖动改变了它在抖动“调试”程序集时生成的代码在抖动已经附加了调试器的程序时;在这些情况下,它会跳出在调试器中更容易理解的代码。看看抖动认为什么是为这种情况生成的“最佳”代码会更有趣,因此您必须在抖动运行后延迟附加调试器。

关于c++ - 64 位模运算的奇怪性能行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2108744/

相关文章:

android - android NDK中的颜色叠加

python - SQLite3executemany()在多个表上插入的生成器的高效设计

c++ - 为什么所有关于 virtual 关键字的模糊不清?

c++ - 虚拟函数调用的性能作为for循环中的上限

matlab - 在 Kubuntu 上构建 MEX 文件 (MATLAB 2012a) 时出错 '/usr/bin/ld: cannot find -lstdc++'

windows - Visual Studio 参数对齐限制和 Windows x64 ABI

Android BarcodeScanner 库在 64 位设备中崩溃

c++ - C++中空字符串包含什么

c++ - 将大二进制字符串写入二进制文件

c++ - SDL_FreeSurface 未释放 RAM/RAM 溢出