Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

I see there's already a similar question a similar question, but it lacks the actual implementation.

I see there's already a similar question, but it lacks the actual implementation.

I see there's already a similar question, but it lacks the actual implementation.

Source Link
Albireo
  • 498
  • 3
  • 8

Pseudo-random number generator implementation check

I was searching for a pseudo-random number generator for C# and stumbled upon Tales from the CryptoRandom by Stephen Toub and Shawn Farkas, so I tried to implement a variation of their code.

The main difference with their implementation is mine returns inclusive ranges (e.g [0,1] and [min,max] instead of [0,1) and [min,max)),

namespace Albireo.SecureRandom
{
 using System;
 using System.Diagnostics.Contracts;
 using System.Security.Cryptography;
 public static class SecureRandom
 {
 private static readonly RNGCryptoServiceProvider Generator = new RNGCryptoServiceProvider();
 public static byte GetByte()
 {
 var buffer = new byte[1];
 Generator.GetBytes(buffer);
 return buffer[0];
 }
 public static double GetDouble()
 {
 var buffer = new byte[8];
 Generator.GetBytes(buffer);
 return BitConverter.ToDouble(buffer, 0);
 }
 public static short GetInt16()
 {
 var buffer = new byte[2];
 Generator.GetBytes(buffer);
 return BitConverter.ToInt16(buffer, 0);
 }
 public static short GetInt16(short minimum, short maximum)
 {
 Contract.Requires<ArgumentException>(minimum < maximum, "minimum < maximum");
 Contract.Ensures(Contract.Result<short>() >= minimum, "result >= minimum");
 Contract.Ensures(Contract.Result<short>() <= maximum, "result <= maximum");
 return (short) (minimum + (Sample() * (maximum - minimum)));
 }
 public static int GetInt32()
 {
 var buffer = new byte[4];
 Generator.GetBytes(buffer);
 return BitConverter.ToInt32(buffer, 0);
 }
 public static int GetInt32(int minimum, int maximum)
 {
 Contract.Requires<ArgumentException>(minimum < maximum, "minimum < maximum");
 Contract.Ensures(Contract.Result<int>() >= minimum, "result >= minimum");
 Contract.Ensures(Contract.Result<int>() <= maximum, "result <= maximum");
 return (int) (minimum + (Sample() * (maximum - minimum)));
 }
 public static long GetInt64()
 {
 var buffer = new byte[8];
 Generator.GetBytes(buffer);
 return BitConverter.ToInt64(buffer, 0);
 }
 public static long GetInt64(long minimum, long maximum)
 {
 Contract.Requires<ArgumentException>(minimum < maximum, "minimum < maximum");
 Contract.Ensures(Contract.Result<long>() >= minimum, "result >= minimum");
 Contract.Ensures(Contract.Result<long>() <= maximum, "result <= maximum");
 return (long) (minimum + (Sample() * (maximum - minimum)));
 }
 public static decimal Sample()
 {
 Contract.Ensures(Contract.Result<decimal>() >= 0, "result >= 0");
 Contract.Ensures(Contract.Result<decimal>() <= 1, "result <= 1");
 var buffer = new byte[8];
 Generator.GetBytes(buffer);
 return (BitConverter.ToUInt64(buffer, 0) & 0x7FFFFFFFFFFFFFFF) / (decimal) long.MaxValue;
 }
 }
}

I see there's already a similar question, but it lacks the actual implementation.

Since I'm not really skilled in mathematics, the main answers I'm looking for are:

  • Is Sample()'s implementation correct? It should return a number between [0,1] by getting a random long, stripping its sign and dividing it by long.MaxValue to obtain the result.
  • Is the computation performed in the various "ranged" methods correct? Usually to get a random value between min and max you do min + (rnd * (max - min + 1)) because rnd is [0,1), but here it's [0,1].
  • Is there a way to have Sample() return a value between [0,1) instead of [0,1] to tons of code or wasting of "incorrect" values? Do note that the code is compiled with the /checked flag so arithmetic overflows/underflows throw an exception.
  • How do I test a PRNG? By definition its results are... random, i.e. I can test GetInt16(short, short) as long as I want, but the numberOfGeneratedTestValues+1 call could still return an illegal value.

Any other comment is still appreciated.

Notes:

  • I do know there is no XML documentation (yet).
  • The class and its methods are static because RNGCryptoServiceProvider is thread safe, so there should be no reason to not have them static.
lang-cs

AltStyle によって変換されたページ (->オリジナル) /