/// <summary>
        /// Tukey tapering window. A rectangular window bounded
        /// by half a cosine window on each side.
        /// </summary>
        /// <param name="width">Width of the window</param>
        /// <param name="r">Fraction of the window occupied by the cosine parts</param>
        public static double[] Tukey(int width, double r = 0.5)
        {
            if (r <= 0)
            {
                return(Generate.Repeat(width, 1.0));
            }
            else if (r >= 1)
            {
                return(Hann(width));
            }

            var w      = new double[width];
            var period = (width - 1) * r;
            var step   = (2 * Math.PI) / period;
            var b1     = (int)Math.Floor(((width - 1) * r * 0.5) + 1);
            var b2     = width - b1;

            for (var i = 0; i < b1; i++)
            {
                w[i] = (1 - Math.Cos(i * step)) * 0.5;
            }
            for (var i = b1; i < b2; i++)
            {
                w[i] = 1;
            }
            for (var i = b2; i < width; i++)
            {
                w[i] = w[width - i - 1];
            }
            return(w);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Generate a random variation, without repetition, by randomly selecting k of n elements with order. This is an O(k) space-complexity implementation optimized for very large N.<br/>
        /// The space complexity of Fisher-Yates Shuffling is O(n+k). When N is very large, the algorithm will be unexecutable in limited memory, and a more memory-efficient algorithm is needed.<br/>
        /// You can explicitly cast N to <see cref="BigInteger"/> if N is out of range of <see cref="int"/> or memory, so that this special implementation is called. However, this implementation is slower than Fisher-Yates Shuffling: don't call it if time is more critical than space.<br/>
        /// The K of type <see cref="BigInteger"/> seems impossible, because the returned array is of size K and must all be stored in memory.
        /// </summary>
        /// <param name="n">Number of elements in the set.</param>
        /// <param name="k">Number of elements to choose from the set. Each element is chosen at most once.</param>
        /// <param name="randomSource">The random number generator to use. Optional; the default random source will be used if null.</param>
        /// <returns>An array of length <c>K</c> that contains the indices of the selections as integers of the interval <c>[0, N)</c>.</returns>
        public static BigInteger[] GenerateVariation(BigInteger n, int k, System.Random randomSource = null)
        {
            if (n < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(n), "Value must not be negative (zero is ok).");
            }
            if (k < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(k), "Value must not be negative (zero is ok).");
            }
            if (k > n)
            {
                throw new ArgumentOutOfRangeException(nameof(k), $"k must be smaller than or equal to n.");
            }

            var random = randomSource ?? SystemRandomSource.Default;

            BigInteger[] selection = new BigInteger[k];
            if (n == 0 || k == 0)
            {
                return(selection);
            }

            selection[0] = random.NextBigIntegerSequence(BigInteger.Zero, n).First();
            bool[]     compareCache;
            bool       keepLooping;
            BigInteger randomNumber;

            for (int a = 1; a < k; a++)
            {
                randomNumber = random.NextBigIntegerSequence(BigInteger.Zero, n - a).First();
                compareCache = Generate.Repeat(a, true);
                do
                {
                    keepLooping = false;
                    for (int b = 0; b < a; ++b)
                    {
                        if (compareCache[b] && randomNumber >= selection[b])
                        {
                            compareCache[b] = false;
                            keepLooping     = true;
                            randomNumber++;
                        }
                    }
                } while (keepLooping);
                selection[a] = randomNumber;
            }

            return(selection);
        }