bchavez / Bogus

:card_index: A simple fake data generator for C#, F#, and VB.NET. Based on and ported from the famed faker.js.
Other
8.66k stars 495 forks source link

Allow for different Pseudo Random Number Generators (PRNGs) #411

Closed DaveRMaltby closed 2 years ago

DaveRMaltby commented 2 years ago

Please describe why you are requesting a feature

Different PRNGs have different tradeoffs on CPU, memory and distribution of results. Bogus is currently bound to using the .NET Random class which is constrained to only one PRNG algorithm (See remarks of the previous link). Bogus is designed in such a manner that adding this feature requires minimal changes.

Please provide a code example of what you are trying to achieve

namespace Bogus
{
   public interface IRandom
   {
      int Next();
      int Next(int minValue, int maxValue);
      void NextBytes(byte[] buffer);
      double NextDouble();
   }

   internal class RandomWrapper : IRandom
   {
      private readonly Random random;

      public RandomWrapper(Random random)
      {
         this.random = random ?? throw new ArgumentNullException(nameof(random));
      }

      public int Next()
      {
         return random.Next();
      }

      public int Next(int minValue, int maxValue)
      {
         return random.Next(minValue, maxValue);
      }

      public void NextBytes(byte[] buffer)
      {
         random.NextBytes(buffer);
      }

      public double NextDouble()
      {
         return random.NextDouble();
      }
   }

   public class Randomizer
   {
...

//CHANGED from the data type Random
      private readonly IRandom localSeed;

      public Randomizer()
      {
//CHANGED
         this.localSeed = new RandomWrapper(Seed);
      }

      public Randomizer(int localSeed)
      {
//CHANGED
         this.localSeed = new RandomWrapper(new Random(localSeed));
      }

...
      /// <summary>
      /// Constructor that uses <see cref="random"/> parameter interface as an abstraction for Random.
      /// Completely ignores the global static <see cref="Seed"/>.
      /// </summary>
      public Randomizer(IRandom random)
      {
         this.localSeed = random;
      }
...
   }
}

namespace Bogus.Tests
{
      private class PseudoRandomNumberGenerator : IRandom
      {
         public int Next() => (int)(DateTime.Now.Ticks & 0xFFFFFFFFL);
         public int Next(int minValue, int maxValue) => Next() % (maxValue - minValue) + minValue;
         public void NextBytes(byte[] buffer) => throw new NotImplementedException();
         public double NextDouble() => throw new NotImplementedException();
      }

      [Fact]
      public void custom_random_interface()
      {
         var nameAlg = new DataSets.Name();
         nameAlg.Random = new Randomizer(new PseudoRandomNumberGenerator());

         var firstName = nameAlg.FirstName();
      }
}

NOTE: The PRNG here (called PseudoRandomNumberGenerator) is only for simplicity and does not at all represent the standard or custom PRNGs that I'd like to use in my final code.

Please answer any or all of the questions below

If the feature request is approved, would you be willing to submit a PR? Yes. I already have a working solution and will provide some unit tests as well.

bchavez commented 2 years ago

Fixed in #413

bchavez commented 2 years ago

@DaveRMaltby, new version released with your PR changes: https://www.nuget.org/packages/Bogus/34.0.2

thanks again for the help!

DaveRMaltby commented 2 years ago

Thank you sir! I'm glad now to be able to return to your NuGet package. I really like your work here. If you need some help on stuff keep me in mind. Again, appreciate it!