最好的方法,没有疯狂的值,distributed with respect to the representable intervals on the floating-point number line(删除了“统一”,因为对于连续的数字线,它显然是不统一的):
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);
}
(*) ... 检查here 是否有低于正常值的浮点数
警告:也会产生正无穷大!为了安全起见,选择 127 的指数。
另一种方法会给你一些疯狂的值(位模式的均匀分布),可能对模糊测试有用:
static float NextFloat(Random random)
{
var buffer = new byte[4];
random.NextBytes(buffer);
return BitConverter.ToSingle(buffer,0);
}
对以前版本的改进是这个,它不会创建“疯狂”值(既不是无穷大也不是 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;
}
}
最没用的方法:
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;
}
浮点数行来自:Intel Architecture Software Developer's Manual Volume 1: Basic Architecture. Y 轴是对数(以 2 为底),因为连续的二进制浮点数不是线性不同的。