xrandom 0.4.0 xrandom: ^0.4.0 copied to clipboard
All-purpose, rock-solid random number generators focused on the reproducibility of tests on different platforms
xrandom #
Classes implementing all-purpose, rock-solid random number generators.
Library priorities:
- generation of identical bit-accurate numbers regardless of the platform
- reproducibility of the same random results in the future
- high-quality randomness
- performance
Algorithms are Xoshiro for quality and Xorshift for speed.
Speed #
Generating 50 million random numbers with AOT-compiled binary.
Time (lower is better) | nextInt | nextDouble | nextBool |
---|---|---|---|
Random (dart:math) | 1172 | 1541 | 1134 |
Xrandom | 719 | 1126 | 710 |
Simplicity #
It's compatible with the standard Random
import 'package:xrandom/xrandom.dart';
final random = Xrandom();
var a = random.nextBool();
var b = random.nextDouble();
var c = random.nextInt(n);
var unordered = [1, 2, 3, 4, 5]..shuffle(random);
Reproducibility #
Xrandom's classes can also be created with expected
method.
It is made specifically for testing.
test('my test', () {
final random = Xrandom.expected();
// you'll get same sequence of numbers every time
expect(random.nextInt(1000), 925);
expect(random.nextInt(1000), 686);
expect(random.nextInt(1000), 509);
});
You can achieve the same determinism by creating the Random
with a seed
argument. However, this does
not protect you from the dart:math implementation updates.
The sequences produced by the expected()
generators are intended to be reproducible.
(but not until the library reaches stable release status)
Which to choose #
If you just want a random number:
final random = Xrandom(); // works on all platforms
quoteOfTheDay = quotes[ random.nextInt(quotes.length) ];
Xrandom
is fast and works everywhere.
If you need billions and billions of randoms in a non-repeating sequence:
final random = XrandomHq(); // works on mobile and desktop
for (var i=0; i<BILLIONS; i++)
feedMonteCarloSimulation( random.nextDouble() );
XrandomHq
is high quality and expected to be run on modern platforms.
That is, on desktops, phones and tablets. But not JavaScript.
If you tried to create XrandomHq
on Node.js but got UnsupportedError
:
final random = XrandomHqJs(); // works on all platforms
for (var i=0; i<BILLIONS; i++)
feedMonteCarloSimulation( random.nextDouble() ); // on JS? O_O
XrandomHqJs
is slightly less high quality, but works everywhere.
Features #
The Xrandom classes has additions compared to the system Random
.
Xrandom.nextFloat() #
nextFloat
generates a floating-point value in range 0.0≤x<1.0.
Unlike the nextDouble
, nextFloat
prefers speed to precision.
It's still a double
that has four billion shades, but it's much faster.
Benchmarks
Time (lower is better) | nextDouble | nextFloat |
---|---|---|
Random (dart:math) | 1653 | - |
Xorshift32 | 1126 | 407 |
Xorshift64 | 1011 | 825 |
Xorshift128 | 1461 | 622 |
Xorshift128p | 1141 | 860 |
Xoshiro128pp | 2095 | 923 |
Xoshiro256pp | 2294 | 1488 |
Splitmix64 | 1098 | 932 |
Xrandom.nextInt32() and Xrandom.nextInt64() #
These methods return the raw output of the generator. Depending on the algorithm, the output is a number consisting of either 32 random bits or 64 random bits.
Xrandom automatically concatenates 32-bit numbers into 64-bit ones,
and vice versa. Therefore, both methods work for all classes.
In general, this is much faster than nextInt
.
Method | Returns | Equivalent of |
---|---|---|
nextInt32() |
32-bit unsigned | nextInt(0xFFFFFFFE)+1 |
nextInt64() |
64-bit signed | nextInt(0xFFFFFFFFFFFFFFFE)+1 |
However, in JavaScript, integers are limited to 53 bits. So only nextInt32()
works there.
Benchmarks
Time (lower is better) | nextInt | nextInt32 | nextInt64 |
---|---|---|---|
Random (dart:math) | 1208 | - | - |
Xorshift32 | 719 | 409 | - |
Xorshift64 | 1114 | 814 | 838 |
Xorshift128 | 907 | 618 | - |
Xorshift128p | 1162 | 854 | 952 |
Xoshiro128pp | 1228 | 912 | - |
Xoshiro256pp | 1746 | 1498 | 2039 |
Splitmix64 | 1248 | 931 | 782 |
Algorithms #
Class | Arch | Algorithm | Algorithm author | Published |
---|---|---|---|---|
Xorshift32 |
32 | xorshift32 | G. Marsaglia | 2003 |
Xorshift64 |
64 | xorshift64 | G. Marsaglia | 2003 |
Xorshift128 |
32 | xorshift128 | G. Marsaglia | 2003 |
Xorshift128p |
64 | xorshift128+ v2 | S. Vigna | 2015 |
Xoshiro128pp |
32 | xoshiro128++ 1.0 | D. Blackman and S. Vigna | 2019 |
Xoshiro256pp |
64 | xoshiro256++ 1.0 | D. Blackman and S. Vigna | 2019 |
Splitmix64 |
64 | splitmix64 | S. Vigna | 2015 |
Class | The same as | Mobile | Desktop | JS |
---|---|---|---|---|
Xrandom |
Xorshift32 |
✓ | ✓ | ✓ |
XrandomHq |
Xoshiro256pp |
✓ | ✓ | ✗ |
XrandomHqJs |
Xoshiro128pp |
✓ | ✓ | ✓ |
Xrandom
, XrandomHq
, XrandomHqJs
are easy-to-remember aliases.
Compatibility #
You can safely use any classes on mobile and desktop platforms.
However, if you also target JavaScript (Web, Node.js), you will have to limit your choice.
Full compatibility table:
Class | Is a | Mobile | Desktop | JavaScript |
---|---|---|---|---|
Xorshift32 |
32-bit | ✓ | ✓ | ✓ |
Xorshift128 |
32-bit | ✓ | ✓ | ✓ |
Xoshiro128pp |
32-bit | ✓ | ✓ | ✓ |
Xorshift64 |
64-bit | ✓ | ✓ | ✗ |
Xorshift128p |
64-bit | ✓ | ✓ | ✗ |
Xoshiro256pp |
64-bit | ✓ | ✓ | ✗ |
Splitmix64 |
64-bit | ✓ | ✓ | ✗ |
If you try to create a JavaScript-incompatible object in JavaScripts-compiled
code, an UnsupportedError
will be thrown.
More benchmarks #
Time (lower is better) | nextInt | nextDouble | nextBool |
---|---|---|---|
Random (dart:math) | 1208 | 1653 | 1177 |
Xorshift32 | 719 | 1126 | 710 |
Xorshift64 | 1114 | 1011 | 685 |
Xorshift128 | 907 | 1461 | 719 |
Xorshift128p | 1162 | 1141 | 694 |
Xoshiro128pp | 1228 | 2095 | 726 |
Xoshiro256pp | 1746 | 2294 | 721 |
Splitmix64 | 1248 | 1098 | 688 |
All the benchmarks on this page are from AOT-compiled binaries running on AMD A9-9420e with Ubuntu 20.04. Time is measured in milliseconds.
Consistency #
The library has been thoroughly tested to match reference numbers generated by C algorithms. The sources in C are taken directly from scientific publications or the reference implementations by the inventors of the algorithms. The Xorshift128+ results are also matched to reference values from JavaScript xorshift library, which tested the 128+ similarly.
Testing is done in the GitHub Actions cloud on Windows, Ubuntu, and macOS in VM and Node.js modes.