特殊随机数

时间:2009-07-31 12:09:44

标签: c# random numbers

我想要一个这样的随机数:(在C#中)

Random r = new Random();
r.next (0,10)

但重要的是随机数要接近8,(或者通常很大), 我的意思是如果我们使用for:

for (int i =0; i<...;i++)
{
  write: r.next (0,10)
}

结果是这样的;

8 7 6 9 1 0 5 3 2
2 3 8 9 7 7 6 2 3
8 8 9 7 2 8 2 8 4
3

6 个答案:

答案 0 :(得分:29)

您需要对结果进行加权。你可以这样做:

private int[] _distribution = new int[] { 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9 };
Random _r = new Random();

public int GetWeightedRandom()
{
    return _distribution[_r.Next(0, _distribution.Length)];
}

如果我知道我的范围很小而且一致,我会使用这个表 - 将它变成自己的类是微不足道的。

为了完整性,我还要添加这个类。这个类借用图像处理并使用伽马校正函数:0到1之间的值被提升到gamma,它返回0到1之间的值,但分布更多到如果γ<1,则为低端。如果γ> 1,则高端为1.0以上1.0。

public class GammaRandom {
    double _gamma;
    Random _r;

    public GammaRandom(double gamma) {
        if (gamma <= 0) throw new ArgumentOutOfRangeException("gamma");
        _gamma = gamma;
        _r = new Random();
    }
    public int Next(int low, int high) {
       if (high <= low) throw new ArgumentOutOfRangeException("high");
       double rand = _r.NextDouble();
       rand = math.Pow(rand, _gamma);
       return (int)((high - low) * rand) + low;
    }
}

(来自评论,将r移出GetWeightedRandom()。还将范围检查添加到Next())

好的,我们真的去这里的小镇。我正在为此引导John双向飞碟 - 这是一个带有模板属性的抽象类,它返回一个将范围[0..1]映射到[0..1]的变换函数,并将随机数缩放到该范围。我也重新实现了伽玛,并实现了罪和cos。

public abstract class DelegatedRandom
{
    private Random _r = new Random();
    public int Next(int low, int high)
    {
        if (high >= low)
            throw new ArgumentOutOfRangeException("high");
        double rand = _r.NextDouble();
        rand = Transform(rand);
        if (rand >= 1.0 || rand < 0) throw new Exception("internal error - expected transform to be between 0 and 1");
        return (int)((high - low) * rand) + low;
    }
    protected abstract Func<double, double> Transform { get; }
}

public class SinRandom : DelegatedRandom
{
    private static double pihalf = Math.PI / 2;
    protected override Func<double, double> Transform
    {
        get { return r => Math.Sin(r * pihalf); }
    }
}
public class CosRandom : DelegatedRandom
{
    private static double pihalf = Math.PI / 2;
    protected override Func<double, double> Transform
    {
        get { return r => Math.Cos(r * pihalf); }
    }
}
public class GammaRandom : DelegatedRandom
{
    private double _gamma;
    public GammaRandom(double gamma)
    {
        if (gamma <= 0) throw new ArgumentOutOfRangeException("gamma");
        _gamma = gamma;
    }
    protected override Func<double, double> Transform
    {
        get { return r => Math.Pow(r, _gamma); }
    }
}

答案 1 :(得分:2)

您需要一个分配函数,该函数取0到1之间的数字并将其转换为您想要的范围内的数字,并且特定数字的权重更高。您可以使用三角函数(sin,cos,...),指数或多项式创建这样的函数。

更新:有关概率分布的更多信息,请查看this page

答案 2 :(得分:2)

您可以查看此SO answer而不是使用数组变体,它可以链接到Math.NET Iridium,实现非均匀随机生成器。

数组变体的优点是您可以获得更加动态的方法,而无需一直重写数组。您也可以使用数组变量(大的非均匀随机数)做一些几乎不可能完成的事情。

答案 3 :(得分:1)

应该可以进行某种额外的加权。取决于你如何指定“接近八”。一个非常简单的方法是:

for (int i =0; i<...;i++)
{
    n = r.next (0,100);
    write: (n*n) / 1000
}

平方会将数字加权到低端,即在这种情况下,33%的时间会得到0,而你只会得到9只有5%左右当时。

这种方法当然可以适应特定情况。

答案 4 :(得分:1)

不完全是您正在寻找的东西,但是一种非常简单的近似正态数字分布的方法是将多代产生在一起。

这项技术的一个典型例子是在“龙与地下城”游戏中,可以通过滚动三个六面骰子并添加结果来确定角色强度。这给出了3到18的范围,最可能的数字大约为10。变体包括:

  • 滚动4个骰子并弃掉最低点。这会使分布偏向更高的数字。
  • 平均得分而不是添加它们。这使得输出范围更容易理解。

或者,this非常接近......

答案 5 :(得分:0)

在我看来,你希望你的随机数被加权到高端 - 这是一个公平的评估吗?

this这样的东西可以帮助你(它是Java,但原则适用)