生成(U)Int64和Decimal的(伪)随机约束值

Oha*_*der 5 c# random

注意:为简洁起见,以下内容无法区分随机性和伪随机性.此外,在此上下文中,约束意味着给定的最小值和最大值之间)

System.Random类提供随机生成整数,双打和字节数组.使用Random.Next,可以轻松生成类型为布尔值,字符,(S)字节,(U)Int16,(U)Int32的随机约束值.使用时Random.NextDouble(),可以类似地生成Double和Single类型的约束值(就我对此类型的理解而言).随机串生成(给定长度和字母的)已经 解决 之前.

考虑剩余的原始数据类型(不包括Object):Decimal和(U)Int64.他们的随机生成也已被解决(Decimal,(U)Int64使用Random.NextBytes()),但不受限制.理论上可以使用拒绝采样(即循环直到生成的值是所需范围),但这显然不是一个实际的解决方案.归一化NextDouble()不起作用,因为它没有足够的有效数字.

简而言之,我要求正确实现以下功能:

long NextLong(long min, long max)
long NextDecimal(decimal min, decimal max)
Run Code Online (Sandbox Code Playgroud)

请注意,由于System.DateTime基于ulong,第一个函数也允许随机约束生成此类结构(类似于此处,仅在刻度而不是分钟内).

jas*_*son 9

这应该做到这一点.对于十进制,我使用Jon Skeet的初始方法来生成随机decimals(无约束).因为long我提供了一种产生随机非负longs的方法,然后用它来创建随机范围内的a值.

请注意,decimal由此产生的分布不是均匀分布[minValue, maxValue].它只是在小数的所有位表示中均匀,落在该范围内[minValue, maxValue].如果不使用拒绝采样,我没有看到一个简单的方法.

对于long所得到的分布是均匀的上[minValue, maxValue).

static class RandomExtensions {
    static int NextInt32(this Random rg) {
        unchecked {
            int firstBits = rg.Next(0, 1 << 4) << 28;
            int lastBits = rg.Next(0, 1 << 28);
            return firstBits | lastBits;
        }
    }

    public static decimal NextDecimal(this Random rg) {
        bool sign = rg.Next(2) == 1;
        return rg.NextDecimal(sign);
    }

    static decimal NextDecimal(this Random rg, bool sign) {
        byte scale = (byte)rg.Next(29);
        return new decimal(rg.NextInt32(),
                           rg.NextInt32(),
                           rg.NextInt32(),
                           sign,
                           scale);
    }

    static decimal NextNonNegativeDecimal(this Random rg) {
        return rg.NextDecimal(false);
    }

    public static decimal NextDecimal(this Random rg, decimal maxValue) {
        return (rg.NextNonNegativeDecimal() / Decimal.MaxValue) * maxValue; ;
    }

    public static decimal NextDecimal(this Random rg, decimal minValue, decimal maxValue) {
        if (minValue >= maxValue) {
            throw new InvalidOperationException();
        }
        decimal range = maxValue - minValue;
        return rg.NextDecimal(range) + minValue;
    }

    static long NextNonNegativeLong(this Random rg) {
        byte[] bytes = new byte[sizeof(long)];
        rg.NextBytes(bytes);
        // strip out the sign bit
        bytes[7] = (byte)(bytes[7] & 0x7f);
        return BitConverter.ToInt64(bytes, 0);
    }

    public static long NextLong(this Random rg, long maxValue) {
        return (long)((rg.NextNonNegativeLong() / (double)Int64.MaxValue) * maxValue);
    }

    public static long NextLong(this Random rg, long minValue, long maxValue) {
        if (minValue >= maxValue) {
            throw new InvalidOperationException();
        }
        long range = maxValue - minValue;
        return rg.NextLong(range) + minValue;
    }
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 6

让我们假设您知道如何生成N个随机位.使用NextBytes或重复调用Random.Next具有适当的限制非常容易.

要在正确的范围内生成long/ulong,请确定范围的大小以及表示它所需的位数.然后,可以使用排斥采样,这将在最坏的情况(如果你想在范围[0,128],这意味着你将生成[0,255]多次的值例如)拒绝一半生成的值.如果你想要一个非零的范围,只需计算范围的大小,生成[0,大小)的随机值,然后添加基数.

生成一个随机小数显然更难,我相信 - 除了其他任何东西,你必须指定你想要的分布.


归档时间:

查看次数:

6621 次

最近记录:

7 年,9 月 前