Пример #1
0
        public static OptimalType GetLeastTypeForAllSubcases(int numItems, int groupSize)
        {
            // This method returns the least type that will be able to handle all subcases without overflowing.
            //
            // n choose (n / 2) is the worst subcase that generates the most combinations.
            // So, if numItems is twice or more groupSize, then there is no subcase that will increase the number of combos.
            //
            BigInteger  numCombos;
            OptimalType returnValue;

            if (numItems >= groupSize + groupSize)
            {
                numCombos = Combination.GetNumCombos(numItems, groupSize);
            }
            else
            {
                numCombos = Combination.GetNumCombosBigInt(numItems, numItems / 2);
            }
            // If overflowed ulong, then only big int will work with all subtypes.
            if (numCombos > ulong.MaxValue)
            {
                returnValue = OptimalType.BigInt;
            }
            else if (numCombos <= uint.MaxValue)
            {
                returnValue = OptimalType.UnsignedInt;
            }
            else
            {
                returnValue = OptimalType.UnsignedLong;
            }
            return(returnValue);
        }
Пример #2
0
        public uint GetNumCombos(int numItems = -1, int groupSize = -1)
        {
            // This method gets the total number of combos for numItems choose groupSize from Pascal's triangle.
            // If Pascal's triangle has not been created, then an alternative method is called to get the # of combinations.
            // If either numItems or groupSize < 0, then NumItems or GroupSize, respectively is used instead.
            //
            // Both numItems and groupSize are optional parameters that provide a way to efficiently calculate the number of
            // combinations from Pascal's Triangle without having to re-create Pascal's Triangle for a different case. But,
            // both numItems and groupSize must be <= to the original NumItems and GroupSize, respectively, that were used to create the instance.
            // If either numItems or groupSize < 0, then NumItems or GroupSize, respectively, is used instead.
            //
            // Zero is returned if overflow occurred.
            // The expected runtime of this algorithm is O(1) when Pascal's Triangle is used.
            //
            string s;
            ulong  numCombos = 0;

            //
            numItems  = (numItems < 0) ? NumItems : numItems;
            groupSize = (groupSize < 0) ? GroupSize : groupSize;
            if ((numItems > NumItems) || (groupSize > GroupSize))
            {
                s = "BinCoeff:GetNumCombos: numItems > NumItems or groupSize > GroupSize. Neither is allowed.";
                ApplicationException ae = new ApplicationException(s);
                throw ae;
            }
            if ((numItems == 0) || (groupSize == 0))
            {
                s = "BinCoeff:GetNumCombos: numItems or groupSize equals zero. Neither is allowed.";
                ApplicationException ae = new ApplicationException(s);
                throw ae;
            }
            if ((groupSize == 1) || (numItems == groupSize + 1))
            {
                return((uint)numItems);
            }
            if (groupSize == numItems)
            {
                return(1);
            }
            // if Pascal's Triangle has not been created, then use an alternate method to obtain the number of combos.
            if (PasTri == null)
            {
                numCombos = Combination.GetNumCombos(numItems, groupSize);
                if (numCombos > uint.MaxValue)
                {
                    return(0);
                }
                return((uint)numCombos);
            }
            uint n          = (uint)numItems - 1;
            int  startIndex = GroupSize - groupSize;

            uint[] indexArray = PasTri[startIndex];
            int    endIndex   = indexArray.Length - 1;

            if (groupSize == 2)
            {
                endIndex -= (NumItems - numItems);
                if ((indexArray.Length > endIndex) && (uint.MaxValue - indexArray[endIndex] > numItems - 1))
                {
                    numCombos = indexArray[endIndex] + (uint)numItems - 1;
                }
            }
            else
            {
                if (numItems == NumItems)
                {
                    uint[] indexArrayPrev = PasTri[startIndex + 1];
                    int    endIndexPrev   = indexArrayPrev.Length - 1;
                    if ((indexArray.Length > n) && (indexArrayPrev.Length > n) && (uint.MaxValue - indexArray[endIndex] > indexArrayPrev[endIndexPrev]))
                    {
                        numCombos = indexArray[endIndex] + indexArrayPrev[endIndexPrev];
                    }
                }
                else
                {
                    endIndex = endIndex - (NumItems - numItems) + 1;
                    if (indexArray.Length > endIndex)
                    {
                        return(indexArray[endIndex]);
                    }
                }
            }
            return((uint)numCombos);
        }
        public BigInteger GetNumCombos(int numItems = -1, int groupSize = -1)
        {
            // This method gets the total number of combos for numItems choose groupSize from Pascal's triangle.
            // If Pascal's triangle has not been created, then an alternative method is called to get the # of combinations.
            // If either numItems or groupSize < 0, then NumItems or GroupSize, respectively is used instead.
            //
            // Both numItems and groupSize are optional parameters that provide a way to efficiently calculate the number of
            // combinations from Pascal's Triangle without having to re-create Pascal's Triangle for a different case. But,
            // both numItems and groupSize must be <= to the original NumItems and GroupSize, respectively, that were used to create the instance.
            // If either numItems or groupSize < 0, then NumItems or GroupSize, respectively, is used instead.
            //
            // Zero is returned if overflow occurred.
            // The expected runtime of this algorithm is O(1) when Pascal's Triangle is used.
            //
            string     s;
            BigInteger numCombos = 0;

            //
            numItems  = (numItems == -1) ? NumItems : numItems;
            groupSize = (groupSize == -1) ? GroupSize : groupSize;
            if ((numItems > NumItems) || (groupSize > GroupSize))
            {
                s = "BinCoeffBigInt:GetNumCombos: numItems > NumItems || groupSize > GroupSize. Neither is allowed. Create a new instance instead.";
                ApplicationException ae = new ApplicationException(s);
                throw ae;
            }
            if ((numItems == 0) || (groupSize == 0))
            {
                s = "BinCoeffBigInt:GetNumCombos: numItems or groupSize equals zero. Neither is allowed.";
                ApplicationException ae = new ApplicationException(s);
                throw ae;
            }
            if ((groupSize == 1) || (numItems == groupSize + 1))
            {
                return(numItems);
            }
            if (groupSize == numItems)
            {
                return(1);
            }
            // There are times when Pascal's triangle may not have been legitimately created. For example 5 choose 5.
            // If this method is called, for example, with 5 choose 3 after being created with a 5 choose 5 case, then this is handled here.
            if (PasTri == null)
            {
                numCombos = Combination.GetNumCombos(numItems, groupSize);
                return(numCombos);
            }
            uint n          = (uint)numItems - 1;
            int  startIndex = GroupSize - groupSize;

            BigInteger[] indexArray = PasTri[startIndex];
            int          endIndex   = indexArray.Length - 1;

            if (groupSize == 2)
            {
                if (numItems != NumItems)
                {
                    endIndex -= (NumItems - numItems);
                }
                numCombos = indexArray[endIndex] + (uint)numItems - 1;
            }
            else
            {
                if (numItems == NumItems)
                {
                    BigInteger[] indexArrayPrev = PasTri[startIndex + 1];
                    int          endIndexPrev   = indexArrayPrev.Length - 1;
                    numCombos = indexArray[endIndex] + indexArrayPrev[endIndexPrev];
                }
                else
                {
                    endIndex = endIndex - (NumItems - numItems) + 1;
                    return(indexArray[endIndex]);
                }
            }
            return(numCombos);
        }