Skip to content

Commit 3d4340c

Browse files
committed
rand -> rand_xoshiro for better reproducibility across archs
1 parent d138e8d commit 3d4340c

File tree

7 files changed

+53
-19
lines changed

7 files changed

+53
-19
lines changed

Cargo.lock

Lines changed: 19 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ js-sys = "0.3.69"
3333
leptos = "0.6.11"
3434
leptos_meta = {version = "0.6.11", features = ["csr"]}
3535
leptos_router = {version = "0.6.11", features = ["csr"]}
36-
rand = {version = "0.8.5", features = ["small_rng"]}
3736
serde = {version = "1", features = ["derive"]}
3837
serde_json = "1.0.115"
3938
unicode-segmentation = "1.10"
4039
urlencoding = "2"
40+
rand_xoshiro = "0.7.0"
4141
# NOTE: if you change the wasm-bindgen version, remember to change it in nix/site.nix as well
4242
wasm-bindgen = "=0.2.93"
4343

@@ -103,7 +103,6 @@ open = {version = "5", optional = true}
103103
parking_lot = "0.12.1"
104104
paste = "1.0.14"
105105
pathdiff = "0.2.1"
106-
rand.workspace = true
107106
rawrrr = {version = "0.2.1", optional = true}
108107
rayon = "1.9.0"
109108
regex = "1.10.3"
@@ -180,6 +179,7 @@ web-sys = {version = "0.3.60", optional = true}
180179
eframe = {version = "0.29.1", optional = true, features = ["persistence"]}
181180
native-dialog = {version = "0.7.0", optional = true}
182181
rmp-serde = {version = "1.3.0", optional = true}
182+
rand_xoshiro = "0.7.0"
183183

184184
[features]
185185
apng = ["dep:png"]

site/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ js-sys.workspace = true
2020
leptos.workspace = true
2121
leptos_meta.workspace = true
2222
leptos_router.workspace = true
23-
rand.workspace = true
23+
rand_xoshiro.workspace = true
2424
serde.workspace = true
2525
serde_json.workspace = true
2626
urlencoding.workspace = true

src/algorithm/dyadic/mod.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ use std::{
1515

1616
use bytemuck::allocation::cast_vec;
1717
use ecow::{eco_vec, EcoVec};
18-
use rand::prelude::*;
18+
use rand_xoshiro::{
19+
rand_core::{RngCore, SeedableRng},
20+
Xoshiro256Plus,
21+
};
22+
1923
#[cfg(not(target_arch = "wasm32"))]
2024
use rayon::prelude::*;
2125
use smallvec::SmallVec;
@@ -2110,7 +2114,7 @@ impl Value {
21102114
let mut hasher = DefaultHasher::new();
21112115
seed.hash(&mut hasher);
21122116
let seed = hasher.finish();
2113-
let mut rng = SmallRng::seed_from_u64(seed);
2117+
let mut rng = Xoshiro256Plus::seed_from_u64(seed);
21142118

21152119
const SHAPE_REQ: &str = "Shape must be an array of natural \
21162120
numbers with at most rank 2";
@@ -2120,7 +2124,7 @@ impl Value {
21202124
let elem_count = validate_size::<f64>(shape.iter().copied(), env)?;
21212125
let mut data = eco_vec![0.0; elem_count];
21222126
for x in data.make_mut() {
2123-
*x = rng.gen();
2127+
*x = f64::from_bits(rng.next_u64());
21242128
}
21252129
Ok(Array::new(shape, data))
21262130
};
@@ -2166,7 +2170,15 @@ impl Value {
21662170
0 => Err(env.error("Cannot pick random row of an empty array").fill()),
21672171
1 => Ok(self.row(0)),
21682172
len => {
2169-
let i = RNG.with_borrow_mut(|rng| rng.gen_range(0..len));
2173+
let i = RNG.with_borrow_mut(|rng| {
2174+
let upper = len.next_power_of_two();
2175+
loop {
2176+
let r = rng.next_u64() as usize;
2177+
if r % upper < len {
2178+
break len;
2179+
}
2180+
}
2181+
});
21702182
Ok(self.row(i))
21712183
}
21722184
}

src/algorithm/monadic/sort.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use std::{cmp::Ordering, ptr};
22

33
use ecow::EcoVec;
4-
use rand::Rng;
4+
use rand_xoshiro::rand_core::SeedableRng;
5+
use rand_xoshiro::Xoshiro256Plus;
56
use rayon::prelude::*;
67

78
use crate::{algorithm::ArrayCmpSlice, random_with, val_as_arr, Array, ArrayValue, Value};

src/constant.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ use std::{
55
};
66

77
use ecow::EcoVec;
8-
use rand::prelude::*;
8+
use rand_xoshiro::rand_core::SeedableRng;
9+
use rand_xoshiro::Xoshiro256Plus;
910

1011
use crate::{
1112
parse_doc_line_fragments, Array, Boxed, PrimDocFragment, SysBackend, Value, WILDCARD_NAN,
@@ -463,7 +464,7 @@ fn music_constant(backend: &dyn SysBackend) -> Value {
463464
hat_mask.push((hat_bits & 1) as f64);
464465
hat_bits >>= 1;
465466
}
466-
let mut rng = SmallRng::seed_from_u64(0);
467+
let mut rng = Xoshiro256Plus::seed_from_u64(0);
467468
let sr = backend.audio_sample_rate();
468469
(0..(BEAT * 2.0 * 16.0 * sr as f64) as usize)
469470
.map(|s| {

src/run_prim.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@ use std::{
1414
collections::HashMap,
1515
f64::consts::{PI, TAU},
1616
iter::repeat_n,
17+
mem::transmute,
1718
sync::{
1819
atomic::{self, AtomicUsize},
1920
OnceLock,
2021
},
22+
time::{SystemTime, UNIX_EPOCH},
2123
};
2224

23-
use rand::prelude::*;
25+
use rand_xoshiro::{
26+
rand_core::{RngCore, SeedableRng},
27+
Xoshiro256Plus,
28+
};
2429

2530
use crate::{
2631
algorithm::{self, ga::GaOp, loops, reduce, table, zip, *},
@@ -1769,22 +1774,22 @@ fn undo_regex(env: &mut Uiua) -> UiuaResult {
17691774
}
17701775

17711776
thread_local! {
1772-
pub(crate) static RNG: RefCell<SmallRng> = RefCell::new(SmallRng::from_entropy());
1777+
pub(crate) static RNG: RefCell<Xoshiro256Plus> = RefCell::new(Xoshiro256Plus::from_seed(transmute(SystemTime::now().saturating_duration_since(UNIX_EPOCH).as_micros())));
17731778
}
17741779

17751780
/// Generate a random number, equivalent to [`Primitive::Rand`]
17761781
pub fn random() -> f64 {
1777-
random_with(|rng| rng.gen())
1782+
random_with(|rng| f64::from_bits(rng.next_u64()))
17781783
}
17791784

17801785
/// Access the interpreter's random number generator for the thread
1781-
pub fn random_with<T>(f: impl FnOnce(&mut SmallRng) -> T) -> T {
1786+
pub fn random_with<T>(f: impl FnOnce(&mut Xoshiro256Plus) -> T) -> T {
17821787
RNG.with(|rng| f(&mut rng.borrow_mut()))
17831788
}
17841789

17851790
/// Seed the random number generator
17861791
pub fn seed_random(seed: u64) {
1787-
random_with(|rng| *rng = SmallRng::seed_from_u64(seed));
1792+
random_with(|rng| *rng = Xoshiro256Plus::seed_from_u64(seed));
17881793
}
17891794

17901795
fn stack_n(env: &mut Uiua, n: usize, inverse: bool) -> UiuaResult {

0 commit comments

Comments
 (0)