/// <summary>
        /// A random <see cref="double"/> between <paramref name="minValue"/> (inclusive) and <paramref name="maxValue"/>
        /// (inclusive). If you wish to have an exclusive range,
        /// use <see cref="MathExtensions.NextAfter(float, double)"/> to adjust the range.
        /// <para/>
        /// The code was inspired by GeoTestUtil from Apache Lucene.
        /// </summary>
        /// <param name="random">The <see cref="Random"/> instance.</param>
        /// <param name="minValue">Left range boundary, inclusive. May be <see cref="double.NegativeInfinity"/>, but not <see cref="double.NaN"/>.</param>
        /// <param name="maxValue">Right range boundary, inclusive. May be <see cref="double.PositiveInfinity"/>, but not <see cref="double.NaN"/>.</param>
        /// <returns>A random <see cref="double"/> between <paramref name="minValue"/> (inclusive) and <paramref name="maxValue"/>
        /// (inclusive).</returns>
        /// <exception cref="ArgumentException"><paramref name="minValue"/> is greater than <paramref name="maxValue"/>.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="minValue"/> or <paramref name="maxValue"/> is <see cref="double.NaN"/>.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="random"/> is <c>null</c>.</exception>
        public static double RandomDoubleBetween(Random random, double minValue, double maxValue)
        {
            if (random is null)
            {
                throw new ArgumentNullException(nameof(random));
            }
            if (maxValue < minValue)
            {
                throw new ArgumentException($"{nameof(minValue)} must be greater than or equal to {nameof(maxValue)}: {minValue}, {maxValue}");
            }
            if (double.IsNaN(minValue))
            {
                throw new ArgumentOutOfRangeException(nameof(minValue), $"{nameof(minValue)} must not be {nameof(double.NaN)}");
            }
            if (double.IsNaN(maxValue))
            {
                throw new ArgumentOutOfRangeException(nameof(maxValue), $"{nameof(maxValue)} must not be {nameof(double.NaN)}");
            }

            bool hasZero = minValue <= 0 && maxValue >= 0;

            int pick = random.Next(
                EvilRangeLeft +
                EvilRangeRight +
                EvilVeryCloseRangeEnds +
                (hasZero ? EvilZeroOrNear : 0) +
                EvilSimpleProportion +
                EvilRandomRepresentationBits);

            // Exact range ends
            pick -= EvilRangeLeft;
            if (pick < 0 || minValue == maxValue)
            {
                return(minValue);
            }

            pick -= EvilRangeRight;
            if (pick < 0)
            {
                return(maxValue);
            }

            // If we're dealing with infinities, adjust them to discrete values.
            Debug.Assert(minValue != maxValue);
            if (double.IsInfinity(minValue))
            {
                minValue = minValue.NextUp();
            }
            if (double.IsInfinity(maxValue))
            {
                maxValue = maxValue.NextAfter(double.NegativeInfinity);
            }

            // Numbers "very" close to range ends. "very" means a few floating point
            // representation steps (ulps) away.
            pick -= EvilVeryCloseRangeEnds;
            if (pick < 0)
            {
                if (random.NextBoolean())
                {
                    return(FuzzUp(random, minValue, maxValue));
                }
                else
                {
                    return(FuzzDown(random, maxValue, minValue));
                }
            }

            // Zero or near-zero values, if within the range.
            if (hasZero)
            {
                pick -= EvilZeroOrNear;
                if (pick < 0)
                {
                    int v = random.Next(4);
                    if (v == 0)
                    {
                        return(0d);
                    }
                    else if (v == 1)
                    {
                        return(-0.0d);
                    }
                    else if (v == 2)
                    {
                        return(FuzzDown(random, 0d, minValue));
                    }
                    else if (v == 3)
                    {
                        return(FuzzUp(random, 0d, maxValue));
                    }
                }
            }

            // Simple proportional selection.
            pick -= EvilSimpleProportion;
            if (pick < 0)
            {
                return(minValue + (maxValue - minValue) * random.NextDouble());
            }

            // Random representation space selection. This will be heavily biased
            // and overselect from the set of tiny values, if they're allowed.
            pick -= EvilRandomRepresentationBits;
            if (pick < 0)
            {
                long from = ToSortable(minValue);
                long to   = ToSortable(maxValue);
                return(FromSortable(RandomNumbers.RandomInt64Between(random, from, to)));
            }

            throw new Exception("Unreachable.");
        }
예제 #2
0
 public static long NextInt64(Random random, long minValue, long maxValue)
 {
     return(RandomInts.RandomInt64Between(random, minValue, maxValue)); // LUCENENET: Moved general random data generation to RandomizedTesting.Generators
 }
예제 #3
0
 /**
  * A random long from <code>min</code> to <code>max</code> (inclusive).
  */
 public static long RandomInt64Between(long min, long max)
 {
     return(RandomNumbers.RandomInt64Between(Random, min, max));
 }