Juniper
Java pseudo-random number generation code with minimal dependencies.
Install / Use
/learn @tommyettinger/JuniperREADME
juniper
Java pseudo-random number generation code with minimal dependencies.

JavaDocs
How to get it?
With Gradle, the dependency (of the core module, if you have multiple) is:
api "com.github.tommyettinger:juniper:0.10.2"
In a libGDX project that has a GWT/HTML backend, the html/build.gradle file
should additionally have:
implementation "com.github.tommyettinger:digital:0.10.0:sources"
implementation "com.github.tommyettinger:juniper:0.10.2:sources"
And the GdxDefinition.gwt.xml file should have:
<inherits name="com.github.tommyettinger.digital" />
<inherits name="com.github.tommyettinger.juniper" />
If you don't use Gradle, then with Maven, the dependency is:
<dependency>
<groupId>com.github.tommyettinger</groupId>
<artifactId>juniper</artifactId>
<version>0.10.2</version>
</dependency>
There are also releases here on GitHub if you don't use any project management tool. You will need to obtain digital as well, of the appropriate version for the juniper release you picked.
What is it?
Juniper provides a superset of the features of java.util.Random with an
EnhancedRandom abstract class and various concrete implementations. Some of
these implementations are well-known algorithms, such as RomuTrioRandom and
Xoshiro256StarStarRandom, but most are essentially new here. All of them
have been tested with PractRand and pass at least a 64TB battery of tests
without any anomalies considered worse than "unusual". Many have also undergone
additional, significantly-more-strenuous testing on the GPU, and the generators
that fail that testing only do so after at least 100PB of data is generated.
This library is compatible with Java 8 language level and higher. It uses only language features from Java 8, and does not need any APIs introduced in Java 8. This should allow it to be used on Android, GWT, and RoboVM. Some extremely out-of-date versions of Android may not be compatible with Java 8 even with core library desugaring; Google is dropping support for older Android versions and developers should follow suit. RoboVM has always had support for language level 8, but in the main branch has never supported Java 8 APIs (not a problem here). GWT has had support for Java 8 in some form since the 2.8.x line of releases; using 2.11.0 or higher is recommended because it improves on this support. Most of these are made at least a little easier by using gdx-liftoff to generate projects (assuming you are making a libGDX app or game), since gdx-liftoff handles core library desugaring on Android and uses GWT 2.11.0 by default.
You can preview what some distributions look like on this page. It uses libGDX to compile to a webpage while still working if run as a desktop application, and several parts of this library have been tailored to fit as many libGDX target platforms as possible.
The name comes from my dog Juniper, who appears to have a deterministic, but seemingly-random, response to any new person she meets.
What are these generators?
tl;dr: You should use com.github.tommyettinger.random.AceRandom if you want the highest speed and the highest quality
over a long sequence of outputs from one generator. You can instead use com.github.tommyettinger.random.DistinctRandom
if you want one state that gets fully randomized from the first output, or com.github.tommyettinger.random.FlowRandom
if you want the same idea as DistinctRandom but have two states that you want to use like inputs to a hash, or you want
multiple approximately-independent streams. All of these have a period of at least 2 to the 64, which is probably enough
for any game and many non-game tasks. If you target GWT, you should generally use
com.github.tommyettinger.random.ChopRandom, since it is much faster on GWT than other generators here, and only
slightly slower on desktop platforms.
Several high-quality and very-fast random number generators are here, such as
com.github.tommyettinger.random.PouchRandom, com.github.tommyettinger.random.WhiskerRandom,
com.github.tommyettinger.random.FlowRandom, com.github.tommyettinger.random.DistinctRandom,
com.github.tommyettinger.random.AceRandom, and com.github.tommyettinger.random.PasarRandom. These extend
the abstract class com.github.tommyettinger.random.EnhancedRandom, and that extends java.util.Random for
compatibility.
The simplest starting point is DistinctRandom; it is much like Java 8's SplittableRandom algorithm, but doesn't support
splitting (since the possibility of low-quality splits is a major criticism of SplittableRandom), and otherwise uses the
same style of code. It simply adds to a counter by a large constant, takes the current value of that counter, gets a
unary hash of it using a similar algorithm to MurmurHash's finalizer step, and returns that. "Unary hash" is another way
of saying "a function that takes an n-bit input and transforms it into a random-seeming n-bit output." The
main reasons you might want DistinctRandom are that it has exactly one long of state, and that it produces every
possible output from nextLong() exactly once over its cycle, with no repeats until potentially years later.
DistinctRandom is able to jump to any point in its cycle, which has a length of exactly 2 to the 64, in constant time
using the skip() method.
This ability to skip is also shared by FlowRandom, but FlowRandom has many possible cycles (2 to the 64 possible cycles,
each with 2 to the 64 long outputs) called streams. FlowRandom is very similar to DistinctRandom in most ways, except
that it has two long states that each cycle with the same period. The relationship between the states is what
determines the current stream, and you can access a FlowRandom's stream with getStream() or change it with
setStream() or shiftStream(). Streams here are not correlated at all, as far as I have been able to determine.
FlowRandom isn't as fast as some other generators here that have streams (such as LaserRandom), but it seems to be much
more robust statistically when its stream changes. Unlike DistinctRandom, a given stream can produce the same result
more than once, and will generally be unable to produce roughly 1/3 of possible long outputs. All possible streams, if
concatenated, would include every long result exactly 2 to the 64 times each. Concatenating all possible streams is,
roughly, how OrbitalRandom works; its code is almost identical to FlowRandom's, but it has one cycle of 2 to the 128
long outputs, at a small speed cost.
AceRandom is the main recommended generator, this time with 5 states. It is the fastest generator here when benchmarked on Java 17 and newer. One state is a counter, which makes AceRandom have a minimum period of 2 to the 64, though its maximum period is much, much higher and its expected period is much higher than I could reach by brute-force generation with current hardware given a century. Ace uses only add, rotate, XOR, and subtract operations. These operations each take the same amount of time on current CPUs, a property that some cryptographic RNGs use to avoid timing attacks. AceRandom is a good all-around default because it resists various ways generators can be constructed so they are correlated with each other; it is also almost always faster than PouchRandom, and much faster than FlowRandom.
WhiskerRandom is often considerably faster than DistinctRandom (which is no slouch either), and generally has very high
quality, but does not have a guaranteed cycle length -- a given seed could be found that has an unusually short cycle,
which would reduce the usefulness of the generator. But, finding such a seed at random is so improbable for a generator
with 256 bits of state that it can essentially be ignored as a weakness unless considering adversarial access (and you
should not use any of the generators here if that is the case, since none are cryptographically secure). A known
potential flaw of WhiskerRandom (and many generators tested so far) is that generators with numerically similar initial
states, such as with a generator initially set to the state 1, 1, 1, 1 and another generator set to 2, 1, 1, 1,
are very often highly correlated. This isn't a problem if you use setSeed(), since it won't produce numerically
similar states often (or possibly won't at all), but can be a problem if you try to use a WhiskerRandom as a hash.
PouchRandom is the fastest generator here when benchmarked on Java 8; it acts like WhiskerRandom but has a guaranteed minimum cycle length of 2 to the 63 (as long as it isn't somehow forced into an invalid state, which its own methods cannot do). While it disallows certain states (state D has to be an odd number, and the other states can't all be 0 at once), if that isn't a problem for your application, it is probably a solid choice. After producing about 25 outputs, numerically similar initial states won't appear correlated, and shouldn't become correlated again for a very long time. It has 4 states and uses multiplication (in this case, it multiplies one state by another, always odd, state).
There's lots of others here. TrimRandom, PasarRandom, ScruffRandom are all good but have the same or similar known flaw that WhiskerRandom has regarding numerically-similar initial states. TricycleRandom and FourWheelRandom don't have that flaw, but aren't quite as fast or high-quality as AceRandom or PouchRandom.
Except for DistinctRandom and FlowRandom, all of these mentioned generators are fast because they are designed to take advantage of ILP -- Instruction Level Parallelism. The idea here came from Mark Overton's Romu generators (see below for RomuTrioRandom), which also have their period sep
Related Skills
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.2kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
