Skip to content

Commit fe92eb6

Browse files
committed
add random
1 parent cc7ca45 commit fe92eb6

File tree

9 files changed

+469
-2
lines changed

9 files changed

+469
-2
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ tasks.withType(JavaCompile) { options.encoding = "UTF-8" }
2626

2727
group = 'com.github.myibu'
2828
archivesBaseName = "algorithm-java"
29-
version = "1.0.0"
29+
version = "1.0.0a"
3030

3131
repositories {
3232
mavenCentral()

docs/LinearCongruence.pdf

23.3 KB
Binary file not shown.

docs/MersenneTwister.pdf

242 KB
Binary file not shown.

readme.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,18 @@ Reference to: [BloomFilter.pdf](./docs/BloomFilter.pdf)
2828
| rShift | `>>` |
2929
| rrShift | `>>>` |
3030

31+
### LinearCongruentialRandom
32+
Reference to: [LinearCongruence.pdf](./docs/LinearCongruence.pdf)
33+
34+
### MersenneTwisterRandom
35+
Reference to: [MersenneTwister.pdf](./docs/MersenneTwister.pdf)
36+
3137
## Installation
3238
```bash
3339
<dependency>
3440
<groupId>com.github.myibu</groupId>
3541
<artifactId>algorithm-java</artifactId>
36-
<version>1.0.0</version>
42+
<version>1.0.0a</version>
3743
</dependency>
3844
```
3945

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.github.myibu.algorithm.random;
2+
3+
import java.util.concurrent.atomic.AtomicLong;
4+
5+
/**
6+
* Linear Congruence method for generating Pseudo Random Numbers
7+
* Copy from "java.util.Random"
8+
* @author myibu
9+
* Created on 2021/9/17
10+
*/
11+
public class LinearCongruentialRandom implements Random {
12+
static final String BadBound = "bound must be positive";
13+
static final String BadRange = "bound must be greater than origin";
14+
static final String BadSize = "size must be non-negative";
15+
16+
private final AtomicLong seed;
17+
private static final long multiplier = 0x5DEECE66DL;
18+
private static final long addend = 0xBL;
19+
private static final long mask = (1L << 48) - 1;
20+
21+
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
22+
23+
public LinearCongruentialRandom() {
24+
this(seedUniquifier() ^ System.nanoTime());
25+
}
26+
27+
private static long seedUniquifier() {
28+
for (;;) {
29+
long current = seedUniquifier.get();
30+
long next = current * 1181783497276652981L;
31+
if (seedUniquifier.compareAndSet(current, next))
32+
return next;
33+
}
34+
}
35+
36+
private static final AtomicLong seedUniquifier
37+
= new AtomicLong(8682522807148012L);
38+
39+
public LinearCongruentialRandom(long seed) {
40+
this.seed = new AtomicLong(initialScramble(seed));
41+
}
42+
43+
private static long initialScramble(long seed) {
44+
return (seed ^ multiplier) & mask;
45+
}
46+
47+
public synchronized void setSeed(long seed) {
48+
this.seed.set(initialScramble(seed));
49+
}
50+
51+
public int next(int bits) {
52+
long oldseed, nextseed;
53+
AtomicLong seed = this.seed;
54+
do {
55+
oldseed = seed.get();
56+
nextseed = (oldseed * multiplier + addend) & mask;
57+
} while (!seed.compareAndSet(oldseed, nextseed));
58+
return (int)(nextseed >>> (48 - bits));
59+
}
60+
61+
@Override
62+
public void nextBytes(byte[] bytes) {
63+
for (int i = 0, len = bytes.length; i < len; )
64+
for (int rnd = nextInt(),
65+
n = Math.min(len - i, Integer.SIZE/Byte.SIZE);
66+
n-- > 0; rnd >>= Byte.SIZE)
67+
bytes[i++] = (byte)rnd;
68+
}
69+
70+
@Override
71+
public int nextInt() {
72+
return next(32);
73+
}
74+
75+
@Override
76+
public int nextInt(int bound) {
77+
if (bound <= 0)
78+
throw new IllegalArgumentException(BadBound);
79+
80+
int r = next(31);
81+
int m = bound - 1;
82+
if ((bound & m) == 0) // i.e., bound is a power of 2
83+
r = (int)((bound * (long)r) >> 31);
84+
else {
85+
for (int u = r;
86+
u - (r = u % bound) + m < 0;
87+
u = next(31))
88+
;
89+
}
90+
return r;
91+
}
92+
93+
@Override
94+
public long nextLong() {
95+
return ((long)(next(32)) << 32) + next(32);
96+
}
97+
98+
public boolean nextBoolean() {
99+
return next(1) != 0;
100+
}
101+
102+
@Override
103+
public float nextFloat() {
104+
return next(24) / ((float)(1 << 24));
105+
}
106+
107+
@Override
108+
public double nextDouble() {
109+
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
110+
}
111+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.github.myibu.algorithm.random;
2+
3+
import java.util.concurrent.atomic.AtomicLong;
4+
5+
/**
6+
* Mersenne Twister method for generating Pseudo Random Numbers
7+
* MT19937
8+
* @author myibu
9+
* Created on 2021/9/17
10+
*/
11+
public class MersenneTwisterRandom implements Random {
12+
static final int MT19937_SIZE = 624; // 624 * 32 - 31 = 19937
13+
static final String BadBound = "bound must be positive";
14+
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
15+
16+
private final long seed;
17+
private long[] mt;
18+
19+
public MersenneTwisterRandom() {
20+
this((int)(seedUniquifier() ^ System.nanoTime()));
21+
}
22+
23+
public MersenneTwisterRandom(long seed) {
24+
this.seed = seed;
25+
this.mt = new long[MT19937_SIZE];
26+
mt[0] = seed;
27+
for (int i = 1; i < MT19937_SIZE; i++) {
28+
mt[i] = 1812433253L * (mt[i-1] ^ (mt[i-1] >> 30)) + i;
29+
}
30+
}
31+
32+
private static long seedUniquifier() {
33+
for (;;) {
34+
long current = seedUniquifier.get();
35+
long next = current * 1181783497276652981L;
36+
if (seedUniquifier.compareAndSet(current, next))
37+
return next;
38+
}
39+
}
40+
41+
private static final AtomicLong seedUniquifier
42+
= new AtomicLong(8682522807148012L);
43+
44+
private void generate() {
45+
for (int i = 0; i < MT19937_SIZE; i++) {
46+
// 2^31 = 0x80000000, 2^31-1 = 0x7fffffff
47+
long y = (mt[i] & 0x80000000L) + (mt[(i+1) % 624] & 0x7fffffffL);
48+
mt[i] = mt[(i + 397) % 624] ^ (y >> 1);
49+
if ((y & 1) != 0)
50+
mt[i] ^= 0x9908b0dfL;
51+
}
52+
}
53+
54+
@Override
55+
public void nextBytes(byte[] bytes) {
56+
for (int i = 0, len = bytes.length; i < len; )
57+
for (int rnd = nextInt(),
58+
n = Math.min(len - i, Integer.SIZE/Byte.SIZE);
59+
n-- > 0; rnd >>= Byte.SIZE)
60+
bytes[i++] = (byte)rnd;
61+
}
62+
63+
@Override
64+
public int nextInt() {
65+
generate();
66+
long y = mt[0];
67+
y = y ^ (y >> 11);
68+
y = y ^ ((y << 7) & 2636928640L);
69+
y = y ^ ((y << 15) & 4022730752L);
70+
y = y ^ (y >> 18);
71+
return (int)y;
72+
}
73+
74+
@Override
75+
public int nextInt(int bound) {
76+
if (bound <= 0)
77+
throw new IllegalArgumentException(BadBound);
78+
79+
int r = nextInt();
80+
int m = bound - 1;
81+
if ((bound & m) == 0) // i.e., bound is a power of 2
82+
r = (int)((bound * (long)r) >> 31);
83+
else {
84+
for (int u = r;
85+
u - (r = u % bound) + m < 0;
86+
u = nextInt())
87+
;
88+
}
89+
return r;
90+
}
91+
92+
@Override
93+
public long nextLong() {
94+
return ((long)(nextInt()) << 32) + nextInt();
95+
}
96+
97+
@Override
98+
public boolean nextBoolean() {
99+
return (nextInt() & 0x00000001) != 0;
100+
}
101+
102+
@Override
103+
public float nextFloat() {
104+
return nextInt() / ((float)(1 << 24));
105+
}
106+
107+
@Override
108+
public double nextDouble() {
109+
return (((long)(nextInt()) << 27) + nextInt()) * DOUBLE_UNIT;
110+
}
111+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.github.myibu.algorithm.random;
2+
/**
3+
* random interface
4+
* @author myibu
5+
* Created on 2021/9/17
6+
*/
7+
public interface Random {
8+
void nextBytes(byte[] bytes);
9+
int nextInt();
10+
int nextInt(int bound);
11+
long nextLong();
12+
boolean nextBoolean();
13+
float nextFloat();
14+
double nextDouble();
15+
}

0 commit comments

Comments
 (0)