Обновление : мой оригинальный анализ ниже был неверным ...
К сожалению, я ошибся в поведении << 32
- C # заставляет оператор левого сдвига ограничивать число сдвигов младшими 5 битами правого операнда (6 бит для сдвига с участием 64-битного левый операнд). Таким образом, ваш исходный код был четко определен и корректен в C # (это неопределенное поведение в C / C ++). По сути, это выражение сдвига:
(this.Array[i] << shift)
эквивалентно:
(this.Array[i] << (shift & 0x1f))
Я бы, вероятно, все еще изменил бы сдвиг, чтобы сделать это явным (если бы по другой причине, что, когда я посмотрел на этот код 6 месяцев спустя, я бы не наткнулся на тот же ошибочный анализ), используя вышеприведенное вместо if (shift == 32)
проверьте.
Оригинальный анализ:
Хорошо, вот второй ответ. Самое главное, я думаю, что ваше оригинальное решение имеет ошибку в том случае, если длина вашего ImmutableBitArray
в битах кратна 32 битам, вы вернете true
для 2 массивов, которые отличаются в последнем массиве Int32[]
элемент.
Например, рассмотрим ImmutableBitArray
с длиной битов 32 бита, которые отличаются. Исходный метод Equals()
будет выполнять операцию сдвига для единственного и единственного Int32
в массиве - но он сместит значения 32 бита, поскольку
int shift = 0x20 - (this.length % 0x20);
будет оцениваться до 32.
Это означает следующий тест:
if (this.Array[i] << shift != other.Array[i] << shift)
Будет проверено на (0 != 0)
, и, следовательно, return false
не будет выполнено.
Я бы изменил ваш Equals()
метод на что-то вроде следующего, что не является существенным изменением - я думаю, что он устраняет вышеупомянутую ошибку и изменяет пару других вещей, которые строго связаны со стилем, поэтому могут не имеет никакого интереса к вам. Также обратите внимание, что я на самом деле не скомпилировал и не протестировал свой метод Equals()
, так что есть почти 100% вероятность, что есть ошибка (или, по крайней мере, синтаксическая ошибка):
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;
}
Обратите внимание, что, строго говоря, оригинальный метод GetHashCode()
не содержит ошибок, даже если он имеет тот же недостаток, потому что даже если вы неправильно смешиваете последний элемент, когда длина в битах кратна 32, равный объект будет по-прежнему возвращать тот же хэш-код. Но я все же, вероятно, решил бы исправить ошибку таким же образом в GetHashCode()
.