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

标签 c# random

注意:为简洁起见,下文将不区分随机性和伪随机性。此外,在这种情况下,约束 表示在给定的最小值和最大值之间)

System.Random 类提供整数、 double 和字节数组的随机生成。 使用 Random.Next,可以轻松生成 Boolean、Char、(S)Byte、(U)Int16、(U)Int32 类型的随机约束值。使用 Random.NextDouble(),可以类似地生成 Double 和 Single 类型的约束值(据我对这种类型的理解)。随机字符串生成(给定长度和字母)has also been tackled before .

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

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

long NextLong(long min, long max)
long NextDecimal(decimal min, decimal max)

请注意,由于 System.DateTime 基于 ulong,因此第一个函数也将允许随机约束生成此类结构(类似于 here ,仅以滴答而不是分钟为单位).

最佳答案

这应该可以做到。对于十进制,我使用 Jon Skeet 的初始方法来生成随机 decimal(无约束)。对于 long,我提供了一种生成随机非负 long 的方法,然后用于在随机范围内创建 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;
    }
}

关于c# - (U)Int64 和 Decimal 的(伪)随机约束值的生成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2000311/

相关文章:

c# - 容器化后无法执行断路器

c - 显示随机数数组的问题

python - 扭曲随机序列的变换产生随机序列?

c++ - 获取低于秒的值

java - 生成具有随机行长度的随机二维数组

javascript - JavaScript Math.Random() 连续两次创建相同数字的可能性有多大?

c# - 将经过处理的视频从 C# 程序发送到 C++ 程序

c# - 字符串程序的范围

c# - 如何使用 FileHelpers 创建用于写入 csv 文件的记录

c# - 具有数据库读取功能的多线程应用程序 - 每个线程都有唯一的记录