在我的应用程序中,我需要比System.Collections.BitArray
类更多的东西。具体来说,我需要位数组:
我创建了自己的struct
,主要是复制BitArray
实现的内部。 (谢谢,.Net Reflector!)
我不会每天处理按位操作,所以我对我的等式实现没有最高的信心。 (它正在通过我投掷的单元测试,但我可能会遗漏边缘情况。)我将我提出的解决方案作为下面的答案。我会感谢别人的反馈和答案,可能更正确或更有效。
就像CLR BitArray
一样,length
字段指的是结构中的位数,而array
字段(或Array
属性)指的是32 -bit整数数组,表示位。
[CLARIFICATION] 我选择在构造函数和其他方法中采用简单的路径,这样我就不能依赖于不必要的位为零。例如,
Not()
通过对整数数组元素进行按位求反(~
)来实现。因此,我需要在比较中处理(或者更确切地说,忽略)它们。一个好的解决方案也是让这些位始终处于归零状态,但在我的情况下会导致更多的工作(对于计算机和我来说都是如此!)
答案 0 :(得分:2)
如果在ImmutableBitArray
的构造函数中,最后一个元素上未使用的'填充位'被强制为零,则不需要跳过箍只检查最后一个元素中的有效位,如填充在相同的情况下将是相同的。
这将很好地简化Equals()
和GetHashCode()
方法:
public bool Equals(ImmutableBitArray other)
{
if (this.length != other.length)
{
return false;
}
for (int i = 0; i < this.Array.Length; i++)
{
if (this.Array[i] != other.Array[i])
{
// since padding bits are forced to zero in the constructor,
// we can test those for equality just as well and the valid
// bits
return false;
}
}
return true;
}
public override int GetHashCode()
{
int hc = this.length;
for (int i = 0; i < this.Array.Length; i++)
{
// since padding bits are forced to zero in the constructor,
// we can mix those into the hashcode no problem
hc ^= this.Array[i];
}
return hc;
}
答案 1 :(得分:2)
更新:我的原始分析不正确......
不幸的是,我对<< 32
的行为不正确 - C#强制左移运算符将限制移位到右操作数的低5位(6位用于涉及64的移位)位左操作数)。因此,您的原始代码在C#中定义良好且正确(在C / C ++中是未定义的行为)。基本上,这个转变表达式:
(this.Array[i] << shift)
相当于:
(this.Array[i] << (shift & 0x1f))
我可能仍然会改变这种明确的转变(如果没有其他原因,当我在6个月之后查看该代码时,我不会偶然发现同样的错误分析)使用上面而不是{{ 1}}检查。
原始分析:
好的,所以这是第二个答案。最重要的是,我认为你的原始解决方案有一个错误,你的if (shift == 32)
的位长是32位的倍数,你将返回ImmutableBitArray
2个数组,它们在最后一个不同true
数组元素。
例如,考虑具有32位不同的Int32[]
s。原始ImmutableBitArray
方法将对数组中的唯一Equals()
执行移位操作 - 但它会将值移位32位,因为
Int32
将评估为32。
这意味着下一个测试:
int shift = 0x20 - (this.length % 0x20);
将测试if (this.Array[i] << shift != other.Array[i] << shift)
,因此(0 != 0)
将不会被执行。
我会将您的return false
方法更改为以下内容,这不是一个重大更改 - 我认为它会处理上面提到的错误并更改其他一些严格与样式相关的内容所以对你没兴趣。另请注意,我实际上没有编译和测试我的Equals()
方法,因此几乎有100%的可能存在错误(或至少存在语法错误):
Equals()
请注意,严格来说,即使原始public bool Equals(ImmutableBitArray other)
{
if (this.length != other.length)
{
return false;
}
int finalIndex = this.Array.Length - 1;
for (int i = 0; i < finalIndex; i++)
{
if (this.Array[i] != other.Array[i])
{
return false;
}
}
// check the last array element, making sure to ignore padding bits
int shift = 32 - (this.length % 32);
if (shift == 32) {
// the last array element has no padding bits - don't shift
shift = 0;
}
if (this.Array[finalIndex] << shift != other.Array[finalIndex] << shift)
{
return false;
}
return true;
}
方法具有相同的缺陷,也不会出现错误,因为即使您在位长为倍数的情况下没有正确混合最后一个元素32,相等的对象仍将返回相同的哈希码。但我仍然可能决定在GetHashCode()
中以同样的方式解决这个缺陷。
答案 2 :(得分:1)
平等方法:
public bool Equals(ImmutableBitArray other)
{
if (this.length != other.length)
{
return false;
}
for (int i = 0; i < this.Array.Length; i++)
{
if (this.Array[i] != other.Array[i])
{
// This does not necessarily mean that the relevant bits of the integer arrays are different.
// Is this before the last element in the integer arrays?
if (i < this.Array.Length - 1)
{
// If so, then the objects are not equal.
return false;
}
// If this is the last element in the array we only need to be concerned about the bits
// up to the length of the bit array.
int shift = 0x20 - (this.length % 0x20);
if (this.Array[i] << shift != other.Array[i] << shift)
{
return false;
}
}
}
return true;
}
必要的GetHashCode覆盖:
public override int GetHashCode()
{
int hc = this.length;
for (int i = 0; i < this.Array.Length; i++)
{
if (i < this.Array.Length - 1)
{
hc ^= this.Array[i];
}
else
{
int shift = 0x20 - (this.length % 0x20);
hc ^= this.Array[this.Array.Length - 1] << shift;
}
}
return hc;
}
答案 3 :(得分:1)
经过几个小时的搜索和学习,我终于得到了答案并想分享。我没有审查性能,因为我只关心可读性。
if (input1.length != input2.length)
{
return false;
}
var result = new BitArray(input1);
result = result.Xor(input2);
if (result.Cast<bool>().Contains(true))
return false;
return true;