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 checkOperand(BitString operand)
        {
            if (operand == null)
            {
                throw new ArgumentNullException();
            }

            if (operand._length != _length)
            {
                throw new ArgumentException();
            }
        }
        public BitString Xor(BitString value)
        {
            checkOperand(value);

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

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

            checkOperand(value);

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

            _version++;

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

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

            //var sw = Stopwatch.StartNew();

            int from = Math.Max(MinPositiveWord, other.MinPositiveWord);
            int to = Math.Min(MaxPositiveWord, other.MaxPositiveWord);

            bool result = false;

            int steps = 0;

            long[] otherArray = other._array;

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

            /*
            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);
            }
            */

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

            int from = Math.Max(MinPositiveWord, other.MinPositiveWord);
            int to = Math.Min(MaxPositiveWord, other.MaxPositiveWord);

            long[] otherArray = other._array;

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

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

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

            int from = Math.Max(MinPositiveWord, other.MinPositiveWord);
            int to = Math.Min(MaxPositiveWord, other.MaxPositiveWord);

            var result = new List<int>();

            long[] otherArray = other._array;

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

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

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

            int from = Math.Max(MinPositiveWord, other.MinPositiveWord);
            int to = Math.Min(MaxPositiveWord, other.MaxPositiveWord);

            int result = 0;

            long[] otherArray = other._array;

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

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

            return result;
        }