有誰知道是否存在一個用於交換uint中字節順序的.NET Framework等價物?.NET等價的_byteswap_ulong/OSSwapInt32 /或bswap32
我試圖移植一些使用MSFTs _byteswap_ulong(相當於* Nix世界中的Apples OSSwapInt32或Bswap32)的c#散列代碼。我可以手動編寫這個函數,但我懷疑它會利用任何編譯器優化(例如,c/C++編譯器提供難以超越的內建值,我希望運行時對內置函數的作用相同)。如果重要,我不關心保留字節順序。
我試過一個基於通用的解決方案,但我不相信這將是最優的。
BitConverter.ToUInt32(BitConverter.GetBytes(g).Reverse().ToArray<byte>(),0);
編輯:
所以我想通了這個特殊的函數被調用多少次在10分鐘內的平均(對於我們的哈希消費國之一)。這個函數被調用10000000000次。因此,我設置了一些微分析來查看c代碼的性能與下面提供的解決方案(以及上面提出的解決方案)的性能。
該C代碼運行了許多操作(使用內在)在約。我可靠的筆記本電腦上有1500毫秒。 我上面介紹的C#代碼幾乎運行在2689581毫秒。巨大的差異。 Matthew Watson提供的c#代碼運行時間接近36000毫秒。 Caramiriel提供的第一個解決方案運行時間接近115014毫秒,提供的第二個解決方案運行速度接近36000.
雖然這些解決方案都沒有接近觸及內部呼叫的速度,但它們比我的原始解決方案好得多(對於許多計算,從44分鐘到36秒)。這對我的應用程序來說完全可以接受雖然如果.NET編譯器提供了一些與本地編譯器相同的內置功能,那將會很不錯。
爲了完整這裏是爲microbenchmarking我的C代碼:
#include "stdafx.h"
#include "windows.h"
unsigned long Swap(unsigned int value)
{
return _byteswap_uint64(value);
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned int value = 0x01020304;
unsigned long NUMITER = 10000000000;
unsigned long a=0;
unsigned long z=0;
int throwAwayLoopCount = 5;
for (int k = 0; k < throwAwayLoopCount; ++k)
{
a = GetTickCount();
for (unsigned long i = 0; i < NUMITER; ++i)
{
value = Swap(value);
}
z = GetTickCount();
printf("Baseline, Cached: time is %4lld milliseconds: value%4lld\n", z-a,value);
}
printf("Baseline, Cached: time is %4lld milliseconds\n", z-a);
return 0;
}
這裏是基準提供的解決方案的C#代碼:
namespace ByteSwapProfiler
{
using System.Runtime.InteropServices;
using System.Diagnostics;
[StructLayout(LayoutKind.Explicit)]
internal struct UInt32Union
{
[FieldOffset(0)]
public UInt32 Value;
[FieldOffset(0)]
public byte Byte1;
[FieldOffset(1)]
public byte Byte2;
[FieldOffset(2)]
public byte Byte3;
[FieldOffset(3)]
public byte Byte4;
}
class Program
{
static uint ByteSwapNaive(uint g)
{
return BitConverter.ToUInt32(BitConverter.GetBytes(g).Reverse().ToArray<byte>(), 0);
}
static uint ByteSwapCaramiriel1(uint value)
{
unchecked
{
return ((value & 0xff000000) >> 24) |
((value & 0x00ff0000) >> 8) |
((value & 0x0000ff00) << 8) |
((value & 0x000000ff) << 24);
}
}
static uint ByteSwapCaramiriel2(UInt32Union src)
{
UInt32Union dest = new UInt32Union
{
Byte1 = src.Byte4,
Byte2 = src.Byte3,
Byte3 = src.Byte2,
Byte4 = src.Byte1
};
return dest.Value;
}
static uint ByteSwapMatthewWatson(uint word)
{
return ((word >> 24) & 0x000000FF) | ((word >> 8) & 0x0000FF00) | ((word << 8) & 0x00FF0000) | ((word << 24) & 0xFF000000);
}
static void Main(string[] args)
{
uint value= 0x01020304;
UInt32Union src = new UInt32Union();
src.Value = value;
ulong NUMITER = 10000000000;
uint throwAwayLoopCount = 5;
var sw = new Stopwatch();
string name = "Naive";
//for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapNaive(value);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"),value);
}
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));
name = "MatthewWatson";
for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapMatthewWatson(value);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"), value);
}
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));
name = "Caramiriel2";
for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapCaramiriel2(src);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"), value);
}
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));
name = "Caramiriel1";
for (int k = 0; k < throwAwayLoopCount; ++k)
{
sw = Stopwatch.StartNew();
for (ulong i = 0; i < NUMITER; ++i)
{
value = ByteSwapCaramiriel1(value);
}
sw.Stop();
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds. Value:{2} \n", name, (sw.ElapsedMilliseconds).ToString("0"), value);
}
Console.Write("{0,-13}, Cached: time is {1,7} milliseconds.\n", name, (sw.ElapsedMilliseconds).ToString("0"));
}
}
}
只是出於好奇,那些是什麼內在? – Jon
@Jon _byteswap_uint64是msfts的內在http://msdn.microsoft.com/en-us/library/5704bbxw(v=vs.80).aspx。你可以到這裏http://msdn.microsoft.com/en-us/library/26td21ds(v=vs.80).aspx –
他們的名單你問這個問題,因爲**你不知道**無論C#選擇是否足夠快。我們也沒有,我們不能分析你的代碼。你必須自己做。 –