Skip to content

Commit

Permalink
Use Java's modified ziggurat for case of SecureRandom (#323)
Browse files Browse the repository at this point in the history
* handle nextGaussian for SecureRandom

* Update CHANGELOG.md
  • Loading branch information
cicirello authored May 31, 2024
1 parent 2e25694 commit f4db821
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 19 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] - 2024-05-30
## [Unreleased] - 2024-05-31

### Added

### Changed
* Improved Gaussian random number generation from ThreadLocalRandom in methods of RandomVariates class (internal change).
* Improved Gaussian random number generation in static methods of RandomVariates to choose between internal implementation of original ziggurat algorithm (for Java legacy random number generators Random and SecureRandom) or the Java API implementation of the modified ziggurat for all others (internal change).
* Improved Gaussian random number generation in EnhancedRandomGenerator class to choose between internal implementation of original ziggurat algorithm (for Java legacy random number generators Random and SecureRandom) or the Java API implementation of the modified ziggurat for all others (internal change).
* Improved Gaussian random number generation in EnhancedRandomGenerator class to choose between internal implementation of original ziggurat algorithm (for Java legacy random number generator Random) or the Java API implementation of the modified ziggurat for all others (internal change).

### Deprecated

Expand Down
46 changes: 29 additions & 17 deletions src/main/java/org/cicirello/math/rand/EnhancedRandomGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/
package org.cicirello.math.rand;

import java.security.SecureRandom;
import java.util.List;
import java.util.Random;
import java.util.SplittableRandom;
Expand Down Expand Up @@ -1791,22 +1792,33 @@ public final long nextLong(long origin, long bound) {
* and only for nextGaussian. Do not try to use for anything else.
*/
static RandomGenerator internalGaussian(RandomGenerator generator) {
return new RandomGenerator() {
@Override
public long nextLong() {
throw new UnsupportedOperationException(
"This internal class is for use with Gaussians only. Something is implemented incorrectly.");
}

@Override
public double nextGaussian() {
return RandomVariates.nextGaussian(generator);
}

@Override
public double nextGaussian(double mean, double stdev) {
return RandomVariates.nextGaussian(mean, stdev, generator);
}
};
return generator instanceof SecureRandom
? new RandomGenerator() {
@Override
public long nextLong() {
// For SecureRandom, just delegate nextLong to SecureRandom.nextLong
// to gain access to Java's modified ziggurat for nextGaussian.
return generator.nextLong();
}
}
: new RandomGenerator() {
@Override
public long nextLong() {
throw new UnsupportedOperationException(
"This internal class is for use with Gaussians only. Something is implemented incorrectly.");
}

@Override
public double nextGaussian() {
// Use library's implementation of original ziggurat gaussian for Random class
return ZigguratGaussian.nextGaussian(generator);
}

@Override
public double nextGaussian(double mean, double stdev) {
// Use library's implementation of original ziggurat gaussian for Random class
return mean + stdev * ZigguratGaussian.nextGaussian(generator);
}
};
}
}
16 changes: 16 additions & 0 deletions src/test/java/org/cicirello/math/rand/ERGNonUniformTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import static org.junit.jupiter.api.Assertions.*;

import java.security.SecureRandom;
import java.util.Random;
import java.util.SplittableRandom;
import java.util.random.RandomGenerator;
Expand Down Expand Up @@ -211,6 +212,21 @@ public void testGaussianMeanStDevRandom() {
assertTrue(lesser > 0);
}

@Test
public void testGaussianSecureRandom() {
EnhancedRandomGenerator erg = new EnhancedRandomGenerator(new SecureRandom());
int positive = 0;
int negative = 0;
for (int i = 0; i < 20; i++) {
double g = erg.nextGaussian();
if (g > 0) positive++;
if (g < 0) negative++;
assertTrue(Math.abs(g) < 5.0);
}
assertTrue(positive > 0);
assertTrue(negative > 0);
}

@Test
public void testInternalGaussianRandom() {
RandomGenerator erg = EnhancedRandomGenerator.internalGaussian(new Random(42));
Expand Down

0 comments on commit f4db821

Please sign in to comment.