用16位字快速交换C#中的尾数

用16位字快速交换C#中的尾数,c#,endianness,C#,Endianness,必须有一种更快更好的方法来交换16位字的字节,而不是这个: public static void Swap(byte[] data) { for (int i = 0; i < data.Length; i += 2) { byte b = data[i]; data[i] = data[i + 1]; data[i + 1] = b; } } 公共静态无效交换(字节[]数据) { 对于(int i=0;i56) |

必须有一种更快更好的方法来交换16位字的字节,而不是这个:

public static void Swap(byte[] data)
{
    for (int i = 0; i < data.Length; i += 2)
    {
        byte b = data[i];
        data[i] = data[i + 1];
        data[i + 1] = b;
    }
}
公共静态无效交换(字节[]数据)
{
对于(int i=0;i
有人有主意吗?

好吧,您可以使用,以避免中间字节。但不会更快,如果IL完全相同,我也不会感到惊讶

for (int i = 0; i < data.Length; i += 2)
{
    data[i] ^= data[i + 1];
    data[i + 1] ^= data[i];
    data[i] ^= data[i + 1];
}
for(int i=0;i
这种方法似乎比原始问题中的方法略快:

private static byte[] _temp = new byte[0];
public static void Swap(byte[] data)
{
    if (data.Length > _temp.Length)
    {
        _temp = new byte[data.Length];
    }
    Buffer.BlockCopy(data, 1, _temp, 0, data.Length - 1);
    for (int i = 0; i < data.Length; i += 2)
    {
        _temp[i + 1] = data[i];
    }
    Buffer.BlockCopy(_temp, 0, data, 0, data.Length);
}
private static byte[]_temp=新字节[0];
公共静态无效交换(字节[]数据)
{
如果(数据长度>温度长度)
{
_temp=新字节[数据长度];
}
块复制(数据,1,_temp,0,数据长度-1);
对于(int i=0;i
我的基准测试假设重复调用该方法,因此
\u temp
数组的大小调整不是一个因素。此方法依赖于这样一个事实,即一半字节交换可以通过初始
Buffer.BlockCopy(…)
调用完成(源位置偏移量为1)

请你们自己做基准,以防我完全失去理智。在我的测试中,此方法所用的时间大约是原始方法的70%(我对其进行了修改,将
字节b
声明在循环之外)。

我一直喜欢这样:

public static Int64 SwapByteOrder(Int64 value) 
{
  var uvalue = (UInt64)value;
  UInt64 swapped = 
       ( (0x00000000000000FF) & (uvalue >> 56)
       | (0x000000000000FF00) & (uvalue >> 40)
       | (0x0000000000FF0000) & (uvalue >> 24)
       | (0x00000000FF000000) & (uvalue >> 8)
       | (0x000000FF00000000) & (uvalue << 8)
       | (0x0000FF0000000000) & (uvalue << 24)
       | (0x00FF000000000000) & (uvalue << 40)
       | (0xFF00000000000000) & (uvalue << 56));
  return (Int64)swapped;
}
公共静态Int64交换字节顺序(Int64值)
{
变量U值=(UInt64)值;
UInt64交换=
((0x00000000000000FF)和(U值>>56)
|(0x000000000000FF00)和(U值>>40)
|(0x0000000000FF0000)和(U值>>24)
|(0x00000000FF000000)和(U值>>8)

|(0x000000FF00000000)和(uvalue在我申请Uberhacker奖励时,我提交了以下内容。在我的测试中,我使用了8192字节的源数组,并调用了
SwapX2
100000次:

public static unsafe void SwapX2(Byte[] source)  
{  
    fixed (Byte* pSource = &source[0])  
    {  
        Byte* bp = pSource;  
        Byte* bp_stop = bp + source.Length;  

        while (bp < bp_stop)  
        {
            *(UInt16*)bp = (UInt16)(*bp << 8 | *(bp + 1));  
            bp += 2;  
        }  
    }  
}
公共静态不安全无效SwapX2(字节[]源)
{  
已修复(字节*pSource=&源[0])
{  
字节*bp=pSource;
字节*bp_stop=bp+源.Length;
同时(bp*(UInt16*)bp=(UInt16)(*bp下一个方法,在我的测试中,几乎比接受的答案快3倍。(在超过3个字符或6个字节时总是快,在少于或等于3个字符或6个字节时慢一点。)(请注意,接受的答案可以在数组边界之外读/写。)

(使用指针时进行更新无需调用属性来获取长度。使用该指针速度稍快,但需要运行时检查,或者如下一个示例所示,需要为每个平台生成项目配置。在每个配置下定义X86和X64。)

静态不安全void SwapV2(字节[]源)
{
已修复(字节*psource=源)
{
#如果X86
变量长度=*((uint*)(psource-4))&0xFFFFFFFEU;
#elif X64
变量长度=*((uint*)(psource-8))&0xFFFFFFFEU;
#否则
变量长度=(source.length和0xFFFFFFFE);
#恩迪夫
而(长度>7)
{
长度-=8;
乌龙*普龙=(乌龙*)(P来源+长度);
*普隆=((*普隆>>8)和0x00FF00FF00FF00FFUL)
|(*普隆3)
{
长度-=4;
uint*puint=(uint*)(psource+长度);
*puint=((*puint>>8)和0x00FF00FFU)
|(*puint 1)
{
ushort*pushort=(ushort*)psource;
*推港=(ushort)((*pushort>>8)

| (*Pushot)您的解决方案似乎不错,但如果您的数据是奇数长度,您的代码将抛出数组越界异常。如果他交换16位字,那么他的数据将永远不会有奇数长度。是的,这将是一个私有方法,并将保证有16位字。为什么您希望更快更好?是吗这是一个O(n)解决方案,没有新的内存分配。除了在循环外声明b,这样就不会每次分配它,你为什么要改进它?很好。但这有点让人困惑。wikipedia声称“在现代(桌面)上”XOR技术比使用临时变量进行交换要慢得多。”哦,好吧。谢谢你的性感解决方案。是的,我想我们所能说的就是它很简洁。我刚刚对它进行了基准测试,得到的结果与你的解决方案相同。因此,其中一种形式很可能比另一种形式优化。Uberhacker奖!我希望大幅调整临时大小比就地交换更昂贵。这有点像是内存泄漏ust有临时设置。@initialZero:在我的基准测试中,我最初将其设置为与测试数组相同的大小,因此没有成本。像这样的临时变量通常是以牺牲内存为代价来购买速度的,这可能是一个好的决定,也可能不是一个好的决定。@MusiGenesis您可以在交换结束时设置temp=null来修复泄漏。这是确定的这是一个很酷的解决方案。谢谢。@FengYuan:不是每个方法都需要线程安全;这完全取决于它的使用方式。你不想知道交换方法不是线程安全的。这是好的工程的核心所在。这段代码有一个错误,当长度奇数时,它在缓冲区外读写。这可能导致将“bp+source.Length”更改为“bp+(source.Length&0xfffffe)”。或者在缓冲区大小为奇数时引发异常。
static unsafe void SwapV2(byte[] source)
{
    fixed (byte* psource = source)
    {
#if X86
        var length = *((uint*)(psource - 4)) & 0xFFFFFFFEU;
#elif X64
        var length = *((uint*)(psource - 8)) & 0xFFFFFFFEU;
#else
        var length = (source.Length & 0xFFFFFFFE);
#endif
        while (length > 7)
        {
            length -= 8;
            ulong* pulong = (ulong*)(psource + length);
            *pulong = ( ((*pulong >> 8) & 0x00FF00FF00FF00FFUL)
                      | ((*pulong << 8) & 0xFF00FF00FF00FF00UL));
        }
        if(length > 3)
        {
            length -= 4;
            uint* puint = (uint*)(psource + length);
            *puint = ( ((*puint >> 8) & 0x00FF00FFU)
                     | ((*puint << 8) & 0xFF00FF00U));
        }
        if(length > 1)
        {
            ushort* pushort = (ushort*)psource;
            *pushort = (ushort) ( (*pushort >> 8)
                                | (*pushort << 8));
        }
    }
}