Boris Eetgerink

March 9, 2023

C#: Random vs. RandomNumberGenerator

Recently I was looking into shuffling a deck of cards and how to implement that in C#. It turns out that shuffling itself is not that hard, but verifying that a deck is shuffled correctly is a lot harder! I won't go into that here. Anyway, shuffling needs a random number generator. I'm familiar with System.Random, but it turns out that there's also System.Security.Cryptography.RandomNumberGenerator. I'm interested in the difference between the two and if one is better to use or not.

The setup

I want to generate numbers between 1 and 52 (inclusive) to simulate picking a card from a deck. To check how random the numbers are distributed I generate 5.2 million numbers. I expect every number to be picked on average 100,000 times.

For System.Random I instantiate Random once and use that instance for every number generated. I use the following method:

Random random = new();
int number = random.Next(1, 53); // maxValue is exclusive.

For System.Security.Cryptography.RandomNumberGenerator I use the recommended static method, so no need to instantiate anything:

int number = RandomNumberGenerator.GetInt32(1, 53); // fromInclusive, toExclusive

I also record the time it takes to instantiate random (if required for the method) and generate all the numbers. The time taken includes registering the number in a dictionary. Finally I register the difference of the numbers taken from the expected average to see if Random (Rnd) or RandomNumberGenerator (Rng) differ much.

The results

Num     Rnd     RndDev  Rng     RngDev
#1:     99856   144     99973   27
#2:     100359  359     100596  596
#3:     99311   689     100068  68
#4:     100271  271     100169  169
#5:     100288  288     99930   70
#6:     99576   424     100045  45
#7:     99198   802     99927   73
#8:     100038  38      100325  325
#9:     99636   364     100263  263
#10:    99759   241     100325  325
#11:    99633   367     99899   101
#12:    100012  12      100072  72
#13:    99668   332     100320  320
#14:    100290  290     99867   133
#15:    100445  445     100572  572
#16:    100135  135     100288  288
#17:    100380  380     100122  122
#18:    100098  98      99842   158
#19:    100638  638     100046  46
#20:    99551   449     99809   191
#21:    100281  281     99971   29
#22:    100174  174     100228  228
#23:    100070  70      99795   205
#24:    100289  289     99702   298
#25:    99442   558     100057  57
#26:    99652   348     99482   518
#27:    100589  589     99726   274
#28:    100446  446     100278  278
#29:    99867   133     99850   150
#30:    100226  226     99504   496
#31:    99994   6       99833   167
#32:    100083  83      99699   301
#33:    100142  142     100026  26
#34:    99869   131     99953   47
#35:    99521   479     99683   317
#36:    100066  66      100725  725
#37:    99982   18      100256  256
#38:    99631   369     100474  474
#39:    100239  239     100261  261
#40:    99822   178     99693   307
#41:    99973   27      100117  117
#42:    100031  31      99393   607
#43:    100077  77      99612   388
#44:    99949   51      99670   330
#45:    100003  3       99872   128
#46:    99615   385     99650   350
#47:    100224  224     100229  229
#48:    99814   186     99873   127
#49:    100439  439     99557   443
#50:    100093  93      100069  69
#51:    100066  66      99829   171
#52:    100189  189     100475  475
Sum:    5200000 13362   5200000 12812
Difference between deviations: 4,20%
Elapsed time Rnd: 00:00:00.2086495
Elapsed time Rng: 00:00:00.4808033

Conclusions and recommendation

  • Both methods are quite fast given the amount of generated numbers, but Random is more than twice as fast!
  • RandomNumberGenerator doesn't always have a better distribution than Random, it varies. The difference between the total deviations looks to be around 10% even though there are some outliers, but I didn't measure that. It doesn't look like one method is statistically better than the other.
  • Random is more flexible, because you can use a seed if you need to. You can also use Random.Shared to use a thread safe instance.

Given the speed and flexibility of Random, I would recommend Random over RandomNumberGenerator.

About Boris Eetgerink

Hey, thanks for reading my blog. Subscribe below for future posts like this one and check my personal site in order to contact me.