在C#中生成随机浮点数的最佳方法

Kri*_*rip 51 c# random floating-point

在C#中生成随机浮点数的最佳方法是什么?

更新:我想从float.Minvalue到float.Maxvalue的随机浮点数.我在一些数学方法的单元测试中使用这些数字.

use*_*116 63

最佳方法,没有疯狂值,相对于浮点数行上的可表示间隔分布(删除"均匀",相对于连续数字线,它显然是不均匀的):

static float NextFloat(Random random)
{
    double mantissa = (random.NextDouble() * 2.0) - 1.0;
    // choose -149 instead of -126 to also generate subnormal floats (*)
    double exponent = Math.Pow(2.0, random.Next(-126, 128));
    return (float)(mantissa * exponent);
}
Run Code Online (Sandbox Code Playgroud)

(*)... 在这里查看次正常浮点数

警告:也会产生正无穷大!选择127的指数是安全的.

另一种方法可以为您提供一些疯狂的值(位模式的均匀分布),可能对模糊测试有用:

static float NextFloat(Random random)
{
    var buffer = new byte[4];
    random.NextBytes(buffer);
    return BitConverter.ToSingle(buffer,0);
}
Run Code Online (Sandbox Code Playgroud)

对此版本的改进是这个版本,它不会创建"疯狂"值(既不是无穷大也不是NaN)并且仍然很快(也相对于浮点数行上的可表示区间分布):

public static float Generate(Random prng)
{
    var sign = prng.Next(2);
    var exponent = prng.Next((1 << 8) - 1); // do not generate 0xFF (infinities and NaN)
    var mantissa = prng.Next(1 << 23);

    var bits = (sign << 31) + (exponent << 23) + mantissa;
    return IntBitsToFloat(bits);
}

private static float IntBitsToFloat(int bits)
{
    unsafe
    {
        return *(float*) &bits;
    }
}
Run Code Online (Sandbox Code Playgroud)

最有用的方法:

static float NextFloat(Random random)
{
    // Not a uniform distribution w.r.t. the binary floating-point number line
    // which makes sense given that NextDouble is uniform from 0.0 to 1.0.
    // Uniform w.r.t. a continuous number line.
    //
    // The range produced by this method is 6.8e38.
    //
    // Therefore if NextDouble produces values in the range of 0.0 to 0.1
    // 10% of the time, we will only produce numbers less than 1e38 about
    // 10% of the time, which does not make sense.
    var result = (random.NextDouble()
                  * (Single.MaxValue - (double)Single.MinValue))
                  + Single.MinValue;
    return (float)result;
}
Run Code Online (Sandbox Code Playgroud)

浮点数行来自:英特尔架构软件开发人员手册第1卷:基本架构.Y轴是对数(基数-2),因为连续的二进制浮点数不是线性的.

比较分布,对数Y轴

  • 使用随机字节很容易以NaN值结束,并且分布可能不均匀.(我不想预测分布.) (2认同)
  • @sixlettervariables:你看起来更漂亮的原因是因为你给出了一个对数刻度.在线性范围内,我相信NextDouble*范围将是统一的. (2认同)

Jon*_*eet 26

有什么理由不使用Random.NextDouble然后再施展float?这将给你一个0到1之间的浮动.

如果您想要一种不同形式的"最佳",您需要指定您的要求.请注意,Random不应将其用于财务或安全等敏感问题 - 您通常应该在整个应用程序中重用现有实例,或者每个线程重用一个实例(因为Random它不是线程安全的).

编辑:正如意见提出,将其转换为一个范围的float.MinValue,float.MaxValue:

// Perform arithmetic in double type to avoid overflowing
double range = (double) float.MaxValue - (double) float.MinValue;
double sample = rng.NextDouble();
double scaled = (sample * range) + float.MinValue;
float f = (float) scaled;
Run Code Online (Sandbox Code Playgroud)

编辑:现在你已经提到这是单元测试,我不确定它是一个理想的方法.您应该使用具体值进行测试 - 确保使用每个相关类别中的样本进行测试 - 无穷大,NaN,非正规数,非常大的数,零等.

  • 只需将它乘以(MaxValue-MinValue)并将MinValue添加到它?像Random.NextDouble*(float.MaxValue-float.MinValue)+ float.MinValue之类的东西 (3认同)

Sun*_*est 5

还有一个版本......(我认为这个版本非常好)

static float NextFloat(Random random)
{
    (float)(float.MaxValue * 2.0 * (rand.NextDouble()-0.5));
}

//inline version
float myVal = (float)(float.MaxValue * 2.0 * (rand.NextDouble()-0.5));
Run Code Online (Sandbox Code Playgroud)

我认为这...

  • 是第二快的(见基准)
  • 均匀分布

还有一个版本......(不是很好,但无论如何发布)

static float NextFloat(Random random)
{
    return float.MaxValue * ((rand.Next() / 1073741824.0f) - 1.0f);
}

//inline version
float myVal = (float.MaxValue * ((rand.Next() / 1073741824.0f) - 1.0f));
Run Code Online (Sandbox Code Playgroud)

我认为这...

  • 是最快的(见基准)
  • 是均匀分布的,因为Next()是一个31位随机值,它只返回2 ^ 31个值.(50%的邻居值将具有相同的值)

测试此页面上的大多数功能:(i7,发布,无需调试,2 ^ 28个循环)

 Sunsetquest1: min: 3.402823E+38  max: -3.402823E+38 time: 3096ms
 SimonMourier: min: 3.402823E+38  max: -3.402819E+38 time: 14473ms
 AnthonyPegram:min: 3.402823E+38  max: -3.402823E+38 time: 3191ms
 JonSkeet:     min: 3.402823E+38  max: -3.402823E+38 time: 3186ms
 Sixlettervar: min: 1.701405E+38  max: -1.701410E+38 time: 19653ms
 Sunsetquest2: min: 3.402823E+38  max: -3.402823E+38 time: 2930ms
Run Code Online (Sandbox Code Playgroud)