在C#中生成随机浮点数的最佳方法是什么?
更新:我想从float.Minvalue到float.Maxvalue的随机浮点数。我在一些数学方法的单元测试中使用这些数字。
答案 0 :(得分:61)
最佳方法,没有疯狂的价值,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)并且仍然很快(也相对于浮点数行上的可表示区间分布):< / p>
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),因为连续的二进制浮点数不会线性差异。
答案 1 :(得分: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;
编辑:现在你已经提到这是用于单元测试,我不确定它是一种理想的方法。您应该使用具体值进行测试 - 确保使用每个相关类别中的样本进行测试 - 无穷大,NaN,非正规数,非常大的数,零等。
答案 2 :(得分: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));
我想这......
还有一个版本......(不是很好,但无论如何发布)
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));
我想这......
测试此页面上的大多数功能:(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
答案 3 :(得分:2)
我采取了与其他人略有不同的方法
static float NextFloat(Random random)
{
double val = random.NextDouble(); // range 0.0 to 1.0
val -= 0.5; // expected range now -0.5 to +0.5
val *= 2; // expected range now -1.0 to +1.0
return float.MaxValue * (float)val;
}
评论解释了我在做什么。获取下一个double,将该数字转换为介于-1和1之间的值,然后将其与float.MaxValue
相乘。
答案 4 :(得分:0)
另一种解决方案是:
static float NextFloat(Random random)
{
float f;
do
{
byte[] bytes = new byte[4];
random.NextBytes(bytes);
f = BitConverter.ToSingle(bytes, 0);
}
while (float.IsInfinity(f) || float.IsNaN(f));
return f;
}
答案 5 :(得分:0)
这是我提出的另一种方式: 让我们假设您希望获得一个介于5.5和7之间的浮点数,其中包含3位小数。
+++ Section()
<<< ButtonRow() {
$0.title = "Tap to force form validation"
}
.onCellSelection { cell, row in
//Do something here once the row has been tapped
}
通过这种方式,您将获得比5.5更大的数字和小于7的数字。
答案 6 :(得分:0)
我更喜欢使用以下代码生成一个小数,最多可达第一个小数点。您可以复制粘贴第3行,在小数点后添加更多数字,方法是将该数字附加在字符串&#34;合并&#34;中。您可以通过将0和9更改为首选值来设置最小值和最大值。
Random r = new Random();
string beforePoint = r.Next(0, 9).ToString();//number before decimal point
string afterPoint = r.Next(0,9).ToString();//1st decimal point
//string secondDP = r.Next(0, 9).ToString();//2nd decimal point
string combined = beforePoint+"."+afterPoint;
decimalNumber= float.Parse(combined);
Console.WriteLine(decimalNumber);
我希望它对你有帮助。