【问题标题】:How to generate a random double with (separately) minimum / maximum limits?如何生成具有(单独)最小/最大限制的随机双精度?
【发布时间】:2016-12-10 00:34:25
【问题描述】:

这就是我想要实现的目标:

public double NextMin (double min)
{
    //Returns a double that is greater than or equal to "min". 
}

public double NextMax (double max)
{
    //Returns a double that is lesser than "max".
}

我尝试了范围扩展,但由于溢出,它返回了很多“无限”:

// Range expanding for min
random.NextDouble() * (double.MaxValue - min) + min;

// Range expanding for max 
random.NextDouble() * (max - double.MinValue) + double.MinValue;

澄清:我需要尽可能大的返回范围,这意味着它们应该包括负数和正数。

【问题讨论】:

  • 为什么要这样做?这是 X-Y 问题吗?
  • @Enigmativity 我将生成一个程序宇宙,我需要一些随机向量采样。我的算法需要这些方法。
  • 如果您假设double.MaxValue == 10.0double.MinValue == -10.0 然后double.MaxValue - double.MinValue == 20.0,但这大于double 的允许范围(在此假设下)。因此,您遇到无穷大问题的原因。

标签: c# math random


【解决方案1】:

我相信这适用于一般情况(前提是 min 小于 max)。

private Random rng = new Random();

private double GetRandomDouble(double min, double max)
{
    var half_min = min / 2.0;
    var half_max = max / 2.0;
    var average = half_min + half_max;
    var factor = max - average;

    return (2.0 * rng.NextDouble() - 1.0) * factor + average;
}

调用Console.WriteLine(GetRandomDouble(double.MinValue, double.MaxValue)); 然后正确地产生介于double.MinValuedouble.MaxValue 之间的值。

然后你只需充实你想要的两种方法,就像这样:

public double NextMin(double min)
{
    return GetRandomDouble(min, double.MaxValue);
}

public double NextMax(double max)
{
    return GetRandomDouble(double.MinValue, max);
}

【讨论】:

  • 确实如此。但是我在(double.MinValue, double.MaxValue) 范围内生成了 10000 个随机数,它们的指数都是 308、307 或 306。指数有什么问题?
  • @S.TarıkÇetin - 指数没有问题。这在数学上是正确的。 0.0 & 1.0 之间 90% 的随机数大于0.1 & 0.1 * double.MaxValue1.79769313486232E+307 所以你应该期望0.0 & double.maxValue 之间的随机数的90% 大于@987654336 @.
  • 所以这是数学没有任何意义的时刻之一......我想分别选择尾数和指数是解决这种情况的方法。
  • @S.TarıkÇetin - 那么你没有均匀分布。如果你想要一个统一的分布,那么你坚持这个答案。否则,您将采用某种非均匀分布,例如钟形曲线。我认为这是一个数学有意义的案例,但它并不直观,因为我们的人类大脑无法处理 308 位的数字。
  • @S.TarıkÇetin 正如您所要求的,数学为您提供了在给定范围内均匀分布的随机值。也许你有不同的想法,但这不是数学的错。
【解决方案2】:

这应该更好地处理溢出。

// Range expanding for min
double.MaxValue - random.NextDouble() * (double.MaxValue - min);

// Range expanding for max 
double.MinValue + random.NextDouble() * (max - double.MinValue);

第二个实际上与您发布的那个相同,我不明白为什么那个不会起作用。

【讨论】:

  • 如果min 在第一种方法中小于0.0max 在第二种方法中大于0.0,这将失败。两者都会溢出。
  • @Enigmativity 没错,当然。太晚了,无法弄清楚如何做到而不像您的解决方案一样损失1-2位精度。为此 +1。
  • 我认为你无法避免。如果计算是double.MaxValue - double.MinValue`,那么您必须除以2.0,以使结果适合double。你必须失去精确度。
【解决方案3】:
private Random rng = new Random();

private double GetRandomDouble(double min, double max)
{
    // Get the base value, scale first and then shift.
    return rng.NextDouble()*(max - min) + min;
}

编辑:我有点困惑为什么这对我有用,而不是对其他人有用。我刚刚运行此代码是 VS 2015.3,但在三次运行中没有一次检测到无限值:

class Program
{
    static void Main(string[] args)
    {
        const int maxIterations = 100000;
        var infinityDetected = false;

        for (int i = 0; i < maxIterations; i++)
        {
            var d = GetRandomDouble(double.MinValue, double.MaxValue);

            if (double.IsInfinity(d))
            {
                infinityDetected = true;
                Console.WriteLine("Infinity detected");
                break;
            }

            Console.WriteLine(d);
        }

        if (!infinityDetected)
        {
            for (int i = 0; i < maxIterations; i++)
            {
                var d = GetRandomDouble(-1.0, double.MaxValue);

                if (double.IsInfinity(d))
                {
                    infinityDetected = true;
                    Console.WriteLine("Infinity detected");
                    break;
                }

                Console.WriteLine(d);
            }
        }

        if (!infinityDetected)
        {
            for (int i = 0; i < maxIterations; i++)
            {
                var d = GetRandomDouble(double.MinValue, 1.0);

                if (double.IsInfinity(d))
                {
                    Console.WriteLine("Infinity detected");
                    break;
                }

                Console.WriteLine(d);
            }
        }

        Console.ReadLine();
    }

    private static Random rng = new Random();

    private static double GetRandomDouble(double min, double max)
    {
        // Get the base value, scale first and then shift.
        return rng.NextDouble() * (max - min) + min;
    }
}

【讨论】:

  • 第一个块返回所有 Infinity。
  • @S.TarıkÇetin 虽然Ideone 不输出无穷大。
  • 我刚刚运行了一个调用GetRandomDouble(double.MinValue,double.MaxValue) 100,000 次的循环,而double.IsInfinity 在传递结果时没有一次返回true。也就是说,输出看起来不像是随机分布的,所以有些不对劲。
  • @jmcilhinney - 我刚刚运行了这段代码并得到了。 OP是对的。
  • @Enigmativity,OP 可能是正确的,他们得到了无穷大,但我运行它但我没有运行它,所以我不确定有什么不同。正如我所说,我运行了一个循环,使用 double 的限制执行该方法 100,000 次,并且完全没有问题。根据您关于分发的 cmets,我现在意识到我看到的输出非常合适。因此,我的代码对我来说似乎 100% 正常工作,但显然不适用于其他人。我真的不知道为什么会这样。
【解决方案4】:

试试这个:

random.NextDouble() * (double.MaxValue - min) + min;
random.NextDouble() * (double.MinValue + max) - max;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 2013-08-10
    相关资源
    最近更新 更多