A quite simple UWP application implemented in C# that can generate and statistically evaluate random numbers. The generator is selected at runtime via strategy design pattern. A two-dimensional graphic facilitates the recognition of recurring patterns in number sequences.
The executable program can be built in five steps:
- Clone the repository. Personally, I like to use SourceTree as a free git client.
- Open the solution file RandomNumbers.sln with Visual Studio.
Note: UWP applications cannot be created from UNC paths (Visual Studio reports „DEP0700: Registration of the app failed. [0x80073CF0] error 0x80070003“). - Using the NuGet package manager:
Add the componentsMicrosoft.NETCore.UniversalWindowsPlatform
,Microsoft.Toolkit.Uwp.UI.Controls
, andWinRTXamlToolkit.Controls.DataVisualization.UWP
. - Select configuration, e.g. Debug/x64.
- Press
F5
.
When designing the software, a Wacom Intuos graphics tablet and Bamboo Paper were very pleasant companions - I will never use real paper again in this development phase! The draft works are recorded in the document RandomNumbers.will, unfortunately mostly in German, I apologize.
Implementation has been done with Microsoft Visual Studio Community 2017 (Version 15.6.3) on platform Windows 10 Professional (Version 1709). However, the latest C# features are not used.
The implementation is based on these software components:
- UWP Community Toolkit (using the RadialProgressBar)
- WinRT XAML Toolkit (for the binning chart diagram)
The program scales an integer random value l
generated in the closed interval [lmin, lmax]
to the floating point interval [dmin, dmax]
. The two interval limits are currently defined as constant values 0.0d
and 1.0d
. Scaling is performed by the static method RandomNumbers.Statistics.Scale()
.
The scaled random numbers are divided into numOfBins = 50
intervals defined in class Binning. Each interval no. i
contains random numbers in the half-open range [dmin + i*δ, dmin + (i + 1)*δ)
with δ = (dmax - dmin)/numOfBins
.
The expected value m
= μ of the scaled random numbers is calculated using the recursion formula
m<k> = (1/k)*(x<k> + (k-1)*m<k-1>)
where x<k>
is the new random number generated.
The variance s
= σ*σ of the random numbers is also calculated recursively using
s<k> = (1-(1/k))*s<k-1> + (k+1)*SQR(m<k> - m<k-1>)
where SQR
denotes squaring. The newly generated random number x<k>
is only included in this formula indirectly via the new estimate m<k>
of the expected value, which must therefore be calculated before the variance is updated:
// Update estimations of expected value and variance:
AveragePrev = viewModel.Average;
viewModel.Average = Statistics.UpdateAverage( k + 1, AveragePrev, r );
viewModel.Variance = Statistics.UpdateVariance( k + 1, viewModel.Variance, AveragePrev, viewModel.Average );
The estimates are implemented as static methods in the class RandomNumbers.Statistics
.
The INumberStorage interface defines methods for storing the generated random numbers.
If the toggle switch Store numbers in file is set to On on the user interface, a file selection dialog will be displayed at the beginning of random number generation. Class CsvFileStorage stores the random numbers in the selected CSV file with a semicolon as a separator between integers and scaled values:
-40;0
19;0,59
-16;0,24
59;0,99
52;0,92
.
.
.
You can read the file with Microsoft Excel, for example.
At the end of the Close
method of CsvFileStorage, Dispose
is explicitly called for the objects used:
public async Task<bool> Close()
{
.
.
.
writer.Dispose();
writer = null;
outputStream.Dispose();
outputStream = null;
stream.Dispose();
stream = null;
return true;
} // Close
This allows reopening the same file immediately without having to wait for the garbage collector to work.
The following limitations currently exist:
- Constant size of image bitmap (512 x 512 pixels)
- Constant number of bins (50)
- No software documentation
- Still too much code behind
- Number generation just single threaded
- No unit testing
- Not tested on platforms other than Windows 10 Professional (x64)
- No performance optimization - there are many intermediate calculations for debugging purposes.
But if experiments with random number generators are to be done quickly, then it does what it should.
There are two behaviors of randomness implemented: System.Random (= Pseudo) and System.Security.Cryptography.RNGCryptoServiceProvider (= Secure). Another random number generator is provided in three steps:
- Define a class that implements the IRandomness interface. Please take the definition of MyRandomness as an example.
- In MainPage.xaml:
Add a list element representing the random number generator to therngSelector
combo box. - In MainPage.xaml.cs:
Extend theswitch (idx)
statement in the callback functionButton_Click
. The function starts or cancels the generation of random numbers in a separate thread.
Observe the distribution of the white pixels in the graphic: If patterns are recognizable, the generator still offers room for improvement.
For the implementation of MyRandomness
I took from Wikipedia the parameters a
(= multiplier), c
(= increment), and m
(= modulus) of the linear congruential generator
x<k+1> = (a*x<k> + c) % m
which is part of the GNU C Library:
a = 1,103,515,245
c = 12,345
m = 2**31 = Int32.MaxValue + 1
I don't want to advertise here, but Head First Design Patterns gives a very good introduction to the strategy pattern. I like this book very much.
Markus A. Stulle // smartcontract.world | Munich, March 2018.