Tôi đã tạo một yêu cầu cho một tính năng như vậy trên Microsoft Connect. Nếu đây là thứ bạn đang tìm kiếm, vui lòng bỏ phiếu cho nó và tăng khả năng hiển thị của nó.
https://connect.microsoft.com/VisualStudio/feedback/details/634346/guassian-normal-distribution-random-numbers
Tính năng này được bao gồm trong Java SDK. Việc triển khai nó có sẵn như một phần của tài liệu và dễ dàng chuyển sang C # hoặc các ngôn ngữ .NET khác.
Nếu bạn đang tìm kiếm tốc độ thuần túy, thì Thuật toán Zigorat thường được công nhận là cách tiếp cận nhanh nhất.
Mặc dù vậy, tôi không phải là chuyên gia về chủ đề này - tôi đã bắt gặp nhu cầu này khi triển khai bộ lọc hạt cho thư viện bóng đá mô phỏng RoboCup 3D và rất ngạc nhiên khi điều này không được đưa vào khuôn khổ.
Trong khi đó, đây là một trình bao bọc để Random
cung cấp triển khai hiệu quả phương pháp phân cực Box Muller:
public sealed class GaussianRandom
{
private bool _hasDeviate;
private double _storedDeviate;
private readonly Random _random;
public GaussianRandom(Random random = null)
{
_random = random ?? new Random();
}
/// <summary>
/// Obtains normally (Gaussian) distributed random numbers, using the Box-Muller
/// transformation. This transformation takes two uniformly distributed deviates
/// within the unit circle, and transforms them into two independently
/// distributed normal deviates.
/// </summary>
/// <param name="mu">The mean of the distribution. Default is zero.</param>
/// <param name="sigma">The standard deviation of the distribution. Default is one.</param>
/// <returns></returns>
public double NextGaussian(double mu = 0, double sigma = 1)
{
if (sigma <= 0)
throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");
if (_hasDeviate)
{
_hasDeviate = false;
return _storedDeviate*sigma + mu;
}
double v1, v2, rSquared;
do
{
// two random values between -1.0 and 1.0
v1 = 2*_random.NextDouble() - 1;
v2 = 2*_random.NextDouble() - 1;
rSquared = v1*v1 + v2*v2;
// ensure within the unit circle
} while (rSquared >= 1 || rSquared == 0);
// calculate polar tranformation for each deviate
var polar = Math.Sqrt(-2*Math.Log(rSquared)/rSquared);
// store first deviate
_storedDeviate = v2*polar;
_hasDeviate = true;
// return second deviate
return v1*polar*sigma + mu;
}
}