Exemplo n.º 1
0
        /// <summary>
        /// The Miller primality test uses a witness sub-routine to determine if a value may be prime
        /// </summary>
        /// <param name="value">The value to be tested for primality.</param>
        /// <param name="powersOfTwo">The powers of 2 from the value - 1.</param>
        /// <param name="factor">The factor from the value - 1.</param>
        /// <param name="witness">The witness value.</param>
        /// <returns>False if value is composite. True if value *could* be prime.</returns>
        /// <remarks>Although this is a translation of the pseudo code from Wikipedia, for prime number 4447483681 witness 2 will exhaust the loop and claim it's a composite.</remarks>
        private static bool WitnessTest(long value, long powersOfTwo, long factor, long witness)
        {
            // First iteration 0 starting power modulo is (witness ^ ((2 ^ 0) * factor)) % value
            // i.e. just (witness ^ factor) % value
            var powerModulo = MathAlgorithms.PowerModulo(_base: witness, exponent: factor, modulus: value);

            // First condition for being identified as a composite is (witness ^ factor) % value != 1
            // If that condition is not met, stop right away.
            if (powerModulo == 1 || powerModulo == value - 1)
            {
                return(true);
            }

            // value - 1 was decomposed in (2 ^ powersOfTwo) * factor
            // Iterate powersOfTwo times to compute all (witness ^ ((2 ^ iteration) * factor)) % value - let's call then f(iteration)
            for (var iteration = 0; iteration < powersOfTwo - 1; iteration++)
            {
                // f(iteration + 1) == (f(iteration) ^ 2) % value
                powerModulo = (powerModulo * powerModulo) % value;

                if (powerModulo == 1)
                {
                    return(false);
                }

                if (powerModulo == value - 1)
                {
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Calculates the count of unique ways of making a target sum given set of coins denominations
        /// </summary>
        /// <param name="targetSum">The target sum.</param>
        /// <param name="coins">The coins denominations available.</param>
        /// <returns>The count of unique ways of making the target sum.</returns>
        public static int OrderedCombinationsOfCoins(int targetSum, Stack <int> coins)
        {
            // When only a single coin denomination remains, check if we can make the target sum with such coins.
            if (coins.Count == 1)
            {
                return((targetSum % coins.Peek()) == 0 ? 1 : 0);
            }

            // Compute a hash of the target and coins denominations to check if we've learnt this result yet.
            var hash = (targetSum.GetHashCode() * 769) ^ coins.ToArray().Aggregate((partialHash, coinToHash) => (partialHash * 769) ^ coinToHash);

            if (learntCoinCombinations.TryGetValue(hash, out int countOfOrderedCombinations))
            {
                return(countOfOrderedCombinations);
            }

            var coin = coins.Pop();

            var runningSum = 0;

            while (runningSum < targetSum)
            {
                countOfOrderedCombinations += MathAlgorithms.OrderedCombinationsOfCoins(targetSum - runningSum, coins);
                runningSum += coin;
            }

            if (runningSum == targetSum)
            {
                countOfOrderedCombinations++;
            }

            coins.Push(coin);
            learntCoinCombinations.Add(hash, countOfOrderedCombinations);
            return(countOfOrderedCombinations);
        }
Exemplo n.º 3
0
        public static bool TryFindFactor(this long value, int offset, ref long factor)
        {
            long pseudoRandomSequence = 2; long doubleSpeedPseudoRandomSequence = 2; factor = 1;

            do
            {
                pseudoRandomSequence            = pseudoRandomSequence.NextPseudoRandomValue(offset: offset, modulus: value);
                doubleSpeedPseudoRandomSequence = doubleSpeedPseudoRandomSequence
                                                  .NextPseudoRandomValue(offset: offset, modulus: value)
                                                  .NextPseudoRandomValue(offset: offset, modulus: value);
                factor = MathAlgorithms.GreatestCommonDivisor(Math.Abs(pseudoRandomSequence - doubleSpeedPseudoRandomSequence), value);
            }while (factor == 1);

            return(!(factor == value));
        }
Exemplo n.º 4
0
        /// <summary>
        /// Gets the greatest common divisor using the binary algorithm.
        /// </summary>
        public static long GreatestCommonDivisor(long leftValue, long rightValue)
        {
            if (leftValue < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(leftValue), leftValue, "Only natural numbers are supported.");
            }

            if (rightValue < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(rightValue), rightValue, "Only natural numbers are supported.");
            }

            if (leftValue == rightValue)
            {
                return(leftValue);
            }

            // Special case zeroes to ensure loop termination going forward.
            if (leftValue == 0)
            {
                return(rightValue);
            }

            if (rightValue == 0)
            {
                return(leftValue);
            }

            var shiftCount = 0;

            // While both values are even, keep binary shifting right i.e. divide by 2 as it is a common divisor.
            // Both values are even if their right most bit is zero.
            // We store the common factors of 2 so we can apply it back to the GCD found on the remaining values.
            // In lower level languages than C# this can be optimized with built-in trailing zero count function.
            for (; ((leftValue | rightValue) & 1) == 0; shiftCount++)
            {
                leftValue  >>= 1;
                rightValue >>= 1;
            }

            // If one value is still even, then the other one must be odd, as per the exit condition of the previous iteration.
            // When one is even and the other odd, 2 is not a common divisor, hence the even number can be divided by 2 while the other remains the same.
            while ((leftValue & 1) == 0)
            {
                leftValue >>= 1;
            }

            // From here on, leftValue is always odd.
            // Now that we have an odd value, we are looking for the odd number which is the gcd of the remaining values
            do
            {
                // Remove all factors of 2 in rightValue, as we ensured current leftValue is odd, hence 2 is not a common divisor.
                while ((rightValue & 1) == 0)
                {
                    rightValue >>= 1;
                }

                // Here both values are odd.
                // Swap if necessary so leftValue <= rightValue.
                MathAlgorithms.SwapIfGreater(ref leftValue, ref rightValue);

                // Setting rightValue to the difference guarantees it is even, while leftValue remains odd.
                // If the difference is zero, we stop as the remaining greatest common divisor is met (and in left value).
                // If the difference is not zero, we need to seek the gcd between it and the smallest value (in left value).
                rightValue = rightValue - leftValue;
            } while (rightValue != 0);

            // Re-apply the common factors of 2.
            return(leftValue << shiftCount);
        }