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

C++ 64位模运算的奇怪性能行为,c++,performance,64-bit,numeric,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,

其中最后三个方法调用的时间大约是前四个方法调用的两倍

唯一的区别是它们的参数不再适合整数。但这有关系吗?该参数被声明为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);            
    }
Stopwatch sw=新秒表();
TestLong(sw,int.MaxValue-3l);
TestLong(sw,int.MaxValue-2l);
TestLong(sw,int.MaxValue-1l);
TestLong(sw,int.MaxValue);
TestLong(短波,整数最大值+1l);
TestLong(短波,整数最大值+2l);
TestLong(sw,int.MaxValue+3l);
Console.ReadLine();
静态无效测试长(秒表开关,长数值)
{
长n=0;
sw.Reset();
sw.Start();
用于(长i=3;i<20000000;i++)
{
n+=num%i;
}
sw.Stop();
控制台写入线(软件运行时间);
}
编辑: 我现在用C尝试了同样的方法,但问题并没有出现在这里,在发布和调试模式下,无论是否启用优化,所有模操作都需要相同的时间:

#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;
}
#包括“stdafx.h”
#包括“time.h”
#包括“限制.h”
静态void TestLong(long-long-num)
{
长n=0;
时钟t=时钟();
用于(长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);
测试长度(INT_最大值-1L);
测试长度(单位最大值+1升);
测试长度(整数最大值+1LL);
测试长度(最大1升);
getchar();
返回0;
}
EDIT2:


谢谢你的建议。我发现.net和c(在调试模式和发布模式下)都不使用原子cpu指令来计算余数,但它们调用了一个这样做的函数

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

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

顺便说一句:即使是简单的长-长值加法,也是通过连续的加法和adc指令计算的。因此,即使我的处理器自己调用64位,它实际上也不是:(

EDIT3:


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

您是否尝试过在您的机器上用本机代码执行相同的操作


如果本机64位余数操作在两个参数都在32位范围内的特殊情况下,基本上将其委托给32位操作,我也不会感到惊讶。(或者可能是JIT做的…)优化这种情况确实很有意义,不是吗?

这是一个多么奇怪的观察结果。您可以做一些事情来进一步研究这一点:在程序开始时添加一个“暂停”,如Console.ReadLine,但在第一次调用您的方法之后。然后在“release”中构建程序模式。然后启动不在调试器中的程序。然后,在暂停时,附加调试器。通过调试器进行调试,并查看针对所讨论的方法进行的JIT代码。应该很容易找到循环体

了解生成的循环体与C程序中的循环体有何不同将是一件有趣的事情


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

我现在使用本机代码尝试了调试器,但这里没有出现问题。当然,这样的优化是有意义的,但为什么有时会这样,有时不会这样。但我不相信这是JIT,因为有问题的值是作为参数传递的ument和我不认为该方法在同一个过程中会多次出现抖动。感谢您的建议。我发现了很多有趣的东西,请参阅我的新编辑:)关于您上次的观察,如果您使用的是普通消费者安装的Windows XP,你几乎肯定是在32位模式下运行你奇特的64位处理器。你的处理器实际上是64位的,是你的操作系统和编译器在32位模式下运行。