在C#中生成随机float的最佳方法

在C#中生成随机float的最好方法是什么?

更新:我想随机浮点数从float.Minvalue float.Maxvalue。 我正在使用这些数字进行一些math方法的unit testing。

最好的办法,没有疯狂的价值观, 分布在浮点数线上的可表示的间隔 (去除“统一”,就连续数字线而言,它是明显不均匀的):

static float NextFloat(Random random) { double mantissa = (random.NextDouble() * 2.0) - 1.0; double exponent = Math.Pow(2.0, random.Next(-126, 128)); return (float)(mantissa * exponent); } 

另一种方法会给你一些疯狂的价值(比特模式的均匀分布),可能对模糊有用:

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

最有用的方法:

 static float NextFloat(Random random) { // Not a uniform distribution wrt the binary floating-point number line // which makes sense given that NextDouble is uniform from 0.0 to 1.0. // Uniform wrt 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; } 

英特尔®架构软件开发人员手册第一卷:基础架构中的浮点数行。 Y轴是对数(基数2),因为连续的二进制浮点数不是线性的。

分布比较,对数Y轴

任何理由不使用Random.NextDouble ,然后Random.NextDouble float ? 这会给你一个0和1之间的浮动。

如果你想要一个不同的“最好的”forms,你需要指定你的要求。 请注意, Random不应该用于财务或安全等敏感事务,而且您通常应该在整个应用程序中重复使用现有的实例,或者每个线程使用一个(因为Random不是线程安全的)。

编辑:build议在注释中,将其转换为float.MinValuefloat.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; 

编辑:现在你已经提到,这是unit testing,我不知道这是一个理想的方法。 你应该用具体的值来testing – 确保你在每个相关类别中testing样本 – 无穷大,NaN,非正规数,非常大的数,零等等。

还有一个版本…(我觉得这个很不错)

 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)); 

我认为这…

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

testing这个页面上的大部分function: (i7,release,没有debugging,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 

我采取了一些稍微不同的方法

 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相乘。

另一个解决scheme是这样做的:

 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; }