public void DecodingTest()
        {
            HashEncodingHelper encodingHelper = new HashEncodingHelper(14, 25);

            int encodedHash;
            int expectedIndex;
            byte expectedR;

            encodedHash = 638739; // 1001 1011 1111 0001 0011
            expectedIndex = 4990; // 1 0011 0111 1110
            expectedR = 20; // 1001 + ToBinary(25 - 14)
            DecodeAndAssert(encodingHelper, encodedHash, expectedIndex, expectedR);

            encodedHash = 3567856; // 11 0110 0111 0000 1111 0000
            expectedIndex = 14456; // 11 1000 0111 1000
            expectedR = 3; // 11
            DecodeAndAssert(encodingHelper, encodedHash, expectedIndex, expectedR);

            encodedHash = 10; // 1010
            expectedIndex = 5; // 111
            expectedR = 7; // 101
            DecodeAndAssert(encodingHelper, encodedHash, expectedIndex, expectedR);

            encodedHash = 265822207; // 1111 1101 1000 0001 1111 1111 1111
            expectedIndex = 12351; // 11 0000 0011 1111
            expectedR = 74; // 11 1111 + ToBinary(25 - 14)
            DecodeAndAssert(encodingHelper, encodedHash, expectedIndex, expectedR);
        }
        private void DecodeAndAssert(HashEncodingHelper encodingHelper, int encodedHash, int expectedIndex, byte expectedR)
        {
            int idx;
            byte r;

            encodingHelper.DecodeHash(encodedHash, out idx, out r);
            Assert.AreEqual(expectedR, r, "decoded value should be as expected"); // 11
            Assert.AreEqual(expectedIndex, idx, "decoded index should be as expected"); // 11 1000 0111 1000
        }
        /// <summary>
        /// Creates a hyperloglog++ instance.
        /// </summary>
        /// <param name="precision">The higher the precision, the higher the accuracy, but also the memory usage. Must be in [4, max(28, sparsePrecision)].</param>
        /// <param name="sparsePrecision">The precision of the sparse representation. Must be inferior or equal to 63.</param>
        public HyperLogLogPlusPlus(byte precision, byte sparsePrecision)
            : base(precision)
        {
            int precisionLimit = Math.Min(sparsePrecision, (byte)28);
            if (precision < MIN_PRECISION || precision > precisionLimit)
                throw new ArgumentException(string.Format("The precision {0} must be between 4 and {1}", precision, precisionLimit));
            if (sparsePrecision > MAX_SPARSE_PRECISION)
                throw new ArgumentException(string.Format("The sparse precision {0} must be inferior or equal to 63.", sparsePrecision));

            SparseRepresentationThreshold = Convert.ToInt32(6 * M);

            SparsePrecision = sparsePrecision;

            HashEncoder = new HashEncodingHelper(precision, sparsePrecision);
        }
 private void EncodeWithPrecisionsAndAssert(ulong hash, uint expectedEncodedHash, byte precision, byte sparsePrecision)
 {
     int encodedHash = new HashEncodingHelper(precision, sparsePrecision).EncodeHash(hash);
     Assert.AreEqual(expectedEncodedHash, (uint)encodedHash, "encoded hashes should be the same");
 }