Skip to content

Commit c096f8c

Browse files
Alinshanssunnycase
authored andcommitted
Add uniform random number generator. (#54)
* Add RNG. * Improve RNG and test. * Fix. * Add next for int64/uint64. * Fix uniform for real number. * Clean up.
1 parent 07359fc commit c096f8c

File tree

2 files changed

+257
-0
lines changed

2 files changed

+257
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace MineCase.Algorithm
6+
{
7+
public struct UniformRNG
8+
{
9+
// https://en.wikipedia.org/wiki/Linear_congruential_generator
10+
// MMIX by Donald Knuth
11+
private static readonly ulong _multiplier = 6364136223846793005;
12+
private static readonly ulong _increment = 1442695040888963407;
13+
14+
private ulong _state;
15+
16+
public UniformRNG(ulong state)
17+
{
18+
if (state == 0)
19+
{
20+
var time = DateTime.Now;
21+
var seed = (ulong)(time.Day << 25 | time.Hour << 20 | time.Minute << 14 | time.Second << 8 | time.Millisecond);
22+
for (int i = 0; i < 4; ++i)
23+
{
24+
seed = seed * _multiplier + _increment;
25+
}
26+
27+
_state = seed;
28+
}
29+
else
30+
{
31+
_state = state;
32+
}
33+
}
34+
35+
public int NextInt32()
36+
{
37+
return (int)Next();
38+
}
39+
40+
public uint NextUInt32()
41+
{
42+
return Next();
43+
}
44+
45+
public long NextInt64()
46+
{
47+
Next();
48+
return (long)_state;
49+
}
50+
51+
public ulong NextUInt64()
52+
{
53+
Next();
54+
return _state;
55+
}
56+
57+
public float NextSingle()
58+
{
59+
return Next() * 2.3283064365386962890625e-10f;
60+
}
61+
62+
public double NextDouble()
63+
{
64+
var t = Next();
65+
return (((ulong)t << 32) | Next()) * 5.4210108624275221700372640043497e-20;
66+
}
67+
68+
public int Uniform(int a, int b)
69+
{
70+
return a == b ? a : (int)(Next() % (b - a) + a);
71+
}
72+
73+
public uint Uniform(uint a, uint b)
74+
{
75+
return a == b ? a : Next() % (b - a) + a;
76+
}
77+
78+
public long Uniform(long a, long b)
79+
{
80+
return a == b ? a : Next() % (b - a) + a;
81+
}
82+
83+
public ulong Uniform(ulong a, ulong b)
84+
{
85+
return a == b ? a : Next() % (b - a) + a;
86+
}
87+
88+
public float Uniform(float a, float b)
89+
{
90+
return NextSingle() * (b - a) + a;
91+
}
92+
93+
public double Uniform(double a, double b)
94+
{
95+
return NextDouble() * (b - a) + a;
96+
}
97+
98+
private uint Next()
99+
{
100+
_state = _state * _multiplier + _increment;
101+
return (uint)_state;
102+
}
103+
}
104+
}

tests/UnitTest/RNGTest.cs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Runtime.CompilerServices;
5+
using System.Text;
6+
using ImageSharp;
7+
using MineCase.Algorithm;
8+
using Xunit;
9+
10+
namespace MineCase.UnitTest
11+
{
12+
public class RNGTest
13+
{
14+
public readonly string RootDir;
15+
16+
public RNGTest()
17+
{
18+
RootDir = SetRootDir();
19+
}
20+
21+
private static string SetRootDir([CallerFilePath]string fileName = null) =>
22+
Path.Combine(Path.GetDirectoryName(fileName), "bin");
23+
24+
[Fact]
25+
public void TestNext()
26+
{
27+
var rng = new UniformRNG(0);
28+
int first = rng.NextInt32(), second = rng.NextInt32();
29+
for (int i = 0; i < 1000000; ++i)
30+
{
31+
first = second;
32+
second = rng.NextInt32();
33+
Assert.NotEqual(first, second);
34+
}
35+
}
36+
37+
[Fact]
38+
public void TestUniform()
39+
{
40+
var rng = new UniformRNG(0);
41+
42+
var i1 = rng.Uniform(1, 2);
43+
Assert.Equal(1, i1);
44+
var i2 = rng.Uniform(1U, 2U);
45+
Assert.Equal(1U, i2);
46+
var i3 = rng.Uniform(1.0f, 1.0f);
47+
Assert.Equal(1.0f, i3);
48+
var i4 = rng.Uniform(1.0, 1.0);
49+
Assert.Equal(1.0, i4);
50+
}
51+
52+
[Fact]
53+
public void TestFrequencyImg()
54+
{
55+
var rng = new UniformRNG(0);
56+
int[] bucket = new int[100];
57+
58+
const int xExtent = 100;
59+
const int yExtent = 200;
60+
61+
using (var file = File.OpenWrite(Path.Combine(RootDir, "rng_frequency.bmp")))
62+
using (var image = new Image<ImageSharp.PixelFormats.Rgb24>(xExtent, yExtent))
63+
{
64+
for (int i = 0; i < 10000; ++i)
65+
{
66+
bucket[rng.Uniform(0, xExtent)]++;
67+
}
68+
69+
for (int i = 0; i < xExtent; ++i)
70+
{
71+
for (int j = 0; j < bucket[i]; ++j)
72+
{
73+
image[i, yExtent - j] = new ImageSharp.PixelFormats.Rgb24(0xFF, 0x69, 0xB4);
74+
}
75+
}
76+
77+
image.SaveAsBmp(file);
78+
}
79+
}
80+
81+
[Fact]
82+
public void TesIntNoiseImg()
83+
{
84+
var rng = new UniformRNG(0);
85+
86+
const int xExtent = 100;
87+
const int yExtent = 100;
88+
89+
using (var file = File.OpenWrite(Path.Combine(RootDir, "rng_int_noise.bmp")))
90+
using (var image = new Image<ImageSharp.PixelFormats.Rgb24>(xExtent, yExtent))
91+
{
92+
for (int i = 0; i < xExtent; ++i)
93+
{
94+
for (int j = 0; j < yExtent; ++j)
95+
{
96+
var color = (byte)rng.Uniform(0, 255);
97+
image[i, j] = new ImageSharp.PixelFormats.Rgb24(color, color, color);
98+
}
99+
}
100+
101+
image.SaveAsBmp(file);
102+
}
103+
}
104+
105+
[Fact]
106+
public void TesFloatNoiseImg()
107+
{
108+
var rng = new UniformRNG(0);
109+
110+
const int xExtent = 100;
111+
const int yExtent = 100;
112+
113+
using (var file = File.OpenWrite(Path.Combine(RootDir, "rng_float_noise.bmp")))
114+
using (var image = new Image<ImageSharp.PixelFormats.Rgb24>(xExtent, yExtent))
115+
{
116+
for (int i = 0; i < xExtent; ++i)
117+
{
118+
for (int j = 0; j < yExtent; ++j)
119+
{
120+
var color = (byte)(rng.Uniform(0.0f, 2.55f) * 100);
121+
image[i, j] = new ImageSharp.PixelFormats.Rgb24(color, color, color);
122+
}
123+
}
124+
125+
image.SaveAsBmp(file);
126+
}
127+
}
128+
129+
[Fact]
130+
public void TesDoubleNoiseImg()
131+
{
132+
var rng = new UniformRNG(0);
133+
134+
const int xExtent = 100;
135+
const int yExtent = 100;
136+
137+
using (var file = File.OpenWrite(Path.Combine(RootDir, "rng_double_noise.bmp")))
138+
using (var image = new Image<ImageSharp.PixelFormats.Rgb24>(xExtent, yExtent))
139+
{
140+
for (int i = 0; i < xExtent; ++i)
141+
{
142+
for (int j = 0; j < yExtent; ++j)
143+
{
144+
var color = (byte)(rng.Uniform(0.0, 2.55) * 100);
145+
image[i, j] = new ImageSharp.PixelFormats.Rgb24(color, color, color);
146+
}
147+
}
148+
149+
image.SaveAsBmp(file);
150+
}
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)