Skip to content

Commit

Permalink
0.6, formatting, tests removed from pub.dev
Browse files Browse the repository at this point in the history
  • Loading branch information
rtmigo committed Mar 21, 2021
1 parent 095c8e2 commit 22c599b
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 169 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 0.6.0

- Tests have been removed from the pub.dev package to reduce the size
of the library

- Updated documentation

# 0.5.1

- Aliases changed to Xrandom, Qrandom, Drandom
Expand Down
101 changes: 9 additions & 92 deletions lib/src/21_base32.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,42 +53,25 @@ abstract class RandomBase32 implements Random {
: combineUpper53bitsJS(nextRaw32(), nextRaw32());
}

/// Generates a non-negative random integer uniformly distributed in
/// the range from 0, inclusive, to [max], exclusive.
///
/// To make the distribution uniform, we use the so-called
/// [Debiased Modulo Once - Java Method](https://git.io/Jm0D7).
///
/// This implementation is slightly faster than the standard one for
/// all [max] values, except for [max], which are powers of two.
@override
int nextInt(int max) {
if (max < 1 || max > 0xFFFFFFFF) {
throw RangeError.range(max, 1, 0xFFFFFFFF);
}
int r = nextRaw32();
int m = max - 1;
for (int u = r; u - (r = u % max) + m < 0; u = nextRaw32()) {
// c'mon relax
}
for (int u = r; u - (r = u % max) + m < 0; u = nextRaw32()) {}
return r;
}

//
// REMARKS to 32's nextInt():
//
// The algorithm used by Dart SDK 2.12 (2021) <https://git.io/Jm0or> is
// very similar to JDK <https://git.io/Jm0Vc>.
//
// O'Neil <https://git.io/Jm0D7> calls it "Debiased Modulo (Once) —
// Java's Method" aka "Debiased Mod (x1)". Her sources contain attempts to
// optimize modulo division here. But these attempts were not even included
// in the article. I didn't do well either.
//
// Both JDK and Dart implementations have "a special treatment" for cases
// when [max] is a power of two. Dart uses this case for speed: it returns
// low-order bits without division. JDK uses this case to get high-order bits
// instead low-order bits (trying to fix LCG on the fly at least for some
// values:).
//
// As for now I removing the "special treatment" since I have doubts whether
// we need to add speed optimizations for only 31 numbers out of 2^32.
// I also have no idea how to take high-order bits fast, considering that
// the code is possibly running in 53-bit JavaScript.
//

/// Generates a random floating point value uniformly distributed
/// in the range from 0.0, inclusive, to 1.0, exclusive.
///
Expand All @@ -105,61 +88,11 @@ abstract class RandomBase32 implements Random {
return nextRaw32().uint32_to_int32() * M_RAN_INVM32 + 0.5;
}

//
// REMARKS to nextFloat():
//
// With 2.12.1 on AMD A9, there were no differences in the performance:
//
// | Time (lower is better) | nextFloat | nextFloatUint | nextFloatInline |
// |------------------------|-----------|---------------|-----------------|
// | Xorshift32 | 370 | 379 | 373 |
//
// nextFloat:
// x.uint32_to_int32()*M_RAN_INVM32 + 0.5;
// nextFloatInline:
// ( (x<=0x7fffffff)?x:(x-0x100000000) )*M_RAN_INVM32 + 0.5;
// nextFloatUint:
// const FACTOR = 1 / UINT32_MAX;
// return (x - 1) * FACTOR
//

@override
double nextDouble() {
return nextRaw32() * 2.3283064365386963e-10 + (nextRaw32() >> 12) * 2.220446049250313e-16;
}

//
// REMARKS to nextDouble():
//
// This method is a bit slower, than ((x>>>11)*0x1.0p-53),
// but it works in Node.js
//
// Vigna <https://prng.di.unimi.it/> suggests it like "аn alternative,
// multiplication-free conversion" of uint64_t to double like that:
//
// static inline double to_double(uint64_t x) {
// const union { uint64_t i; double d; } u
// = { .i = UINT64_C(0x3FF) << 52 | x >> 12 };
// return u.d - 1.0;
// }
//
// The same technique used in Chrome's JavaScript V8 <https://git.io/Jqpma>:
//
// static inline double ToDouble(uint64_t state0) {
// // Exponent for double values for [1.0 .. 2.0)
// static const uint64_t kExponentBits = uint64_t{0x3FF0000000000000};
// uint64_t random = (state0 >> 12) | kExponentBits;
// return bit_cast<double>(random) - 1;
// }
//
// Dart does not support typecasting of this kind.
//
// But here is how Madsen <https://git.io/JqWCP> does it in JavaScript:
// t2[0] * 2.3283064365386963e-10 + (t2[1] >>> 12) * 2.220446049250313e-16;
// or
// t2[0] * Math.pow(2, -32) + (t2[1] >>> 12) * Math.pow(2, -52);
//

@override
bool nextBool() {
// we're returning bits from higher to lower: like uint32s from int64s
Expand All @@ -180,20 +113,4 @@ abstract class RandomBase32 implements Random {

@internal
int boolCache_prevShift = 0;

//
// REMARKS to nextBool():
//
// in dart:math it is return nextInt(2) == 0;
// which is an equivalent of
// if ((2&-2)==2) return next()&(2-1);
//
// benchmarks 2021-03 with Xorshift32 (on Dell Seashell):
// Random (from dart:math) 2424
// XorShift32 return nextInt(2)==0 2136
// XorShift32 this.next() % 2 == 0 1903
// XorShift32 this.next() >= 0x80000000 1821
// XorShift32 returning bits 1423
//
//
}
63 changes: 21 additions & 42 deletions lib/src/21_base64.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ abstract class RandomBase64 extends RandomBase32 {
int nextRaw64();

/// Generates a non-negative random integer uniformly distributed in the range
/// from 0 to 0xFFFFFFFF, both inclusive.
/// from 0 to (2^32)-1, both inclusive.
///
/// The raw numbers generated by the algorithm are 64-bit. This method returns
/// the upper 32 bits, and then the lower 32 bits of the generated numbers.
Expand Down Expand Up @@ -48,56 +48,35 @@ abstract class RandomBase64 extends RandomBase32 {
bool _split64_charged = false;
int _split64 = 0;

//
// REMARKS to nextInt32:
//
// In 32-bit generators, to get an int64, we use te FIRST four bytes as
// the UPPER, and the NEXT as the LOWER parts of int64. It's just because
// most suggestions on the internet look like (rnd32()<<32)|rnd32().
// That is, we have a conveyor like this:
//
// F1( FFFF, LLLL, FFFF, LLLL ) -> FFFFLLLL, FFFFLLLL
//
// In 64-bit generators, to split an int64 to two 32-bit integers, we want
// the opposite, i.e.
//
// F2 ( FFFFLLLL, FFFFLLLL ) -> FFFF, LLLL, FFFF, LLLL
//
// So F1(F2(X))=X, F2(F1(Y))=Y.
//
// That's why we return highest bytes first, lowest bytes second
//


/// Generates a non-negative random floating point value uniformly distributed
/// in the range from 0.0, inclusive, to 1.0, exclusive.
///
/// To create this number, it takes a 64-bit integer from [nextRaw64] and uses
/// the highest 53 bits to fill in all the significant bits of the resulting [double].
///
/// By choosing the upper bits, we get rid of the lower bits, which is good.
/// The lower bits are not so unpredictably random on many generators.
///
/// This method is [recommended](https://prng.di.unimi.it/) by S. Vigna for
/// his Xorshift+ and Xoshiro family:
///
/// "(in C) 64-bit unsigned integer x should be converted to a 64-bit double using
/// the expression
/// (x >> 11) * 0x1.0p-53
/// In Java you can use almost the same expression for a (signed)
/// 64-bit integer:
/// (x >>> 11) * 0x1.0p-53"
@override
double nextDouble() {
// the result of printf("%.60e", 0x1.0p-53):
// Z is the C99's printf("%.60e", 0x1.0p-53):
const double Z = 1.110223024625156540423631668090820312500000000000000000000000e-16;

//_____(this.nextInt64()_>>>_11______________________)_*_0x1.0p-53
return ((this.nextRaw64() >> 11) & ~(-1 << (64 - 11))) * Z;

// This can be slightly optimized if instead of the most significant 53 bits,
// we are satisfied with 53 bits that are one bit lower. Then, instead of an
// unsigned shift (two operations), a bit mask (one operation) will suffice.
//
// But we don't do that for the sake of compatibility.
}

//
// REMARKS to nextDouble:
//
// we have a 64-bit integer to be converted to a float with only 53
// significant bits.
//
// Vigna (https://prng.di.unimi.it/):
// 64-bit unsigned integer x should be converted to a 64-bit double using
// the expression
// (x >> 11) * 0x1.0p-53
// In Java you can use almost the same expression for a (signed)
// 64-bit integer:
// (x >>> 11) * 0x1.0p-53
//

@override
bool nextBool() {
// we're returning bits from higher to lower
Expand Down
37 changes: 18 additions & 19 deletions lib/src/60_xorshift128plus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,26 @@ class Xorshift128p extends RandomBase64 {

late int _S0, _S1;

/// Implements algorithm from "Further scramblings of Marsaglia’s xorshift generators"
/// by Sebastiano Vigna.
///
/// There were at least two known versions of this algorithm.
///
/// With constants 23, 17, 26:
/// - in paper by Vigna <https://arxiv.org/pdf/1404.0390v1.pdf> - Apr 2014
/// - in JavaScript V8 engine <https://git.io/Jqpma>
/// - on Wikipedia <https://en.wikipedia.org/wiki/Xorshift> (2021)
///
/// With constants 23, 18, 5:
/// - in paper by Vigna https://arxiv.org/pdf/1404.0390v2.pdf - Dec 2015
/// - in paper by Vigna https://arxiv.org/pdf/1404.0390v3.pdf - May 2016
/// - in JavaScript xorshift library <https://git.io/JqWCP>
///
/// "the most recent set of constants according to the author of the algorithm are:
/// 23, 18, and 5. Those are theoretically better than the initial set of numbers"
/// <https://stackoverflow.com/a/34432126>
@override
int nextRaw64() {
// algorithm from "Further scramblings of Marsaglia’s xorshift generators"
// by Sebastiano Vigna
//
// https://arxiv.org/abs/1404.0390 [v2] Mon, 14 Dec 2015 - page 6
// https://arxiv.org/abs/1404.0390 [v3] Mon, 23 May 2016 - page 6

// There were at least two versions of the constants used in algorithm.
// 23, 17, 26
// - in paper by Vigna https://arxiv.org/pdf/1404.0390v1.pdf - Apr 2014
// - in JavaScript V8 engine https://git.io/Jqpma
// - on Wikipedia https://en.wikipedia.org/wiki/Xorshift
//
// 23, 18, 5
// - in paper by Vigna https://arxiv.org/pdf/1404.0390v2.pdf - Dec 2015
// - in JavaScript xorshift library <https://git.io/JqWCP>

// "the most recent set of constants according to the author of the algorithm are:
// 23, 18, and 5. Apparently it doesn't matter too much, but those are theoretically
// better than the initial set of numbers" <https://stackoverflow.com/a/34432126>

var s1 = _S0;
final s0 = _S1;
Expand Down
10 changes: 0 additions & 10 deletions lib/src/60_xoshiro128pp.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,6 @@ class Xoshiro128pp extends RandomBase32 {
return result & 0xFFFFFFFF;
}

// 3d1dc8a9 35bd9d36 387f1182 4eb8afb6
// 8e446f3a 3918f5f9 5c0a0b89 4a3a19c3
// 97382e38 f6a908dd abec010a 86797d7d
// 1f2f7252 ef22f9ba 342cf1c2 7152f3fe

// static const defaultSeedA = 0x8e446f3a;
// static const defaultSeedB = 0x3918f5f9;
// static const defaultSeedC = 0x5c0a0b89;
// static const defaultSeedD = 0x4a3a19c3;

static const defaultSeedA = 0x543f8723;
static const defaultSeedB = 0xb887dcb9;
static const defaultSeedC = 0xe97537a6;
Expand Down
2 changes: 0 additions & 2 deletions lib/src/60_xoshiro256pp.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class Xoshiro256pp extends RandomBase64 {

@override
int nextRaw64() {
// https://prng.di.unimi.it/xoshiro256plusplus.c

final result =
(((_S0 + _S3) << 23) | (((_S0 + _S3) >> (64 - 23)) & ~((-1 << (64 - (64 - 23)))))) + _S0;

Expand Down
3 changes: 0 additions & 3 deletions lib/xrandom.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: (c) 2021 Art Galkin <github.com/rtmigo>
// SPDX-License-Identifier: MIT


export 'src/21_base32.dart' show RandomBase32;
export 'src/21_base64.dart' show RandomBase64;
export 'src/50_splitmix64.dart' show Splitmix64;
Expand All @@ -13,5 +12,3 @@ export 'src/60_xorshift64.dart' show Xorshift64;
export 'src/60_xoshiro128pp.dart' show Xoshiro128pp;
export 'src/60_xoshiro256pp.dart' show Xoshiro256pp;
export 'src/90_aliases.dart' show Xrandom, Qrandom, Drandom;


1 change: 1 addition & 0 deletions pubpub.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ echo "$temp_pub_dir"
rsync -Rrv ./ "$temp_pub_dir" \
--exclude=".git" \
--exclude="pubpub.sh" \
--exclude="test/" \
--exclude="todo.txt" \
--exclude="benchmark/" \
--exclude="reference/" \
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: xrandom
description: "All-purpose, rock-solid random number generators
focused on the consistency and reproducibility"
version: 0.5.1
version: 0.6.0
homepage: https://github.com/rtmigo/xrandom

environment:
Expand Down

0 comments on commit 22c599b

Please sign in to comment.