1. ホーム
  2. c#

[解決済み] .NETでの2つのバイト配列の比較

2022-02-04 14:22:36

質問

どうすれば早くできるのですか?

もちろん、できますよ。

static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length)
        return false;

    for (int i=0; i<a1.Length; i++)
        if (a1[i]!=a2[i])
            return false;

    return true;
}

しかし、私が探しているのは、どちらかの BCL 関数や、高度に最適化された実績のある方法でこれを行うことができます。

java.util.Arrays.equals((sbyte[])(Array)a1, (sbyte[])(Array)a2);

はうまく動くのですが、x64ではうまくいかないようです。

私の超高速回答をご覧ください こちら .

解決方法は?

ユーザー名 ギル が安全でないコードを提案し、この解決策が生まれました。

// Copyright (c) 2008-2013 Hafthor Stefansson
// Distributed under the MIT/X11 software license
// Ref: http://www.opensource.org/licenses/mit-license.php.
static unsafe bool UnsafeCompare(byte[] a1, byte[] a2) {
  if(a1==a2) return true;
  if(a1==null || a2==null || a1.Length!=a2.Length)
    return false;
  fixed (byte* p1=a1, p2=a2) {
    byte* x1=p1, x2=p2;
    int l = a1.Length;
    for (int i=0; i < l/8; i++, x1+=8, x2+=8)
      if (*((long*)x1) != *((long*)x2)) return false;
    if ((l & 4)!=0) { if (*((int*)x1)!=*((int*)x2)) return false; x1+=4; x2+=4; }
    if ((l & 2)!=0) { if (*((short*)x1)!=*((short*)x2)) return false; x1+=2; x2+=2; }
    if ((l & 1)!=0) if (*((byte*)x1) != *((byte*)x2)) return false;
    return true;
  }
}

これは、配列の可能な限り多くの部分で 64 ビットベースの比較を行います。これは、配列がqwordアライメントで開始されるという事実を当てにしているようなものです。qwordアライメントでなくても動作しますが、qwordアライメントである場合ほど高速ではありません。

単純な for ループを使用します。J#ライブラリを使用すると、オリジナルの for のループになります。.SequenceEqualを使うと、IEnumerator.MoveNextを使っているためか、7倍ほど遅くなる。LINQベースのソリューションは、少なくともこれより遅いか、もっと悪いと想像しています。