Wie zufällig doppelten Wert aus zufälligen Byte-Array-Werten erhalten?
Frage
Ich möchte RNGCryptoServiceProvider als meine Quelle von Zufallszahlen verwenden. Da es nur kann sie als ein Array von Byte-Werten ausgegeben, wie kann ich sie auf 0 bis 1 Doppel Wert konvertieren, während Einheitlichkeit der Ergebnisse zu bewahren?
Lösung
byte[] result = new byte[8];
rng.GetBytes(result);
return (double)BitConverter.ToUInt64(result,0) / ulong.MaxValue;
Andere Tipps
Dies ist, wie ich dies tun würde.
private static readonly System.Security.Cryptography.RNGCryptoServiceProvider _secureRng;
public static double NextSecureDouble()
{
var bytes = new byte[8];
_secureRng.GetBytes(bytes);
var v = BitConverter.ToUInt64(bytes, 0);
// We only use the 53-bits of integer precision available in a IEEE 754 64-bit double.
// The result is a fraction,
// r = (0, 9007199254740991) / 9007199254740992 where 0 <= r && r < 1.
v &= ((1UL << 53) - 1);
var r = (double)v / (double)(1UL << 53);
return r;
}
übereinstimmend die
9007199254740991 / 9007199254740992 is ~= 0.99999999999999988897769753748436
ist, was dieRandom.NextDouble
Methode zurück, wie es Maximalwert ist (siehe https://msdn.microsoft.com/en-us/library/system.random.nextdouble (v = vs.110) aspx ).
Im Allgemeinen ist die Standardabweichung einer kontinuierlichen, gleichmäßige Verteilung ist. (Max - min) / sqrt (12)
Bei einer Probengröße von 1000 Ich bin zuverlässig innerhalb eines 2% Fehlermarge zu bekommen.
Mit einer Probengröße von 10000 Ich bin zuverlässig innerhalb eines 1% Fehlermarge zu bekommen.
Hier ist, wie ich diese Ergebnisse bestätigt.
[Test]
public void Randomness_SecureDoubleTest()
{
RunTrials(1000, 0.02);
RunTrials(10000, 0.01);
}
private static void RunTrials(int sampleSize, double errorMargin)
{
var q = new Queue<double>();
while (q.Count < sampleSize)
{
q.Enqueue(Randomness.NextSecureDouble());
}
for (int k = 0; k < 1000; k++)
{
// rotate
q.Dequeue();
q.Enqueue(Randomness.NextSecureDouble());
var avg = q.Average();
// Dividing by n−1 gives a better estimate of the population standard
// deviation for the larger parent population than dividing by n,
// which gives a result which is correct for the sample only.
var actual = Math.Sqrt(q.Sum(x => (x - avg) * (x - avg)) / (q.Count - 1));
// see http://stats.stackexchange.com/a/1014/4576
var expected = (q.Max() - q.Min()) / Math.Sqrt(12);
Assert.AreEqual(expected, actual, errorMargin);
}
}
Sie können die BitConverter.ToDouble (...) Methode verwenden. Es dauert in einem Byte-Array und eine Doppel zurück. Thre sind entsprechende Methoden für die meist anderen primitiven Typen, sowie eine Methode aus der Primitiven zu einer Byte-Array zu gehen.
Verwenden BitConverter eine Folge von zufälligen Bytes in einen Double zu konvertieren:
byte[] random_bytes = new byte[8]; // BitConverter will expect an 8-byte array
new RNGCryptoServiceProvider().GetBytes(random_bytes);
double my_random_double = BitConverter.ToDouble(random_bytes, 0);