2015-07-18 8 views
6

Der überraschende Ausgang des Code unten zeigt Arithmetik auf Doppel fast 100% schneller als auf lange:Warum C# -Arithmetik bei Doppel scheint schneller als Arithmetik bei langen?

Test_DivOperator Arithmetik gemessene Zeit Float: 15974,5024 ms.

Test_DivOperator Ganzzahl arithmetische gemessene Zeit: 28548.183 ms.

Die verwendeten Buildeinstellungen sind .Net4.5 C# 5.0 (Platform Ziel: x64)

Die verwendete Hardware ist Intel Core i5-2520M (Lauf Windows7 64Bit)

Hinweis: Der verwendete Operator (hier ist Division) wirkt sich auf die Ergebnisse aus, Division maximiert diese Beobachtung

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."); 
+0

Das Speichern von Elementen in einem Array mit nicht definierter Länge kann aufgrund der Neuzuweisung ebenfalls einen Overhead verursachen. Dies führt eine zusätzliche Variable in Ihrem Test ein. – GolezTrol

+0

Weiterführendes Lesematerial: [Optimierung von Ganzzahl-Divisionen] (http://www.codeproject.com/Articles/17480/Optimizing-integer-divisions-with-Multiply-Shift-i). – GolezTrol

+0

@GolezTrol Zuweisung erfolgt nicht innerhalb der gemessenen Zeit, alle Arrays sind von fester Größe .. auch die beiden Schleifen sind identisch. –

Antwort

5

Dies ist nicht unerwartet. 64-Bit-Integer-Division ist nur so langsam.

Ihr Prozessor ist ein Sandy Bridge, an der table von Latenzen und Durchsätze, 64-Bit-Suche idiv viel höhere Latenz und viel schlechter Durchsatz als divsd.

Andere Mikroarchitekturen zeigen einen ähnlichen Unterschied.

Doing die tatsächliche Mathematik, 2.8548183E10ns/500000000 = 57ns pro Iteration, bei einer Frequenz von 3,2 GHz, das ist etwa 183 Zyklen, gibt es zwei Divisionen und einige zusätzliche Overhead, so dass es nicht komisch ist.

Für Doppel funktioniert es auf 32ns, 102 Zyklen, eigentlich mehr als ich erwartet hätte.

+0

Danke! Bei der Kompilierung für x86 (32Bit) habe ich bessere Ergebnisse bei beiden Operationen, aber die Ganzzahl-Division ist noch schlechter, macht das auch Sinn? Test_DivOperator Float arithmetische gemessene Zeit: 8283.6531 ms. Test_DivOperator Ganzzahl arithmetische gemessene Zeit: 13384.8858 ms Es scheint die öffentliche Annahme, dass Integer-Arithmetik einfacher ist als Fließkomma-Arithmetik und daher schneller nicht mehr real ist zumindest für diese Mikroarchitektur, haben Sie weitere Informationen darüber? –

+1

@AhmedKhalaf es ist alles in der Tabelle, die ich verbunden bin, Ganzzahlarithmetik ist in der Regel schnell, nur nicht Division. 32-Bit-Division ist nicht annähernd so schlecht wie 64-Bit-Division, aber Float-Division ist auch schneller als Doppel-Division, so dass es immer noch gewinnt. – harold

+0

Ich meinte, warum wäre Integer Division langsamer als Fließkomma? (für vergleichbare Anzahl von Bits 64Bit-vs-double). Auf dem Papier ist die ganzzahlige Division einfacher als Fließkomma. Zusätzlich liefern experimentelle Ergebnisse für den obigen Code, der Addition verwendet, stattdessen 5740,8368 ms doppelt. VS 6957,6446 ms für 64-Bit-Integer (kompiliert für x86 nicht x64). –