为什么双精度C#算术似乎比长精度C#算术更快?

为什么双精度C#算术似乎比长精度C#算术更快?,c#,performance,floating-point,double,long-integer,C#,Performance,Floating Point,Double,Long Integer,下面代码令人惊讶的输出显示,double上的算术运算速度几乎比long上快100%: Test_操作员浮点运算测量时间:15974.5024 ms Test_DivOperator整数算术测量时间:28548.183毫秒 使用的构建设置为.Net4.5 C#5.0(平台目标:x64) 使用的硬件是英特尔Core i5-2520M(运行64位Windows7) 注:使用的运算符(此处为除法)不会影响结果,除法可最大化此观察值 const int numOfIterations=1//此值将从游戏中

下面代码令人惊讶的输出显示,double上的算术运算速度几乎比long上快100%:

Test_操作员浮点运算测量时间:15974.5024 ms

Test_DivOperator整数算术测量时间:28548.183毫秒

使用的构建设置为.Net4.5 C#5.0(平台目标:x64)

使用的硬件是英特尔Core i5-2520M(运行64位Windows7)

注:使用的运算符(此处为除法)不会影响结果,除法可最大化此观察值

const int numOfIterations=1//此值将从游戏中删除内存访问
重复次数常数=500000000//CPU限制的应用程序
Random rand=新的Random();
double[]操作数1=新的double[numOfIterations];
double[]操作数2=新的double[numOfIterations];
double[]操作数3=新的double[numOfIterations];
long[]Int64Operation1=新的long[numOfIterations];
long[]int64operans2=新的long[numOfIterations];
long[]Int64Operand3=新的long[numOfIterations];
对于(int i=0;i
这并非意外。64位整数除法就是这么慢

您的处理器是一座沙桥,从延迟和吞吐量的角度来看,64位
idiv
divsd
具有更高的延迟和更差的吞吐量

其他微体系结构也显示出类似的差异

进行实际计算,每次迭代2.8548183E10ns/500000000=57ns,频率为3.2GHz,约为183个周期,有两个分段和一些额外的开销,因此这并不奇怪


对于double,结果是32ns,102个周期,实际上比我预期的要多。

在未定义长度的数组中存储项目也会由于重新分配而引入开销。这在测试中引入了一个额外变量。相关阅读资料:。@GolezTrol分配未在测量的时间内完成,所有数组的大小都是固定的。。另外,这两个循环是相同的。谢谢!在为x86(32位)编译时,我在这两种操作上都得到了更好的结果,但整数除法更糟糕,这也有意义吗?Test-DivU运算符浮点运算测量时间:8283.6531 ms。Test-DivU运算符整数运算测量时间:13384.8858 ms似乎公众认为整数运算比浮点运算简单,因此更快不再是事实,至少对于这种微体系结构而言,你有进一步的信息吗?@AhmedKhalaf这都在我链接的表中,整数运算通常很快,只是不是除法。32位除法不如64位除法差,但浮点除法也比双除法快,所以它仍然赢。我的意思是为什么整数除法比浮点除法慢?(用于64位与双位的可比位数)。在纸上,整数除法比浮点除法简单。此外,使用加法的上述代码的实验结果给出了双5740.8368毫秒,而64位整数的实验结果为6957.6446毫秒(针对x86而不是x64进行编译)。@AhmedKhalaf整数比同样大小的浮点数有更多的位要除(64位除法实际上是将128位数字除以64位数字,一个双精度整数只有53位可除),并且除法在很大程度上是一个连续的过程。浮点除法似乎在某种程度上更受欢迎,它直接内置于自身的µOp中,而整数除法则使用一组µOp。除此之外,JIT还增加了开销。假设除法的这一推理是正确的,那么这对于加法又有什么意义呢?您知道基于C++/非托管代码的类似比较吗?
const int numOfIterations = 1; //this value takes memory access out of the game
const int numOfRepetitions = 500000000; //CPU bound application
Random rand = new Random();
double[] Operand1 = new double[numOfIterations];
double[] Operand2 = new double[numOfIterations];
double[] Operand3 = new double[numOfIterations];

long[] Int64Operand1 = new long[numOfIterations];
long[] Int64Operand2 = new long[numOfIterations];
long[] Int64Operand3 = new long[numOfIterations];

for (int i = 0; i < numOfIterations; i++)
{
    Operand1[i]=(rand.NextDouble() * 100);
    Operand2[i]=(rand.NextDouble() * 80);
    Operand3[i]=(rand.NextDouble() * 17);
    Int64Operand1[i] = (long)Operand1[i];
    Int64Operand2[i] = (long)Operand2[i]+1;
    Int64Operand3[i] = (long)Operand3[i]+1;
}

double[] StdResult = new double[numOfIterations];
long[] NewResult = new long[numOfIterations];

TimeSpan begin = Process.GetCurrentProcess().TotalProcessorTime;

for (int j = 0; j < numOfRepetitions; j++)
{
    for (int i = 0; i < numOfIterations; i++)
    {
        double result = Operand1[i] / Operand2[i];
        result = result / Operand3[i];
        StdResult[i]=(result);
    }

}

TimeSpan end = Process.GetCurrentProcess().TotalProcessorTime;
Console.WriteLine("Test_DivOperator Float arithmetic measured time: " + (end - begin).TotalMilliseconds + " ms.");

begin = Process.GetCurrentProcess().TotalProcessorTime;

for (int j = 0; j < numOfRepetitions; j++)
{
    for (int i = 0; i < numOfIterations; i++)
    {
        long result =    Int64Operand1[i] / Int64Operand2[i];
        result = result / Int64Operand3[i];
        NewResult[i]=(result);
    }

}

end = Process.GetCurrentProcess().TotalProcessorTime;
Console.WriteLine("Test_DivOperator Integer arithmetic measured time: " + (end - begin).TotalMilliseconds + " ms.");