diff --git a/ASFFreeGames/RandomUtils.cs b/ASFFreeGames/RandomUtils.cs
index e9ef9ae..de69199 100644
--- a/ASFFreeGames/RandomUtils.cs
+++ b/ASFFreeGames/RandomUtils.cs
@@ -1,6 +1,8 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace Maxisoft.ASF;
@@ -8,35 +10,6 @@ namespace Maxisoft.ASF;
#nullable enable
public static class RandomUtils {
- ///
- /// Generates a random number from a normal distribution with the specified mean and standard deviation.
- ///
- /// The random number generator to use.
- /// The mean of the normal distribution.
- /// The standard deviation of the normal distribution.
- /// A random number from the normal distribution.
- ///
- /// This method uses the Box-Muller transform to convert two uniformly distributed random numbers into two normally distributed random numbers.
- ///
- public static double NextGaussian([NotNull] this RandomNumberGenerator random, double mean, double standardDeviation) {
- Debug.Assert(random != null, nameof(random) + " != null");
-
- // Generate two uniform random numbers
- Span bytes = stackalloc byte[8];
- random.GetBytes(bytes);
- double u1 = BitConverter.ToUInt32(bytes) / (double) uint.MaxValue;
- random.GetBytes(bytes);
- double u2 = BitConverter.ToUInt32(bytes) / (double) uint.MaxValue;
-
- // Apply the Box-Muller formula
- double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
-
- // Scale and shift to get a random number with the desired mean and standard deviation
- double randNormal = mean + (standardDeviation * randStdNormal);
-
- return randNormal;
- }
-
internal sealed class GaussianRandom : RandomNumberGenerator {
// A flag to indicate if there is a stored value for the next Gaussian number
private bool HasNextGaussian;
@@ -55,23 +28,20 @@ private double NextDouble() {
return NextGaussianValue;
}
- // Generate two uniform random numbers
- Span bytes = stackalloc byte[8];
- GetBytes(bytes);
- float u1 = BitConverter.ToUInt32(bytes) / (float) uint.MaxValue;
- GetBytes(bytes);
- float u2 = BitConverter.ToUInt32(bytes) / (float) uint.MaxValue;
+ Span bytes = stackalloc byte[16];
+ Fill(bytes);
+ Span ulongs = MemoryMarshal.Cast(bytes);
+ double u1 = ulongs[0] / (double) ulong.MaxValue;
+ double u2 = ulongs[1] / (double) ulong.MaxValue;
// Apply the Box-Muller formula
- float r = MathF.Sqrt(-2.0f * MathF.Log(u1));
- float theta = 2.0f * MathF.PI * u2;
+ double r = Math.Sqrt(-2.0f * Math.Log(u1));
+ double theta = 2.0 * Math.PI * u2;
- // Store one of the values for next time
- NextGaussianValue = r * MathF.Sin(theta);
+ NextGaussianValue = r * Math.Sin(theta);
HasNextGaussian = true;
- // Return the other value
- return r * MathF.Cos(theta);
+ return r * Math.Cos(theta);
}
///