public void BitGetSetTest()
        {
            const int n = 250;

            var array = new BitArray(n);
            var str = new BitString(n);

            for (var i = 0; i < n; i++)
            {
                var value = Randomizer.Next(0, 2) == 0;
                array.Set(i, value);
                str.Set(i, value);

                Assert.IsTrue(array.Get(i) == value);
                Assert.IsTrue(str.Get(i) == value);
            }
        }
        public BitString(BitString bits)
        {
            if (bits == null)
            {
                throw new ArgumentNullException("bits");
            }

            _length = bits._length;
            _array = new long[(_length + 63) / 64];

            _minPositiveWord = bits._minPositiveWord;
            _maxPositiveWord = bits._maxPositiveWord;

            if (_array.Length == 1)
            {
                _array[0] = bits._array[0];
            }
            else
            {
                Array.Copy(bits._array, _array, _array.Length);
            }
        }
 private void EnsureArgumentIsValid(BitString other)
 {
     if (other == null)
         throw new ArgumentNullException();
     if (other._length != _length)
         throw new ArgumentException();
 }
        public BitString Xor(BitString value)
        {
            EnsureArgumentIsValid(value);

            long ints = (_length + 63) / 64;
            for (long i = 0; i < ints; i++)
            {
                _array[i] ^= value._array[i];
                RefreshBordersByWord(i);
            }

            //_version++;
            return this;
        }
        public BitString Or(BitString value)
        {
            #if DEBUG
            var sw = Stopwatch.StartNew();
            #endif

            EnsureArgumentIsValid(value);

            long ints = (_length + 63) / 64;
            for (long i = 0; i < ints; i++)
            {
                _array[i] |= value._array[i];
                RefreshBordersByWord(i);
            }

            //_version++;

            #if DEBUG
            Console.WriteLine("OR -> Len: {0}, Time: {1}", this._array.Length, sw.Elapsed.TotalMilliseconds);
            #endif

            return this;
        }
        public bool HaveCommonBits(BitString other)
        {
            if (Length != other.Length)
            {
                throw new ArgumentException("Bit strings must have same size", "other");
            }

            #if DEBUG
            var sw = Stopwatch.StartNew();
            #endif

            long from = Math.Max(_minPositiveWord, other._minPositiveWord);
            long to = Math.Min(_maxPositiveWord, other._maxPositiveWord);

            bool result = false;

            #if DEBUG
            int steps = 0;
            #endif
            long[] otherArray = other._array;

            for (long i = from; i <= to; i++)
            {
            #if DEBUG
                steps++;
            #endif
                long v1 = _array[i];
                long v2 = otherArray[i];
                if (v1 != 0 && v2 != 0 && ((v1 & v2) != 0))
                {
                    result = true;
                    break;
                }
            }

            #if DEBUG
            if (sw.Elapsed.TotalMilliseconds > 0.1)
            {
                Console.WriteLine("HCB -> Min: {0}, Max: {1}, Delta: {2}, Steps: {3}, Time: {4}", from, to, to - from, steps, sw.Elapsed.TotalMilliseconds);
            }
            #endif

            return result;
        }
        public int GetLastCommonBitIndex(BitString other)
        {
            if (Length != other.Length)
            {
                throw new ArgumentException("Bit strings must have same size", "other");
            }

            long from = Math.Max(_minPositiveWord, other._minPositiveWord);
            long to = Math.Min(_maxPositiveWord, other._maxPositiveWord);

            long[] otherArray = other._array;

            for (long i = from; i <= to; i++)
            {
                long v1 = _array[i];
                long v2 = otherArray[i];
                long n = v1 & v2;
                if (n != 0)
                {
                    var bits1 = BitSetsIn16Bits[(int)(n & 0xffffu)];
                    var bits2 = BitSetsIn16Bits[(int)((n >> 16) & 0xffffu)];
                    var bits3 = BitSetsIn16Bits[(int)((n >> 32) & 0xffffu)];
                    var bits4 = BitSetsIn16Bits[(int)((n >> 48) & 0xffffu)];

                    if (bits4.Length > 0)
                        return bits4[bits4.Length - 1] + 48 + (int)i * 64;
                    if (bits3.Length > 0)
                        return bits3[bits3.Length - 1] + 32 + (int)i * 64;
                    if (bits2.Length > 0)
                        return bits2[bits2.Length - 1] + 16 + (int)i * 64;
                    return bits1[bits1.Length - 1] + (int)i * 64;
                }
            }

            return -1;
        }
        public List<int> GetCommonIndices(BitString other)
        {
            if (Length != other.Length)
            {
                throw new ArgumentException("Bit strings must have same size", "other");
            }

            long from = Math.Max(_minPositiveWord, other._minPositiveWord);
            long to = Math.Min(_maxPositiveWord, other._maxPositiveWord);

            var result = new List<int>();

            long[] otherArray = other._array;

            for (long i = from; i <= to; i++)
            {
                long v1 = _array[i];
                long v2 = otherArray[i];
                long n = v1 & v2;
                if (n != 0)
                {
                    var bits1 = BitSetsIn16Bits[(int)(n & 0xffffu)];
                    var bits2 = BitSetsIn16Bits[(int)((n >> 16) & 0xffffu)];
                    var bits3 = BitSetsIn16Bits[(int)((n >> 32) & 0xffffu)];
                    var bits4 = BitSetsIn16Bits[(int)((n >> 48) & 0xffffu)];

                    if (bits1.Length > 0)
                        result.Add(bits1[0] + (int)i * 64);
                    else if (bits2.Length > 0)
                        result.Add(bits2[0] + 16 + (int)i * 64);
                    else if (bits3.Length > 0)
                        result.Add(bits3[0] + 32 + (int)i * 64);
                    else
                        result.Add(bits4[0] + 48 + (int)i * 64);
                }
            }

            return result;
        }
        public int CountCommonBits(BitString other)
        {
            if (Length != other.Length)
            {
                throw new ArgumentException("Bit strings must have same size", "other");
            }

            long from = Math.Max(_minPositiveWord, other._minPositiveWord);
            long to = Math.Min(_maxPositiveWord, other._maxPositiveWord);

            int result = 0;

            long[] otherArray = other._array;

            for (long i = from; i <= to; i++)
            {
                long v1 = _array[i];
                long v2 = otherArray[i];
                long n = v1 & v2;
                if (n != 0)
                {
                    var bits1 = BitSetsIn16Bits[(int)(n & 0xffffu)];
                    var bits2 = BitSetsIn16Bits[(int)((n >> 16) & 0xffffu)];
                    var bits3 = BitSetsIn16Bits[(int)((n >> 32) & 0xffffu)];
                    var bits4 = BitSetsIn16Bits[(int)((n >> 48) & 0xffffu)];

                    result += bits1.Length + bits2.Length + bits3.Length + bits4.Length;
                }
            }

            return result;
        }